rust_hdl_widgets/ramrom/
ram.rs1use 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}