bitsy_lang/sim/ext/
mem.rs

1use super::*;
2
3/// A same-cycle random-access memory.
4/// Has 64KiB of memory.
5/// Addressed by a 32-bit address (only the bottom 16 bits are usable).
6/// Reads and writes a 32-bit word at a time.
7#[derive(Debug)]
8pub struct Mem {
9    mem: [u8; 1 << 16],
10    read_addr: u32,
11    write_enable: bool,
12    write_addr: u32,
13    write_data: u32
14}
15
16impl Mem {
17    pub fn new() -> Mem {
18        let mem = [0; 1 << 16];
19        Mem {
20            mem,
21            read_addr: 0,
22            write_enable: false,
23            write_addr: 0,
24            write_data: 0,
25        }
26    }
27
28    pub fn load_from_file<P: AsRef<std::path::Path>>(&mut self, path: P) -> anyhow::Result<()> {
29        let data = std::fs::read(&path)?;
30        let len = data.len().min(1<<16);
31        for i in 0..len {
32            self.mem[i] = data[i];
33        }
34        Ok(())
35    }
36
37    fn read(&self) -> Value {
38        if self.read_addr >= 1<<16 {
39            //eprintln!("Out of bounds read: {:0x}", self.read_addr);
40            return Value::Word(32, 0);
41        }
42        let val: u64 =
43            (self.mem[self.read_addr as usize] as u64) |
44            ((self.mem[self.read_addr as usize + 1] as u64) << 8) |
45            ((self.mem[self.read_addr as usize + 2] as u64) << 16) |
46            ((self.mem[self.read_addr as usize + 3] as u64) << 24)
47        ;
48        Value::Word(32, val)
49    }
50
51    pub fn render(&self) -> String {
52        let mem = if let Some(index) = self.mem.iter().position(|&x| x == 0) {
53            &self.mem[..index+1]
54        } else {
55            &self.mem
56        };
57        format!("RAM: {:?}", String::from_utf8_lossy(mem))
58    }
59}
60
61impl ExtInstance for Mem {
62    fn incoming_ports(&self) -> Vec<PortName> {
63        vec![
64            "read_addr".to_string(),
65            "write_enable".to_string(),
66            "write_addr".to_string(),
67            "write_data".to_string(),
68        ]
69    }
70    fn outgoing_ports(&self) -> Vec<PortName> { vec!["read_data".to_string()] }
71
72    fn update(&mut self, port: &PortName, value: Value) -> Vec<(PortName, Value)>  {
73        if value.is_x() {
74            return vec![("read_data".to_string(), self.read())];
75        }
76        if port == "read_addr" {
77            if let Value::Word(32, addr) = value {
78                self.read_addr = addr as u32;
79                return vec![("read_data".to_string(), self.read())];
80            } else {
81                panic!("Mem must receive a Word<32> on read_addr. Received {value:?}")
82            }
83        } else if port == "write_enable" {
84            match value {
85                Value::Word(1, 0) => self.write_enable = false,
86                Value::Word(1, 1) => self.write_enable = true,
87                _ => panic!(),
88            }
89        } else if port == "write_addr" {
90            match value {
91                Value::Word(32, v) => self.write_addr = v.try_into().unwrap(),
92                _ => panic!("write_addr value must be Word<32>: {value:?}"),
93            }
94        } else if port == "write_data" {
95            match value {
96                Value::Word(32, v) => self.write_data = v.try_into().unwrap(),
97                _ => panic!("write_data value must be Word<32>: {value:?}"),
98            }
99        } else {
100            panic!("Mem may only recieve data on read_data: received data on {port} {value:?}")
101        }
102        vec![]
103    }
104
105    fn reset(&mut self) -> Vec<(PortName, Value)> {
106        /*
107        for (i, ch) in "Hello, World!\0".bytes().enumerate() {
108            self.mem[i] = ch;
109        }
110
111        vec![("read_data".to_string(), self.read())]
112        */
113        vec![]
114    }
115
116    fn clock(&mut self) -> Vec<(PortName, Value)> {
117//        println!("Mem was clocked: {}", self.render());
118        if self.write_enable {
119            println!("Writing to RAM: 0x{:08x} <= {:08x}", self.write_addr, self.write_data);
120            self.mem[self.write_addr as usize]       = self.write_data as u8 & 0xff;
121            self.mem[(self.write_addr + 1) as usize] = (self.write_data >>  8) as u8;
122            self.mem[(self.write_addr + 2) as usize] = (self.write_data >> 16) as u8;
123            self.mem[(self.write_addr + 3) as usize] = (self.write_data >> 24) as u8;
124            let read_data = self.read();
125            //println!("Mem wrote {read_data:?} at address 0x{:x}", self.write_addr);
126            vec![("read_data".to_string(), read_data)]
127        } else {
128            vec![]
129        }
130    }
131}
132