From c0bab06765bb1126935254f5b84a26fbac22fc72 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 28 May 2018 19:16:53 +0200 Subject: [PATCH] core: add sequential-triggering and simplify control --- litescope/core.py | 87 +++++++++++++++++---------- litescope/software/driver/analyzer.py | 20 +++--- 2 files changed, 66 insertions(+), 41 deletions(-) diff --git a/litescope/core.py b/litescope/core.py index ce7dc51..1222db8 100644 --- a/litescope/core.py +++ b/litescope/core.py @@ -28,25 +28,55 @@ def core_layout(dw): class FrontendTrigger(Module, AutoCSR): - def __init__(self, dw): + def __init__(self, dw, depth=16): self.sink = sink = stream.Endpoint(core_layout(dw)) self.source = source = stream.Endpoint(core_layout(dw)) - self.value = CSRStorage(dw) - self.mask = CSRStorage(dw) + self.enable = CSRStorage() + self.done = CSRStatus() + + self.mem_write = CSR() + self.mem_mask = CSRStorage(dw) + self.mem_value = CSRStorage(dw) # # # - value = Signal(dw) - mask = Signal(dw) - self.specials += [ - MultiReg(self.value.storage, value, "scope"), - MultiReg(self.mask.storage, mask, "scope") + # control re-synchronization + enable = Signal() + enable_d = Signal() + self.specials += MultiReg(self.enable.storage, enable, "scope") + self.sync.scope += enable_d.eq(enable) + + # status re-synchronization + done = Signal() + self.specials += MultiReg(done, self.done.status) + + # memory and configuration + mem = stream.AsyncFIFO([("mask", dw), ("value", dw)], depth) + mem = ClockDomainsRenamer({"write": "sys", "read": "scope"})(mem) + self.submodules += mem + self.comb += [ + mem.sink.valid.eq(self.mem_write.re), + mem.sink.mask.eq(self.mem_mask.storage), + mem.sink.value.eq(self.mem_value.storage) ] + # hit and memory read/flush + hit = Signal() + flush = WaitTimer(depth) + self.submodules += flush + self.comb += [ + flush.wait.eq(~(~enable & enable_d)), # flush when disabling + hit.eq((sink.data & mem.source.mask) == mem.source.value), + mem.source.ready.eq(enable & (hit | ~flush.done)), + ] + + # output self.comb += [ sink.connect(source), - source.hit.eq((sink.data & mask) == value) + # we are done when mem is empty + done.eq(~mem.source.valid), + source.hit.eq(done) ] @@ -119,14 +149,12 @@ class AnalyzerStorage(Module, AutoCSR): def __init__(self, dw, depth): self.sink = sink = stream.Endpoint(core_layout(dw)) - self.start = CSR() + self.enable = CSRStorage() + self.done = CSRStatus() + self.length = CSRStorage(bits_for(depth)) self.offset = CSRStorage(bits_for(depth)) - self.idle = CSRStatus() - self.wait = CSRStatus() - self.run = CSRStatus() - self.mem_valid = CSRStatus() self.mem_ready = CSR() self.mem_data = CSRStatus(dw) @@ -135,27 +163,24 @@ class AnalyzerStorage(Module, AutoCSR): # control re-synchronization - start = Signal() + enable = Signal() + enable_d = Signal() + + enable = Signal() + enable_d = Signal() + self.specials += MultiReg(self.enable.storage, enable, "scope") + self.sync.scope += enable_d.eq(enable) + length = Signal(max=depth) offset = Signal(max=depth) - - start_ps = PulseSynchronizer("sys", "scope") - self.submodules += start_ps - self.comb += start_ps.i.eq(self.start.re) self.specials += [ MultiReg(self.length.storage, length, "scope"), MultiReg(self.offset.storage, offset, "scope") ] # status re-synchronization - idle = Signal() - wait = Signal() - run = Signal() - self.specials += [ - MultiReg(idle, self.idle.status), - MultiReg(wait, self.wait.status), - MultiReg(run, self.run.status) - ] + done = Signal() + self.specials += MultiReg(done, self.done.status) # memory mem = stream.SyncFIFO([("data", dw)], depth, buffered=True) @@ -175,8 +200,8 @@ class AnalyzerStorage(Module, AutoCSR): fsm = ClockDomainsRenamer("scope")(fsm) self.submodules += fsm fsm.act("IDLE", - idle.eq(1), - If(start_ps.o, + done.eq(1), + If(enable & ~enable_d, NextState("FLUSH") ), sink.ready.eq(1), @@ -191,7 +216,6 @@ class AnalyzerStorage(Module, AutoCSR): ) ) fsm.act("WAIT", - wait.eq(1), sink.connect(mem.sink, omit={"hit"}), If(sink.valid & sink.hit, NextState("RUN") @@ -199,7 +223,6 @@ class AnalyzerStorage(Module, AutoCSR): mem.source.ready.eq(mem.level >= self.offset.storage) ) fsm.act("RUN", - run.eq(1), sink.connect(mem.sink, omit={"hit"}), If(mem.level >= self.length.storage, NextState("IDLE"), @@ -209,7 +232,7 @@ class AnalyzerStorage(Module, AutoCSR): # memory read self.comb += [ self.mem_valid.status.eq(cdc.source.valid), - cdc.source.ready.eq(self.mem_ready.re), + cdc.source.ready.eq(self.mem_ready.re | ~self.enable.storage), self.mem_data.status.eq(cdc.source.data) ] diff --git a/litescope/software/driver/analyzer.py b/litescope/software/driver/analyzer.py index 8d617ff..d8951c3 100644 --- a/litescope/software/driver/analyzer.py +++ b/litescope/software/driver/analyzer.py @@ -23,6 +23,10 @@ class LiteScopeAnalyzerDriver: self.group = 0 self.data = DumpData(self.dw) + # disable frontend and storage + self.frontend_trigger_enable.write(0) + self.storage_enable.write(0) + def get_config(self): csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#') for item in csv_reader: @@ -62,30 +66,28 @@ class LiteScopeAnalyzerDriver: self.mux_value.write(value) def configure_trigger(self, value=0, mask=0, cond=None): + self.frontend_trigger_enable.write(0) if cond is not None: for k, v in cond.items(): value |= getattr(self, k + "_o")*v mask |= getattr(self, k + "_m") - t = getattr(self, "frontend_trigger_value") - m = getattr(self, "frontend_trigger_mask") - t.write(value) - m.write(mask) + self.frontend_trigger_mem_mask.write(mask) + self.frontend_trigger_mem_value.write(value) + self.frontend_trigger_mem_write.write(1) def configure_subsampler(self, value): self.frontend_subsampler_value.write(value-1) def run(self, offset, length): - # flush cdc - for i in range(4): - self.storage_mem_ready.write(1) if self.debug: print("[running]...") self.storage_offset.write(offset) self.storage_length.write(length) - self.storage_start.write(1) + self.storage_enable.write(1) + self.frontend_trigger_enable.write(1) def done(self): - return self.storage_idle.read() + return self.storage_done.read() def wait_done(self): while not self.done():