rust_hdl_sim/
ad7193_sim.rs

1use rust_hdl_core::prelude::*;
2use rust_hdl_widgets::prelude::*;
3use std::time::Duration;
4
5#[derive(Copy, Clone, PartialEq, Debug, LogicState)]
6enum AD7193State {
7    Init,
8    Ready,
9    GettingCmd,
10    ReadCmd,
11    WaitSlaveIdle,
12    WriteCmd,
13    DoWrite,
14    SingleConversion,
15    SingleConversionCommit,
16}
17
18#[derive(LogicBlock)]
19pub struct AD7193Simulator {
20    // Slave SPI bus
21    pub wires: SPIWiresSlave,
22    pub clock: Signal<In, Clock>,
23    // ROM that stores register widths
24    reg_width_rom: ROM<Bits<5>, 3>,
25    // RAM that stores register contents
26    reg_ram: RAM<Bits<24>, 3>,
27    // Used to time a single conversion
28    oneshot: Shot<32>,
29    // Separate bits out of a SPI message
30    cmd: Signal<Local, Bits<8>>,
31    reg_index: Signal<Local, Bits<3>>,
32    rw_flag: Signal<Local, Bit>,
33    // The spi slave device
34    spi_slave: SPISlave<64>,
35    // FSM state
36    state: DFF<AD7193State>,
37    reg_write_index: DFF<Bits<3>>,
38    // Rolling counter to emulate conversions
39    conversion_counter: DFF<Bits<24>>,
40}
41
42#[derive(Clone, Copy)]
43pub struct AD7193Config {
44    pub spi: SPIConfig,
45    pub sample_time: Duration,
46}
47
48impl AD7193Config {
49    pub fn hw() -> Self {
50        Self {
51            spi: SPIConfig {
52                clock_speed: 48_000_000,
53                cs_off: true,
54                mosi_off: true,
55                speed_hz: 400_000,
56                cpha: true,
57                cpol: true,
58            },
59            sample_time: Duration::from_micros(10100),
60        }
61    }
62    pub fn sw() -> Self {
63        Self {
64            spi: SPIConfig {
65                clock_speed: 1_000_000,
66                cs_off: true,
67                mosi_off: true,
68                speed_hz: 10_000,
69                cpha: true,
70                cpol: true,
71            },
72            sample_time: Duration::from_micros(100),
73        }
74    }
75}
76
77pub const AD7193_REG_WIDTHS: [u32; 8] = [8, 24, 24, 24, 8, 8, 24, 24];
78const AD7193_REG_INITS: [u64; 8] = [0x40, 0x80060, 0x117, 0x0, 0xa2, 0x0, 0x800000, 0x5544d0];
79
80impl AD7193Simulator {
81    pub fn new(config: AD7193Config) -> Self {
82        assert!(config.spi.clock_speed > 10 * config.spi.speed_hz);
83        let reg_width_rom = AD7193_REG_WIDTHS.iter().map(|x| x.to_bits()).into();
84        let reg_ram = AD7193_REG_INITS.iter().map(|x| x.to_bits()).into();
85        Self {
86            wires: Default::default(),
87            clock: Default::default(),
88            reg_width_rom,
89            reg_ram,
90            oneshot: Shot::new(config.spi.clock_speed, config.sample_time),
91            cmd: Default::default(),
92            reg_index: Default::default(),
93            rw_flag: Default::default(),
94            spi_slave: SPISlave::new(config.spi),
95            state: Default::default(),
96            reg_write_index: Default::default(),
97            conversion_counter: Default::default(),
98        }
99    }
100}
101
102impl Logic for AD7193Simulator {
103    #[hdl_gen]
104    fn update(&mut self) {
105        // Connect the spi bus
106        SPIWiresSlave::link(&mut self.wires, &mut self.spi_slave.wires);
107        // Clock internal components
108        self.reg_ram.read_clock.next = self.clock.val();
109        self.reg_ram.write_clock.next = self.clock.val();
110        clock!(self, clock, oneshot, spi_slave);
111        dff_setup!(self, clock, state, reg_write_index, conversion_counter);
112        // Set default values
113        self.spi_slave.start_send.next = false;
114        self.cmd.next = self.spi_slave.data_inbound.val().get_bits::<8>(0);
115        self.reg_index.next = self.cmd.val().get_bits::<3>(3);
116        self.rw_flag.next = self.cmd.val().get_bit(6);
117        self.reg_width_rom.address.next = self.reg_index.val();
118        self.reg_ram.read_address.next = self.reg_index.val();
119        self.reg_ram.write_address.next = self.reg_index.val();
120        self.spi_slave.continued_transaction.next = false;
121        self.spi_slave.bits.next = 0.into();
122        self.spi_slave.data_outbound.next = 0.into();
123        self.reg_ram.write_enable.next = false;
124        self.reg_ram.write_data.next = 0.into();
125        self.spi_slave.disabled.next = false;
126        self.oneshot.trigger.next = false;
127        match self.state.q.val() {
128            AD7193State::Init => {
129                if self.spi_slave.transfer_done.val() {
130                    self.state.d.next = AD7193State::Ready;
131                }
132            }
133            AD7193State::Ready => {
134                self.spi_slave.continued_transaction.next = true;
135                self.spi_slave.bits.next = 8.into();
136                self.spi_slave.data_outbound.next = 0xFF.into();
137                self.spi_slave.start_send.next = true;
138                self.state.d.next = AD7193State::GettingCmd;
139            }
140            AD7193State::GettingCmd => {
141                if self.spi_slave.transfer_done.val() {
142                    if self.rw_flag.val() {
143                        self.state.d.next = AD7193State::ReadCmd;
144                    } else {
145                        self.reg_write_index.d.next = self.reg_index.val();
146                        self.state.d.next = AD7193State::WriteCmd;
147                    }
148                }
149            }
150            AD7193State::ReadCmd => {
151                self.spi_slave.continued_transaction.next = true;
152                self.spi_slave.bits.next = bit_cast::<16, 5>(self.reg_width_rom.data.val()) + 8;
153                self.spi_slave.data_outbound.next =
154                    (bit_cast::<64, 24>(self.reg_ram.read_data.val()) << 8)
155                        | Bits::<64>::from(0xBA);
156                self.spi_slave.start_send.next = true;
157                self.state.d.next = AD7193State::WaitSlaveIdle;
158            }
159            AD7193State::WriteCmd => {
160                self.spi_slave.continued_transaction.next = true;
161                self.spi_slave.bits.next = bit_cast::<16, 5>(self.reg_width_rom.data.val());
162                self.spi_slave.data_outbound.next = 0xFFFF_FFFF_u64.to_bits();
163                self.spi_slave.start_send.next = true;
164                self.state.d.next = AD7193State::DoWrite;
165            }
166            AD7193State::DoWrite => {
167                if self.spi_slave.transfer_done.val() {
168                    self.reg_ram.write_data.next =
169                        bit_cast::<24, 64>(self.spi_slave.data_inbound.val());
170                    self.reg_ram.write_enable.next = true;
171                    self.reg_ram.write_address.next = self.reg_write_index.q.val();
172                    self.state.d.next = AD7193State::WaitSlaveIdle;
173                    if (self.reg_write_index.q.val() == 1)
174                        & self.spi_slave.data_inbound.val().get_bit(21)
175                    {
176                        self.state.d.next = AD7193State::SingleConversion;
177                        self.oneshot.trigger.next = true;
178                    }
179                }
180            }
181            AD7193State::WaitSlaveIdle => {
182                if !self.spi_slave.busy.val() {
183                    self.state.d.next = AD7193State::Ready;
184                }
185            }
186            AD7193State::SingleConversion => {
187                self.spi_slave.disabled.next = true;
188                if self.oneshot.fired.val() {
189                    self.state.d.next = AD7193State::SingleConversionCommit;
190                }
191            }
192            AD7193State::SingleConversionCommit => {
193                self.reg_ram.write_address.next = 3.into();
194                self.reg_ram.write_data.next = self.conversion_counter.q.val();
195                self.reg_ram.write_enable.next = true;
196                self.conversion_counter.d.next = self.conversion_counter.q.val() + 0x100;
197                self.spi_slave.data_outbound.next = 0.into();
198                self.state.d.next = AD7193State::Ready;
199            }
200            _ => {
201                self.state.d.next = AD7193State::Init;
202            }
203        }
204        if self.spi_slave.transfer_done.val() & self.spi_slave.data_inbound.val().all() {
205            println!("Reset encountered");
206            self.state.d.next = AD7193State::Ready;
207        }
208    }
209}
210
211#[test]
212fn test_ad7193_synthesizes() {
213    let mut uut = AD7193Simulator::new(AD7193Config::sw());
214    uut.connect_all();
215    yosys_validate("ad7193", &generate_verilog(&uut)).unwrap();
216}
217
218#[derive(LogicBlock)]
219struct Test7193 {
220    clock: Signal<In, Clock>,
221    master: SPIMaster<64>,
222    adc: AD7193Simulator,
223}
224
225impl Logic for Test7193 {
226    #[hdl_gen]
227    fn update(&mut self) {
228        clock!(self, clock, master, adc);
229        SPIWiresMaster::join(&mut self.master.wires, &mut self.adc.wires);
230    }
231}
232
233impl Default for Test7193 {
234    fn default() -> Self {
235        Self {
236            clock: Default::default(),
237            master: SPIMaster::new(AD7193Config::sw().spi),
238            adc: AD7193Simulator::new(AD7193Config::sw()),
239        }
240    }
241}
242
243#[cfg(test)]
244fn reg_read(
245    reg_index: u32,
246    x: Box<Test7193>,
247    sim: &mut Sim<Test7193>,
248) -> Result<(Bits<64>, Box<Test7193>), SimError> {
249    let cmd = (((1 << 6) | (reg_index << 3)) << 24).into();
250    let result = do_spi_txn(32, cmd, false, x, sim)?;
251    let width = AD7193_REG_WIDTHS[reg_index as usize];
252    let reg_val = if width == 8 {
253        (result.0 >> 16) & 0xFF
254    } else {
255        result.0 & 0xFFFFFF
256    };
257    Ok((reg_val, result.1))
258}
259
260#[cfg(test)]
261fn reg_write(
262    reg_index: u32,
263    reg_value: u64,
264    x: Box<Test7193>,
265    sim: &mut Sim<Test7193>,
266) -> Result<Box<Test7193>, SimError> {
267    let mut cmd = (((0 << 6) | (reg_index << 3)) << 24).into();
268    if AD7193_REG_WIDTHS[reg_index as usize] == 8 {
269        cmd = cmd | reg_value << 16;
270    } else {
271        cmd = cmd | reg_value;
272    }
273    let ret = do_spi_txn(32, cmd, false, x, sim)?;
274    Ok(ret.1)
275}
276
277#[cfg(test)]
278fn do_spi_txn(
279    bits: u16,
280    value: u64,
281    continued: bool,
282    mut x: Box<Test7193>,
283    sim: &mut Sim<Test7193>,
284) -> Result<(Bits<64>, Box<Test7193>), SimError> {
285    wait_clock_true!(sim, clock, x);
286    x.master.data_outbound.next = value.to_bits();
287    x.master.bits_outbound.next = bits.to_bits();
288    x.master.continued_transaction.next = continued;
289    x.master.start_send.next = true;
290    wait_clock_cycle!(sim, clock, x);
291    x.master.start_send.next = false;
292    x = sim
293        .watch(|x| x.master.transfer_done.val().into(), x)
294        .unwrap();
295    let ret = x.master.data_inbound.val();
296    for _ in 0..50 {
297        wait_clock_cycle!(sim, clock, x);
298    }
299    Ok((ret, x))
300}
301
302#[cfg(test)]
303fn mk_test7193() -> Test7193 {
304    let mut uut = Test7193::default();
305    uut.clock.connect();
306    uut.master.continued_transaction.connect();
307    uut.master.start_send.connect();
308    uut.master.data_outbound.connect();
309    uut.master.bits_outbound.connect();
310    uut.connect_all();
311    uut
312}
313
314#[test]
315fn test_yosys_validate_test_fixture() {
316    let uut = mk_test7193();
317    yosys_validate("7193_1", &generate_verilog(&uut)).unwrap();
318}
319
320#[test]
321fn test_reg_reads() {
322    let uut = mk_test7193();
323    let mut sim = Simulation::new();
324    sim.add_clock(5, |x: &mut Box<Test7193>| x.clock.next = !x.clock.val());
325    sim.add_testbench(move |mut sim: Sim<Test7193>| {
326        let mut x = sim.init()?;
327        // Wait for reset to complete
328        wait_clock_cycles!(sim, clock, x, 20);
329        // Do the first read to initialize the chip
330        let result = do_spi_txn(32, 0xFFFFFFFF, false, x, &mut sim)?;
331        x = result.1;
332        for ndx in 0..8 {
333            println!("Reading register index {}", ndx);
334            let result = reg_read(ndx, x, &mut sim)?;
335            x = result.1;
336            println!("Value {} -> {:x}", ndx, result.0);
337            sim_assert!(
338                sim,
339                result.0 == Bits::<64>::from(AD7193_REG_INITS[ndx as usize]),
340                x
341            );
342            wait_clock_true!(sim, clock, x);
343        }
344        sim.done(x)
345    });
346    sim.run(Box::new(uut), 1_000_000).unwrap();
347}
348
349#[test]
350fn test_reg_writes() {
351    let uut = mk_test7193();
352    let mut sim = Simulation::new();
353    sim.add_clock(5, |x: &mut Box<Test7193>| x.clock.next = !x.clock.val());
354    sim.add_testbench(move |mut sim: Sim<Test7193>| {
355        let mut x = sim.init()?;
356
357        // Wait for reset to complete
358        wait_clock_cycles!(sim, clock, x, 20);
359        // Initialize the chip...
360        let result = do_spi_txn(32, 0xFFFFFFFF, false, x, &mut sim)?;
361        x = result.1;
362        for ndx in 0..8 {
363            let result = reg_read(ndx, x, &mut sim)?;
364            x = result.1;
365            sim_assert!(
366                sim,
367                result.0 == Bits::<64>::from(AD7193_REG_INITS[ndx as usize]),
368                x
369            );
370            x = reg_write(ndx, AD7193_REG_INITS[ndx as usize] + 1, x, &mut sim)?;
371            let result = reg_read(ndx, x, &mut sim)?;
372            x = result.1;
373            sim_assert!(
374                sim,
375                result.0 == Bits::<64>::from(AD7193_REG_INITS[ndx as usize] + 1),
376                x
377            );
378        }
379        sim.done(x)
380    });
381    sim.run(Box::new(uut), 1_000_000).unwrap();
382}
383
384#[test]
385fn test_single_conversion() {
386    let uut = mk_test7193();
387    let mut sim = Simulation::new();
388    sim.add_clock(5, |x: &mut Box<Test7193>| x.clock.next = !x.clock.val());
389    sim.add_testbench(move |mut sim: Sim<Test7193>| {
390        let mut x = sim.init()?;
391
392        // Wait for reset to complete
393        wait_clock_cycles!(sim, clock, x, 20);
394        // Initialize the chip...
395        let result = do_spi_txn(32, 0xFFFFFFFF, false, x, &mut sim)?;
396        x = result.1;
397        for n in 0..3 {
398            wait_clock_cycle!(sim, clock, x, 100);
399            let result = do_spi_txn(32, 0x8382006, true, x, &mut sim)?;
400            x = result.1;
401            wait_clock_cycle!(sim, clock, x, 100);
402            sim_assert!(sim, x.master.wires.miso.val(), x);
403            x = sim.watch(|x| !x.master.wires.miso.val(), x)?;
404            wait_clock_cycle!(sim, clock, x, 100);
405            let result = reg_read(3, x, &mut sim)?;
406            println!("Conversion {} -> {:x}", n, result.0);
407            x = result.1;
408            sim_assert!(sim, result.0 == Bits::<64>::from(n * 0x100), x);
409            println!("Conversion {} completed", n);
410        }
411        sim.done(x)
412    });
413    sim.run(Box::new(uut), 10_000_000).unwrap();
414}