1use crate::Error;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
10#[repr(u8)]
11pub enum CsActiveByte {
12 #[default]
13 Low = 0,
14 High = 1,
15}
16
17impl CsActiveByte {
18 pub fn from_byte(byte: u8) -> Result<Self, Error> {
19 match byte {
20 0 => Ok(CsActiveByte::Low),
21 1 => Ok(CsActiveByte::High),
22 _ => Err(Error::ParseError),
23 }
24 }
25
26 pub fn to_byte(&self) -> u8 {
27 *self as u8
28 }
29}
30
31impl From<CsActive> for CsActiveByte {
32 fn from(cs: CsActive) -> Self {
33 match cs {
34 CsActive::Low => CsActiveByte::Low,
35 CsActive::High => CsActiveByte::High,
36 }
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
42pub enum CsActive {
43 #[allow(dead_code)]
44 High,
45
46 #[default]
47 Low,
48}
49
50impl core::fmt::Display for CsActive {
51 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
52 match self {
53 CsActive::High => write!(f, "Active High"),
54 CsActive::Low => write!(f, "Active Low"),
55 }
56 }
57}
58
59impl From<CsActiveByte> for CsActive {
60 fn from(byte: CsActiveByte) -> Self {
61 match byte {
62 CsActiveByte::Low => CsActive::Low,
63 CsActiveByte::High => CsActive::High,
64 }
65 }
66}
67
68impl CsActive {
69 fn bit(&self) -> usize {
70 match self {
71 CsActive::High => 1,
72 CsActive::Low => 0,
73 }
74 }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
78#[repr(u8)]
79pub enum RomTypeByte {
80 Type2364 = 0x00,
81 Type2332 = 0x01,
82 Type2316 = 0x02,
83}
84
85impl RomTypeByte {
86 pub fn from_byte(byte: u8) -> Result<Self, Error> {
87 match byte {
88 0x00 => Ok(RomTypeByte::Type2364),
89 0x01 => Ok(RomTypeByte::Type2332),
90 0x02 => Ok(RomTypeByte::Type2316),
91 _ => Err(Error::ParseError),
92 }
93 }
94
95 pub fn to_byte(&self) -> u8 {
96 *self as u8
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
103pub enum RomType {
104 Type2364 { cs: CsActive },
106
107 Type2332 { cs1: CsActive, cs2: CsActive },
109
110 Type2316 {
112 cs1: CsActive,
113 cs2: CsActive,
114 cs3: CsActive,
115 },
116}
117
118impl core::fmt::Display for RomType {
119 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120 write!(f, "{} ({})", self.type_str(), self.cs_str())
121 }
122}
123
124impl RomType {
125 const CS_2364_ADDR: usize = 13;
126 const CS1_2332_ADDR: usize = 13;
127 const CS2_2332_ADDR: usize = 12;
128 const CS1_2316_ADDR: usize = 13;
129 const CS2_2316_ADDR: usize = 11;
130 const CS3_2316_ADDR: usize = 12;
131
132 pub const fn max_size() -> usize {
134 8192
135 }
136
137 pub const fn size(&self) -> usize {
139 match self {
140 RomType::Type2364 { .. } => 8192,
141 RomType::Type2332 { .. } => 4096,
142 RomType::Type2316 { .. } => 2048,
143 }
144 }
145
146 pub fn cs_active_mask(&self) -> usize {
148 match self {
149 RomType::Type2364 { cs } => cs.bit() << Self::CS_2364_ADDR,
150 RomType::Type2332 { cs1, cs2 } => {
151 cs1.bit() << Self::CS1_2332_ADDR | cs2.bit() << Self::CS2_2332_ADDR
152 }
153 RomType::Type2316 { cs1, cs2, cs3 } => {
154 cs1.bit() << Self::CS1_2316_ADDR
155 | cs2.bit() << Self::CS2_2316_ADDR
156 | cs3.bit() << Self::CS3_2316_ADDR
157 }
158 }
159 }
160
161 pub const fn all() -> &'static [RomType] {
163 &ALL_ROM_TYPES
164 }
165
166 pub const fn type_str(&self) -> &'static str {
167 match self {
168 RomType::Type2364 { .. } => "2364",
169 RomType::Type2332 { .. } => "2332",
170 RomType::Type2316 { .. } => "2316",
171 }
172 }
173
174 pub const fn cs_str(&self) -> &'static str {
175 match self {
176 RomType::Type2364 { cs } => match cs {
177 CsActive::Low => "CS Low",
178 CsActive::High => "CS High",
179 },
180 RomType::Type2332 { cs1, cs2 } => match (cs1, cs2) {
181 (CsActive::Low, CsActive::Low) => "CS1 Low, CS2 Low",
182 (CsActive::Low, CsActive::High) => "CS1 Low, CS2 High",
183 (CsActive::High, CsActive::Low) => "CS1 High, CS2 Low",
184 (CsActive::High, CsActive::High) => "CS1 High, CS2 High",
185 },
186 RomType::Type2316 { cs1, cs2, cs3 } => match (cs1, cs2, cs3) {
187 (CsActive::Low, CsActive::Low, CsActive::Low) => "CS1 Low, CS2 Low, CS3 Low",
188 (CsActive::Low, CsActive::Low, CsActive::High) => "CS1 Low, CS2 Low, CS3 High",
189 (CsActive::Low, CsActive::High, CsActive::Low) => "CS1 Low, CS2 High, CS3 Low",
190 (CsActive::Low, CsActive::High, CsActive::High) => "CS1 Low, CS2 High, CS3 High",
191 (CsActive::High, CsActive::Low, CsActive::Low) => "CS1 High, CS2 Low, CS3 Low",
192 (CsActive::High, CsActive::Low, CsActive::High) => "CS1 High, CS2 Low, CS3 High",
193 (CsActive::High, CsActive::High, CsActive::Low) => "CS1 High, CS2 High, CS3 Low",
194 (CsActive::High, CsActive::High, CsActive::High) => "CS1 High, CS2 High, CS3 High",
195 },
196 }
197 }
198
199 pub const fn binary_size() -> usize {
201 4
202 }
203
204 pub fn from_bytes(buf: &[u8]) -> Result<Self, Error> {
206 if buf.len() < Self::binary_size() {
207 return Err(Error::ParseError);
208 }
209 match RomTypeByte::from_byte(buf[0])? {
210 RomTypeByte::Type2364 => {
211 let cs = CsActiveByte::from_byte(buf[1])?.into();
212 Ok(RomType::Type2364 { cs })
213 }
214 RomTypeByte::Type2332 => {
215 let cs1 = CsActiveByte::from_byte(buf[1])?.into();
216 let cs2 = CsActiveByte::from_byte(buf[2])?.into();
217 Ok(RomType::Type2332 { cs1, cs2 })
218 }
219 RomTypeByte::Type2316 => {
220 let cs1 = CsActiveByte::from_byte(buf[1])?.into();
221 let cs2 = CsActiveByte::from_byte(buf[2])?.into();
222 let cs3 = CsActiveByte::from_byte(buf[3])?.into();
223 Ok(RomType::Type2316 { cs1, cs2, cs3 })
224 }
225 }
226 }
227
228 pub fn to_bytes(&self, buf: &mut [u8]) -> Result<(), Error> {
230 if buf.len() < Self::binary_size() {
231 return Err(Error::ParseError);
232 }
233 match self {
234 RomType::Type2364 { cs } => {
235 buf[0] = RomTypeByte::Type2364.to_byte();
236 buf[1] = CsActiveByte::from(*cs).to_byte();
237 buf[2] = 0;
238 buf[3] = 0;
239 }
240 RomType::Type2332 { cs1, cs2 } => {
241 buf[0] = RomTypeByte::Type2332.to_byte();
242 buf[1] = CsActiveByte::from(*cs1).to_byte();
243 buf[2] = CsActiveByte::from(*cs2).to_byte();
244 buf[3] = 0;
245 }
246 RomType::Type2316 { cs1, cs2, cs3 } => {
247 buf[0] = RomTypeByte::Type2316.to_byte();
248 buf[1] = CsActiveByte::from(*cs1).to_byte();
249 buf[2] = CsActiveByte::from(*cs2).to_byte();
250 buf[3] = CsActiveByte::from(*cs3).to_byte();
251 }
252 }
253 Ok(())
254 }
255}
256
257const NUM_ROM_TYPES: usize = 14;
259const ALL_ROM_TYPES: [RomType; NUM_ROM_TYPES] = [
260 RomType::Type2364 { cs: CsActive::Low },
261 RomType::Type2364 { cs: CsActive::High },
262 RomType::Type2332 {
263 cs1: CsActive::Low,
264 cs2: CsActive::Low,
265 },
266 RomType::Type2332 {
267 cs1: CsActive::Low,
268 cs2: CsActive::High,
269 },
270 RomType::Type2332 {
271 cs1: CsActive::High,
272 cs2: CsActive::Low,
273 },
274 RomType::Type2332 {
275 cs1: CsActive::High,
276 cs2: CsActive::High,
277 },
278 RomType::Type2316 {
279 cs1: CsActive::Low,
280 cs2: CsActive::Low,
281 cs3: CsActive::Low,
282 },
283 RomType::Type2316 {
284 cs1: CsActive::Low,
285 cs2: CsActive::Low,
286 cs3: CsActive::High,
287 },
288 RomType::Type2316 {
289 cs1: CsActive::Low,
290 cs2: CsActive::High,
291 cs3: CsActive::Low,
292 },
293 RomType::Type2316 {
294 cs1: CsActive::Low,
295 cs2: CsActive::High,
296 cs3: CsActive::High,
297 },
298 RomType::Type2316 {
299 cs1: CsActive::High,
300 cs2: CsActive::Low,
301 cs3: CsActive::Low,
302 },
303 RomType::Type2316 {
304 cs1: CsActive::High,
305 cs2: CsActive::Low,
306 cs3: CsActive::High,
307 },
308 RomType::Type2316 {
309 cs1: CsActive::High,
310 cs2: CsActive::High,
311 cs3: CsActive::Low,
312 },
313 RomType::Type2316 {
314 cs1: CsActive::High,
315 cs2: CsActive::High,
316 cs3: CsActive::High,
317 },
318];