remove stale programmer.py
[litex.git] / misoclib / dvisampler / analysis.py
1 from migen.fhdl.std import *
2 from migen.genlib.cdc import MultiReg, PulseSynchronizer
3 from migen.genlib.fifo import AsyncFIFO
4 from migen.genlib.record import Record
5 from migen.bank.description import *
6 from migen.flow.actor import *
7
8 from misoclib.dvisampler.common import channel_layout
9
10 class SyncPolarity(Module):
11 def __init__(self):
12 self.valid_i = Signal()
13 self.data_in0 = Record(channel_layout)
14 self.data_in1 = Record(channel_layout)
15 self.data_in2 = Record(channel_layout)
16
17 self.valid_o = Signal()
18 self.de = Signal()
19 self.hsync = Signal()
20 self.vsync = Signal()
21 self.r = Signal(8)
22 self.g = Signal(8)
23 self.b = Signal(8)
24
25 ###
26
27 de = self.data_in0.de
28 de_r = Signal()
29 c = self.data_in0.c
30 c_polarity = Signal(2)
31 c_out = Signal(2)
32
33 self.comb += [
34 self.de.eq(de_r),
35 self.hsync.eq(c_out[0]),
36 self.vsync.eq(c_out[1])
37 ]
38
39 self.sync.pix += [
40 self.valid_o.eq(self.valid_i),
41 self.r.eq(self.data_in2.d),
42 self.g.eq(self.data_in1.d),
43 self.b.eq(self.data_in0.d),
44
45 de_r.eq(de),
46 If(de_r & ~de,
47 c_polarity.eq(c),
48 c_out.eq(0)
49 ).Else(
50 c_out.eq(c ^ c_polarity)
51 )
52 ]
53
54 class ResolutionDetection(Module, AutoCSR):
55 def __init__(self, nbits=11):
56 self.valid_i = Signal()
57 self.vsync = Signal()
58 self.de = Signal()
59
60 self._hres = CSRStatus(nbits)
61 self._vres = CSRStatus(nbits)
62
63 ###
64
65 # Detect DE transitions
66 de_r = Signal()
67 pn_de = Signal()
68 self.sync.pix += de_r.eq(self.de)
69 self.comb += pn_de.eq(~self.de & de_r)
70
71 # HRES
72 hcounter = Signal(nbits)
73 self.sync.pix += If(self.valid_i & self.de,
74 hcounter.eq(hcounter + 1)
75 ).Else(
76 hcounter.eq(0)
77 )
78
79 hcounter_st = Signal(nbits)
80 self.sync.pix += If(self.valid_i,
81 If(pn_de, hcounter_st.eq(hcounter))
82 ).Else(
83 hcounter_st.eq(0)
84 )
85 self.specials += MultiReg(hcounter_st, self._hres.status)
86
87 # VRES
88 vsync_r = Signal()
89 p_vsync = Signal()
90 self.sync.pix += vsync_r.eq(self.vsync),
91 self.comb += p_vsync.eq(self.vsync & ~vsync_r)
92
93 vcounter = Signal(nbits)
94 self.sync.pix += If(self.valid_i & p_vsync,
95 vcounter.eq(0)
96 ).Elif(pn_de,
97 vcounter.eq(vcounter + 1)
98 )
99
100 vcounter_st = Signal(nbits)
101 self.sync.pix += If(self.valid_i,
102 If(p_vsync, vcounter_st.eq(vcounter))
103 ).Else(
104 vcounter_st.eq(0)
105 )
106 self.specials += MultiReg(vcounter_st, self._vres.status)
107
108 class FrameExtraction(Module, AutoCSR):
109 def __init__(self, word_width):
110 # in pix clock domain
111 self.valid_i = Signal()
112 self.vsync = Signal()
113 self.de = Signal()
114 self.r = Signal(8)
115 self.g = Signal(8)
116 self.b = Signal(8)
117
118 # in sys clock domain
119 word_layout = [("sof", 1), ("pixels", word_width)]
120 self.frame = Source(word_layout)
121 self.busy = Signal()
122
123 self._r_overflow = CSR()
124
125 ###
126
127 # start of frame detection
128 vsync_r = Signal()
129 new_frame = Signal()
130 self.comb += new_frame.eq(self.vsync & ~vsync_r)
131 self.sync.pix += vsync_r.eq(self.vsync)
132
133 # pack pixels into words
134 cur_word = Signal(word_width)
135 cur_word_valid = Signal()
136 encoded_pixel = Signal(24)
137 self.comb += encoded_pixel.eq(Cat(self.b, self.g, self.r))
138 pack_factor = word_width//24
139 assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
140 pack_counter = Signal(max=pack_factor)
141 self.sync.pix += [
142 cur_word_valid.eq(0),
143 If(new_frame,
144 cur_word_valid.eq(pack_counter == (pack_factor - 1)),
145 pack_counter.eq(0),
146 ).Elif(self.valid_i & self.de,
147 [If(pack_counter == (pack_factor-i-1),
148 cur_word[24*i:24*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)],
149 cur_word_valid.eq(pack_counter == (pack_factor - 1)),
150 pack_counter.eq(pack_counter + 1)
151 )
152 ]
153
154 # FIFO
155 fifo = RenameClockDomains(AsyncFIFO(word_layout, 512),
156 {"write": "pix", "read": "sys"})
157 self.submodules += fifo
158 self.comb += [
159 fifo.din.pixels.eq(cur_word),
160 fifo.we.eq(cur_word_valid)
161 ]
162 self.sync.pix += \
163 If(new_frame,
164 fifo.din.sof.eq(1)
165 ).Elif(cur_word_valid,
166 fifo.din.sof.eq(0)
167 )
168 self.comb += [
169 self.frame.stb.eq(fifo.readable),
170 self.frame.payload.eq(fifo.dout),
171 fifo.re.eq(self.frame.ack),
172 self.busy.eq(0)
173 ]
174
175 # overflow detection
176 pix_overflow = Signal()
177 pix_overflow_reset = Signal()
178 self.sync.pix += [
179 If(fifo.we & ~fifo.writable,
180 pix_overflow.eq(1)
181 ).Elif(pix_overflow_reset,
182 pix_overflow.eq(0)
183 )
184 ]
185
186 sys_overflow = Signal()
187 self.specials += MultiReg(pix_overflow, sys_overflow)
188 self.submodules.overflow_reset = PulseSynchronizer("sys", "pix")
189 self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys")
190 self.comb += [
191 pix_overflow_reset.eq(self.overflow_reset.o),
192 self.overflow_reset_ack.i.eq(pix_overflow_reset)
193 ]
194
195 overflow_mask = Signal()
196 self.comb += [
197 self._r_overflow.w.eq(sys_overflow & ~overflow_mask),
198 self.overflow_reset.i.eq(self._r_overflow.re)
199 ]
200 self.sync += \
201 If(self._r_overflow.re,
202 overflow_mask.eq(1)
203 ).Elif(self.overflow_reset_ack.o,
204 overflow_mask.eq(0)
205 )