mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
add Run Length Encoding
This commit is contained in:
parent
eeab7051be
commit
492a5acfe3
6 changed files with 178 additions and 65 deletions
1
README
1
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:
|
||||
|
|
|
@ -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")
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in a new issue