litex/misoclib/dvisampler/analysis.py

206 lines
4.9 KiB
Python

from migen.fhdl.std import *
from migen.genlib.cdc import MultiReg, PulseSynchronizer
from migen.genlib.fifo import AsyncFIFO
from migen.genlib.record import Record
from migen.bank.description import *
from migen.flow.actor import *
from misoclib.dvisampler.common import channel_layout
class SyncPolarity(Module):
def __init__(self):
self.valid_i = Signal()
self.data_in0 = Record(channel_layout)
self.data_in1 = Record(channel_layout)
self.data_in2 = Record(channel_layout)
self.valid_o = Signal()
self.de = Signal()
self.hsync = Signal()
self.vsync = Signal()
self.r = Signal(8)
self.g = Signal(8)
self.b = Signal(8)
###
de = self.data_in0.de
de_r = Signal()
c = self.data_in0.c
c_polarity = Signal(2)
c_out = Signal(2)
self.comb += [
self.de.eq(de_r),
self.hsync.eq(c_out[0]),
self.vsync.eq(c_out[1])
]
self.sync.pix += [
self.valid_o.eq(self.valid_i),
self.r.eq(self.data_in2.d),
self.g.eq(self.data_in1.d),
self.b.eq(self.data_in0.d),
de_r.eq(de),
If(de_r & ~de,
c_polarity.eq(c),
c_out.eq(0)
).Else(
c_out.eq(c ^ c_polarity)
)
]
class ResolutionDetection(Module, AutoCSR):
def __init__(self, nbits=11):
self.valid_i = Signal()
self.vsync = Signal()
self.de = Signal()
self._hres = CSRStatus(nbits)
self._vres = CSRStatus(nbits)
###
# Detect DE transitions
de_r = Signal()
pn_de = Signal()
self.sync.pix += de_r.eq(self.de)
self.comb += pn_de.eq(~self.de & de_r)
# HRES
hcounter = Signal(nbits)
self.sync.pix += If(self.valid_i & self.de,
hcounter.eq(hcounter + 1)
).Else(
hcounter.eq(0)
)
hcounter_st = Signal(nbits)
self.sync.pix += If(self.valid_i,
If(pn_de, hcounter_st.eq(hcounter))
).Else(
hcounter_st.eq(0)
)
self.specials += MultiReg(hcounter_st, self._hres.status)
# VRES
vsync_r = Signal()
p_vsync = Signal()
self.sync.pix += vsync_r.eq(self.vsync),
self.comb += p_vsync.eq(self.vsync & ~vsync_r)
vcounter = Signal(nbits)
self.sync.pix += If(self.valid_i & p_vsync,
vcounter.eq(0)
).Elif(pn_de,
vcounter.eq(vcounter + 1)
)
vcounter_st = Signal(nbits)
self.sync.pix += If(self.valid_i,
If(p_vsync, vcounter_st.eq(vcounter))
).Else(
vcounter_st.eq(0)
)
self.specials += MultiReg(vcounter_st, self._vres.status)
class FrameExtraction(Module, AutoCSR):
def __init__(self, word_width):
# in pix clock domain
self.valid_i = Signal()
self.vsync = Signal()
self.de = Signal()
self.r = Signal(8)
self.g = Signal(8)
self.b = Signal(8)
# in sys clock domain
word_layout = [("sof", 1), ("pixels", word_width)]
self.frame = Source(word_layout)
self.busy = Signal()
self._r_overflow = CSR()
###
# start of frame detection
vsync_r = Signal()
new_frame = Signal()
self.comb += new_frame.eq(self.vsync & ~vsync_r)
self.sync.pix += vsync_r.eq(self.vsync)
# pack pixels into words
cur_word = Signal(word_width)
cur_word_valid = Signal()
encoded_pixel = Signal(24)
self.comb += encoded_pixel.eq(Cat(self.b, self.g, self.r))
pack_factor = word_width//24
assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
pack_counter = Signal(max=pack_factor)
self.sync.pix += [
cur_word_valid.eq(0),
If(new_frame,
cur_word_valid.eq(pack_counter == (pack_factor - 1)),
pack_counter.eq(0),
).Elif(self.valid_i & self.de,
[If(pack_counter == (pack_factor-i-1),
cur_word[24*i:24*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)],
cur_word_valid.eq(pack_counter == (pack_factor - 1)),
pack_counter.eq(pack_counter + 1)
)
]
# FIFO
fifo = RenameClockDomains(AsyncFIFO(word_layout, 512),
{"write": "pix", "read": "sys"})
self.submodules += fifo
self.comb += [
fifo.din.pixels.eq(cur_word),
fifo.we.eq(cur_word_valid)
]
self.sync.pix += \
If(new_frame,
fifo.din.sof.eq(1)
).Elif(cur_word_valid,
fifo.din.sof.eq(0)
)
self.comb += [
self.frame.stb.eq(fifo.readable),
self.frame.payload.eq(fifo.dout),
fifo.re.eq(self.frame.ack),
self.busy.eq(0)
]
# overflow detection
pix_overflow = Signal()
pix_overflow_reset = Signal()
self.sync.pix += [
If(fifo.we & ~fifo.writable,
pix_overflow.eq(1)
).Elif(pix_overflow_reset,
pix_overflow.eq(0)
)
]
sys_overflow = Signal()
self.specials += MultiReg(pix_overflow, sys_overflow)
self.submodules.overflow_reset = PulseSynchronizer("sys", "pix")
self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys")
self.comb += [
pix_overflow_reset.eq(self.overflow_reset.o),
self.overflow_reset_ack.i.eq(pix_overflow_reset)
]
overflow_mask = Signal()
self.comb += [
self._r_overflow.w.eq(sys_overflow & ~overflow_mask),
self.overflow_reset.i.eq(self._r_overflow.re)
]
self.sync += \
If(self._r_overflow.re,
overflow_mask.eq(1)
).Elif(self.overflow_reset_ack.o,
overflow_mask.eq(0)
)