155 lines
3.7 KiB
Python
155 lines
3.7 KiB
Python
from migen.fhdl.std import *
|
|
from migen.flow.actor import *
|
|
from migen.flow.network import *
|
|
from migen.fhdl.specials import Memory
|
|
from migen.bus import csr
|
|
from migen.bank import description, csrgen
|
|
from migen.bank.description import *
|
|
from migen.actorlib.fifo import SyncFIFO
|
|
|
|
class RunLenghEncoder(Module, AutoCSR):
|
|
def __init__(self, width, length):
|
|
self.width = width
|
|
self.length = length
|
|
|
|
self.sink = Sink([("d", width)])
|
|
self.source = Source([("d", width)])
|
|
|
|
self._r_enable = CSRStorage()
|
|
|
|
###
|
|
enable = self._r_enable.storage
|
|
stb_i = self.sink.stb
|
|
dat_i = self.sink.payload.d
|
|
ack_i = self.sink.ack
|
|
|
|
# Register Input
|
|
stb_i_d = Signal()
|
|
dat_i_d = Signal(width)
|
|
|
|
self.sync += [
|
|
dat_i_d.eq(dat_i),
|
|
stb_i_d.eq(stb_i)
|
|
]
|
|
|
|
# Detect change
|
|
change = Signal()
|
|
comb = [diff.eq(stb_i & (~enable | (dat_i_d != dat_i)))]
|
|
|
|
change_d = Signal()
|
|
change_rising = Signal()
|
|
self.sync += change_d.eq(change)
|
|
self.comb += change_rising.eq(change & ~change_d)
|
|
|
|
# Generate RLE word
|
|
rle_cnt = Signal(max=length)
|
|
rle_max = Signal()
|
|
|
|
comb +=[If(rle_cnt == length, rle_max.eq(enable))]
|
|
|
|
sync +=[
|
|
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
|
|
dat_o = self.source.payload.d
|
|
ack_o = self.source.ack
|
|
|
|
comb +=[
|
|
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),
|
|
),
|
|
ack_i.eq(1) #FIXME
|
|
]
|
|
|
|
|
|
|
|
class Recorder(Module, AutoCSR):
|
|
def __init__(self, width, depth):
|
|
self.width = width
|
|
|
|
self.sink = Sink([("hit", 1), ("d", width)])
|
|
|
|
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)
|
|
|
|
###
|
|
|
|
length = self._r_length.storage
|
|
offset = self._r_offset.storage
|
|
done = Signal(reset=1)
|
|
ongoing = Signal()
|
|
|
|
cnt = Signal(max=depth)
|
|
|
|
fifo = SyncFIFO([("d", width)], depth)
|
|
self.submodules += fifo
|
|
|
|
# Write fifo is done only when done = 0
|
|
# Fifo must always be pulled by software between
|
|
# acquisition (Todo: add a flush funtionnality)
|
|
self.comb +=[
|
|
fifo.sink.stb.eq(self.sink.stb & ~done),
|
|
fifo.sink.payload.d.eq(self.sink.payload.d),
|
|
self.sink.ack.eq(1)
|
|
]
|
|
|
|
# Done, Ongoing:
|
|
# 0, 0 : Storage triggered but hit was not yet seen
|
|
# Data are recorded to fifo, if "offset" datas
|
|
# in the fifo, ack is set on fifo.source to
|
|
# store only "offset" datas.
|
|
#
|
|
# 0, 1 : Hit was seen, ack is no longer set on fifo.source
|
|
# we are storing "length"-"offset" data in this
|
|
# phase
|
|
#
|
|
# 1, 0 : We have stored "length" datas in fifo. Write to
|
|
# fifo is disabled.
|
|
# Software must now read data from the fifo until
|
|
# it is empty
|
|
|
|
# done & ongoing
|
|
self.sync += [
|
|
If(self._r_trigger.re & self._r_trigger.r, done.eq(0)
|
|
).Elif(cnt==length, done.eq(1)),
|
|
|
|
If(self.sink.stb & self.sink.payload.hit & ~done, ongoing.eq(1)
|
|
).Elif(done, ongoing.eq(0)),
|
|
]
|
|
|
|
# fifo ack & csr connection
|
|
self.comb += [
|
|
If(~done & ~ongoing & (cnt >= offset), fifo.source.ack.eq(1)
|
|
).Else(fifo.source.ack.eq(self._r_read_en.re & self._r_read_en.r)),
|
|
self._r_read_empty.status.eq(~fifo.source.stb),
|
|
self._r_read_dat.status.eq(fifo.source.payload.d),
|
|
self._r_done.status.eq(done)
|
|
]
|
|
|
|
# cnt
|
|
self.sync += [
|
|
If(done == 1,
|
|
cnt.eq(0)
|
|
).Elif(fifo.sink.stb & fifo.sink.ack & ~(fifo.source.stb & fifo.source.ack),
|
|
cnt.eq(cnt+1),
|
|
)
|
|
] |