1use super::ad7193_sim::AD7193Config;
2use rust_hdl_core::prelude::*;
3use rust_hdl_widgets::prelude::*;
4
5#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
6enum MAX31856State {
7 Start,
8 Ready,
9 GettingCmd,
10 RegFetchRead,
11 ReadCmd,
12 WaitReadComplete,
13 WriteCmd,
14 DoWrite,
15}
16
17#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
18enum DAQState {
19 Idle,
20 Convert,
21 Copy0,
22 Copy1,
23}
24
25#[derive(LogicBlock)]
26pub struct MAX31856Simulator {
27 pub wires: SPIWiresSlave,
29 pub clock: Signal<In, Clock>,
30 reg_ram: RAM<Bits<8>, 4>,
32 auto_conversions_enabled: DFF<Bit>,
34 auto_conversion_strobe: Strobe<32>,
35 auto_conversion_counter: DFF<Bits<19>>,
36 cmd: Signal<Local, Bits<8>>,
38 rw_flag: Signal<Local, Bit>,
39 reg_index: Signal<Local, Bits<4>>,
40 spi_slave: SPISlave<64>,
42 state: DFF<MAX31856State>,
44 reg_read_index: DFF<Bits<4>>,
45 reg_write_index: DFF<Bits<4>>,
46 boot: DFF<Bits<4>>,
48 dstate: DFF<DAQState>,
50}
51
52const MAX31856_REG_INITS: [u8; 16] = [
53 0x00, 0x03, 0xFF, 0x7F, 0xC0, 0x7F, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54];
55
56impl MAX31856Simulator {
57 pub fn new(config: SPIConfig) -> Self {
58 let reg_ram = MAX31856_REG_INITS.iter().map(|x| x.to_bits()).into();
59 Self {
60 wires: Default::default(),
61 clock: Default::default(),
62 reg_ram,
63 auto_conversions_enabled: Default::default(),
64 auto_conversion_strobe: Strobe::new(config.clock_speed, 100.0),
65 auto_conversion_counter: Default::default(),
66 cmd: Default::default(),
67 rw_flag: Default::default(),
68 spi_slave: SPISlave::new(config),
69 state: Default::default(),
70 reg_read_index: Default::default(),
71 reg_write_index: Default::default(),
72 boot: DFF::default(),
73 reg_index: Default::default(),
74 dstate: Default::default(),
75 }
76 }
77}
78
79impl Logic for MAX31856Simulator {
80 #[hdl_gen]
81 fn update(&mut self) {
82 SPIWiresSlave::link(&mut self.wires, &mut self.spi_slave.wires);
84 self.reg_ram.write_clock.next = self.clock.val();
86 self.reg_ram.read_clock.next = self.clock.val();
87 dff_setup!(
89 self,
90 clock,
91 auto_conversions_enabled,
92 auto_conversion_counter,
93 state,
94 reg_read_index,
95 reg_write_index,
96 boot,
97 dstate
98 );
99 clock!(self, clock, auto_conversion_strobe, spi_slave);
100 self.spi_slave.start_send.next = false;
102 self.spi_slave.continued_transaction.next = false;
103 self.spi_slave.bits.next = 0.into();
104 self.spi_slave.data_outbound.next = 0.into();
105 self.reg_ram.write_enable.next = false;
106 self.spi_slave.disabled.next = false;
107 self.cmd.next = self.spi_slave.data_inbound.val().get_bits::<8>(0);
108 self.reg_index.next = self.cmd.val().get_bits::<4>(0);
109 self.rw_flag.next = self.cmd.val().get_bit(7);
110 self.reg_ram.read_address.next = self.reg_read_index.q.val();
111 self.reg_ram.write_address.next = self.reg_write_index.q.val();
112 self.reg_ram.write_data.next = self.spi_slave.data_inbound.val().get_bits::<8>(0);
113 self.auto_conversion_strobe.enable.next = self.auto_conversions_enabled.q.val();
114 match self.state.q.val() {
115 MAX31856State::Start => {
116 self.boot.d.next = self.boot.q.val() + 1;
117 if self.boot.q.val().all() {
118 self.state.d.next = MAX31856State::Ready
119 }
120 }
121 MAX31856State::Ready => {
122 self.spi_slave.continued_transaction.next = true;
123 self.spi_slave.bits.next = 8.into();
124 self.spi_slave.data_outbound.next = 0xFF.into();
125 self.spi_slave.start_send.next = true;
126 self.state.d.next = MAX31856State::GettingCmd;
127 }
128 MAX31856State::GettingCmd => {
129 if self.spi_slave.transfer_done.val() {
130 if !self.rw_flag.val() {
131 self.reg_read_index.d.next = self.reg_index.val();
132 self.state.d.next = MAX31856State::RegFetchRead;
133 } else {
134 self.reg_write_index.d.next = self.reg_index.val();
135 self.state.d.next = MAX31856State::WriteCmd;
136 }
137 }
138 }
139 MAX31856State::RegFetchRead => {
140 self.state.d.next = MAX31856State::ReadCmd;
141 }
142 MAX31856State::ReadCmd => {
143 self.spi_slave.continued_transaction.next = true;
144 self.spi_slave.bits.next = 8.into();
145 self.spi_slave.data_outbound.next = bit_cast::<64, 8>(self.reg_ram.read_data.val());
146 self.spi_slave.start_send.next = true;
147 self.state.d.next = MAX31856State::WaitReadComplete;
148 }
149 MAX31856State::WaitReadComplete => {
150 if !self.spi_slave.busy.val() & self.spi_slave.transfer_done.val() {
151 self.state.d.next = MAX31856State::Ready;
152 }
153 if self.spi_slave.busy.val() & self.spi_slave.transfer_done.val() {
154 self.reg_read_index.d.next = self.reg_read_index.q.val() + 1;
155 self.state.d.next = MAX31856State::RegFetchRead;
156 }
157 }
158 MAX31856State::WriteCmd => {
159 self.spi_slave.continued_transaction.next = true;
160 self.spi_slave.bits.next = 8.into();
161 self.spi_slave.data_outbound.next = 0xFF.into();
162 self.spi_slave.start_send.next = true;
163 self.state.d.next = MAX31856State::DoWrite;
164 }
165 MAX31856State::DoWrite => {
166 if !self.spi_slave.busy.val() & self.spi_slave.transfer_done.val() {
167 if !self.reg_write_index.q.val().any() {
168 self.auto_conversions_enabled.d.next =
169 self.spi_slave.data_inbound.val().get_bit(7);
170 }
171 self.reg_ram.write_enable.next = true;
172 self.state.d.next = MAX31856State::Ready;
173 }
174 if self.spi_slave.busy.val() & self.spi_slave.transfer_done.val() {
175 self.reg_ram.write_enable.next = true;
176 self.reg_write_index.d.next = self.reg_write_index.q.val() + 1;
177 self.state.d.next = MAX31856State::WriteCmd;
178 }
179 }
180 _ => {
181 self.state.d.next = MAX31856State::Start;
182 }
183 }
184 match self.dstate.q.val() {
188 DAQState::Idle => {
189 if self.auto_conversion_strobe.strobe.val() {
190 self.auto_conversion_counter.d.next = self.auto_conversion_counter.q.val() + 1;
191 self.dstate.d.next = DAQState::Convert;
192 }
193 }
194 DAQState::Convert => {
195 self.reg_ram.write_address.next = 0x0E.into();
196 self.reg_ram.write_data.next =
197 bit_cast::<8, 3>(self.auto_conversion_counter.q.val().get_bits::<3>(0)) << 5;
198 self.reg_ram.write_enable.next = true;
199 self.dstate.d.next = DAQState::Copy0;
200 }
201 DAQState::Copy0 => {
202 self.reg_ram.write_address.next = 0x0D.into();
203 self.reg_ram.write_data.next =
204 self.auto_conversion_counter.q.val().get_bits::<8>(3);
205 self.reg_ram.write_enable.next = true;
206 self.dstate.d.next = DAQState::Copy1;
207 }
208 DAQState::Copy1 => {
209 self.reg_ram.write_address.next = 0x0C.into();
210 self.reg_ram.write_data.next =
211 self.auto_conversion_counter.q.val().get_bits::<8>(11);
212 self.reg_ram.write_enable.next = true;
213 self.dstate.d.next = DAQState::Idle;
214 }
215 _ => {
216 self.dstate.d.next = DAQState::Idle;
217 }
218 }
219 }
220}
221
222#[test]
223fn test_max31856_synthesizes() {
224 let mut uut = MAX31856Simulator::new(SPIConfig {
225 clock_speed: 1_000_000,
226 cs_off: true,
227 mosi_off: true,
228 speed_hz: 10_000,
229 cpha: true,
230 cpol: true,
231 });
232 uut.connect_all();
233 yosys_validate("max31856", &generate_verilog(&uut)).unwrap();
234}
235
236#[derive(LogicBlock)]
237struct Test31856 {
238 clock: Signal<In, Clock>,
239 master: SPIMaster<64>,
240 uut: MAX31856Simulator,
241}
242
243impl Logic for Test31856 {
244 #[hdl_gen]
245 fn update(&mut self) {
246 clock!(self, clock, master, uut);
247 SPIWiresMaster::join(&mut self.master.wires, &mut self.uut.wires);
248 }
249}
250
251impl Default for Test31856 {
252 fn default() -> Self {
253 Self {
254 clock: Default::default(),
255 master: SPIMaster::new(AD7193Config::sw().spi),
256 uut: MAX31856Simulator::new(AD7193Config::sw().spi),
257 }
258 }
259}
260
261#[cfg(test)]
262fn reg_read(
263 reg_index: u32,
264 x: Box<Test31856>,
265 sim: &mut Sim<Test31856>,
266) -> Result<(Bits<64>, Box<Test31856>), SimError> {
267 let cmd = (reg_index << 8) as u64;
268 let result = do_spi_txn(16, cmd.into(), false, x, sim)?;
269 let reg_val = result.0 & 0xFF;
270 Ok((reg_val, result.1))
271}
272
273#[cfg(test)]
274fn reg_write(
275 reg_index: u32,
276 reg_value: u64,
277 x: Box<Test31856>,
278 sim: &mut Sim<Test31856>,
279) -> Result<Box<Test31856>, SimError> {
280 let mut cmd = (((1 << 7) | reg_index) << 8) as u64;
281 cmd = cmd | (reg_value & 0xFF);
282 let ret = do_spi_txn(16, cmd.into(), false, x, sim)?;
283 Ok(ret.1)
284}
285
286#[cfg(test)]
287fn do_spi_txn(
288 bits: u16,
289 value: u64,
290 continued: bool,
291 mut x: Box<Test31856>,
292 sim: &mut Sim<Test31856>,
293) -> Result<(Bits<64>, Box<Test31856>), SimError> {
294 wait_clock_true!(sim, clock, x);
295 wait_clock_cycles!(sim, clock, x, 10);
296 x.master.data_outbound.next = value.to_bits();
297 x.master.bits_outbound.next = bits.to_bits();
298 x.master.continued_transaction.next = continued;
299 x.master.start_send.next = true;
300 wait_clock_cycle!(sim, clock, x);
301 x.master.start_send.next = false;
302 x = sim.watch(
303 |x| x.clock.val().clk && x.master.transfer_done.val().into(),
304 x,
305 )?;
306 let ret = x.master.data_inbound.val();
307 wait_clock_true!(sim, clock, x);
308 wait_clock_cycles!(sim, clock, x, 50);
309 Ok((ret, x))
310}
311
312#[cfg(test)]
313fn mk_test31856() -> Test31856 {
314 let mut uut = Test31856::default();
315 uut.clock.connect();
316 uut.master.continued_transaction.connect();
317 uut.master.start_send.connect();
318 uut.master.data_outbound.connect();
319 uut.master.bits_outbound.connect();
320 uut.connect_all();
321 uut
322}
323
324#[test]
325fn test_yosys_validate_test_fixture() {
326 let uut = mk_test31856();
327 yosys_validate("31856_1", &generate_verilog(&uut)).unwrap();
328}
329
330#[test]
331fn test_multireg_reads() {
332 let uut = mk_test31856();
333 let mut sim = Simulation::new();
334 sim.add_clock(5, |x: &mut Box<Test31856>| x.clock.next = !x.clock.val());
335 sim.add_testbench(move |mut sim: Sim<Test31856>| {
336 let mut x = sim.init()?;
337
338 wait_clock_true!(sim, clock, x);
339 wait_clock_cycles!(sim, clock, x, 20);
340 let cmd = 1 << 32;
341 let result = do_spi_txn(40, cmd, false, x, &mut sim)?;
342 x = result.1;
343 sim_assert_eq!(
344 sim,
345 result.0 & 0xFF_FF_FF_FF,
346 Bits::<64>::from(0x03_FF_7F_C0),
347 x
348 );
349 sim.done(x)
350 });
351 sim.run(Box::new(uut), 100_000).unwrap();
352}
353
354#[test]
355fn test_multireg_write() {
356 let uut = mk_test31856();
357 let mut sim = Simulation::new();
358 sim.add_clock(5, |x: &mut Box<Test31856>| x.clock.next = !x.clock.val());
359 sim.add_testbench(move |mut sim: Sim<Test31856>| {
360 let mut x = sim.init()?;
361
362 wait_clock_true!(sim, clock, x);
363 wait_clock_cycles!(sim, clock, x, 20);
364 let cmd = 0x81 << 32 | 0xDEADBEEF;
365 println!("CMD = {:x}", cmd);
366 let result = do_spi_txn(40, cmd, false, x, &mut sim)?;
367 x = result.1;
368 let cmd = 0x1 << 32;
369 let result = do_spi_txn(40, cmd, false, x, &mut sim)?;
370 x = result.1;
371 sim_assert_eq!(
372 sim,
373 result.0 & 0xFF_FF_FF_FF,
374 0xDEADBEEF_u32.to_bits::<64>(),
375 x
376 );
377 sim.done(x)
378 });
379 sim.run(Box::new(uut), 100_000).unwrap();
380}
381
382#[test]
383fn test_reg_reads() {
384 let uut = mk_test31856();
385 let mut sim = Simulation::new();
386 sim.add_clock(5, |x: &mut Box<Test31856>| x.clock.next = !x.clock.val());
387 sim.add_testbench(move |mut sim: Sim<Test31856>| {
388 let mut x = sim.init()?;
389
390 wait_clock_true!(sim, clock, x);
391 wait_clock_cycles!(sim, clock, x, 20);
392 for ndx in 0..16 {
393 println!("Reading register index {}", ndx);
394 let result = reg_read(ndx, x, &mut sim)?;
395 x = result.1;
396 println!("Value {} -> {:x}", ndx, result.0);
397 sim_assert_eq!(
398 sim,
399 result.0,
400 MAX31856_REG_INITS[ndx as usize].to_bits::<64>(),
401 x
402 );
403 wait_clock_true!(sim, clock, x);
404 }
405 sim.done(x)
406 });
407 sim.run(Box::new(uut), 1_000_000).unwrap();
409}
410
411#[test]
412fn test_reg_writes() {
413 use std::num::Wrapping;
414 let uut = mk_test31856();
415 let mut sim = Simulation::new();
416 sim.add_clock(5, |x: &mut Box<Test31856>| x.clock.next = !x.clock.val());
417 sim.add_testbench(move |mut sim: Sim<Test31856>| {
418 let mut x = sim.init()?;
419
420 wait_clock_true!(sim, clock, x);
422 wait_clock_cycles!(sim, clock, x, 20);
423 for ndx in 0..16 {
424 let result = reg_read(ndx, x, &mut sim)?;
425 x = result.1;
426 sim_assert_eq!(
427 sim,
428 result.0,
429 MAX31856_REG_INITS[ndx as usize].to_bits::<64>(),
430 x
431 );
432 println!("Read of register {} -> {:x}", ndx, result.0);
433 x = reg_write(
434 ndx,
435 (MAX31856_REG_INITS[ndx as usize] as u64 + 1) as u64,
436 x,
437 &mut sim,
438 )?;
439 let result = reg_read(ndx, x, &mut sim)?;
440 x = result.1;
441 sim_assert_eq!(
442 sim,
443 result.0,
444 (Wrapping(MAX31856_REG_INITS[ndx as usize]) + Wrapping(1))
445 .0
446 .to_bits::<64>(),
447 x
448 );
449 println!("Re-read of register {} -> {:x}", ndx, result.0);
450 }
451 sim.done(x)
452 });
453 sim.run(Box::new(uut), 1_000_000).unwrap();
454}
455
456#[test]
457fn test_single_conversion() {
458 let uut = mk_test31856();
459 let mut sim = Simulation::new();
460 sim.add_clock(5, |x: &mut Box<Test31856>| x.clock.next = !x.clock.val());
461 sim.add_testbench(move |mut sim: Sim<Test31856>| {
462 let mut x = sim.init()?;
463
464 wait_clock_true!(sim, clock, x);
465 wait_clock_cycles!(sim, clock, x, 50);
466 x = reg_write(0, 0x80, x, &mut sim)?;
467 x = sim.wait(200_000, x)?;
468 let result = reg_read(0x0E, x, &mut sim)?;
469 x = result.1;
470 sim_assert_eq!(sim, result.0 & 0xFF, 0x40, x);
471 let cmd = 0xC << 24;
472 let result = do_spi_txn(32, cmd, false, x, &mut sim)?;
473 x = result.1;
474 sim_assert_eq!(sim, result.0 & 0xFFFFFF, 0x40, x);
475 sim.done(x)
476 });
477 sim.run_to_file(Box::new(uut), 1_000_000, "/tmp/mread.vcd")
479 .unwrap();
480}