rust_hdl_widgets/ramrom/
ram.rs

1use crate::ramrom::rom::make_btree_from_iterable;
2use rust_hdl_core::prelude::*;
3use rust_hdl_core::timing::TimingInfo;
4use std::collections::BTreeMap;
5
6#[derive(LogicInterface, Default)]
7pub struct RAMWrite<D: Synth, const N: usize> {
8    pub address: Signal<In, Bits<N>>,
9    pub clock: Signal<In, Clock>,
10    pub data: Signal<In, D>,
11    pub enable: Signal<In, bool>,
12}
13
14#[derive(LogicBlock, Default)]
15pub struct RAM<D: Synth, const N: usize> {
16    pub read_address: Signal<In, Bits<N>>,
17    pub read_clock: Signal<In, Clock>,
18    pub read_data: Signal<Out, D>,
19    pub write_address: Signal<In, Bits<N>>,
20    pub write_clock: Signal<In, Clock>,
21    pub write_data: Signal<In, D>,
22    pub write_enable: Signal<In, bool>,
23    _sim: Box<BTreeMap<Bits<N>, D>>,
24}
25
26impl<D: Synth, const N: usize> RAM<D, N> {
27    pub fn new(values: BTreeMap<Bits<N>, D>) -> Self {
28        Self {
29            _sim: Box::new(values),
30            ..Default::default()
31        }
32    }
33}
34
35impl<I: Iterator<Item = D>, D: Synth, const N: usize> From<I> for RAM<D, N> {
36    fn from(v: I) -> Self {
37        Self::new(make_btree_from_iterable(v))
38    }
39}
40
41impl<D: Synth, const N: usize> Logic for RAM<D, N> {
42    fn update(&mut self) {
43        if self.read_clock.pos_edge() {
44            self.read_data.next = *self
45                ._sim
46                .get(&self.read_address.val())
47                .unwrap_or(&D::default());
48        }
49        if self.write_clock.pos_edge() && self.write_enable.val() {
50            self._sim
51                .insert(self.write_address.val(), self.write_data.val());
52        }
53    }
54
55    fn connect(&mut self) {
56        self.read_data.connect();
57    }
58
59    fn hdl(&self) -> Verilog {
60        let init = if self._sim.len() != 0 {
61            format!(
62                "initial begin\n{};\nend\n",
63                self._sim
64                    .iter()
65                    .map(|x| {
66                        format!(
67                            "mem[{}] = {}",
68                            x.0.verilog().to_string(),
69                            x.1.verilog().to_string()
70                        )
71                    })
72                    .collect::<Vec<_>>()
73                    .join(";\n")
74            )
75        } else {
76            "".into()
77        };
78        Verilog::Custom(format!(
79            "\
80reg[{D}:0] mem[{Acount}:0];
81
82{init}
83
84always @(posedge read_clock) begin
85   read_data <= mem[read_address];
86end
87
88always @(posedge write_clock) begin
89   if (write_enable) begin
90      mem[write_address] <= write_data;
91   end
92end
93            ",
94            D = D::BITS - 1,
95            Acount = (1 << N) - 1,
96            init = init
97        ))
98    }
99
100    fn timing(&self) -> Vec<TimingInfo> {
101        vec![
102            TimingInfo {
103                name: "ram_read".into(),
104                clock: "read_clock".into(),
105                inputs: vec!["read_address".into()],
106                outputs: vec!["read_data".into()],
107            },
108            TimingInfo {
109                name: "ram_write".into(),
110                clock: "write_clock".into(),
111                inputs: vec![
112                    "write_address".into(),
113                    "write_data".into(),
114                    "write_enable".into(),
115                ],
116                outputs: vec![],
117            },
118        ]
119    }
120}