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 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 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}