forked from M-Labs/artiq-zynq
frameline GW: add gearbox proto
This commit is contained in:
parent
520b746440
commit
050b4a1d97
@ -401,90 +401,111 @@ class Frame_Header_Decoder(Module):
|
|||||||
|
|
||||||
class Custom_Pixel_Gearbox(Module):
|
class Custom_Pixel_Gearbox(Module):
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
assert size in [8]
|
assert size in [8, 16]
|
||||||
|
|
||||||
self.x_size = Signal(3*char_width)
|
self.x_size = Signal(3*char_width)
|
||||||
|
|
||||||
i_dw, o_dw = word_dw, size*4
|
sink_dw, source_dw = word_dw, size*4
|
||||||
self.sink = stream.Endpoint([("data", i_dw)])
|
self.sink = stream.Endpoint([("data", sink_dw)])
|
||||||
self.source = stream.Endpoint(pixel4x_layout)
|
self.source = stream.Endpoint(pixel4x_layout)
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
io_lcm = lcm(i_dw, o_dw)
|
shift_reg_size = lcm(sink_dw, source_dw)
|
||||||
if (io_lcm//i_dw) < 2:
|
# ensure the shift register is at least twice the size of sink/source dw
|
||||||
io_lcm = io_lcm * 2
|
if (shift_reg_size//sink_dw) < 2:
|
||||||
if (io_lcm//o_dw) < 2:
|
shift_reg_size = shift_reg_size * 2
|
||||||
io_lcm = io_lcm * 2
|
if (shift_reg_size//source_dw) < 2:
|
||||||
|
shift_reg_size = shift_reg_size * 2
|
||||||
|
|
||||||
|
# Control interface
|
||||||
|
|
||||||
self.shift_register = Signal(io_lcm, reset_less=True)
|
reset_reg = Signal()
|
||||||
|
level = Signal(max=shift_reg_size)
|
||||||
|
we = Signal()
|
||||||
|
re = Signal()
|
||||||
|
self.w_cnt = Signal(max=shift_reg_size//sink_dw)
|
||||||
|
self.r_cnt = Signal(max=shift_reg_size//source_dw)
|
||||||
|
|
||||||
# Input sink
|
|
||||||
|
|
||||||
i_inc = Signal()
|
|
||||||
i_count = Signal(max=io_lcm//i_dw)
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
self.sink.ack.eq(1), # assume downstream is not blocked
|
|
||||||
i_inc.eq(self.sink.stb),
|
|
||||||
]
|
|
||||||
|
|
||||||
self.sync += [
|
self.sync += [
|
||||||
If(i_inc,
|
If(reset_reg,
|
||||||
If(i_count == ((io_lcm//i_dw) - 1),
|
level.eq(level.reset),
|
||||||
i_count.eq(i_count.reset),
|
).Else(
|
||||||
).Else(
|
If(we & ~re, level.eq(level + sink_dw)),
|
||||||
i_count.eq(i_count + 1),
|
If(~we & re, level.eq(level - source_dw)),
|
||||||
)
|
If(we & re, level.eq(level + sink_dw - source_dw)),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
If(reset_reg,
|
||||||
|
self.w_cnt.eq(self.w_cnt.reset),
|
||||||
|
self.r_cnt.eq(self.r_cnt.reset),
|
||||||
|
).Else(
|
||||||
|
If(we,
|
||||||
|
If(self.w_cnt == ((shift_reg_size//sink_dw) - 1),
|
||||||
|
self.w_cnt.eq(self.w_cnt.reset),
|
||||||
|
).Else(
|
||||||
|
self.w_cnt.eq(self.w_cnt + 1),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
If(re,
|
||||||
|
If(self.r_cnt == ((shift_reg_size//source_dw) - 1),
|
||||||
|
self.r_cnt.eq(self.r_cnt.reset),
|
||||||
|
).Else(
|
||||||
|
self.r_cnt.eq(self.r_cnt + 1),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
self.submodules.fsm = fsm = FSM(reset_state="COPY")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
valid_stb = Signal()
|
||||||
|
self.comb += self.source.stb.eq((level >= source_dw) | valid_stb)
|
||||||
|
|
||||||
i_cases = {}
|
fsm.act(
|
||||||
for i in range(io_lcm//i_dw):
|
"COPY",
|
||||||
i_cases[i] = [
|
self.sink.ack.eq(1),
|
||||||
self.shift_register[i_dw*i:i_dw*(i+1)].eq(self.sink.data),
|
# self.source.stb.eq(level >= source_dw),
|
||||||
|
we.eq(self.sink.stb),
|
||||||
|
re.eq((self.source.stb & self.source.ack)),
|
||||||
|
If(self.sink.stb & self.sink.eop,
|
||||||
|
NextState("NEWLINE"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
fsm.act(
|
||||||
|
"NEWLINE",
|
||||||
|
reset_reg.eq(1),
|
||||||
|
valid_stb.eq(1),
|
||||||
|
# self.source.stb.eq(1),
|
||||||
|
NextState("COPY"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Data path
|
||||||
|
|
||||||
|
self.shift_register = Signal(shift_reg_size, reset_less=True)
|
||||||
|
|
||||||
|
sink_cases = {}
|
||||||
|
for i in range(shift_reg_size//sink_dw):
|
||||||
|
sink_cases[i] = [
|
||||||
|
self.shift_register[sink_dw*i:sink_dw*(i+1)].eq(self.sink.data),
|
||||||
]
|
]
|
||||||
self.sync += If(self.sink.stb, Case(i_count, i_cases))
|
self.sync += If(self.sink.stb, Case(self.w_cnt, sink_cases))
|
||||||
|
|
||||||
# Output source
|
source_cases = {}
|
||||||
|
for i in range(shift_reg_size//source_dw):
|
||||||
level = Signal(max=io_lcm)
|
source_cases[i] = []
|
||||||
o_inc = Signal()
|
|
||||||
o_count = Signal(max=io_lcm//o_dw)
|
|
||||||
|
|
||||||
self.comb += [
|
|
||||||
self.source.stb.eq(level >= o_dw),
|
|
||||||
o_inc.eq(self.source.stb & self.source.ack)
|
|
||||||
]
|
|
||||||
|
|
||||||
self.sync += [
|
|
||||||
If(o_inc,
|
|
||||||
If(o_count == ((io_lcm//o_dw) - 1),
|
|
||||||
o_count.eq(o_count.reset),
|
|
||||||
).Else(
|
|
||||||
o_count.eq(o_count + 1),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
If(i_inc & ~o_inc, level.eq(level + i_dw)),
|
|
||||||
If(~i_inc & o_inc, level.eq(level - o_dw)),
|
|
||||||
If(i_inc & o_inc, level.eq(level + i_dw - o_dw)),
|
|
||||||
]
|
|
||||||
|
|
||||||
o_cases = {}
|
|
||||||
for i in range(io_lcm//o_dw):
|
|
||||||
o_cases[i] = []
|
|
||||||
for j in range(4):
|
for j in range(4):
|
||||||
o_cases[i].append(
|
source_cases[i].append(
|
||||||
self.source.data[pixel_width * j : pixel_width * (j + 1)].eq(
|
self.source.data[pixel_width * j : pixel_width * (j + 1)].eq(
|
||||||
self.shift_register[(o_dw * i) + (size * j) : (o_dw * i) + (size * (j + 1))]
|
self.shift_register[(source_dw * i) + (size * j) : (source_dw * i) + (size * (j + 1))]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
self.comb += Case(o_count, o_cases)
|
|
||||||
|
|
||||||
# Handle line break
|
# precalcule which last pixels are valid
|
||||||
|
|
||||||
# precalcule which pixels are valid
|
|
||||||
self.valid = Signal(4)
|
self.valid = Signal(4)
|
||||||
bit_cases = {
|
bit_cases = {
|
||||||
0: self.valid.eq(0b1111),
|
0: self.valid.eq(0b1111),
|
||||||
@ -494,28 +515,16 @@ class Custom_Pixel_Gearbox(Module):
|
|||||||
}
|
}
|
||||||
self.sync += Case(self.x_size[:2], bit_cases)
|
self.sync += Case(self.x_size[:2], bit_cases)
|
||||||
|
|
||||||
# TODO: reset the o_count & i_count after eop
|
|
||||||
line_break_r = Signal()
|
|
||||||
self.sync += [
|
|
||||||
line_break_r.eq(self.sink.eop),
|
|
||||||
If(line_break_r,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# get which last pixels are valid
|
|
||||||
# use end of line to reset o_count, i_count, level & stb the last pixel
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
If(line_break_r,
|
Case(self.r_cnt, source_cases),
|
||||||
|
If(valid_stb,
|
||||||
self.source.valid.eq(self.valid),
|
self.source.valid.eq(self.valid),
|
||||||
).Else(
|
).Else(
|
||||||
self.source.valid.eq(0b1111),
|
self.source.valid.eq(0b1111),
|
||||||
)
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Frame_Deserializer(Module):
|
class Frame_Deserializer(Module):
|
||||||
def __init__(self, width, pixel_size):
|
def __init__(self, width, pixel_size):
|
||||||
self.new_frame = Signal()
|
self.new_frame = Signal()
|
||||||
@ -528,7 +537,7 @@ class Frame_Deserializer(Module):
|
|||||||
self.sync += eol_inserter.l_size.eq(self.l_size),
|
self.sync += eol_inserter.l_size.eq(self.l_size),
|
||||||
|
|
||||||
|
|
||||||
self.submodules.gearbox = gearbox = Custom_Pixel_Gearbox(8)
|
self.submodules.gearbox = gearbox = Custom_Pixel_Gearbox(16)
|
||||||
self.sync += gearbox.x_size.eq(self.x_size),
|
self.sync += gearbox.x_size.eq(self.x_size),
|
||||||
|
|
||||||
self.comb += eol_inserter.source.connect(gearbox.sink)
|
self.comb += eol_inserter.source.connect(gearbox.sink)
|
||||||
|
Loading…
Reference in New Issue
Block a user