ce6bbaca1965e5e03efa3ad053612abcfd877bed
[litex.git] / milkymist / dvisampler / chansync.py
1 from migen.fhdl.std import *
2 from migen.genlib.cdc import MultiReg
3 from migen.genlib.fifo import _inc
4 from migen.genlib.record import Record, layout_len
5 from migen.genlib.misc import optree
6 from migen.bank.description import *
7
8 from milkymist.dvisampler.common import channel_layout
9
10 class _SyncBuffer(Module):
11 def __init__(self, width, depth):
12 self.din = Signal(width)
13 self.dout = Signal(width)
14 self.re = Signal()
15
16 ###
17
18 produce = Signal(max=depth)
19 consume = Signal(max=depth)
20 storage = Memory(width, depth)
21 self.specials += storage
22
23 wrport = storage.get_port(write_capable=True)
24 self.specials += wrport
25 self.comb += [
26 wrport.adr.eq(produce),
27 wrport.dat_w.eq(self.din),
28 wrport.we.eq(1)
29 ]
30 self.sync += _inc(produce, depth)
31
32 rdport = storage.get_port(async_read=True)
33 self.specials += rdport
34 self.comb += [
35 rdport.adr.eq(consume),
36 self.dout.eq(rdport.dat_r)
37 ]
38 self.sync += If(self.re, _inc(consume, depth))
39
40 class ChanSync(Module, AutoCSR):
41 def __init__(self, nchan=3, depth=8):
42 self.valid_i = Signal()
43 self.chan_synced = Signal()
44
45 self._r_channels_synced = CSRStatus()
46
47 lst_control = []
48 all_control = Signal()
49 for i in range(nchan):
50 name = "data_in" + str(i)
51 data_in = Record(channel_layout, name=name)
52 setattr(self, name, data_in)
53 name = "data_out" + str(i)
54 data_out = Record(channel_layout, name=name)
55 setattr(self, name, data_out)
56
57 ###
58
59 syncbuffer = _SyncBuffer(layout_len(channel_layout), depth)
60 self.add_submodule(syncbuffer, "pix")
61 self.comb += [
62 syncbuffer.din.eq(data_in.raw_bits()),
63 data_out.raw_bits().eq(syncbuffer.dout)
64 ]
65 is_control = Signal()
66 self.comb += [
67 is_control.eq(~data_out.de),
68 syncbuffer.re.eq(~is_control | all_control)
69 ]
70 lst_control.append(is_control)
71
72 some_control = Signal()
73 self.comb += [
74 all_control.eq(optree("&", lst_control)),
75 some_control.eq(optree("|", lst_control))
76 ]
77 self.sync.pix += If(~self.valid_i,
78 self.chan_synced.eq(0)
79 ).Else(
80 If(some_control,
81 If(all_control,
82 self.chan_synced.eq(1)
83 ).Else(
84 self.chan_synced.eq(0)
85 )
86 )
87 )
88 self.specials += MultiReg(self.chan_synced, self._r_channels_synced.status)