litex/miscope/storage.py

86 lines
2.4 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 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),
)
]