1use rust_hdl_core::prelude::*;
2use rust_hdl_widgets::prelude::*;
3
4#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
5enum ADS868XState {
6 Ready,
7 Waiting,
8 Dispatch,
9 ReadWordCmd,
10 ReadByteCmd,
11 WriteWordCmd,
12 WriteMSBCmd,
13 WriteLSBCmd,
14 WriteDone,
15 Nop,
16}
17
18#[derive(LogicBlock)]
19pub struct ADS868XSimulator {
20 pub wires: SPIWiresSlave,
21 pub clock: Signal<In, Clock>,
22 reg_ram: RAM<Bits<16>, 5>,
24 spi_slave: SPISlave<32>,
26 state: DFF<ADS868XState>,
28 conversion_counter: DFF<Bits<16>>,
30 inbound: DFF<Bits<32>>,
32 read_cmd: Signal<Local, Bits<5>>,
34 write_cmd: Signal<Local, Bits<7>>,
35 address: Signal<Local, Bits<9>>,
36 data_parity: Signal<Local, Bit>,
37 id_parity: Signal<Local, Bit>,
38}
39
40impl ADS868XSimulator {
41 pub fn spi_hw() -> SPIConfig {
42 SPIConfig {
43 clock_speed: 48_000_000,
44 cs_off: true,
45 mosi_off: true,
46 speed_hz: 400_000,
47 cpha: false,
48 cpol: false,
49 }
50 }
51 pub fn spi_sw() -> SPIConfig {
52 SPIConfig {
53 clock_speed: 1_000_000,
54 cs_off: true,
55 mosi_off: true,
56 speed_hz: 10_000,
57 cpha: false,
58 cpol: false,
59 }
60 }
61
62 pub fn new(spi_config: SPIConfig) -> Self {
63 assert!(spi_config.clock_speed > 10 * spi_config.speed_hz);
64 Self {
65 wires: Default::default(),
66 clock: Default::default(),
67 reg_ram: Default::default(),
68 spi_slave: SPISlave::new(spi_config),
69 state: Default::default(),
70 conversion_counter: Default::default(),
71 inbound: Default::default(),
72 read_cmd: Default::default(),
73 write_cmd: Default::default(),
74 address: Default::default(),
75 data_parity: Default::default(),
76 id_parity: Default::default(),
77 }
78 }
79}
80
81#[test]
82fn test_indexing() {
83 let val: Bits<32> = 0b11000_00_101_001_100_00000000_00000000.into();
84 assert_eq!(val.get_bits::<5>(27).index(), 0b11000);
85 assert_eq!(val.get_bits::<9>(16).index(), 0b101_001_100);
86}
87
88impl Logic for ADS868XSimulator {
89 #[hdl_gen]
90 fn update(&mut self) {
91 SPIWiresSlave::link(&mut self.wires, &mut self.spi_slave.wires);
93 self.reg_ram.read_clock.next = self.clock.val();
95 self.reg_ram.write_clock.next = self.clock.val();
96 clock!(self, clock, spi_slave);
97 dff_setup!(self, clock, state, conversion_counter, inbound);
98 self.spi_slave.start_send.next = false;
100 self.spi_slave.continued_transaction.next = false;
101 self.spi_slave.bits.next = 0.into();
102 self.spi_slave.data_outbound.next = 0.into();
103 self.reg_ram.write_enable.next = false;
104 self.reg_ram.write_data.next = 0.into();
105 self.spi_slave.disabled.next = false;
106 self.read_cmd.next = self.inbound.q.val().get_bits::<5>(27);
107 self.write_cmd.next = self.inbound.q.val().get_bits::<7>(25);
108 self.address.next = self.inbound.q.val().get_bits::<9>(16);
109 self.reg_ram.write_address.next = bit_cast::<5, 9>(self.address.val() >> 1);
110 self.reg_ram.read_address.next = 0.into();
111 self.data_parity.next = self.conversion_counter.q.val().xor();
112 self.id_parity.next = (self.reg_ram.read_data.val() & 0x0FF).xor();
113 match self.state.q.val() {
114 ADS868XState::Ready => {
115 if !self.spi_slave.busy.val() {
116 self.state.d.next = ADS868XState::Nop;
117 }
118 }
119 ADS868XState::Waiting => {
120 if self.spi_slave.transfer_done.val() {
121 self.inbound.d.next = self.spi_slave.data_inbound.val();
122 self.state.d.next = ADS868XState::Dispatch;
123 }
124 }
125 ADS868XState::Dispatch => {
126 if self.read_cmd.val() == 0b11001 {
127 self.state.d.next = ADS868XState::ReadWordCmd;
128 self.reg_ram.read_address.next = bit_cast::<5, 9>(self.address.val() >> 1);
129 } else if self.read_cmd.val() == 0b01001 {
130 self.state.d.next = ADS868XState::ReadByteCmd;
131 self.reg_ram.read_address.next = bit_cast::<5, 9>(self.address.val() >> 1);
132 } else if self.write_cmd.val() == 0b11010_00 {
133 self.state.d.next = ADS868XState::WriteWordCmd;
134 } else if self.write_cmd.val() == 0b11010_01 {
135 self.state.d.next = ADS868XState::WriteMSBCmd;
136 self.reg_ram.read_address.next = bit_cast::<5, 9>(self.address.val() >> 1);
137 } else if self.write_cmd.val() == 0b11010_10 {
138 self.state.d.next = ADS868XState::WriteLSBCmd;
139 self.reg_ram.read_address.next = bit_cast::<5, 9>(self.address.val() >> 1);
140 } else {
141 self.reg_ram.read_address.next = 0x02.into();
142 self.state.d.next = ADS868XState::Nop;
143 }
144 }
145 ADS868XState::ReadWordCmd => {
146 self.spi_slave.data_outbound.next =
147 bit_cast::<32, 16>(self.reg_ram.read_data.val());
148 self.spi_slave.bits.next = 16.into();
149 self.spi_slave.start_send.next = true;
150 self.state.d.next = ADS868XState::Waiting;
151 }
152 ADS868XState::ReadByteCmd => {
153 if self.address.val().get_bit(0) {
154 self.spi_slave.data_outbound.next =
155 bit_cast::<32, 16>(self.reg_ram.read_data.val() >> 8);
156 } else {
157 self.spi_slave.data_outbound.next =
158 bit_cast::<32, 16>(self.reg_ram.read_data.val() & 0xFF);
159 }
160 self.spi_slave.bits.next = 8.into();
161 self.spi_slave.start_send.next = true;
162 self.state.d.next = ADS868XState::Waiting;
163 }
164 ADS868XState::WriteWordCmd => {
165 self.reg_ram.write_data.next = bit_cast::<16, 32>(self.inbound.q.val() & 0xFFFF);
166 self.reg_ram.write_enable.next = true;
167 self.state.d.next = ADS868XState::WriteDone;
168 }
169 ADS868XState::WriteLSBCmd => {
170 self.reg_ram.write_data.next = bit_cast::<16, 32>(self.inbound.q.val() & 0x00FF)
171 | (self.reg_ram.read_data.val() & 0xFF00);
172 self.reg_ram.write_enable.next = true;
173 self.state.d.next = ADS868XState::WriteDone;
174 }
175 ADS868XState::WriteMSBCmd => {
176 self.reg_ram.write_data.next = bit_cast::<16, 32>(self.inbound.q.val() & 0xFF00)
177 | (self.reg_ram.read_data.val() & 0x00FF);
178 self.reg_ram.write_enable.next = true;
179 self.state.d.next = ADS868XState::WriteDone;
180 }
181 ADS868XState::WriteDone => {
182 self.spi_slave.bits.next = 32.into();
183 self.spi_slave.data_outbound.next = self.inbound.q.val();
184 self.spi_slave.start_send.next = true;
185 self.state.d.next = ADS868XState::Waiting;
186 }
187 ADS868XState::Nop => {
188 self.spi_slave.bits.next = 32.into();
189 self.spi_slave.data_outbound.next =
199 (bit_cast::<32, 16>(self.conversion_counter.q.val()) << 16)
200 | (bit_cast::<32, 16>(self.reg_ram.read_data.val() & 0x0FF) << 12)
201 | (bit_cast::<32, 1>(self.data_parity.val().into()) << 8)
202 | (bit_cast::<32, 1>(
203 (self.data_parity.val() ^ self.id_parity.val()).into(),
204 ) << 9);
205 self.spi_slave.start_send.next = true;
206 self.state.d.next = ADS868XState::Waiting;
207 self.conversion_counter.d.next = self.conversion_counter.q.val() + 1;
208 }
209 _ => {
210 self.state.d.next = ADS868XState::Ready;
211 }
212 }
213 }
214}
215
216#[test]
217fn test_ads8689_synthesizes() {
218 let mut uut = ADS868XSimulator::new(ADS868XSimulator::spi_sw());
219 uut.connect_all();
220 yosys_validate("ads8689", &generate_verilog(&uut)).unwrap();
221}
222
223#[derive(LogicBlock)]
224struct Test8689 {
225 clock: Signal<In, Clock>,
226 master: SPIMaster<32>,
227 adc: ADS868XSimulator,
228}
229
230impl Logic for Test8689 {
231 #[hdl_gen]
232 fn update(&mut self) {
233 clock!(self, clock, master, adc);
234 SPIWiresMaster::join(&mut self.master.wires, &mut self.adc.wires);
235 }
236}
237
238impl Default for Test8689 {
239 fn default() -> Self {
240 Self {
241 clock: Default::default(),
242 master: SPIMaster::new(ADS868XSimulator::spi_sw()),
243 adc: ADS868XSimulator::new(ADS868XSimulator::spi_sw()),
244 }
245 }
246}
247
248#[cfg(test)]
249fn do_spi_txn(
250 bits: u16,
251 value: u64,
252 continued: bool,
253 mut x: Box<Test8689>,
254 sim: &mut Sim<Test8689>,
255) -> Result<(Bits<32>, Box<Test8689>), SimError> {
256 wait_clock_true!(sim, clock, x);
257 x.master.data_outbound.next = value.to_bits();
258 x.master.bits_outbound.next = bits.to_bits();
259 x.master.continued_transaction.next = continued;
260 x.master.start_send.next = true;
261 wait_clock_cycle!(sim, clock, x);
262 x.master.start_send.next = false;
263 x = sim
264 .watch(|x| x.master.transfer_done.val().into(), x)
265 .unwrap();
266 let ret = x.master.data_inbound.val();
267 for _ in 0..50 {
268 wait_clock_cycle!(sim, clock, x);
269 }
270 Ok((ret, x))
271}
272
273#[cfg(test)]
274fn mk_test8689() -> Test8689 {
275 let mut uut = Test8689::default();
276 uut.clock.connect();
277 uut.master.continued_transaction.connect();
278 uut.master.start_send.connect();
279 uut.master.data_outbound.connect();
280 uut.master.bits_outbound.connect();
281 uut.connect_all();
282 uut
283}
284
285#[test]
286fn test_yosys_validate_test_fixture() {
287 let uut = mk_test8689();
288 yosys_validate("8689_1", &generate_verilog(&uut)).unwrap();
289}
290
291#[test]
292fn test_reg_writes() {
293 let uut = mk_test8689();
294 let mut sim = Simulation::new();
295 sim.add_clock(5, |x: &mut Box<Test8689>| x.clock.next = !x.clock.val());
296 sim.add_testbench(move |mut sim: Sim<Test8689>| {
297 let mut x = sim.init()?;
298
299 wait_clock_cycles!(sim, clock, x, 50);
300 wait_clock_true!(sim, clock, x);
301 wait_clock_cycle!(sim, clock, x);
302 let result = do_spi_txn(32, 0xd0_02_00_02, false, x, &mut sim)?;
304 x = result.1;
305 wait_clock_cycle!(sim, clock, x);
306 wait_clock_cycle!(sim, clock, x);
307 let result = do_spi_txn(32, 0x48_02_00_00, false, x, &mut sim)?;
308 x = result.1;
309 let result = do_spi_txn(8, 0x00, false, x, &mut sim)?;
310 println!("ID Register read {:x}", result.0);
311 x = result.1;
312 sim_assert_eq!(sim, result.0.index(), 2, x);
313 wait_clock_cycle!(sim, clock, x);
318 let result = do_spi_txn(32, 0xd0_10_40_08, false, x, &mut sim)?;
319 x = result.1;
320 wait_clock_cycle!(sim, clock, x);
321 let result = do_spi_txn(32, 0xc8_10_00_00, false, x, &mut sim)?;
322 x = result.1;
323 wait_clock_cycle!(sim, clock, x);
324 let result = do_spi_txn(16, 0x00, false, x, &mut sim)?;
325 x = result.1;
326 sim_assert_eq!(sim, result.0.index(), 0x40_08, x);
327 for i in 0..5 {
328 wait_clock_cycle!(sim, clock, x);
329 let result = do_spi_txn(32, 0x00_00_00_00, false, x, &mut sim)?;
330 x = result.1;
331 println!("Reading is {:x}", result.0);
332 sim_assert_eq!(sim, (result.0 & 0xFFFF0000), ((i + 2) << 16), x);
333 let parity_bit = result.0 & 0x100 != 0;
334 let data: Bits<32> = (result.0 & 0xFFFF0000) >> 16;
335 sim_assert_eq!(sim, data.xor(), parity_bit, x);
336 }
337 sim.done(x)
338 });
339 sim.run_to_file(Box::new(uut), 1_000_000, &vcd_path!("ad868x.vcd"))
341 .unwrap();
342}
343
344#[test]
345fn test_parity_calculations() {
346 for sample in [
347 0x00020C00,
348 0x92ab1400_u32,
349 0x734b1800,
350 0x4fc81400,
351 0x7bee1400,
352 0x94821800_u32,
353 0x5eb31400,
354 0x4eaa1400,
355 0x8ac91800_u32,
356 0x95321800_u32,
357 0x54c01800,
358 0x561a1800,
359 0x91601800_u32,
360 0x7e401800,
361 0x50961400,
362 ] {
363 let mut data = (sample & 0xFFFF_0000_u32) >> 16;
364 let mut parity = false;
365 for _ in 0..16 {
366 parity = parity ^ (data & 0x1 != 0);
367 data = data >> 1;
368 }
369 let adc_flag = (sample & 0x800) != 0;
370 assert_eq!(adc_flag, parity);
371 }
372}