virt_ic/chip/
memories.rs

1use std::time::Duration;
2
3use rand::random;
4
5use crate::{generate_chip, State};
6
7use super::{ChipBuilder, ChipRunner, ChipSet, Pin, PinType};
8
9/// # A 256-bytes RAM chip
10///
11/// # Diagram
12/// CS: Chip Select (active low)
13/// WE: Write Enable (active low)
14/// OE: Output Enable (active low)
15/// A0-7: Addresses
16/// IO0-7: Input/Output
17/// ```
18///        ---__---
19///  !CS --|1   22|-- VCC
20///  !WE --|2   21|-- UNUSED
21///  !OE --|3   20|-- IO7
22///   A0 --|4   19|-- IO6
23///   A1 --|5   18|-- IO5
24///   A2 --|6   17|-- IO4
25///   A3 --|7   16|-- IO3
26///   A4 --|8   15|-- IO2
27///   A5 --|9   14|-- IO1
28///   A6 --|10  13|-- IO0
29///  GND --|11  12|-- A7
30///        --------
31/// ```
32#[derive(Debug, Clone)]
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34pub struct Ram256B {
35    powered: bool,
36    ram: Vec<u8>,
37    pub vcc: Pin,
38    pub gnd: Pin,
39    pub cs: Pin,
40    pub we: Pin,
41    pub oe: Pin,
42    pub a0: Pin,
43    pub a1: Pin,
44    pub a2: Pin,
45    pub a3: Pin,
46    pub a4: Pin,
47    pub a5: Pin,
48    pub a6: Pin,
49    pub a7: Pin,
50    pub io0: Pin,
51    pub io1: Pin,
52    pub io2: Pin,
53    pub io3: Pin,
54    pub io4: Pin,
55    pub io5: Pin,
56    pub io6: Pin,
57    pub io7: Pin,
58}
59
60impl Ram256B {
61    pub const CS: usize = 1;
62    pub const WE: usize = 2;
63    pub const OE: usize = 3;
64    pub const A0: usize = 4;
65    pub const A1: usize = 5;
66    pub const A2: usize = 6;
67    pub const A3: usize = 7;
68    pub const A4: usize = 8;
69    pub const A5: usize = 9;
70    pub const A6: usize = 10;
71    pub const A7: usize = 12;
72    pub const IO0: usize = 13;
73    pub const IO1: usize = 14;
74    pub const IO2: usize = 15;
75    pub const IO3: usize = 16;
76    pub const IO4: usize = 17;
77    pub const IO5: usize = 18;
78    pub const IO6: usize = 19;
79    pub const IO7: usize = 20;
80    pub const VCC: usize = 22;
81    pub const GND: usize = 11;
82
83    fn set_io_type(&mut self, pin_type: PinType) {
84        self.io0.pin_type = pin_type;
85        self.io1.pin_type = pin_type;
86        self.io2.pin_type = pin_type;
87        self.io3.pin_type = pin_type;
88        self.io4.pin_type = pin_type;
89        self.io5.pin_type = pin_type;
90        self.io6.pin_type = pin_type;
91        self.io7.pin_type = pin_type;
92    }
93}
94
95generate_chip!(
96    Ram256B,
97    cs: Ram256B::CS,
98    we: Ram256B::WE,
99    oe: Ram256B::OE,
100    a0: Ram256B::A0,
101    a1: Ram256B::A1,
102    a2: Ram256B::A2,
103    a3: Ram256B::A3,
104    a4: Ram256B::A4,
105    a5: Ram256B::A5,
106    a6: Ram256B::A6,
107    a7: Ram256B::A7,
108    io0: Ram256B::IO0,
109    io1: Ram256B::IO1,
110    io2: Ram256B::IO2,
111    io3: Ram256B::IO3,
112    io4: Ram256B::IO4,
113    io5: Ram256B::IO5,
114    io6: Ram256B::IO6,
115    io7: Ram256B::IO7,
116    vcc: Ram256B::VCC,
117    gnd: Ram256B::GND
118);
119
120impl ChipBuilder<ChipSet> for Ram256B {
121    fn build() -> ChipSet {
122        ChipSet::Ram256B(Ram256B {
123            powered: false,
124            ram: Vec::from([0; 256]),
125            vcc: Pin::from(PinType::Input),
126            gnd: Pin::from(PinType::Output),
127            cs: Pin::from(PinType::Input),
128            we: Pin::from(PinType::Input),
129            oe: Pin::from(PinType::Input),
130            a0: Pin::from(PinType::Input),
131            a1: Pin::from(PinType::Input),
132            a2: Pin::from(PinType::Input),
133            a3: Pin::from(PinType::Input),
134            a4: Pin::from(PinType::Input),
135            a5: Pin::from(PinType::Input),
136            a6: Pin::from(PinType::Input),
137            a7: Pin::from(PinType::Input),
138            io0: Pin::from(PinType::Floating),
139            io1: Pin::from(PinType::Floating),
140            io2: Pin::from(PinType::Floating),
141            io3: Pin::from(PinType::Floating),
142            io4: Pin::from(PinType::Floating),
143            io5: Pin::from(PinType::Floating),
144            io6: Pin::from(PinType::Floating),
145            io7: Pin::from(PinType::Floating),
146        })
147    }
148}
149
150impl ChipRunner for Ram256B {
151    fn run(&mut self, _: Duration) {
152        if self.vcc.state.as_logic(1.0) == State::High {
153            if !self.powered {
154                for i in 0..256 {
155                    self.ram[i] = random::<u8>();
156                }
157                self.powered = true;
158            }
159            self.gnd.state = State::Low;
160
161            // check Chip Select (active low)
162            if self.cs.state == State::Low {
163                // check Write Enable (active low)
164                if self.we.state == State::Low {
165                    // IO = Input
166                    self.set_io_type(PinType::Input);
167                    // read data on IO pins
168                    let addr = Pin::read_threshold(
169                        &[
170                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
171                            &self.a7,
172                        ],
173                        3.3,
174                    );
175                    self.ram[addr] = Pin::read_threshold(
176                        &[
177                            &self.io0, &self.io1, &self.io2, &self.io3, &self.io4, &self.io5,
178                            &self.io6, &self.io7,
179                        ],
180                        3.3,
181                    ) as u8;
182                } else if self.oe.state == State::Low {
183                    // IO = Output
184                    self.set_io_type(PinType::Output);
185
186                    // display data on IO pins
187                    let addr = Pin::read_threshold(
188                        &[
189                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
190                            &self.a7,
191                        ],
192                        3.3,
193                    );
194                    Pin::write(
195                        &mut [
196                            &mut self.io0,
197                            &mut self.io1,
198                            &mut self.io2,
199                            &mut self.io3,
200                            &mut self.io4,
201                            &mut self.io5,
202                            &mut self.io6,
203                            &mut self.io7,
204                        ],
205                        self.ram[addr] as usize,
206                    );
207                } else {
208                    self.set_io_type(PinType::Floating);
209                }
210            } else {
211                self.set_io_type(PinType::Floating);
212            }
213        } else if self.powered {
214            self.set_io_type(PinType::Floating);
215            self.powered = false;
216        }
217    }
218}
219
220impl ToString for Ram256B {
221    fn to_string(&self) -> std::string::String {
222        let mut string = String::from(
223            "ADR| 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n---+------------------------------------------------",
224        );
225        for (addr, byte) in self.ram.iter().enumerate() {
226            if addr % 16 == 0 {
227                string.push_str(&format!("\n {addr:02X}|"));
228            }
229            string.push_str(&format!(
230                "{}{byte:02X}",
231                if self.cs.state.as_logic(3.3) == State::Low
232                    && Pin::read_threshold(
233                        &[
234                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
235                            &self.a7
236                        ],
237                        3.3
238                    ) == addr
239                {
240                    ">"
241                } else {
242                    " "
243                }
244            ));
245        }
246        string.push('\n');
247        string
248    }
249}
250
251/// # A 8KB RAM chip
252///
253/// # Diagram
254/// CS: Chip Select (active low)
255/// WE: Write Enable (active low)
256/// OE: Output Enable (active low)
257/// A0-12: Addresses
258/// IO0-7: Input/Output
259/// ```
260///        ---__---
261///  !CS --|1   26|-- VCC
262///  !WE --|2   25|-- IO7
263///  !OE --|3   24|-- IO6
264///   A0 --|4   23|-- IO5
265///   A1 --|5   22|-- IO4
266///   A2 --|6   21|-- IO3
267///   A3 --|7   20|-- IO2
268///   A4 --|8   19|-- IO1
269///   A5 --|9   18|-- IO0
270///   A6 --|10  17|-- A12
271///   A7 --|11  16|-- A11
272///   A8 --|12  15|-- A10
273///  GND --|13  14|-- A9
274///        --------
275/// ```
276#[derive(Debug, Clone)]
277#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
278pub struct Ram8KB {
279    powered: bool,
280    ram: Vec<u8>,
281    pub vcc: Pin,
282    pub gnd: Pin,
283    pub cs: Pin,
284    pub we: Pin,
285    pub oe: Pin,
286    pub a0: Pin,
287    pub a1: Pin,
288    pub a2: Pin,
289    pub a3: Pin,
290    pub a4: Pin,
291    pub a5: Pin,
292    pub a6: Pin,
293    pub a7: Pin,
294    pub a8: Pin,
295    pub a9: Pin,
296    pub a10: Pin,
297    pub a11: Pin,
298    pub a12: Pin,
299    pub io0: Pin,
300    pub io1: Pin,
301    pub io2: Pin,
302    pub io3: Pin,
303    pub io4: Pin,
304    pub io5: Pin,
305    pub io6: Pin,
306    pub io7: Pin,
307}
308
309impl Ram8KB {
310    pub const CS: usize = 1;
311    pub const WE: usize = 2;
312    pub const OE: usize = 3;
313    pub const A0: usize = 4;
314    pub const A1: usize = 5;
315    pub const A2: usize = 6;
316    pub const A3: usize = 7;
317    pub const A4: usize = 8;
318    pub const A5: usize = 9;
319    pub const A6: usize = 10;
320    pub const A7: usize = 11;
321    pub const A8: usize = 12;
322    pub const A9: usize = 14;
323    pub const A10: usize = 15;
324    pub const A11: usize = 16;
325    pub const A12: usize = 17;
326    pub const IO0: usize = 18;
327    pub const IO1: usize = 19;
328    pub const IO2: usize = 20;
329    pub const IO3: usize = 21;
330    pub const IO4: usize = 22;
331    pub const IO5: usize = 23;
332    pub const IO6: usize = 24;
333    pub const IO7: usize = 25;
334    pub const VCC: usize = 26;
335    pub const GND: usize = 13;
336
337    fn set_io_type(&mut self, pin_type: PinType) {
338        self.io0.pin_type = pin_type;
339        self.io1.pin_type = pin_type;
340        self.io2.pin_type = pin_type;
341        self.io3.pin_type = pin_type;
342        self.io4.pin_type = pin_type;
343        self.io5.pin_type = pin_type;
344        self.io6.pin_type = pin_type;
345        self.io7.pin_type = pin_type;
346    }
347}
348
349generate_chip!(
350    Ram8KB,
351    cs: Ram8KB::CS,
352    we: Ram8KB::WE,
353    oe: Ram8KB::OE,
354    a0: Ram8KB::A0,
355    a1: Ram8KB::A1,
356    a2: Ram8KB::A2,
357    a3: Ram8KB::A3,
358    a4: Ram8KB::A4,
359    a5: Ram8KB::A5,
360    a6: Ram8KB::A6,
361    a7: Ram8KB::A7,
362    a8: Ram8KB::A8,
363    a9: Ram8KB::A9,
364    a10: Ram8KB::A10,
365    a11: Ram8KB::A11,
366    a12: Ram8KB::A12,
367    io0: Ram8KB::IO0,
368    io1: Ram8KB::IO1,
369    io2: Ram8KB::IO2,
370    io3: Ram8KB::IO3,
371    io4: Ram8KB::IO4,
372    io5: Ram8KB::IO5,
373    io6: Ram8KB::IO6,
374    io7: Ram8KB::IO7,
375    vcc: Ram8KB::VCC,
376    gnd: Ram8KB::GND
377);
378
379impl ChipBuilder<ChipSet> for Ram8KB {
380    fn build() -> ChipSet {
381        ChipSet::Ram8KB(Ram8KB {
382            powered: false,
383            ram: Vec::from([0; 8192]),
384            vcc: Pin::from(PinType::Input),
385            gnd: Pin::from(PinType::Output),
386            cs: Pin::from(PinType::Input),
387            we: Pin::from(PinType::Input),
388            oe: Pin::from(PinType::Input),
389            a0: Pin::from(PinType::Input),
390            a1: Pin::from(PinType::Input),
391            a2: Pin::from(PinType::Input),
392            a3: Pin::from(PinType::Input),
393            a4: Pin::from(PinType::Input),
394            a5: Pin::from(PinType::Input),
395            a6: Pin::from(PinType::Input),
396            a7: Pin::from(PinType::Input),
397            a8: Pin::from(PinType::Input),
398            a9: Pin::from(PinType::Input),
399            a10: Pin::from(PinType::Input),
400            a11: Pin::from(PinType::Input),
401            a12: Pin::from(PinType::Input),
402            io0: Pin::from(PinType::Floating),
403            io1: Pin::from(PinType::Floating),
404            io2: Pin::from(PinType::Floating),
405            io3: Pin::from(PinType::Floating),
406            io4: Pin::from(PinType::Floating),
407            io5: Pin::from(PinType::Floating),
408            io6: Pin::from(PinType::Floating),
409            io7: Pin::from(PinType::Floating),
410        })
411    }
412}
413
414impl ChipRunner for Ram8KB {
415    fn run(&mut self, _: Duration) {
416        if self.vcc.state.as_logic(1.0) == State::High {
417            if !self.powered {
418                for i in 0..256 {
419                    self.ram[i] = random::<u8>();
420                }
421                self.powered = true;
422            }
423            self.gnd.state = State::Low;
424
425            // check Chip Select (active low)
426            if self.cs.state == State::Low {
427                // check Write Enable (active low)
428                if self.we.state == State::Low {
429                    // IO = Input
430                    self.set_io_type(PinType::Input);
431                    // read data on IO pins
432                    let addr = Pin::read_threshold(
433                        &[
434                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
435                            &self.a7, &self.a8, &self.a9, &self.a10, &self.a11, &self.a12,
436                        ],
437                        3.3,
438                    );
439                    self.ram[addr] = Pin::read_threshold(
440                        &[
441                            &self.io0, &self.io1, &self.io2, &self.io3, &self.io4, &self.io5,
442                            &self.io6, &self.io7,
443                        ],
444                        3.3,
445                    ) as u8;
446                } else if self.oe.state == State::Low {
447                    // IO = Output
448                    self.set_io_type(PinType::Output);
449
450                    // display data on IO pins
451                    let addr = Pin::read_threshold(
452                        &[
453                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
454                            &self.a7, &self.a8, &self.a9, &self.a10, &self.a11, &self.a12,
455                        ],
456                        3.3,
457                    );
458                    Pin::write(
459                        &mut [
460                            &mut self.io0,
461                            &mut self.io1,
462                            &mut self.io2,
463                            &mut self.io3,
464                            &mut self.io4,
465                            &mut self.io5,
466                            &mut self.io6,
467                            &mut self.io7,
468                        ],
469                        self.ram[addr] as usize,
470                    );
471                } else {
472                    self.set_io_type(PinType::Floating);
473                }
474            } else {
475                self.set_io_type(PinType::Floating);
476            }
477        } else if self.powered {
478            self.set_io_type(PinType::Floating);
479            self.powered = false;
480        }
481    }
482}
483
484impl ToString for Ram8KB {
485    fn to_string(&self) -> std::string::String {
486        let mut string = String::from(
487            "  ADR| 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n-----+------------------------------------------------",
488        );
489        for (addr, byte) in self.ram.iter().enumerate() {
490            if addr % 16 == 0 {
491                string.push_str(&format!("\n {addr:04X}|"));
492            }
493            string.push_str(&format!(
494                "{}{byte:02X}",
495                if self.cs.state.as_logic(3.3) == State::Low
496                    && Pin::read_threshold(
497                        &[
498                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
499                            &self.a7, &self.a8, &self.a9, &self.a10, &self.a11, &self.a12,
500                        ],
501                        3.3
502                    ) == addr
503                {
504                    ">"
505                } else {
506                    " "
507                }
508            ));
509        }
510        string.push('\n');
511        string
512    }
513}
514
515/// # A 256-bytes ROM chip
516///
517/// # Diagram
518/// CS: Chip Select (active low)
519/// OE: Output Enable (active low)
520/// A0-7: Addresses
521/// IO0-7: Input/Output
522/// ```
523///         ---__---
524///   !CS --|1   22|-- VCC
525/// UNUSED--|2   21|-- UNUSED
526///   !OE --|3   20|-- IO7
527///    A0 --|4   19|-- IO6
528///    A1 --|5   18|-- IO5
529///    A2 --|6   17|-- IO4
530///    A3 --|7   16|-- IO3
531///    A4 --|8   15|-- IO2
532///    A5 --|9   14|-- IO1
533///    A6 --|10  13|-- IO0
534///   GND --|11  12|-- A7
535///         --------
536/// ```
537#[derive(Debug, Clone)]
538#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
539pub struct Rom256B {
540    powered: bool,
541    rom: Vec<u8>,
542    pub vcc: Pin,
543    pub gnd: Pin,
544    pub cs: Pin,
545    pub oe: Pin,
546    pub a0: Pin,
547    pub a1: Pin,
548    pub a2: Pin,
549    pub a3: Pin,
550    pub a4: Pin,
551    pub a5: Pin,
552    pub a6: Pin,
553    pub a7: Pin,
554    pub io0: Pin,
555    pub io1: Pin,
556    pub io2: Pin,
557    pub io3: Pin,
558    pub io4: Pin,
559    pub io5: Pin,
560    pub io6: Pin,
561    pub io7: Pin,
562}
563
564impl Rom256B {
565    pub const CS: usize = 1;
566    pub const OE: usize = 3;
567    pub const A0: usize = 4;
568    pub const A1: usize = 5;
569    pub const A2: usize = 6;
570    pub const A3: usize = 7;
571    pub const A4: usize = 8;
572    pub const A5: usize = 9;
573    pub const A6: usize = 10;
574    pub const A7: usize = 12;
575    pub const IO0: usize = 13;
576    pub const IO1: usize = 14;
577    pub const IO2: usize = 15;
578    pub const IO3: usize = 16;
579    pub const IO4: usize = 17;
580    pub const IO5: usize = 18;
581    pub const IO6: usize = 19;
582    pub const IO7: usize = 20;
583    pub const VCC: usize = 22;
584    pub const GND: usize = 11;
585
586    fn set_io_type(&mut self, pin_type: PinType) {
587        self.io0.pin_type = pin_type;
588        self.io1.pin_type = pin_type;
589        self.io2.pin_type = pin_type;
590        self.io3.pin_type = pin_type;
591        self.io4.pin_type = pin_type;
592        self.io5.pin_type = pin_type;
593        self.io6.pin_type = pin_type;
594        self.io7.pin_type = pin_type;
595    }
596
597    pub fn set_data(mut self, data: &[u8]) -> Self {
598        self.rom = Vec::from(data);
599        self.rom.resize(256, 0);
600        self
601    }
602}
603
604generate_chip!(
605    Rom256B,
606    cs: Rom256B::CS,
607    oe: Rom256B::OE,
608    a0: Rom256B::A0,
609    a1: Rom256B::A1,
610    a2: Rom256B::A2,
611    a3: Rom256B::A3,
612    a4: Rom256B::A4,
613    a5: Rom256B::A5,
614    a6: Rom256B::A6,
615    a7: Rom256B::A7,
616    io0: Rom256B::IO0,
617    io1: Rom256B::IO1,
618    io2: Rom256B::IO2,
619    io3: Rom256B::IO3,
620    io4: Rom256B::IO4,
621    io5: Rom256B::IO5,
622    io6: Rom256B::IO6,
623    io7: Rom256B::IO7,
624    vcc: Rom256B::VCC,
625    gnd: Rom256B::GND
626);
627
628impl ChipBuilder<Rom256B> for Rom256B {
629    fn build() -> Rom256B {
630        Rom256B {
631            powered: false,
632            rom: Vec::from([0; 256]),
633            vcc: Pin::from(PinType::Input),
634            gnd: Pin::from(PinType::Output),
635            cs: Pin::from(PinType::Input),
636            oe: Pin::from(PinType::Input),
637            a0: Pin::from(PinType::Input),
638            a1: Pin::from(PinType::Input),
639            a2: Pin::from(PinType::Input),
640            a3: Pin::from(PinType::Input),
641            a4: Pin::from(PinType::Input),
642            a5: Pin::from(PinType::Input),
643            a6: Pin::from(PinType::Input),
644            a7: Pin::from(PinType::Input),
645            io0: Pin::from(PinType::Floating),
646            io1: Pin::from(PinType::Floating),
647            io2: Pin::from(PinType::Floating),
648            io3: Pin::from(PinType::Floating),
649            io4: Pin::from(PinType::Floating),
650            io5: Pin::from(PinType::Floating),
651            io6: Pin::from(PinType::Floating),
652            io7: Pin::from(PinType::Floating),
653        }
654    }
655}
656
657impl From<Rom256B> for ChipSet {
658    fn from(value: Rom256B) -> Self {
659        ChipSet::Rom256B(value)
660    }
661}
662
663impl ChipRunner for Rom256B {
664    fn run(&mut self, _: Duration) {
665        if self.vcc.state.as_logic(1.0) == State::High {
666            if !self.powered {
667                self.powered = true;
668            }
669            self.gnd.state = State::Low;
670
671            // check Chip Select (active low)
672            if self.cs.state == State::Low {
673                // check Output Enable (active low)
674                if self.oe.state == State::Low {
675                    // IO = Output
676                    self.set_io_type(PinType::Output);
677
678                    // display data on IO pins
679                    let addr = Pin::read_threshold(
680                        &[
681                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
682                            &self.a7,
683                        ],
684                        3.3,
685                    );
686                    Pin::write(
687                        &mut [
688                            &mut self.io0,
689                            &mut self.io1,
690                            &mut self.io2,
691                            &mut self.io3,
692                            &mut self.io4,
693                            &mut self.io5,
694                            &mut self.io6,
695                            &mut self.io7,
696                        ],
697                        self.rom[addr] as usize,
698                    );
699                } else {
700                    self.set_io_type(PinType::Floating);
701                }
702            } else {
703                self.set_io_type(PinType::Floating);
704            }
705        } else if self.powered {
706            self.set_io_type(PinType::Floating);
707            self.powered = false;
708        }
709    }
710}
711
712impl ToString for Rom256B {
713    fn to_string(&self) -> std::string::String {
714        let mut string = String::from(
715            "ADR| 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n---+------------------------------------------------",
716        );
717        for (addr, byte) in self.rom.iter().enumerate() {
718            if addr % 16 == 0 {
719                string.push_str(&format!("\n {addr:02X}|"));
720            }
721            string.push_str(&format!(
722                "{}{byte:02X}",
723                if self.cs.state.as_logic(3.3) == State::Low
724                    && Pin::read_threshold(
725                        &[
726                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
727                            &self.a7
728                        ],
729                        3.3
730                    ) > 0
731                {
732                    ">"
733                } else {
734                    " "
735                }
736            ));
737        }
738        string.push('\n');
739        string
740    }
741}
742
743/// # A 8KB ROM chip
744///
745/// # Diagram
746/// CS: Chip Select (active low)
747/// WE: Write Enable (active low)
748/// OE: Output Enable (active low)
749/// A0-12: Addresses
750/// IO0-7: Input/Output
751/// ```
752///         ---__---
753///   !CS --|1   26|-- VCC
754/// UNUSED--|2   25|-- IO7
755///   !OE --|3   24|-- IO6
756///    A0 --|4   23|-- IO5
757///    A1 --|5   22|-- IO4
758///    A2 --|6   21|-- IO3
759///    A3 --|7   20|-- IO2
760///    A4 --|8   19|-- IO1
761///    A5 --|9   18|-- IO0
762///    A6 --|10  17|-- A12
763///    A7 --|11  16|-- A11
764///    A8 --|12  15|-- A10
765///   GND --|13  14|-- A9
766///         --------
767/// ```
768#[derive(Debug, Clone)]
769#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
770pub struct Rom8KB {
771    powered: bool,
772    rom: Vec<u8>,
773    pub vcc: Pin,
774    pub gnd: Pin,
775    pub cs: Pin,
776    pub oe: Pin,
777    pub a0: Pin,
778    pub a1: Pin,
779    pub a2: Pin,
780    pub a3: Pin,
781    pub a4: Pin,
782    pub a5: Pin,
783    pub a6: Pin,
784    pub a7: Pin,
785    pub a8: Pin,
786    pub a9: Pin,
787    pub a10: Pin,
788    pub a11: Pin,
789    pub a12: Pin,
790    pub io0: Pin,
791    pub io1: Pin,
792    pub io2: Pin,
793    pub io3: Pin,
794    pub io4: Pin,
795    pub io5: Pin,
796    pub io6: Pin,
797    pub io7: Pin,
798}
799
800impl Rom8KB {
801    pub const CS: usize = 1;
802    pub const OE: usize = 3;
803    pub const A0: usize = 4;
804    pub const A1: usize = 5;
805    pub const A2: usize = 6;
806    pub const A3: usize = 7;
807    pub const A4: usize = 8;
808    pub const A5: usize = 9;
809    pub const A6: usize = 10;
810    pub const A7: usize = 11;
811    pub const A8: usize = 12;
812    pub const A9: usize = 14;
813    pub const A10: usize = 15;
814    pub const A11: usize = 16;
815    pub const A12: usize = 17;
816    pub const IO0: usize = 18;
817    pub const IO1: usize = 19;
818    pub const IO2: usize = 20;
819    pub const IO3: usize = 21;
820    pub const IO4: usize = 22;
821    pub const IO5: usize = 23;
822    pub const IO6: usize = 24;
823    pub const IO7: usize = 25;
824    pub const VCC: usize = 26;
825    pub const GND: usize = 13;
826
827    fn set_io_type(&mut self, pin_type: PinType) {
828        self.io0.pin_type = pin_type;
829        self.io1.pin_type = pin_type;
830        self.io2.pin_type = pin_type;
831        self.io3.pin_type = pin_type;
832        self.io4.pin_type = pin_type;
833        self.io5.pin_type = pin_type;
834        self.io6.pin_type = pin_type;
835        self.io7.pin_type = pin_type;
836    }
837
838    pub fn set_data(mut self, data: &[u8]) -> Self {
839        self.rom = Vec::from(data);
840        self.rom.resize(8192, 0);
841        self
842    }
843}
844
845generate_chip!(
846    Rom8KB,
847    cs: Rom8KB::CS,
848    oe: Rom8KB::OE,
849    a0: Rom8KB::A0,
850    a1: Rom8KB::A1,
851    a2: Rom8KB::A2,
852    a3: Rom8KB::A3,
853    a4: Rom8KB::A4,
854    a5: Rom8KB::A5,
855    a6: Rom8KB::A6,
856    a7: Rom8KB::A7,
857    a8: Rom8KB::A8,
858    a9: Rom8KB::A9,
859    a10: Rom8KB::A10,
860    a11: Rom8KB::A11,
861    a12: Rom8KB::A12,
862    io0: Rom8KB::IO0,
863    io1: Rom8KB::IO1,
864    io2: Rom8KB::IO2,
865    io3: Rom8KB::IO3,
866    io4: Rom8KB::IO4,
867    io5: Rom8KB::IO5,
868    io6: Rom8KB::IO6,
869    io7: Rom8KB::IO7,
870    vcc: Rom8KB::VCC,
871    gnd: Rom8KB::GND
872);
873
874impl ChipBuilder<Rom8KB> for Rom8KB {
875    fn build() -> Rom8KB {
876        Rom8KB {
877            powered: false,
878            rom: Vec::from([0; 8192]),
879            vcc: Pin::from(PinType::Input),
880            gnd: Pin::from(PinType::Output),
881            cs: Pin::from(PinType::Input),
882            oe: Pin::from(PinType::Input),
883            a0: Pin::from(PinType::Input),
884            a1: Pin::from(PinType::Input),
885            a2: Pin::from(PinType::Input),
886            a3: Pin::from(PinType::Input),
887            a4: Pin::from(PinType::Input),
888            a5: Pin::from(PinType::Input),
889            a6: Pin::from(PinType::Input),
890            a7: Pin::from(PinType::Input),
891            a8: Pin::from(PinType::Input),
892            a9: Pin::from(PinType::Input),
893            a10: Pin::from(PinType::Input),
894            a11: Pin::from(PinType::Input),
895            a12: Pin::from(PinType::Input),
896            io0: Pin::from(PinType::Floating),
897            io1: Pin::from(PinType::Floating),
898            io2: Pin::from(PinType::Floating),
899            io3: Pin::from(PinType::Floating),
900            io4: Pin::from(PinType::Floating),
901            io5: Pin::from(PinType::Floating),
902            io6: Pin::from(PinType::Floating),
903            io7: Pin::from(PinType::Floating),
904        }
905    }
906}
907
908impl From<Rom8KB> for ChipSet {
909    fn from(value: Rom8KB) -> Self {
910        ChipSet::Rom8KB(value)
911    }
912}
913
914impl ChipRunner for Rom8KB {
915    fn run(&mut self, _: Duration) {
916        if self.vcc.state.as_logic(1.0) == State::High {
917            if !self.powered {
918                self.powered = true;
919            }
920            self.gnd.state = State::Low;
921
922            // check Chip Select (active low)
923            if self.cs.state == State::Low {
924                // check Output Enable (active low)
925                if self.oe.state == State::Low {
926                    // IO = Output
927                    self.set_io_type(PinType::Output);
928
929                    // display data on IO pins
930                    let addr = Pin::read_threshold(
931                        &[
932                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
933                            &self.a7, &self.a8, &self.a9, &self.a10, &self.a11, &self.a12,
934                        ],
935                        3.3,
936                    );
937                    Pin::write(
938                        &mut [
939                            &mut self.io0,
940                            &mut self.io1,
941                            &mut self.io2,
942                            &mut self.io3,
943                            &mut self.io4,
944                            &mut self.io5,
945                            &mut self.io6,
946                            &mut self.io7,
947                        ],
948                        self.rom[addr] as usize,
949                    );
950                } else {
951                    self.set_io_type(PinType::Floating);
952                }
953            } else {
954                self.set_io_type(PinType::Floating);
955            }
956        } else if self.powered {
957            self.set_io_type(PinType::Floating);
958            self.powered = false;
959        }
960    }
961}
962
963impl ToString for Rom8KB {
964    fn to_string(&self) -> std::string::String {
965        let mut string = String::from(
966            "  ADR| 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n-----+------------------------------------------------",
967        );
968        for (addr, byte) in self.rom.iter().enumerate() {
969            if addr % 16 == 0 {
970                string.push_str(&format!("\n {addr:04X}|"));
971            }
972            string.push_str(&format!(
973                "{}{byte:02X}",
974                if self.cs.state.as_logic(3.3) == State::Low
975                    && Pin::read_threshold(
976                        &[
977                            &self.a0, &self.a1, &self.a2, &self.a3, &self.a4, &self.a5, &self.a6,
978                            &self.a7, &self.a8, &self.a9, &self.a10, &self.a11, &self.a12,
979                        ],
980                        3.3
981                    ) == addr
982                {
983                    ">"
984                } else {
985                    " "
986                }
987            ));
988        }
989        string.push('\n');
990        string
991    }
992}