rust_hdl_hls/
sdram_controller_tester.rs

1use crate::bridge::Bridge;
2use crate::bus::{SoCBusResponder, SoCPortController};
3use crate::miso_wide_port::MISOWidePort;
4use crate::mosi_port::MOSIPort;
5use crate::mosi_wide_port::MOSIWidePort;
6use crate::HLSNamedPorts;
7use rust_hdl_core::prelude::*;
8use rust_hdl_widgets::prelude::*;
9
10#[derive(Debug, Copy, Clone, LogicState, PartialEq)]
11enum State {
12    Idle,
13    Writing,
14    Reading,
15}
16
17#[derive(LogicBlock)]
18pub struct SDRAMControllerTester<const R: usize, const C: usize> {
19    pub dram: SDRAMDriver<16>,
20    pub upstream: SoCBusResponder<16, 8>,
21    local_bridge: Bridge<16, 8, 5>,
22    count: MOSIWidePort<32, 16>,
23    cmd: MOSIPort<16>,
24    write_out: MISOWidePort<32, 16>,
25    error_out: MISOWidePort<32, 16>,
26    validation_out: MISOWidePort<32, 16>,
27    controller: SDRAMBaseController<R, C, 64, 16>,
28    lsfr: LFSRSimple,
29    entropy_funnel: CrossWidenFIFO<32, 6, 7, 64, 3, 4>,
30    output_funnel: CrossNarrowFIFO<64, 3, 4, 32, 6, 7>,
31    lsfr_validate: LFSRSimple,
32    dram_address: DFF<Bits<32>>,
33    error_count: DFF<Bits<32>>,
34    validation_count: DFF<Bits<32>>,
35    write_count: DFF<Bits<32>>,
36    output_pipeline: DFF<Bits<32>>,
37    output_avail: DFF<Bit>,
38    state: DFF<State>,
39    clock: Signal<Local, Clock>,
40}
41
42impl<const R: usize, const C: usize> SDRAMControllerTester<R, C> {
43    pub fn new(cas_delay: u32, timings: MemoryTimings, buffer: OutputBuffer) -> Self {
44        Self {
45            dram: Default::default(),
46            upstream: Default::default(),
47            local_bridge: Bridge::new(["count", "cmd", "errors", "valid", "write"]),
48            count: Default::default(),
49            cmd: Default::default(),
50            write_out: Default::default(),
51            error_out: Default::default(),
52            validation_out: Default::default(),
53            controller: SDRAMBaseController::new(cas_delay, timings, buffer),
54            lsfr: Default::default(),
55            entropy_funnel: CrossWidenFIFO::new(WordOrder::LeastSignificantFirst),
56            output_funnel: CrossNarrowFIFO::new(WordOrder::LeastSignificantFirst),
57            lsfr_validate: Default::default(),
58            dram_address: Default::default(),
59            error_count: Default::default(),
60            validation_count: Default::default(),
61            write_count: Default::default(),
62            output_pipeline: Default::default(),
63            output_avail: Default::default(),
64            state: Default::default(),
65            clock: Default::default(),
66        }
67    }
68}
69
70impl<const R: usize, const C: usize> HLSNamedPorts for SDRAMControllerTester<R, C> {
71    fn ports(&self) -> Vec<String> {
72        self.local_bridge.ports()
73    }
74}
75
76impl<const R: usize, const C: usize> Logic for SDRAMControllerTester<R, C> {
77    #[hdl_gen]
78    fn update(&mut self) {
79        SoCBusResponder::<16, 8>::link(&mut self.upstream, &mut self.local_bridge.upstream);
80        SDRAMDriver::<16>::link(&mut self.dram, &mut self.controller.sdram);
81        self.clock.next = self.upstream.clock.val();
82        clock!(self, clock, controller, lsfr, lsfr_validate);
83        dff_setup!(
84            self,
85            clock,
86            dram_address,
87            error_count,
88            validation_count,
89            write_count,
90            output_pipeline,
91            output_avail,
92            state
93        );
94        self.controller.clock.next = self.upstream.clock.val();
95        SoCPortController::<16>::join(&mut self.local_bridge.nodes[0], &mut self.count.bus);
96        SoCPortController::<16>::join(&mut self.local_bridge.nodes[1], &mut self.cmd.bus);
97        SoCPortController::<16>::join(&mut self.local_bridge.nodes[2], &mut self.error_out.bus);
98        SoCPortController::<16>::join(
99            &mut self.local_bridge.nodes[3],
100            &mut self.validation_out.bus,
101        );
102        SoCPortController::<16>::join(&mut self.local_bridge.nodes[4], &mut self.write_out.bus);
103        self.cmd.ready.next = false;
104        self.controller.data_in.next = self.entropy_funnel.data_out.val();
105        self.entropy_funnel.data_in.next = self.lsfr.num.val();
106        self.lsfr.strobe.next = !self.entropy_funnel.full.val();
107        self.entropy_funnel.write.next = !self.entropy_funnel.full.val();
108        self.entropy_funnel.write_clock.next = self.upstream.clock.val();
109        self.entropy_funnel.read_clock.next = self.upstream.clock.val();
110        self.controller.data_in.next = self.entropy_funnel.data_out.val();
111        self.controller.cmd_address.next = self.dram_address.q.val();
112        self.controller.write_not_read.next = false;
113        self.controller.cmd_strobe.next = false;
114        self.entropy_funnel.read.next = false;
115        self.output_funnel.data_in.next = self.controller.data_out.val();
116        self.output_funnel.write.next = self.controller.data_valid.val();
117        self.output_funnel.write_clock.next = self.upstream.clock.val();
118        self.output_funnel.read_clock.next = self.upstream.clock.val();
119        self.error_out.strobe_in.next = false;
120        self.validation_out.strobe_in.next = false;
121        self.write_out.strobe_in.next = false;
122        match self.state.q.val() {
123            State::Idle => {
124                self.cmd.ready.next = true;
125                if self.cmd.strobe_out.val() {
126                    self.error_count.d.next = 0.into();
127                    self.dram_address.d.next = 0.into();
128                    self.state.d.next = State::Writing;
129                    self.validation_count.d.next = 0.into();
130                    self.write_count.d.next = 0.into();
131                }
132            }
133            State::Writing => {
134                if self.write_count.q.val() >= self.count.port_out.val() {
135                    if !self.controller.busy.val() {
136                        self.dram_address.d.next = 0.into();
137                        self.state.d.next = State::Reading;
138                        self.write_out.strobe_in.next = true;
139                    }
140                } else if !self.controller.busy.val() & !self.entropy_funnel.empty.val() {
141                    self.controller.write_not_read.next = true;
142                    self.controller.cmd_strobe.next = true;
143                    self.dram_address.d.next = self.dram_address.q.val() + 4;
144                    self.entropy_funnel.read.next = true;
145                    self.write_count.d.next = self.write_count.q.val() + 4;
146                }
147            }
148            State::Reading => {
149                if self.dram_address.q.val() >= self.count.port_out.val() {
150                    if self.validation_count.q.val() >= self.count.port_out.val() {
151                        self.state.d.next = State::Idle;
152                        self.error_out.strobe_in.next = true;
153                        self.validation_out.strobe_in.next = true;
154                    }
155                } else if !self.controller.busy.val() & !self.output_funnel.full.val() {
156                    self.controller.write_not_read.next = false;
157                    self.controller.cmd_strobe.next = true;
158                    self.dram_address.d.next = self.dram_address.q.val() + 4;
159                }
160            }
161            _ => {
162                self.state.d.next = State::Idle;
163            }
164        }
165        // Do the validation piece - we need a pipeline register
166        // to meet timing.
167        // Feed the output_pipeline register
168        self.output_funnel.read.next = false;
169        if !self.output_avail.q.val() & !self.output_funnel.empty.val() {
170            self.output_pipeline.d.next = self.output_funnel.data_out.val();
171            self.output_funnel.read.next = true;
172            self.output_avail.d.next = true;
173        }
174        // Validate the output_pipeline value
175        self.lsfr_validate.strobe.next = false;
176        if self.output_avail.q.val() {
177            if self.output_pipeline.q.val() != self.lsfr_validate.num.val() {
178                self.error_count.d.next = self.error_count.q.val() + 2;
179            }
180            self.output_avail.d.next = false;
181            self.lsfr_validate.strobe.next = true;
182            self.validation_count.d.next = self.validation_count.q.val() + 2;
183        }
184        self.error_out.port_in.next = self.error_count.q.val();
185        self.validation_out.port_in.next = self.validation_count.q.val();
186        self.write_out.port_in.next = self.write_count.q.val();
187    }
188}
189
190#[test]
191fn test_sdram_controller_tester_synthesizes() {
192    let mut uut = SDRAMControllerTester::<6, 4>::new(
193        3,
194        MemoryTimings::fast_boot_sim(100e6),
195        OutputBuffer::DelayOne,
196    );
197    uut.connect_all();
198    yosys_validate("sdram_controller_tester_hls", &generate_verilog(&uut)).unwrap();
199}