From 8e6e483f922018eff8629dba728a4676f86a5ca5 Mon Sep 17 00:00:00 2001 From: David Lenfesty Date: Sat, 27 May 2023 13:20:08 -0600 Subject: [PATCH] gw: switch to strobe-style control bits for controller --- gateware/litex_main.py | 1 + gateware/sampler/controller.py | 198 ++++++++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 6 deletions(-) diff --git a/gateware/litex_main.py b/gateware/litex_main.py index ae1568e..8a11a18 100755 --- a/gateware/litex_main.py +++ b/gateware/litex_main.py @@ -185,6 +185,7 @@ def main(): results.append(run_test("SamplerController", controller.test_bus_access)) results.append(run_test("SamplerController", controller.test_simple_waveform)) results.append(run_test("SamplerController", controller.test_simple_waveform_capture_offset)) + results.append(run_test("SamplerController", controller.test_multiple_reads)) results.append(run_test("PeakDetector", peak_detector.test_simple_waveform)) results.append(run_test("PeakDetector", peak_detector.test_scrunched_simple_waveform)) results.append(run_test("PeakDetector", peak_detector.test_decay_simple_waveform)) diff --git a/gateware/sampler/controller.py b/gateware/sampler/controller.py index 070a897..d15b1ec 100644 --- a/gateware/sampler/controller.py +++ b/gateware/sampler/controller.py @@ -27,11 +27,14 @@ class SamplerController(Module): Registers -------- - 0x00: Control Register (RW) - Bit 0 - Begin capture. Resets all FIFOs and starts the peak detector + 0x00: Control Register (WO) + Bit 0 - Start capture + Bit 1 - Stop capture. Does nothing if capture is not ongoing + Bit 2 - Clear sample buffers 0x01: Status Register (RO) Bit 0 - Capture complete. Set by peak detection block and cleared when capture is began + Bit 1 - Sampling running 0x02: trigger_run_len (RW) Number of samples to acquire after triggering sample. @@ -138,7 +141,7 @@ class SamplerController(Module): # Handle explicit config registers cases = { - 0: rw_register(control_register), + 0: rw_register(control_register, read=False), 1: rw_register(status_register, write=False), 2: rw_register(trigger_run_len), 3: rw_register(self.peak_detector.thresh_value), @@ -156,6 +159,8 @@ class SamplerController(Module): # Connect up control registers bus self.sync += [ self.control_regs_bus.ack.eq(0), + # Hold control register low to use as strobe functionality + control_register.eq(0), If(self.control_regs_bus.cyc & self.control_regs_bus.stb, self.control_regs_bus.ack.eq(1), Case(self.control_regs_bus.adr, cases)), @@ -180,13 +185,20 @@ class SamplerController(Module): # We have sampled enough, update status and stop sampling If(post_trigger_count + 1 >= trigger_run_len, status_register[0].eq(1), - control_register[0].eq(0))), + sample_enable.eq(0))), ] # Update register storage - self.comb += [ - sample_enable.eq(control_register[0]), + self.sync += [ + status_register[1].eq(sample_enable), + If(control_register[0], sample_enable.eq(1)), + If(control_register[1], sample_enable.eq(0)), ] + for buffer in self.buffers: + self.sync += [ + buffer.clear.eq(0), + If(control_register[2], buffer.clear.eq(1)), + ] def write_wishbone(bus, address, value): # Set up bus @@ -341,6 +353,11 @@ def test_simple_waveform(): sample = (yield dut.bus.dat_r) data.append(sample) + # Manually validated, this is what we should read on a correct + # run + assert data[15] == 138 + assert data[16] == 132 + # Test pass return @@ -418,3 +435,172 @@ def test_simple_waveform_capture_offset(): assert False, "We should have triggered" run_simulation(dut, test_fn()) + + +def test_multiple_reads(): + """ + Testing multiple triggers/captures in succession to ensure typical (i.e. repeated) operation + works correctly. + """ + # Enable, trigger works correctly + # Enable, tick a bit of data in, should not trigger, and trigger should have reset immediately + # Enable again, and tick in lots of data, should trigger again now + """Test a simple waveform captured at an offset""" + from .peak_detector import create_waveform + _, data = create_waveform() + data = [int(d) for d in data] + dut = TestSoC(data, buffer_len=32) + + def test_fn(): + # Set settings + yield from write_wishbone(dut.bus, 2, 0) # trigger_run_len = 0 + yield from write_wishbone(dut.bus, 3, 800) # thresh_value = 800 + yield from write_wishbone(dut.bus, 4, 10) # thresh_time = 10 + yield from write_wishbone(dut.bus, 5, 1) # decay_value = 1 + yield from write_wishbone(dut.bus, 5, 0) # decay_period = 0 + + # Start controller + yield from write_wishbone(dut.bus, 0, 1) + + triggered_yet = False + triggered_num = 0 + for i in range(1000): + (yield dut.samplers[0].index.eq(i)) + (yield dut.samplers[0].valid.eq(1)) + yield + + (yield dut.samplers[0].valid.eq(0)) + yield + + # Total of 6 clocks per sample clock + yield + yield + yield + yield + + if not triggered_yet and (yield dut.controller.peak_detector.triggered) == 1: + # Triggered, now we need to run some number of cycles + triggered_yet = True + + if triggered_yet: + triggered_num += 1 + if triggered_num > 16: + # We should now have collected all our samples + yield from read_wishbone(dut.bus, 1) + assert (yield dut.bus.dat_r) == 1, "Trigger did not propogate to WB!" + + # Check that length is correct + yield from read_wishbone(dut.bus, 0x100) + len = (yield dut.bus.dat_r) + assert len == 32, f"Len ({len}) not correct!" + + # Read data in + data = [] + for i in range(32): + yield from read_wishbone(dut.bus, 0x800 + i) + sample = (yield dut.bus.dat_r) + data.append(sample) + + + # Manually validated from test above to be offset into the + # data + assert data[15] == 138 + assert data[16] == 132 + break + + assert triggered_yet, "We should have triggered" + + # Clear out sampler and re-enable + yield from write_wishbone(dut.bus, 0, 0b101) + yield + + assert (yield dut.controller.peak_detector.triggered) == 0, "Trigger should have been cleared" + assert (yield dut.controller.buffers[0].len) == 0, "Buffers should have been cleared" + + # Tick a few clocks through, and we shouldn't have triggered + for i in range(10): + (yield dut.samplers[0].index.eq(i)) + (yield dut.samplers[0].valid.eq(1)) + yield + + (yield dut.samplers[0].valid.eq(0)) + yield + + # Total of 6 clocks per sample clock + yield + yield + yield + yield + + assert (yield dut.controller.peak_detector.triggered) == 0, "We didn't push enough data through to trigger" + + # Disable sampler, run lots of data through, we should not trigger + yield from write_wishbone(dut.bus, 0, 0b010) + for i in range(1000): + (yield dut.samplers[0].index.eq(i)) + (yield dut.samplers[0].valid.eq(1)) + yield + + (yield dut.samplers[0].valid.eq(0)) + yield + + # Total of 6 clocks per sample clock + yield + yield + yield + yield + + # Enable sampler and run again, we should get another trigger + yield from write_wishbone(dut.bus, 2, 16) # trigger_run_len = 16 + yield from write_wishbone(dut.bus, 0, 1) + triggered_yet = False + triggered_num = 0 + for i in range(1000): + (yield dut.samplers[0].index.eq(i)) + (yield dut.samplers[0].valid.eq(1)) + yield + + (yield dut.samplers[0].valid.eq(0)) + yield + + # Total of 6 clocks per sample clock + yield + yield + yield + yield + + if not triggered_yet and (yield dut.controller.peak_detector.triggered) == 1: + # Triggered, now we need to run some number of cycles + triggered_yet = True + + if triggered_yet: + triggered_num += 1 + if triggered_num > 16: + # We should now have collected all our samples + yield from read_wishbone(dut.bus, 1) + assert (yield dut.bus.dat_r) == 1, "Trigger did not propogate to WB!" + + # Check that length is correct + yield from read_wishbone(dut.bus, 0x100) + len = (yield dut.bus.dat_r) + assert len == 32, f"Len ({len}) not correct!" + + # Read data in + data = [] + for i in range(32): + yield from read_wishbone(dut.bus, 0x800 + i) + sample = (yield dut.bus.dat_r) + data.append(sample) + + + # Manually validated from test above to be offset into the + # data + assert data[0] == 138 + assert data[1] == 132 + + # Test pass + return + + assert triggered_yet, "We should have triggered" + + run_simulation(dut, test_fn(), vcd_name="controller.vcd")