storage: simplify run length encoder...
[litex.git] / miscope / storage.py
1 from migen.fhdl.std import *
2 from migen.bank.description import *
3 from migen.genlib.fifo import SyncFIFO
4 from migen.genlib.fsm import FSM, NextState
5
6 from miscope.std import *
7
8 class RunLengthEncoder(Module, AutoCSR):
9 def __init__(self, width, length=1024):
10 self.width = width
11 self.length = length
12
13 self.sink = rec_dat(width)
14 self.source = rec_dat(width)
15
16 self._r_enable = CSRStorage()
17
18 ###
19
20 enable = self._r_enable.storage
21
22 fsm = FSM(reset_state="BYPASS")
23 self.submodules += fsm
24
25 sink_d = rec_dat(width)
26 self.sync += If(self.sink.stb, sink_d.eq(self.sink))
27
28 cnt = Signal(max=length)
29 cnt_inc = Signal()
30 cnt_reset = Signal()
31 cnt_max = Signal()
32
33 self.sync += \
34 If(cnt_reset,
35 cnt.eq(1),
36 ).Elif(cnt_inc,
37 cnt.eq(cnt+1)
38 )
39 self.comb += cnt_max.eq(cnt == length)
40
41 change = Signal()
42 self.comb += change.eq(self.sink.stb & (self.sink.dat != sink_d.dat))
43
44 fsm.act("BYPASS",
45 sink_d.connect(self.source),
46 cnt_reset.eq(1),
47 If(enable & ~change & self.sink.stb, NextState("COUNT"))
48 )
49
50 fsm.act("COUNT",
51 cnt_inc.eq(self.sink.stb),
52 If(change | cnt_max | ~enable,
53 self.source.stb.eq(1),
54 self.source.dat[width-1].eq(1), # Set RLE bit
55 self.source.dat[:flen(cnt)].eq(cnt),
56 NextState("BYPASS")
57 )
58 ),
59
60 class Recorder(Module, AutoCSR):
61 def __init__(self, width, depth):
62 self.width = width
63
64 self.trig_sink = rec_hit()
65 self.dat_sink = rec_dat(width)
66
67 self._r_trigger = CSR()
68 self._r_length = CSRStorage(bits_for(depth))
69 self._r_offset = CSRStorage(bits_for(depth))
70 self._r_done = CSRStatus()
71
72 self._r_read_en = CSR()
73 self._r_read_empty = CSRStatus()
74 self._r_read_dat = CSRStatus(width)
75
76 ###
77
78 fifo = SyncFIFO(width, depth)
79 self.submodules += fifo
80
81 fsm = FSM(reset_state="IDLE")
82 self.submodules += fsm
83
84
85 self.comb += [
86 self._r_read_empty.status.eq(~fifo.readable),
87 self._r_read_dat.status.eq(fifo.dout),
88 ]
89
90 fsm.act("IDLE",
91 If(self._r_trigger.re & self._r_trigger.r,
92 NextState("PRE_HIT_RECORDING"),
93 fifo.flush.eq(1),
94 ),
95 fifo.re.eq(self._r_read_en.re & self._r_read_en.r),
96 self._r_done.status.eq(1)
97 )
98
99 fsm.act("PRE_HIT_RECORDING",
100 fifo.we.eq(self.dat_sink.stb),
101 fifo.din.eq(self.dat_sink.dat),
102
103 fifo.re.eq(fifo.level >= self._r_offset.storage),
104
105 If(self.trig_sink.stb & self.trig_sink.hit, NextState("POST_HIT_RECORDING"))
106 )
107
108 fsm.act("POST_HIT_RECORDING",
109 fifo.we.eq(self.dat_sink.stb),
110 fifo.din.eq(self.dat_sink.dat),
111
112 If(~fifo.writable | (fifo.level >= self._r_length.storage), NextState("IDLE"))
113 )