2013-09-21 07:04:07 -04:00
|
|
|
from migen.fhdl.std import *
|
|
|
|
from migen.bank.description import *
|
2013-09-22 07:04:18 -04:00
|
|
|
from migen.genlib.fifo import SyncFIFO
|
2014-05-13 15:30:32 -04:00
|
|
|
from migen.genlib.fsm import FSM, NextState
|
2013-09-22 07:04:18 -04:00
|
|
|
|
|
|
|
from miscope.std import *
|
2013-09-21 07:04:07 -04:00
|
|
|
|
2013-09-22 12:41:44 -04:00
|
|
|
class RunLengthEncoder(Module, AutoCSR):
|
2014-05-20 03:02:35 -04:00
|
|
|
def __init__(self, width, length=1024):
|
2013-09-22 06:35:46 -04:00
|
|
|
self.width = width
|
|
|
|
self.length = length
|
|
|
|
|
2013-09-22 07:04:18 -04:00
|
|
|
self.sink = rec_dat(width)
|
2014-05-20 03:02:35 -04:00
|
|
|
self.source = rec_dat(width)
|
2013-09-22 06:35:46 -04:00
|
|
|
|
|
|
|
self._r_enable = CSRStorage()
|
|
|
|
|
2014-05-13 15:30:32 -04:00
|
|
|
###
|
|
|
|
|
2014-05-20 03:02:35 -04:00
|
|
|
enable = self._r_enable.storage
|
2013-09-22 06:35:46 -04:00
|
|
|
stb_i = self.sink.stb
|
2013-09-22 07:04:18 -04:00
|
|
|
dat_i = self.sink.dat
|
2013-09-22 06:35:46 -04:00
|
|
|
|
|
|
|
# Register Input
|
|
|
|
stb_i_d = Signal()
|
|
|
|
dat_i_d = Signal(width)
|
|
|
|
|
2014-05-20 03:02:35 -04:00
|
|
|
self.sync += \
|
2013-09-22 12:41:44 -04:00
|
|
|
If(stb_i,
|
|
|
|
dat_i_d.eq(dat_i),
|
|
|
|
stb_i_d.eq(stb_i)
|
|
|
|
)
|
2014-05-20 03:02:35 -04:00
|
|
|
|
2013-09-22 06:35:46 -04:00
|
|
|
# Detect change
|
|
|
|
change = Signal()
|
2014-05-20 03:02:35 -04:00
|
|
|
self.comb += change.eq(stb_i & (~enable | (dat_i_d != dat_i)))
|
2013-09-22 06:35:46 -04:00
|
|
|
|
|
|
|
change_d = Signal()
|
|
|
|
change_rising = Signal()
|
2013-09-22 12:41:44 -04:00
|
|
|
self.sync += If(stb_i, change_d.eq(change))
|
|
|
|
self.comb += change_rising.eq(stb_i & (change & ~change_d))
|
2013-09-22 06:35:46 -04:00
|
|
|
|
|
|
|
# Generate RLE word
|
|
|
|
rle_cnt = Signal(max=length)
|
|
|
|
rle_max = Signal()
|
|
|
|
|
2014-05-20 03:02:35 -04:00
|
|
|
self.comb += If(rle_cnt == length, rle_max.eq(enable))
|
2013-09-22 06:35:46 -04:00
|
|
|
|
2014-05-20 03:02:35 -04:00
|
|
|
self.sync += \
|
2013-09-22 06:35:46 -04:00
|
|
|
If(change | rle_max,
|
|
|
|
rle_cnt.eq(0)
|
|
|
|
).Else(
|
|
|
|
rle_cnt.eq(rle_cnt + 1)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Mux RLE word and data
|
|
|
|
stb_o = self.source.stb
|
2013-09-22 07:04:18 -04:00
|
|
|
dat_o = self.source.dat
|
2013-09-22 06:35:46 -04:00
|
|
|
|
2014-05-20 03:02:35 -04:00
|
|
|
self.comb += \
|
2013-09-22 06:35:46 -04:00
|
|
|
If(change_rising & ~rle_max,
|
|
|
|
stb_o.eq(1),
|
|
|
|
dat_o[width-1].eq(1),
|
|
|
|
dat_o[:flen(rle_cnt)].eq(rle_cnt)
|
|
|
|
).Elif(change_d | rle_max,
|
|
|
|
stb_o.eq(stb_i_d),
|
|
|
|
dat_o.eq(dat_i_d)
|
|
|
|
).Else(
|
|
|
|
stb_o.eq(0),
|
2014-05-20 03:02:35 -04:00
|
|
|
)
|
2013-09-22 06:35:46 -04:00
|
|
|
|
2013-09-21 07:04:07 -04:00
|
|
|
class Recorder(Module, AutoCSR):
|
|
|
|
def __init__(self, width, depth):
|
|
|
|
self.width = width
|
|
|
|
|
2013-09-22 12:41:44 -04:00
|
|
|
self.trig_sink = rec_hit()
|
|
|
|
self.dat_sink = rec_dat(width)
|
2013-09-21 07:04:07 -04:00
|
|
|
|
|
|
|
self._r_trigger = CSR()
|
|
|
|
self._r_length = CSRStorage(bits_for(depth))
|
|
|
|
self._r_offset = CSRStorage(bits_for(depth))
|
|
|
|
self._r_done = CSRStatus()
|
|
|
|
|
|
|
|
self._r_read_en = CSR()
|
|
|
|
self._r_read_empty = CSRStatus()
|
|
|
|
self._r_read_dat = CSRStatus(width)
|
|
|
|
|
|
|
|
###
|
|
|
|
|
2013-09-22 07:04:18 -04:00
|
|
|
fifo = SyncFIFO(width, depth)
|
2013-09-21 07:04:07 -04:00
|
|
|
self.submodules += fifo
|
|
|
|
|
2014-05-13 15:30:32 -04:00
|
|
|
fsm = FSM(reset_state="IDLE")
|
|
|
|
self.submodules += fsm
|
|
|
|
|
2013-09-21 07:04:07 -04:00
|
|
|
|
|
|
|
self.comb += [
|
2013-09-22 07:04:18 -04:00
|
|
|
self._r_read_empty.status.eq(~fifo.readable),
|
|
|
|
self._r_read_dat.status.eq(fifo.dout),
|
2013-09-21 07:04:07 -04:00
|
|
|
]
|
|
|
|
|
2014-05-13 15:30:32 -04:00
|
|
|
fsm.act("IDLE",
|
|
|
|
If(self._r_trigger.re & self._r_trigger.r,
|
|
|
|
NextState("PRE_HIT_RECORDING"),
|
|
|
|
fifo.flush.eq(1),
|
|
|
|
),
|
|
|
|
fifo.re.eq(self._r_read_en.re & self._r_read_en.r),
|
|
|
|
self._r_done.status.eq(1)
|
|
|
|
)
|
|
|
|
|
|
|
|
fsm.act("PRE_HIT_RECORDING",
|
|
|
|
fifo.we.eq(self.dat_sink.stb),
|
|
|
|
fifo.din.eq(self.dat_sink.dat),
|
|
|
|
|
|
|
|
fifo.re.eq(fifo.level >= self._r_offset.storage),
|
|
|
|
|
|
|
|
If(self.trig_sink.stb & self.trig_sink.hit, NextState("POST_HIT_RECORDING"))
|
|
|
|
)
|
|
|
|
|
|
|
|
fsm.act("POST_HIT_RECORDING",
|
|
|
|
fifo.we.eq(self.dat_sink.stb),
|
|
|
|
fifo.din.eq(self.dat_sink.dat),
|
|
|
|
|
|
|
|
If(~fifo.writable | (fifo.level >= self._r_length.storage), NextState("IDLE"))
|
|
|
|
)
|