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 Type23128 = 0x03,
84 Type27512 = 0x04,
85}
86
87impl RomTypeByte {
88 pub fn from_byte(byte: u8) -> Result<Self, Error> {
89 match byte {
90 0x00 => Ok(RomTypeByte::Type2364),
91 0x01 => Ok(RomTypeByte::Type2332),
92 0x02 => Ok(RomTypeByte::Type2316),
93 0x03 => Ok(RomTypeByte::Type23128),
94 0x04 => Ok(RomTypeByte::Type27512),
95 _ => Err(Error::ParseError),
96 }
97 }
98
99 pub fn to_byte(&self) -> u8 {
100 *self as u8
101 }
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
107pub enum RomType {
108 Type27512,
110
111 Type23128 {
113 cs1: CsActive,
114 cs2: CsActive,
115 cs3: CsActive,
116 },
117
118 Type2364 { cs: CsActive },
120
121 Type2332 { cs1: CsActive, cs2: CsActive },
123
124 Type2316 {
126 cs1: CsActive,
127 cs2: CsActive,
128 cs3: CsActive,
129 },
130}
131
132impl core::fmt::Display for RomType {
133 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134 write!(f, "{} ({})", self.type_str(), self.cs_str())
135 }
136}
137
138impl RomType {
139 const CS1_23128_ADDR: usize = 17;
140 const CS2_23128_ADDR: usize = 16;
141 const CS3_23128_ADDR: usize = 14;
142 const CS_2364_ADDR: usize = 13;
143 const CS1_2332_ADDR: usize = 13;
144 const CS2_2332_ADDR: usize = 12;
145 const CS1_2316_ADDR: usize = 13;
146 const CS2_2316_ADDR: usize = 11;
147 const CS3_2316_ADDR: usize = 12;
148
149 pub const fn max_size() -> usize {
151 65536
152 }
153
154 pub const fn size(&self) -> usize {
156 match self {
157 RomType::Type27512 => 65536,
158 RomType::Type23128 { .. } => 16384,
159 RomType::Type2364 { .. } => 8192,
160 RomType::Type2332 { .. } => 4096,
161 RomType::Type2316 { .. } => 2048,
162 }
163 }
164
165 pub const fn rom_pins(&self) -> usize {
167 match self {
168 RomType::Type27512 => 28,
169 RomType::Type23128 { .. } => 28,
170 RomType::Type2364 { .. } => 24,
171 RomType::Type2332 { .. } => 24,
172 RomType::Type2316 { .. } => 24,
173 }
174 }
175
176 pub const fn invalid_addr_lines(&self) -> &'static [u8] {
177 match self {
178 RomType::Type27512 => &[],
179 RomType::Type23128 { .. } => &[15],
180 RomType::Type2364 { .. } => &[],
181 RomType::Type2332 { .. } => &[],
182 RomType::Type2316 { .. } => &[],
183 }
184 }
185
186 pub fn cs_active_mask(&self) -> usize {
188 match self {
189 RomType::Type27512 => 0,
190 RomType::Type23128 { cs1, cs2, cs3 } => {
191 cs1.bit() << Self::CS1_23128_ADDR
192 | cs2.bit() << Self::CS2_23128_ADDR
193 | cs3.bit() << Self::CS3_23128_ADDR
194 }
195 RomType::Type2364 { cs } => cs.bit() << Self::CS_2364_ADDR,
196 RomType::Type2332 { cs1, cs2 } => {
197 cs1.bit() << Self::CS1_2332_ADDR | cs2.bit() << Self::CS2_2332_ADDR
198 }
199 RomType::Type2316 { cs1, cs2, cs3 } => {
200 cs1.bit() << Self::CS1_2316_ADDR
201 | cs2.bit() << Self::CS2_2316_ADDR
202 | cs3.bit() << Self::CS3_2316_ADDR
203 }
204 }
205 }
206
207 pub const fn all() -> &'static [RomType] {
209 &ALL_ROM_TYPES
210 }
211
212 pub const fn type_str(&self) -> &'static str {
213 match self {
214 RomType::Type27512 => "27512",
215 RomType::Type23128 { .. } => "23128",
216 RomType::Type2364 { .. } => "2364",
217 RomType::Type2332 { .. } => "2332",
218 RomType::Type2316 { .. } => "2316",
219 }
220 }
221
222 pub const fn cs_str(&self) -> &'static str {
223 match self {
224 RomType::Type27512 => "N/A",
225 RomType::Type23128 { cs1, cs2, cs3 } => match (cs1, cs2, cs3) {
226 (CsActive::Low, CsActive::Low, CsActive::Low) => "CS1 Low, CS2 Low, CS3 Low",
227 (CsActive::Low, CsActive::Low, CsActive::High) => "CS1 Low, CS2 Low, CS3 High",
228 (CsActive::Low, CsActive::High, CsActive::Low) => "CS1 Low, CS2 High, CS3 Low",
229 (CsActive::Low, CsActive::High, CsActive::High) => "CS1 Low, CS2 High, CS3 High",
230 (CsActive::High, CsActive::Low, CsActive::Low) => "CS1 High, CS2 Low, CS3 Low",
231 (CsActive::High, CsActive::Low, CsActive::High) => "CS1 High, CS2 Low, CS3 High",
232 (CsActive::High, CsActive::High, CsActive::Low) => "CS1 High, CS2 High, CS3 Low",
233 (CsActive::High, CsActive::High, CsActive::High) => "CS1 High, CS2 High, CS3 High",
234 },
235 RomType::Type2364 { cs } => match cs {
236 CsActive::Low => "CS Low",
237 CsActive::High => "CS High",
238 },
239 RomType::Type2332 { cs1, cs2 } => match (cs1, cs2) {
240 (CsActive::Low, CsActive::Low) => "CS1 Low, CS2 Low",
241 (CsActive::Low, CsActive::High) => "CS1 Low, CS2 High",
242 (CsActive::High, CsActive::Low) => "CS1 High, CS2 Low",
243 (CsActive::High, CsActive::High) => "CS1 High, CS2 High",
244 },
245 RomType::Type2316 { cs1, cs2, cs3 } => match (cs1, cs2, cs3) {
246 (CsActive::Low, CsActive::Low, CsActive::Low) => "CS1 Low, CS2 Low, CS3 Low",
247 (CsActive::Low, CsActive::Low, CsActive::High) => "CS1 Low, CS2 Low, CS3 High",
248 (CsActive::Low, CsActive::High, CsActive::Low) => "CS1 Low, CS2 High, CS3 Low",
249 (CsActive::Low, CsActive::High, CsActive::High) => "CS1 Low, CS2 High, CS3 High",
250 (CsActive::High, CsActive::Low, CsActive::Low) => "CS1 High, CS2 Low, CS3 Low",
251 (CsActive::High, CsActive::Low, CsActive::High) => "CS1 High, CS2 Low, CS3 High",
252 (CsActive::High, CsActive::High, CsActive::Low) => "CS1 High, CS2 High, CS3 Low",
253 (CsActive::High, CsActive::High, CsActive::High) => "CS1 High, CS2 High, CS3 High",
254 },
255 }
256 }
257
258 pub const fn binary_size() -> usize {
260 4
261 }
262
263 pub fn from_bytes(buf: &[u8]) -> Result<Self, Error> {
265 if buf.len() < Self::binary_size() {
266 return Err(Error::ParseError);
267 }
268 match RomTypeByte::from_byte(buf[0])? {
269 RomTypeByte::Type27512 => Ok(RomType::Type27512 {}),
270 RomTypeByte::Type23128 => {
271 let cs1 = CsActiveByte::from_byte(buf[1])?.into();
272 let cs2 = CsActiveByte::from_byte(buf[2])?.into();
273 let cs3 = CsActiveByte::from_byte(buf[3])?.into();
274 Ok(RomType::Type23128 { cs1, cs2, cs3 })
275 }
276 RomTypeByte::Type2364 => {
277 let cs = CsActiveByte::from_byte(buf[1])?.into();
278 Ok(RomType::Type2364 { cs })
279 }
280 RomTypeByte::Type2332 => {
281 let cs1 = CsActiveByte::from_byte(buf[1])?.into();
282 let cs2 = CsActiveByte::from_byte(buf[2])?.into();
283 Ok(RomType::Type2332 { cs1, cs2 })
284 }
285 RomTypeByte::Type2316 => {
286 let cs1 = CsActiveByte::from_byte(buf[1])?.into();
287 let cs2 = CsActiveByte::from_byte(buf[2])?.into();
288 let cs3 = CsActiveByte::from_byte(buf[3])?.into();
289 Ok(RomType::Type2316 { cs1, cs2, cs3 })
290 }
291 }
292 }
293
294 pub fn to_bytes(&self, buf: &mut [u8]) -> Result<(), Error> {
296 if buf.len() < Self::binary_size() {
297 return Err(Error::ParseError);
298 }
299 match self {
300 RomType::Type27512 => {
301 buf[0] = RomTypeByte::Type27512.to_byte();
302 buf[1] = 0;
303 buf[2] = 0;
304 buf[3] = 0;
305 }
306 RomType::Type23128 { cs1, cs2, cs3 } => {
307 buf[0] = RomTypeByte::Type23128.to_byte();
308 buf[1] = CsActiveByte::from(*cs1).to_byte();
309 buf[2] = CsActiveByte::from(*cs2).to_byte();
310 buf[3] = CsActiveByte::from(*cs3).to_byte();
311 }
312 RomType::Type2364 { cs } => {
313 buf[0] = RomTypeByte::Type2364.to_byte();
314 buf[1] = CsActiveByte::from(*cs).to_byte();
315 buf[2] = 0;
316 buf[3] = 0;
317 }
318 RomType::Type2332 { cs1, cs2 } => {
319 buf[0] = RomTypeByte::Type2332.to_byte();
320 buf[1] = CsActiveByte::from(*cs1).to_byte();
321 buf[2] = CsActiveByte::from(*cs2).to_byte();
322 buf[3] = 0;
323 }
324 RomType::Type2316 { cs1, cs2, cs3 } => {
325 buf[0] = RomTypeByte::Type2316.to_byte();
326 buf[1] = CsActiveByte::from(*cs1).to_byte();
327 buf[2] = CsActiveByte::from(*cs2).to_byte();
328 buf[3] = CsActiveByte::from(*cs3).to_byte();
329 }
330 }
331 Ok(())
332 }
333}
334
335const NUM_ROM_TYPES: usize = 23;
337const ALL_ROM_TYPES: [RomType; NUM_ROM_TYPES] = [
338 RomType::Type27512 {},
339 RomType::Type23128 {
340 cs1: CsActive::Low,
341 cs2: CsActive::Low,
342 cs3: CsActive::Low,
343 },
344 RomType::Type23128 {
345 cs1: CsActive::Low,
346 cs2: CsActive::Low,
347 cs3: CsActive::High,
348 },
349 RomType::Type23128 {
350 cs1: CsActive::Low,
351 cs2: CsActive::High,
352 cs3: CsActive::Low,
353 },
354 RomType::Type23128 {
355 cs1: CsActive::Low,
356 cs2: CsActive::High,
357 cs3: CsActive::High,
358 },
359 RomType::Type23128 {
360 cs1: CsActive::High,
361 cs2: CsActive::Low,
362 cs3: CsActive::Low,
363 },
364 RomType::Type23128 {
365 cs1: CsActive::High,
366 cs2: CsActive::Low,
367 cs3: CsActive::High,
368 },
369 RomType::Type23128 {
370 cs1: CsActive::High,
371 cs2: CsActive::High,
372 cs3: CsActive::Low,
373 },
374 RomType::Type23128 {
375 cs1: CsActive::High,
376 cs2: CsActive::High,
377 cs3: CsActive::High,
378 },
379 RomType::Type2364 { cs: CsActive::Low },
380 RomType::Type2364 { cs: CsActive::High },
381 RomType::Type2332 {
382 cs1: CsActive::Low,
383 cs2: CsActive::Low,
384 },
385 RomType::Type2332 {
386 cs1: CsActive::Low,
387 cs2: CsActive::High,
388 },
389 RomType::Type2332 {
390 cs1: CsActive::High,
391 cs2: CsActive::Low,
392 },
393 RomType::Type2332 {
394 cs1: CsActive::High,
395 cs2: CsActive::High,
396 },
397 RomType::Type2316 {
398 cs1: CsActive::Low,
399 cs2: CsActive::Low,
400 cs3: CsActive::Low,
401 },
402 RomType::Type2316 {
403 cs1: CsActive::Low,
404 cs2: CsActive::Low,
405 cs3: CsActive::High,
406 },
407 RomType::Type2316 {
408 cs1: CsActive::Low,
409 cs2: CsActive::High,
410 cs3: CsActive::Low,
411 },
412 RomType::Type2316 {
413 cs1: CsActive::Low,
414 cs2: CsActive::High,
415 cs3: CsActive::High,
416 },
417 RomType::Type2316 {
418 cs1: CsActive::High,
419 cs2: CsActive::Low,
420 cs3: CsActive::Low,
421 },
422 RomType::Type2316 {
423 cs1: CsActive::High,
424 cs2: CsActive::Low,
425 cs3: CsActive::High,
426 },
427 RomType::Type2316 {
428 cs1: CsActive::High,
429 cs2: CsActive::High,
430 cs3: CsActive::Low,
431 },
432 RomType::Type2316 {
433 cs1: CsActive::High,
434 cs2: CsActive::High,
435 cs3: CsActive::High,
436 },
437];