From: Florent Kermarrec Date: Sat, 23 Mar 2013 12:57:59 +0000 (+0100) Subject: add Run Length Encoding X-Git-Tag: 24jan2021_ls180~2575^2~101 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=492a5acfe3286b5a48da97c093ec6cc15aad9d73;p=litex.git add Run Length Encoding --- diff --git a/README b/README index cdffe5f6..846e7b60 100644 --- a/README +++ b/README @@ -36,6 +36,7 @@ to be ready to debug! [> Status: Miio & Mila working on board with standard term. +RLE working on board. RangeDetector and EdgeDector terms not tested. [> Examples: diff --git a/examples/de0_nano/client/test_mila.py b/examples/de0_nano/client/test_mila.py index 4887851b..89768709 100644 --- a/examples/de0_nano/client/test_mila.py +++ b/examples/de0_nano/client/test_mila.py @@ -16,6 +16,7 @@ trig_w = 16 dat_w = 16 rec_size = 512 rec_offset = 32 +enable_rle = True # Miscope Configuration # MiLa @@ -35,6 +36,8 @@ def capture(size): sum_tt = gen_truth_table("term") mila.trigger.sum.set(sum_tt) mila.recorder.reset() + if enable_rle: + mila.recorder.enable_rle() recorder.set_size(rec_size) mila.recorder.set_offset(rec_offset) mila.recorder.arm() @@ -46,7 +49,7 @@ def capture(size): print("-Receiving Data...", end=' ') sys.stdout.flush() - dat_vcd += mila.recorder.pull(size) + dat_vcd += mila.recorder.pull(rec_size) print("[Done]") print("Capturing ...") @@ -61,6 +64,9 @@ mila_layout = [ ("cnt", 8), ] +if enable_rle: + dat_vcd = dat_vcd.decode_rle() + myvcd = Vcd() myvcd.add_from_layout(mila_layout, dat_vcd) myvcd.write("test_mila.vcd") \ No newline at end of file diff --git a/miscope/recorder.py b/miscope/recorder.py index caebb7a5..2d634678 100644 --- a/miscope/recorder.py +++ b/miscope/recorder.py @@ -81,24 +81,88 @@ class Storage: return Fragment(comb, sync, specials={self._mem}) + fsm.get_fragment() +class RLE: + + # + # Definition + # + def __init__(self, width, length): + self.width = width + self.length = length + + # Control + self.enable = Signal() + + # Input + self.dat_i = Signal(width) + + # Output + self.stb_o = Signal() + self.dat_o = Signal(width) + + def get_fragment(self): + + # Register Input + dat_i_d = Signal(self.width) + + sync =[dat_i_d.eq(self.dat_i)] + + # Detect diff + diff = Signal() + comb = [diff.eq(~self.enable | (dat_i_d != self.dat_i))] + + diff_rising = RisingEdge(diff) + diff_d = Signal() + sync +=[diff_d.eq(diff)] + + # Generate RLE word + rle_cnt = Signal(max=self.length) + rle_max = Signal() + + comb +=[If(rle_cnt == self.length, rle_max.eq(self.enable))] + + sync +=[ + If(diff | rle_max, + rle_cnt.eq(0) + ).Else( + rle_cnt.eq(rle_cnt + 1) + ) + ] + + # Mux RLE word and data + comb +=[ + If(diff_rising.o & (~rle_max), + self.stb_o.eq(1), + self.dat_o[self.width-1].eq(1), + self.dat_o[:len(rle_cnt)].eq(rle_cnt) + ).Elif(diff_d | rle_max, + self.stb_o.eq(1), + self.dat_o.eq(dat_i_d) + ).Else( + self.stb_o.eq(0), + ) + ] + + return Fragment(comb, sync) + diff_rising.get_fragment() + class Sequencer: # # Definition # def __init__(self): - # Controller interface + # Control self.rst = Signal() self.arm = Signal() - # Trigger interface + # Trigger self.hit = Signal() - # Recorder interface + # Recorder self.start = Signal() self.done = Signal() - # Others + # Internal self.enable = Signal() def get_fragment(self): @@ -129,12 +193,13 @@ class Sequencer: REC_RST_BASE = 0x00 -REC_ARM_BASE = 0x01 -REC_DONE_BASE = 0x02 -REC_SIZE_BASE = 0x03 -REC_OFFSET_BASE = 0x05 -REC_READ_BASE = 0x07 -REC_READ_DATA_BASE = 0x08 +REC_RLE_BASE = 0x01 +REC_ARM_BASE = 0x02 +REC_DONE_BASE = 0x03 +REC_SIZE_BASE = 0x04 +REC_OFFSET_BASE = 0x06 +REC_READ_BASE = 0x08 +REC_READ_DATA_BASE = 0x09 class Recorder: # @@ -147,9 +212,11 @@ class Recorder: self.storage = Storage(self.width, self.depth) self.sequencer = Sequencer() + self.rle = RLE(self.width, (2**(width-2))) # csr interface self._rst = RegisterField("rst", reset=1) + self._rle = RegisterField("rle", reset=0) self._arm = RegisterField("arm", reset=0) self._done = RegisterField("done", reset=0, access_bus=READ_ONLY, access_dev=WRITE_ONLY) @@ -161,7 +228,7 @@ class Recorder: self._pull_dat = RegisterField("pull_dat", self.width, reset=1, access_bus=READ_ONLY, access_dev=WRITE_ONLY) - self.regs = [self._rst, self._arm, self._done, self._size, self._offset, + self.regs = [self._rst, self._rle, self._arm, self._done, self._size, self._offset, self._pull_stb, self._pull_dat] # set address / interface @@ -188,6 +255,7 @@ class Recorder: self.sequencer.rst.eq(self._rst.field.r), self.storage.rst.eq(self._rst.field.r), + self.rle.enable.eq(self._rle.field.r), self.sequencer.arm.eq(self._arm.field.r), self.storage.offset.eq(self._offset.field.r), self.storage.size.eq(self._size.field.r), @@ -204,13 +272,17 @@ class Recorder: self.sequencer.done.eq(self.storage.done), self.sequencer.hit.eq(self.hit), - self.storage.push_stb.eq(self.sequencer.enable), - self.storage.push_dat.eq(self.dat) + self.rle.dat_i.eq(self.dat), + + self.storage.push_stb.eq(self.sequencer.enable & self.rle.stb_o), + self.storage.push_dat.eq(self.rle.dat_o) ] return self.bank.get_fragment() + Fragment(comb) +\ self.storage.get_fragment() + self.sequencer.get_fragment() +\ - _pull_stb_rising.get_fragment() + _pull_stb_rising.get_fragment() + self.rle.get_fragment() + + # # Driver @@ -218,7 +290,13 @@ class Recorder: def reset(self): self.interface.write(self.bank.get_base() + REC_RST_BASE, 1) self.interface.write(self.bank.get_base() + REC_RST_BASE, 0) - + + def enable_rle(self): + self.interface.write(self.bank.get_base() + REC_RLE_BASE, 1) + + def disable_rle(self): + self.interface.write(self.bank.get_base() + REC_RLE_BASE, 0) + def arm(self): self.interface.write(self.bank.get_base() + REC_ARM_BASE, 1) self.interface.write(self.bank.get_base() + REC_ARM_BASE, 0) diff --git a/miscope/tools/vcd.py b/miscope/tools/vcd.py index 192ce383..481a1238 100644 --- a/miscope/tools/vcd.py +++ b/miscope/tools/vcd.py @@ -40,6 +40,25 @@ class VcdDat(list): else: raise KeyError + def decode_rle(self): + rle_bit = self[-1] + rle_dat = self[:self.width-1] + + dat = VcdDat(self.width) + i=0 + last = 0 + for d in self: + if rle_bit[i]: + if len(dat) >= 1: + # FIX ME... why is rle_dat in reverse orderd... + for j in range(int(dec2bin(rle_dat[i])[::-1],2)): + dat.append(last) + else: + dat.append(d) + last = d + i +=1 + return dat + class Var: def __init__(self, name, width, values=[], type="wire", default="x"): self.type = type diff --git a/sim/tb_RecorderCsr.py b/sim/tb_RecorderCsr.py index d9f086f8..9aaf3d01 100644 --- a/sim/tb_RecorderCsr.py +++ b/sim/tb_RecorderCsr.py @@ -5,7 +5,7 @@ from migen.sim.generic import Simulator, PureSimulable, TopLevel from migen.sim.icarus import Runner from migen.bus.transactions import * -from miscope import recorder +from miscope.recorder import * arm_done = False dat = 0 @@ -14,23 +14,28 @@ rec_done = False dat_rdy = False +rec_size = 128 + def csr_transactions(): - #Reset - yield TWrite(0, 1) - yield TWrite(0, 0) + # Reset + yield TWrite(REC_RST_BASE, 1) + yield TWrite(REC_RST_BASE, 0) + + # RLE + yield TWrite(REC_RLE_BASE, 1) - #Size - yield TWrite(3, 0) - yield TWrite(4, 32) + # Size + yield TWrite(REC_SIZE_BASE + 0, 0) + yield TWrite(REC_SIZE_BASE + 1, rec_size) - #Offset - yield TWrite(5, 0) - yield TWrite(6, 0) + # Offset + yield TWrite(REC_OFFSET_BASE + 0, 0) + yield TWrite(REC_OFFSET_BASE + 1, 0) - #Arm - yield TWrite(1, 1) - yield TWrite(1, 0) + # Arm + yield TWrite(REC_ARM_BASE, 1) + yield TWrite(REC_ARM_BASE, 0) for t in range(10): yield None @@ -43,14 +48,14 @@ def csr_transactions(): yield None global dat_rdy - for t in range(32): - yield TWrite(7, 1) + for t in range(rec_size): + yield TWrite(REC_READ_BASE, 1) dat_rdy = False - yield TWrite(7, 0) - yield TRead(8) - yield TRead(9) - yield TRead(10) - yield TRead(11) + yield TWrite(REC_READ_BASE, 0) + yield TRead(REC_READ_DATA_BASE + 0) + yield TRead(REC_READ_DATA_BASE + 1) + yield TRead(REC_READ_DATA_BASE + 2) + yield TRead(REC_READ_DATA_BASE + 3) dat_rdy = True dat_rdy = False @@ -63,7 +68,7 @@ def main(): csr_master0 = csr.Initiator(csr_transactions()) # Recorder - recorder0 = recorder.Recorder(32, 1024) + recorder0 = Recorder(32, 1024) # Csr Interconnect csrcon0 = csr.Interconnect(csr_master0.bus, @@ -79,16 +84,15 @@ def main(): arm_done = False global dat - s.wr(recorder0.dat,dat) + s.wr(recorder0.dat, dat//5) dat += 1 global rec_done - if s.rd(recorder0.sequencer.rec_done) == 1: + if s.rd(recorder0.sequencer.enable) == 0: rec_done = True if dat_rdy: print("%08X" %s.rd(recorder0._pull_dat.field.w)) - # Simulation def end_simulation(s): diff --git a/sim/tb_miscope.py b/sim/tb_miscope.py index 8ad225e2..5b2107d8 100644 --- a/sim/tb_miscope.py +++ b/sim/tb_miscope.py @@ -5,7 +5,8 @@ from migen.sim.generic import Simulator, PureSimulable, TopLevel from migen.sim.icarus import Runner from migen.bus.transactions import * -from miscope import trigger, recorder +from miscope.trigger import * +from miscope.recorder import * from miscope.tools.truthtable import * from miscope.tools.vcd import * @@ -15,7 +16,8 @@ RECORDER_ADDR = 0x0200 rec_done = False dat_rdy = False -dat_vcd = [] +dat_vcd = VcdDat(32) +rec_size = 64 def term_prog(off, dat): for i in range(4): @@ -62,20 +64,23 @@ def csr_transactions(trigger0, recorder0): # Recorder Prog ############################## #Reset - yield TWrite(recorder0.address + 0, 1) - yield TWrite(recorder0.address + 0, 0) + yield TWrite(recorder0.address + REC_RST_BASE, 1) + yield TWrite(recorder0.address + REC_RST_BASE, 0) + + # RLE + yield TWrite(REC_RLE_BASE, 0) #Size - yield TWrite(recorder0.address + 3, 0) - yield TWrite(recorder0.address + 4, 64) + yield TWrite(recorder0.address + REC_SIZE_BASE + 0, 0) + yield TWrite(recorder0.address + REC_OFFSET_BASE + 1, rec_size) #Offset - yield TWrite(recorder0.address + 5, 0) - yield TWrite(recorder0.address + 6, 16) + yield TWrite(recorder0.address + REC_OFFSET_BASE + 0, 0) + yield TWrite(recorder0.address + REC_OFFSET_BASE + 1, 16) #Arm - yield TWrite(recorder0.address + 1, 1) - yield TWrite(recorder0.address + 1, 0) + yield TWrite(recorder0.address + REC_ARM_BASE, 1) + yield TWrite(recorder0.address + REC_ARM_BASE, 0) # Wait Record to be done ############################## @@ -86,14 +91,14 @@ def csr_transactions(trigger0, recorder0): # Read recorded data ############################## global dat_rdy - for t in range(64): - yield TWrite(recorder0.address + 7, 1) + for t in range(rec_size): + yield TWrite(recorder0.address + REC_READ_BASE, 1) dat_rdy = False - yield TWrite(recorder0.address + 7, 0) - yield TRead(recorder0.address + 8) - yield TRead(recorder0.address + 9) - yield TRead(recorder0.address + 10) - yield TRead(recorder0.address + 11) + yield TWrite(recorder0.address + REC_READ_BASE, 0) + yield TRead(recorder0.address + REC_READ_DATA_BASE + 0) + yield TRead(recorder0.address + REC_READ_DATA_BASE + 1) + yield TRead(recorder0.address + REC_READ_DATA_BASE + 2) + yield TRead(recorder0.address + REC_READ_DATA_BASE + 3) dat_rdy = True dat_rdy = False @@ -108,14 +113,14 @@ trig_sig_val = 0 def main(): # Trigger - term0 = trigger.Term(32) - term1 = trigger.Term(32) - term2 = trigger.Term(32) - term3 = trigger.Term(32) - trigger0 = trigger.Trigger(32, [term0, term1, term2, term3], address=TRIGGER_ADDR) + term0 = Term(32) + term1 = Term(32) + term2 = Term(32) + term3 = Term(32) + trigger0 = Trigger(32, [term0, term1, term2, term3], address=TRIGGER_ADDR) # Recorder - recorder0 = recorder.Recorder(32, 1024, address=RECORDER_ADDR) + recorder0 = Recorder(32, 1024, address=RECORDER_ADDR) # Csr Master csr_master0 = csr.Initiator(csr_transactions(trigger0, recorder0)) @@ -146,7 +151,7 @@ def main(): # Recorder Data def recorder_data(s): global rec_done - if s.rd(recorder0.sequencer.rec_done) == 1: + if s.rd(recorder0.sequencer.done) == 1: rec_done = True global dat_rdy @@ -160,7 +165,7 @@ def main(): def end_simulation(s): s.interrupt = csr_master0.done myvcd = Vcd() - myvcd.add(Var("wire", 32, "trig_dat", dat_vcd)) + myvcd.add(Var("trig_dat", 32, dat_vcd)) f = open("tb_miscope_out.vcd", "w") f.write(str(myvcd)) f.close()