From c5137773f6395ddd8c0426687cf76860ea4df9fc Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 9 Mar 2022 22:07:27 +0100 Subject: [PATCH] core: Change upload protocol to allow bursting through xBone Instead of using a very wide CSR, we force it to max 32 bits and read each captured words as several sub-words. Also, instead of checking for 'valid' flag every time, we just read the 'level' of the memory buffer. Given the way LiteScope works, we know capture is done and this is how many words there is to read. All in all this means that reading the data off the buffer is just reading the same address over and over meaning we can use very long bursts which helps _a_lot_ to speed things up. Signed-off-by: Sylvain Munaut --- litescope/core.py | 28 ++++++++++++++++----- litescope/software/driver/analyzer.py | 35 +++++++++++++++++++-------- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/litescope/core.py b/litescope/core.py index 2c6bd42..1ae3f63 100644 --- a/litescope/core.py +++ b/litescope/core.py @@ -150,8 +150,9 @@ class _Storage(Module, AutoCSR): self.length = CSRStorage(bits_for(depth)) self.offset = CSRStorage(bits_for(depth)) - self.mem_valid = CSRStatus() - self.mem_data = CSRStatus(data_width) + read_width = min(32, data_width) + self.mem_level = CSRStatus(bits_for(depth)) + self.mem_data = CSRStatus(read_width) # # # @@ -167,8 +168,10 @@ class _Storage(Module, AutoCSR): self.specials += MultiReg(self.offset.storage, offset, "scope") # Status re-synchronization - done = Signal() + done = Signal() + level = Signal().like(self.mem_level.status) self.specials += MultiReg(done, self.done.status) + self.specials += MultiReg(level, self.mem_level.status) # Memory mem = stream.SyncFIFO([("data", data_width)], depth, buffered=True) @@ -178,6 +181,8 @@ class _Storage(Module, AutoCSR): {"write": "scope", "read": "sys"})(cdc) self.submodules += mem, cdc + self.comb += level.eq(mem.level) + # Flush mem_flush = WaitTimer(depth) mem_flush = ClockDomainsRenamer("scope")(mem_flush) @@ -218,10 +223,21 @@ class _Storage(Module, AutoCSR): ) # Memory read + if data_width > read_width: + pad_bits = - data_width % read_width + self.submodules.w_conv = w_conv = stream.Converter(data_width + pad_bits, read_width) + self.comb += [ + self.w_conv.sink.data.eq(Cat(cdc.source.data, Constant(0, pad_bits))), + self.w_conv.sink.valid.eq(cdc.source.valid), + cdc.source.ready.eq(self.w_conv.sink.ready), + ] + read_source = w_conv.source + else: + read_source = cdc.source + self.comb += [ - self.mem_valid.status.eq(cdc.source.valid), - cdc.source.ready.eq(self.mem_data.we | ~self.enable.storage), - self.mem_data.status.eq(cdc.source.data) + read_source.ready.eq(self.mem_data.we | ~self.enable.storage), + self.mem_data.status.eq(read_source.data) ] diff --git a/litescope/software/driver/analyzer.py b/litescope/software/driver/analyzer.py index ee9d9ec..f3bebfd 100644 --- a/litescope/software/driver/analyzer.py +++ b/litescope/software/driver/analyzer.py @@ -152,16 +152,31 @@ class LiteScopeAnalyzerDriver: def upload(self): if self.debug: print("[uploading]...") - length = self.storage_length.read() - for position in range(1, length + 1): - if self.debug: - sys.stdout.write("[{}>{}] {}%\r".format('=' * (20*position//length), - ' ' * (20-20*position//length), - 100*position//length)) - sys.stdout.flush() - if not self.storage_mem_valid.read(): - break - self.data.append(self.storage_mem_data.read()) + + length = self.storage_mem_level.read() + remaining = length + swpw = (self.data_width + 31) // 32 # Sub-Words per word + mwbl = 192 // swpw # Max Burst len (in # of words) + + while remaining > 0: + rdw = min(remaining, mwbl) + rdsw = rdw * swpw + datas = self.storage_mem_data.readfn(self.storage_mem_data.addr, length=rdsw, burst="fixed") + + for i, sv in enumerate(datas): + j = i % swpw + if j == 0: + v = 0 + v |= sv << (32 * j) + if j == (swpw - 1): + self.data.append(v) + + remaining -= rdw + + sys.stdout.write("[{}>{}] {}%\r".format('=' * (20-20*remaining//length), + ' ' * (20*remaining//length), + 100-(100*remaining//length))) + if self.debug: print("") return self.data