Skip to content

Commit b9e390c

Browse files
committedJan 25, 2016
Merge pull request #188 from timvideos/encoder_buffer
Use new encoder buffer
2 parents a6bf3bb + b040d1b commit b9e390c

22 files changed

+785
-483
lines changed
 

‎firmware/lm32/encoder.c

+9-5
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,15 @@ void encoder_service(void) {
182182
if(elapsed(&last_event, identifier_frequency_read()/encoder_target_fps))
183183
can_start = 1;
184184
if(can_start & encoder_done()) {
185-
encoder_init(encoder_quality);
186-
encoder_start(processor_h_active, processor_v_active);
187-
encoder_reader_dma_length_write(processor_h_active*processor_v_active*2);
188-
encoder_reader_dma_shoot_write(1);
189-
frame_cnt++;
185+
encoder_init(encoder_quality);
186+
encoder_start(processor_h_active, processor_v_active);
187+
can_start = 0;
188+
frame_cnt++;
189+
}
190+
if(encoder_reader_done_read()) {
191+
encoder_reader_h_width_write(processor_h_active);
192+
encoder_reader_v_width_write(processor_v_active);
193+
encoder_reader_start_write(1);
190194
}
191195
if(elapsed(&last_fps_event, identifier_frequency_read())) {
192196
encoder_fps = frame_cnt;

‎firmware/lm32/hdmi_in0.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ int hdmi_in0_fb_index;
2121
#define FRAMEBUFFER_MASK (FRAMEBUFFER_COUNT - 1)
2222

2323
#define HDMI_IN0_FRAMEBUFFERS_BASE 0x00000000
24-
#define HDMI_IN0_FRAMEBUFFERS_SIZE 1280*720*2
24+
#define HDMI_IN0_FRAMEBUFFERS_SIZE 1920*1080*2
2525

2626
unsigned int hdmi_in0_framebuffer_base(char n) {
2727
return HDMI_IN0_FRAMEBUFFERS_BASE + n*HDMI_IN0_FRAMEBUFFERS_SIZE;

‎firmware/lm32/hdmi_in1.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ int hdmi_in1_fb_index;
2121
#define FRAMEBUFFER_MASK (FRAMEBUFFER_COUNT - 1)
2222

2323
#define HDMI_IN1_FRAMEBUFFERS_BASE 0x01000000
24-
#define HDMI_IN1_FRAMEBUFFERS_SIZE 1280*720*2
24+
#define HDMI_IN1_FRAMEBUFFERS_SIZE 1920*1080*2
2525

2626
unsigned int hdmi_in1_framebuffer_base(char n) {
2727
return HDMI_IN1_FRAMEBUFFERS_BASE + n*HDMI_IN1_FRAMEBUFFERS_SIZE;

‎firmware/lm32/processor.c

+17-3
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,20 @@ static const struct video_timing video_modes[PROCESSOR_MODE_COUNT] = {
252252
.v_blanking = 30,
253253
.v_sync_offset = 5,
254254
.v_sync_width = 5
255+
},
256+
// 1920x1080 @ 30.00 Hz ModeLine "1920x1080" 89.01 1920 2448 2492 2640 1080 1084 1089 1125 +HSync +VSync
257+
{
258+
.pixel_clock = 8901,
259+
260+
.h_active = 1920,
261+
.h_blanking = 720,
262+
.h_sync_offset = 528,
263+
.h_sync_width = 44,
264+
265+
.v_active = 1080,
266+
.v_blanking = 45,
267+
.v_sync_offset = 4,
268+
.v_sync_width = 5
255269
}
256270
};
257271

@@ -487,16 +501,16 @@ void processor_update(void)
487501
/* encoder */
488502
#ifdef CSR_HDMI_IN0_BASE
489503
if(processor_encoder_source == VIDEO_IN_HDMI_IN0) {
490-
encoder_reader_dma_base_write((hdmi_in0_framebuffer_base(hdmi_in0_fb_index)));
504+
encoder_reader_base_write((hdmi_in0_framebuffer_base(hdmi_in0_fb_index)));
491505
}
492506
#endif
493507
#ifdef CSR_HDMI_IN1_BASE
494508
if(processor_encoder_source == VIDEO_IN_HDMI_IN1) {
495-
encoder_reader_dma_base_write((hdmi_in1_framebuffer_base(hdmi_in1_fb_index)));
509+
encoder_reader_base_write((hdmi_in1_framebuffer_base(hdmi_in1_fb_index)));
496510
}
497511
#endif
498512
if(processor_encoder_source == VIDEO_IN_PATTERN)
499-
encoder_reader_dma_base_write(pattern_framebuffer_base());
513+
encoder_reader_base_write(pattern_framebuffer_base());
500514
#endif
501515
}
502516

‎firmware/lm32/processor.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef __PROCESSOR_H
22
#define __PROCESSOR_H
33

4-
#define PROCESSOR_MODE_COUNT 11
4+
#define PROCESSOR_MODE_COUNT 12
55
#define PROCESSOR_MODE_DESCLEN 32
66

77
enum {

‎gateware/encoder/__init__.py

+54-59
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,15 @@
33
from migen.fhdl.std import *
44
from migen.bus import wishbone
55
from migen.genlib.record import *
6-
from migen.genlib.cdc import MultiReg
76
from migen.bank.description import *
87
from migen.flow.actor import *
9-
from migen.flow.network import *
108
from migen.actorlib.fifo import SyncFIFO
119
from migen.actorlib import structuring, spi
1210
from migen.bank.eventmanager import *
1311

1412
from misoclib.mem.sdram.frontend import dma_lasmi
1513

1614
from gateware.csc.ycbcr422to444 import YCbCr422to444
17-
from gateware.csc.ymodulator import YModulator
18-
19-
20-
class EncoderReader(Module, AutoCSR):
21-
def __init__(self, lasmim):
22-
self.source = source = Source(EndpointDescription([("data", 16)], packetized=True))
23-
24-
reader = dma_lasmi.Reader(lasmim)
25-
self.dma = spi.DMAReadController(reader, mode=spi.MODE_SINGLE_SHOT)
26-
27-
pack_factor = lasmim.dw//16
28-
packed_dat = structuring.pack_layout(16, pack_factor)
29-
cast = structuring.Cast(lasmim.dw, packed_dat)
30-
unpack = structuring.Unpack(pack_factor, [("data", 16)], reverse=True)
31-
32-
33-
# graph
34-
g = DataFlowGraph()
35-
g.add_pipeline(self.dma, cast, unpack)
36-
self.submodules += CompositeActor(g)
37-
self.comb += Record.connect(unpack.source, source)
38-
39-
self.sync += \
40-
If(self.dma._busy.status == 0,
41-
source.sop.eq(1),
42-
).Elif(source.stb & source.ack,
43-
source.sop.eq(0)
44-
)
45-
46-
# irq
47-
self.submodules.ev = EventManager()
48-
self.ev.done = EventSourceProcess()
49-
self.ev.finalize()
50-
self.comb += self.ev.done.trigger.eq(self.dma._busy.status)
5115

5216

5317
class EncoderBandwidth(Module, AutoCSR):
@@ -78,46 +42,74 @@ def __init__(self, platform):
7842
# # #
7943

8044
# chroma upsampler
81-
self.submodules.chroma_upsampler = chroma_upsampler = YCbCr422to444()
45+
chroma_upsampler = RenameClockDomains(YCbCr422to444(), "encoder")
46+
self.submodules += chroma_upsampler
8247
self.comb += [
8348
Record.connect(self.sink, chroma_upsampler.sink, leave_out=["data"]),
8449
chroma_upsampler.sink.y.eq(self.sink.data[:8]),
8550
chroma_upsampler.sink.cb_cr.eq(self.sink.data[8:])
8651
]
8752

88-
# encoder fifo
89-
encoder_fifo_full = Signal()
90-
self.comb += chroma_upsampler.source.ack.eq(~encoder_fifo_full)
91-
9253
# output fifo
9354
output_fifo_almost_full = Signal()
94-
self.submodules.output_fifo = output_fifo = SyncFIFO([("data", 8)], 1024)
55+
output_fifo = RenameClockDomains(SyncFIFO([("data", 8)], 1024), "encoder")
56+
self.submodules += output_fifo
9557
self.comb += [
9658
output_fifo_almost_full.eq(output_fifo.fifo.level > 1024-128),
9759
Record.connect(output_fifo.source, self.source)
9860
]
9961

62+
# Wishbone cross domain crossing
63+
jpeg_bus = wishbone.Interface()
64+
self.specials += Instance("wb_async_reg",
65+
i_wbm_clk=ClockSignal(),
66+
i_wbm_rst=ResetSignal(),
67+
i_wbm_adr_i=self.bus.adr,
68+
i_wbm_dat_i=self.bus.dat_w,
69+
o_wbm_dat_o=self.bus.dat_r,
70+
i_wbm_we_i=self.bus.we,
71+
i_wbm_sel_i=self.bus.sel,
72+
i_wbm_stb_i=self.bus.stb,
73+
o_wbm_ack_o=self.bus.ack,
74+
o_wbm_err_o=self.bus.err,
75+
#o_wbm_rty_o=,
76+
i_wbm_cyc_i=self.bus.cyc,
77+
78+
i_wbs_clk=ClockSignal("encoder"),
79+
i_wbs_rst=ResetSignal("encoder"),
80+
o_wbs_adr_o=jpeg_bus.adr,
81+
i_wbs_dat_i=jpeg_bus.dat_r,
82+
o_wbs_dat_o=jpeg_bus.dat_w,
83+
o_wbs_we_o=jpeg_bus.we,
84+
o_wbs_sel_o=jpeg_bus.sel,
85+
o_wbs_stb_o=jpeg_bus.stb,
86+
i_wbs_ack_i=jpeg_bus.ack,
87+
i_wbs_err_i=jpeg_bus.err,
88+
i_wbs_rty_i=0,
89+
o_wbs_cyc_o=jpeg_bus.cyc)
90+
91+
10092
# encoder
10193
self.specials += Instance("JpegEnc",
102-
i_CLK=ClockSignal(),
103-
i_RST=ResetSignal(),
104-
105-
i_OPB_ABus=Cat(Signal(2), self.bus.adr) & 0x3ff,
106-
i_OPB_BE=self.bus.sel,
107-
i_OPB_DBus_in=self.bus.dat_w,
108-
i_OPB_RNW=~self.bus.we,
109-
i_OPB_select=self.bus.stb & self.bus.cyc,
110-
o_OPB_DBus_out=self.bus.dat_r,
111-
o_OPB_XferAck=self.bus.ack,
94+
i_CLK=ClockSignal("encoder"),
95+
i_RST=ResetSignal("encoder"),
96+
97+
i_OPB_ABus=Cat(Signal(2), jpeg_bus.adr) & 0x3ff,
98+
i_OPB_BE=jpeg_bus.sel,
99+
i_OPB_DBus_in=jpeg_bus.dat_w,
100+
i_OPB_RNW=~jpeg_bus.we,
101+
i_OPB_select=jpeg_bus.stb & jpeg_bus.cyc,
102+
o_OPB_DBus_out=jpeg_bus.dat_r,
103+
o_OPB_XferAck=jpeg_bus.ack,
112104
#o_OPB_retry=,
113105
#o_OPB_toutSup=,
114-
o_OPB_errAck=self.bus.err,
106+
o_OPB_errAck=jpeg_bus.err,
115107

116-
i_iram_wdata=Cat(chroma_upsampler.source.y,
117-
chroma_upsampler.source.cb,
118-
chroma_upsampler.source.cr),
119-
i_iram_wren=chroma_upsampler.source.stb & ~encoder_fifo_full,
120-
o_iram_fifo_afull=encoder_fifo_full,
108+
i_fdct_ack=chroma_upsampler.source.ack,
109+
i_fdct_stb=chroma_upsampler.source.stb,
110+
i_fdct_data=Cat(chroma_upsampler.source.y,
111+
chroma_upsampler.source.cb,
112+
chroma_upsampler.source.cr),
121113

122114
o_ram_byte=output_fifo.sink.data,
123115
o_ram_wren=output_fifo.sink.stb,
@@ -127,6 +119,9 @@ def __init__(self, platform):
127119
# add vhdl sources
128120
platform.add_source_dir(os.path.join(platform.soc_ext_path, "gateware", "encoder", "vhdl"))
129121

122+
# add verilog sources
123+
platform.add_source(os.path.join(platform.soc_ext_path, "gateware", "encoder", "verilog", "wb_async_reg.v"))
124+
130125
# bandwidth
131-
self.submodules.bandwidth = EncoderBandwidth()
126+
self.submodules.bandwidth = EncoderBandwidth() # XXX add CDC
132127
self.comb += self.bandwidth.nbytes_inc.eq(self.source.stb & self.source.ack)

‎gateware/encoder/buffer.py

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
from migen.fhdl.std import *
2+
from migen.genlib.record import *
3+
from migen.genlib.fsm import FSM, NextState
4+
from migen.genlib.misc import chooser
5+
from migen.flow.actor import *
6+
7+
class EncoderBuffer(Module):
8+
def __init__(self):
9+
self.sink = sink = Sink(EndpointDescription([("data", 128)], packetized=True))
10+
self.source = source = Source(EndpointDescription([("data", 16)], packetized=True))
11+
12+
# # #
13+
14+
# mem
15+
mem = Memory(128, 16)
16+
write_port = mem.get_port(write_capable=True)
17+
read_port = mem.get_port(async_read=True)
18+
self.specials += mem, write_port, read_port
19+
20+
write_sel = Signal()
21+
write_swap = Signal()
22+
read_sel = Signal(reset=1)
23+
read_swap = Signal()
24+
self.sync += [
25+
If(write_swap,
26+
write_sel.eq(~write_sel)
27+
),
28+
If(read_swap,
29+
read_sel.eq(~read_sel)
30+
)
31+
]
32+
33+
34+
# write path
35+
v_write_clr = Signal()
36+
v_write_inc = Signal()
37+
v_write = Signal(3)
38+
self.sync += \
39+
If(v_write_clr,
40+
v_write.eq(0)
41+
).Elif(v_write_inc,
42+
v_write.eq(v_write + 1)
43+
)
44+
45+
self.comb += [
46+
write_port.adr.eq(v_write),
47+
write_port.adr[-1].eq(write_sel),
48+
write_port.dat_w.eq(sink.data),
49+
write_port.we.eq(sink.stb & sink.ack)
50+
]
51+
52+
self.submodules.write_fsm = write_fsm = FSM(reset_state="IDLE")
53+
write_fsm.act("IDLE",
54+
v_write_clr.eq(1),
55+
If(write_sel != read_sel,
56+
NextState("WRITE")
57+
)
58+
)
59+
write_fsm.act("WRITE",
60+
sink.ack.eq(1),
61+
If(sink.stb,
62+
If(v_write == 7,
63+
write_swap.eq(1),
64+
NextState("IDLE")
65+
).Else(
66+
v_write_inc.eq(1)
67+
)
68+
)
69+
)
70+
71+
# read path
72+
h_read_clr = Signal()
73+
h_read_inc = Signal()
74+
h_read = Signal(3)
75+
self.sync += \
76+
If(h_read_clr,
77+
h_read.eq(0)
78+
).Elif(h_read_inc,
79+
h_read.eq(h_read + 1)
80+
)
81+
82+
v_read_clr = Signal()
83+
v_read_inc = Signal()
84+
v_read = Signal(3)
85+
self.sync += \
86+
If(v_read_clr,
87+
v_read.eq(0)
88+
).Elif(v_read_inc,
89+
v_read.eq(v_read + 1)
90+
)
91+
92+
self.comb += [
93+
read_port.adr.eq(v_read),
94+
read_port.adr[-1].eq(read_sel),
95+
chooser(read_port.dat_r, h_read, source.data, reverse=True)
96+
]
97+
98+
self.submodules.read_fsm = read_fsm = FSM(reset_state="IDLE")
99+
read_fsm.act("IDLE",
100+
h_read_clr.eq(1),
101+
v_read_clr.eq(1),
102+
If(read_sel == write_sel,
103+
read_swap.eq(1),
104+
NextState("READ")
105+
)
106+
)
107+
read_fsm.act("READ",
108+
source.stb.eq(1),
109+
source.sop.eq((h_read == 0) & (v_read == 0)),
110+
source.eop.eq((h_read == 7) & (v_read == 7)),
111+
If(source.ack,
112+
If(h_read == 7,
113+
h_read_clr.eq(1),
114+
If(v_read == 7,
115+
NextState("IDLE")
116+
).Else(
117+
v_read_inc.eq(1)
118+
)
119+
).Else(
120+
h_read_inc.eq(1)
121+
)
122+
)
123+
)

‎gateware/encoder/dma.py

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import os
2+
3+
from migen.fhdl.std import *
4+
from migen.genlib.record import *
5+
from migen.genlib.fsm import FSM, NextState
6+
from migen.bank.description import *
7+
from migen.flow.actor import *
8+
from migen.actorlib.fifo import SyncFIFO
9+
from migen.actorlib import structuring, spi
10+
11+
from misoclib.mem.sdram.frontend import dma_lasmi
12+
13+
14+
class EncoderDMAReader(Module, AutoCSR):
15+
def __init__(self, lasmim):
16+
self.source = source = Source(EndpointDescription([("data", 128)]))
17+
self.base = CSRStorage(32)
18+
self.h_width = CSRStorage(16)
19+
self.v_width = CSRStorage(16)
20+
self.start = CSR()
21+
self.done = CSRStatus()
22+
23+
# # #
24+
25+
pixel_bits = 16 # ycbcr 4:2:2
26+
burst_pixels = lasmim.dw//pixel_bits
27+
alignment_bits = bits_for(lasmim.dw//8) - 1
28+
29+
self.submodules.reader = reader = dma_lasmi.Reader(lasmim)
30+
self.submodules.converter = structuring.Converter(EndpointDescription([("data", lasmim.dw)]),
31+
EndpointDescription([("data", 128)]),
32+
reverse=True)
33+
self.comb += [
34+
Record.connect(reader.data, self.converter.sink, leave_out=set(["d"])),
35+
self.converter.sink.data.eq(reader.data.d),
36+
Record.connect(self.converter.source, source)
37+
]
38+
39+
base = Signal(32)
40+
h_width = self.h_width.storage
41+
v_width = self.v_width.storage
42+
start = self.start.r & self.start.re
43+
done = self.done.status
44+
self.sync += If(start, base.eq(self.base.storage))
45+
46+
h_clr = Signal()
47+
h_clr_lsb = Signal()
48+
h_inc = Signal()
49+
h = Signal(16)
50+
h_next = Signal(16)
51+
self.comb += h_next.eq(h + burst_pixels)
52+
self.sync += \
53+
If(h_clr,
54+
h.eq(0)
55+
).Elif(h_clr_lsb,
56+
h[:3].eq(0),
57+
h[3:].eq(h[3:])
58+
).Elif(h_inc,
59+
h.eq(h_next)
60+
)
61+
62+
v_clr = Signal()
63+
v_inc = Signal()
64+
v_dec7 = Signal()
65+
v = Signal(16)
66+
self.sync += \
67+
If(v_clr,
68+
v.eq(0)
69+
).Elif(v_inc,
70+
v.eq(v + 1)
71+
).Elif(v_dec7,
72+
v.eq(v - 7)
73+
)
74+
75+
self.submodules.fsm = fsm = FSM(reset_state="IDLE")
76+
fsm.act("IDLE",
77+
h_clr.eq(1),
78+
v_clr.eq(1),
79+
If(start,
80+
NextState("READ")
81+
).Else(
82+
done.eq(1)
83+
)
84+
)
85+
fsm.act("READ",
86+
reader.address.stb.eq(1),
87+
If(reader.address.ack,
88+
# last burst of 8 pixels
89+
If(h_next[:3] == 0,
90+
# last line of a block of 8 pixels
91+
If(v[:3] == 7,
92+
# last block of a line
93+
If(h >= h_width - burst_pixels,
94+
h_clr.eq(1),
95+
v_inc.eq(1),
96+
# last line
97+
If(v >= v_width - 1,
98+
NextState("IDLE")
99+
)
100+
).Else(
101+
h_inc.eq(1),
102+
v_dec7.eq(1)
103+
)
104+
).Else(
105+
h_clr_lsb.eq(1),
106+
v_inc.eq(1)
107+
)
108+
).Else(
109+
h_inc.eq(1)
110+
)
111+
)
112+
)
113+
114+
read_address = Signal(lasmim.aw + alignment_bits)
115+
self.comb += [
116+
read_address.eq(v * h_width + h),
117+
reader.address.a.eq(base[alignment_bits:] +
118+
read_address[alignment_bits - log2_int(pixel_bits//8):])
119+
]

‎gateware/encoder/test/Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
HDLDIR = ../../../
2+
PYTHON = python3
3+
4+
CMD = PYTHONPATH=$(HDLDIR) $(PYTHON)
5+
6+
buffer_tb:
7+
$(CMD) buffer_tb.py
8+
9+
dma_tb:
10+
$(CMD) dma_tb.py
11+
12+
clean:
13+
rm -rf *.vvp *.v *.vcd
14+
15+
.PHONY: clean

‎gateware/encoder/test/buffer_tb.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from migen.fhdl.std import *
2+
from migen.sim.generic import run_simulation
3+
from migen.flow.actor import EndpointDescription
4+
5+
from gateware.encoder.buffer import EncoderBuffer
6+
from gateware.csc.test.common import *
7+
8+
9+
class TB(Module):
10+
def __init__(self):
11+
stream_description = EndpointDescription([("data", 128)], packetized=True)
12+
13+
self.submodules.streamer = PacketStreamer(stream_description)
14+
self.submodules.streamer_randomizer = AckRandomizer(stream_description, 50)
15+
self.submodules.buffer = EncoderBuffer()
16+
self.submodules.logger_randomizer = AckRandomizer(stream_description, 50)
17+
self.submodules.logger = PacketLogger(stream_description)
18+
self.comb += [
19+
Record.connect(self.streamer.source, self.streamer_randomizer.sink),
20+
Record.connect(self.streamer_randomizer.source, self.buffer.sink),
21+
Record.connect(self.buffer.source, self.logger_randomizer.sink),
22+
Record.connect(self.logger_randomizer.source, self.logger.sink)
23+
]
24+
25+
def check_pixel(self, value, index, block):
26+
line = block[index//8]
27+
reference = (line >> 16*(7-index%8)) & 0xffff
28+
return value == reference
29+
30+
def gen_simulation(self, selfp):
31+
# create 8x8 blocks (one 8 pixels line per stb)
32+
blocks = []
33+
for i in range(8):
34+
block = [randn(2**128) for line in range(8)]
35+
blocks.append(block)
36+
37+
# send blocks
38+
for block in blocks:
39+
packet = Packet(block)
40+
self.streamer.send(packet)
41+
42+
# receive the 8x8 blocks (1 pixel per stb)
43+
errors = 0
44+
for block in blocks:
45+
yield from self.logger.receive()
46+
for index, value in enumerate(self.logger.packet):
47+
errors += not self.check_pixel(value, index, block)
48+
print("blocks: {}, errors: {}".format(len(blocks), errors))
49+
50+
if __name__ == "__main__":
51+
run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)

‎gateware/encoder/test/dma_tb.py

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from migen.fhdl.std import *
2+
from migen.sim.generic import run_simulation
3+
from migen.flow.actor import EndpointDescription
4+
5+
from misoclib.mem.sdram.frontend import dma_lasmi
6+
7+
from gateware.encoder.dma import EncoderDMAReader
8+
from gateware.csc.test.common import *
9+
10+
from misoclib.mem.sdram.module import MT48LC4M16
11+
from misoclib.mem.sdram.phy.simphy import SDRAMPHYSim
12+
from misoclib.mem.sdram.core import SDRAMCore
13+
from misoclib.mem.sdram.core.lasmicon import LASMIconSettings
14+
15+
from misoclib.mem import sdram
16+
17+
18+
class TB(Module):
19+
def __init__(self):
20+
# sdram
21+
sdram_module = MT48LC4M16(75*1000000)
22+
sdram_phy_settings = sdram.PhySettings(
23+
memtype="SDR",
24+
dfi_databits=1*16,
25+
nphases=1,
26+
rdphase=0,
27+
wrphase=0,
28+
rdcmdphase=0,
29+
wrcmdphase=0,
30+
cl=2,
31+
read_latency=4,
32+
write_latency=0
33+
)
34+
self.submodules.sdram_phy = SDRAMPHYSim(sdram_module, sdram_phy_settings)
35+
self.submodules.sdram_core = SDRAMCore(self.sdram_phy,
36+
sdram_module.geom_settings,
37+
sdram_module.timing_settings,
38+
LASMIconSettings(with_refresh=False))
39+
40+
# dma writer
41+
self.submodules.dma_writer = dma_lasmi.Writer(self.sdram_core.crossbar.get_master())
42+
43+
# dma reader
44+
self.submodules.dma_reader = EncoderDMAReader(self.sdram_core.crossbar.get_master())
45+
self.comb += self.dma_reader.source.ack.eq(1)
46+
47+
def check_line(self, value, x, y, memory_data):
48+
line = memory_data[16*y + x: 16*y + x + 8]
49+
reference = 0
50+
for i in range(128//16):
51+
reference |= (line[::-1][i] << 16*i)
52+
if value != reference:
53+
print("x:%d, y:%d "%(x, y))
54+
print("v %32x" %(value))
55+
print("l %32x" %(reference))
56+
return value == reference
57+
58+
def gen_simulation(self, selfp):
59+
selfp.sdram_core.dfii._control.storage = 1
60+
for i in range(16):
61+
yield
62+
63+
# write (init memory)
64+
memory_data = [randn(2**16) for i in range(16*16)] # 16x16 pixels = 4 macroblocks
65+
for i, value in enumerate(memory_data):
66+
selfp.dma_writer.address_data.stb = 1
67+
selfp.dma_writer.address_data.a = i
68+
selfp.dma_writer.address_data.d = memory_data[i]
69+
yield
70+
while selfp.dma_writer.address_data.ack == 0:
71+
yield
72+
selfp.dma_writer.address_data.stb = 0
73+
yield
74+
75+
# read
76+
selfp.dma_reader.base.storage = 0
77+
selfp.dma_reader.h_width.storage = 16
78+
selfp.dma_reader.v_width.storage = 16
79+
yield
80+
selfp.dma_reader.start.r = 1
81+
selfp.dma_reader.start.re = 1
82+
yield
83+
selfp.dma_reader.start.r = 0
84+
selfp.dma_reader.start.re = 0
85+
86+
errors = 0
87+
x_indexs = [0]*8 + [8]*8 + \
88+
[0]*8 + [8]*8
89+
y_indexs = [i for i in range(8)] + [i for i in range(8)] + \
90+
[i + 8 for i in range(8)] + [i + 8 for i in range(8)]
91+
for i in range(len(memory_data)*16//128):
92+
yield
93+
while selfp.dma_reader.source.stb == 0:
94+
yield
95+
x = x_indexs[i]
96+
y = y_indexs[i]
97+
errors += not self.check_line(selfp.dma_reader.source.data, x, y, memory_data)
98+
print("errors : {}".format(errors))
99+
100+
if __name__ == "__main__":
101+
run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/*
2+
Copyright (c) 2015-2016 Alex Forencich
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
The above copyright notice and this permission notice shall be included in
10+
all copies or substantial portions of the Software.
11+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
13+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
17+
THE SOFTWARE.
18+
*/
19+
20+
// Language: Verilog 2001
21+
22+
`timescale 1ns / 1ps
23+
24+
/*
25+
* Wishbone register
26+
*/
27+
module wb_async_reg #
28+
(
29+
parameter DATA_WIDTH = 32, // width of data bus in bits (8, 16, 32, or 64)
30+
parameter ADDR_WIDTH = 32, // width of address bus in bits
31+
parameter SELECT_WIDTH = (DATA_WIDTH/8) // width of word select bus (1, 2, 4, or 8)
32+
)
33+
(
34+
// master side
35+
input wire wbm_clk,
36+
input wire wbm_rst,
37+
input wire [ADDR_WIDTH-1:0] wbm_adr_i, // ADR_I() address
38+
input wire [DATA_WIDTH-1:0] wbm_dat_i, // DAT_I() data in
39+
output wire [DATA_WIDTH-1:0] wbm_dat_o, // DAT_O() data out
40+
input wire wbm_we_i, // WE_I write enable input
41+
input wire [SELECT_WIDTH-1:0] wbm_sel_i, // SEL_I() select input
42+
input wire wbm_stb_i, // STB_I strobe input
43+
output wire wbm_ack_o, // ACK_O acknowledge output
44+
output wire wbm_err_o, // ERR_O error output
45+
output wire wbm_rty_o, // RTY_O retry output
46+
input wire wbm_cyc_i, // CYC_I cycle input
47+
48+
// slave side
49+
input wire wbs_clk,
50+
input wire wbs_rst,
51+
output wire [ADDR_WIDTH-1:0] wbs_adr_o, // ADR_O() address
52+
input wire [DATA_WIDTH-1:0] wbs_dat_i, // DAT_I() data in
53+
output wire [DATA_WIDTH-1:0] wbs_dat_o, // DAT_O() data out
54+
output wire wbs_we_o, // WE_O write enable output
55+
output wire [SELECT_WIDTH-1:0] wbs_sel_o, // SEL_O() select output
56+
output wire wbs_stb_o, // STB_O strobe output
57+
input wire wbs_ack_i, // ACK_I acknowledge input
58+
input wire wbs_err_i, // ERR_I error input
59+
input wire wbs_rty_i, // RTY_I retry input
60+
output wire wbs_cyc_o // CYC_O cycle output
61+
);
62+
63+
reg [ADDR_WIDTH-1:0] wbm_adr_i_reg = 0;
64+
reg [DATA_WIDTH-1:0] wbm_dat_i_reg = 0;
65+
reg [DATA_WIDTH-1:0] wbm_dat_o_reg = 0;
66+
reg wbm_we_i_reg = 0;
67+
reg [SELECT_WIDTH-1:0] wbm_sel_i_reg = 0;
68+
reg wbm_stb_i_reg = 0;
69+
reg wbm_ack_o_reg = 0;
70+
reg wbm_err_o_reg = 0;
71+
reg wbm_rty_o_reg = 0;
72+
reg wbm_cyc_i_reg = 0;
73+
74+
reg wbm_done_sync1 = 0;
75+
reg wbm_done_sync2 = 0;
76+
reg wbm_done_sync3 = 0;
77+
78+
reg [ADDR_WIDTH-1:0] wbs_adr_o_reg = 0;
79+
reg [DATA_WIDTH-1:0] wbs_dat_i_reg = 0;
80+
reg [DATA_WIDTH-1:0] wbs_dat_o_reg = 0;
81+
reg wbs_we_o_reg = 0;
82+
reg [SELECT_WIDTH-1:0] wbs_sel_o_reg = 0;
83+
reg wbs_stb_o_reg = 0;
84+
reg wbs_ack_i_reg = 0;
85+
reg wbs_err_i_reg = 0;
86+
reg wbs_rty_i_reg = 0;
87+
reg wbs_cyc_o_reg = 0;
88+
89+
reg wbs_cyc_o_sync1 = 0;
90+
reg wbs_cyc_o_sync2 = 0;
91+
reg wbs_cyc_o_sync3 = 0;
92+
93+
reg wbs_stb_o_sync1 = 0;
94+
reg wbs_stb_o_sync2 = 0;
95+
reg wbs_stb_o_sync3 = 0;
96+
97+
reg wbs_done_reg = 0;
98+
99+
assign wbm_dat_o = wbm_dat_o_reg;
100+
assign wbm_ack_o = wbm_ack_o_reg;
101+
assign wbm_err_o = wbm_err_o_reg;
102+
assign wbm_rty_o = wbm_rty_o_reg;
103+
104+
assign wbs_adr_o = wbs_adr_o_reg;
105+
assign wbs_dat_o = wbs_dat_o_reg;
106+
assign wbs_we_o = wbs_we_o_reg;
107+
assign wbs_sel_o = wbs_sel_o_reg;
108+
assign wbs_stb_o = wbs_stb_o_reg;
109+
assign wbs_cyc_o = wbs_cyc_o_reg;
110+
111+
// master side logic
112+
always @(posedge wbm_clk) begin
113+
if (wbm_rst) begin
114+
wbm_adr_i_reg <= 0;
115+
wbm_dat_i_reg <= 0;
116+
wbm_dat_o_reg <= 0;
117+
wbm_we_i_reg <= 0;
118+
wbm_sel_i_reg <= 0;
119+
wbm_stb_i_reg <= 0;
120+
wbm_ack_o_reg <= 0;
121+
wbm_err_o_reg <= 0;
122+
wbm_rty_o_reg <= 0;
123+
wbm_cyc_i_reg <= 0;
124+
end else begin
125+
if (wbm_cyc_i_reg & wbm_stb_i_reg) begin
126+
// cycle - hold master
127+
if (wbm_done_sync2 & ~wbm_done_sync3) begin
128+
// end of cycle - store slave
129+
wbm_dat_o_reg <= wbs_dat_i_reg;
130+
wbm_ack_o_reg <= wbs_ack_i_reg;
131+
wbm_err_o_reg <= wbs_err_i_reg;
132+
wbm_rty_o_reg <= wbs_rty_i_reg;
133+
wbm_we_i_reg <= 0;
134+
wbm_stb_i_reg <= 0;
135+
end
136+
end else begin
137+
// idle - store master
138+
wbm_adr_i_reg <= wbm_adr_i;
139+
wbm_dat_i_reg <= wbm_dat_i;
140+
wbm_dat_o_reg <= 0;
141+
wbm_we_i_reg <= wbm_we_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
142+
wbm_sel_i_reg <= wbm_sel_i;
143+
wbm_stb_i_reg <= wbm_stb_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o);
144+
wbm_ack_o_reg <= 0;
145+
wbm_err_o_reg <= 0;
146+
wbm_rty_o_reg <= 0;
147+
wbm_cyc_i_reg <= wbm_cyc_i;
148+
end
149+
end
150+
151+
// synchronize signals
152+
wbm_done_sync1 <= wbs_done_reg;
153+
wbm_done_sync2 <= wbm_done_sync1;
154+
wbm_done_sync3 <= wbm_done_sync2;
155+
end
156+
157+
// slave side logic
158+
always @(posedge wbs_clk) begin
159+
if (wbs_rst) begin
160+
wbs_adr_o_reg <= 0;
161+
wbs_dat_i_reg <= 0;
162+
wbs_dat_o_reg <= 0;
163+
wbs_we_o_reg <= 0;
164+
wbs_sel_o_reg <= 0;
165+
wbs_stb_o_reg <= 0;
166+
wbs_ack_i_reg <= 0;
167+
wbs_err_i_reg <= 0;
168+
wbs_rty_i_reg <= 0;
169+
wbs_cyc_o_reg <= 0;
170+
wbs_done_reg <= 0;
171+
end else begin
172+
if (wbs_ack_i | wbs_err_i | wbs_rty_i) begin
173+
// end of cycle - store slave
174+
wbs_dat_i_reg <= wbs_dat_i;
175+
wbs_ack_i_reg <= wbs_ack_i;
176+
wbs_err_i_reg <= wbs_err_i;
177+
wbs_rty_i_reg <= wbs_rty_i;
178+
wbs_we_o_reg <= 0;
179+
wbs_stb_o_reg <= 0;
180+
wbs_done_reg <= 1;
181+
end else if (wbs_stb_o_sync2 & ~wbs_stb_o_sync3) begin
182+
// beginning of cycle - store master
183+
wbs_adr_o_reg <= wbm_adr_i_reg;
184+
wbs_dat_i_reg <= 0;
185+
wbs_dat_o_reg <= wbm_dat_i_reg;
186+
wbs_we_o_reg <= wbm_we_i_reg;
187+
wbs_sel_o_reg <= wbm_sel_i_reg;
188+
wbs_stb_o_reg <= wbm_stb_i_reg;
189+
wbs_ack_i_reg <= 0;
190+
wbs_err_i_reg <= 0;
191+
wbs_rty_i_reg <= 0;
192+
wbs_cyc_o_reg <= wbm_cyc_i_reg;
193+
wbs_done_reg <= 0;
194+
end else if (~wbs_cyc_o_sync2 & wbs_cyc_o_sync3) begin
195+
// cyc deassert
196+
wbs_adr_o_reg <= 0;
197+
wbs_dat_i_reg <= 0;
198+
wbs_dat_o_reg <= 0;
199+
wbs_we_o_reg <= 0;
200+
wbs_sel_o_reg <= 0;
201+
wbs_stb_o_reg <= 0;
202+
wbs_ack_i_reg <= 0;
203+
wbs_err_i_reg <= 0;
204+
wbs_rty_i_reg <= 0;
205+
wbs_cyc_o_reg <= 0;
206+
wbs_done_reg <= 0;
207+
end
208+
end
209+
210+
// synchronize signals
211+
wbs_cyc_o_sync1 <= wbm_cyc_i_reg;
212+
wbs_cyc_o_sync2 <= wbs_cyc_o_sync1;
213+
wbs_cyc_o_sync3 <= wbs_cyc_o_sync2;
214+
215+
wbs_stb_o_sync1 <= wbm_stb_i_reg;
216+
wbs_stb_o_sync2 <= wbs_stb_o_sync1;
217+
wbs_stb_o_sync3 <= wbs_stb_o_sync2;
218+
end
219+
220+
endmodule

‎gateware/encoder/vhdl/BUF_FIFO.vhd

-345
This file was deleted.

‎gateware/encoder/vhdl/FDCT.vhd

+2-12
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,6 @@ architecture RTL of FDCT is
118118
signal rd_en_d1 : std_logic:='0';
119119
signal rdaddr : unsigned(31 downto 0):=(others=>'0');
120120
signal bf_dval : std_logic:='0';
121-
signal bf_dval_m1 : std_logic:='0';
122-
signal bf_dval_m2 : std_logic:='0';
123-
signal bf_dval_m3 : std_logic:='0';
124121
signal wr_cnt : unsigned(5 downto 0):=(others=>'0');
125122
signal dbuf_data : std_logic_vector(11 downto 0):=(others=>'0');
126123
signal dbuf_q : std_logic_vector(11 downto 0):=(others=>'0');
@@ -185,6 +182,7 @@ begin
185182
zz_data <= dbuf_q;
186183

187184
bf_fifo_rd <= bf_fifo_rd_s;
185+
bf_dval <= bf_fifo_rd_s;
188186

189187
-------------------------------------------------------------------
190188
-- FRAM1 (Frame RAM, hold 16x8)
@@ -248,9 +246,6 @@ begin
248246
eoi_fdct <= '0';
249247
start_int <= '0';
250248
bf_fifo_rd_s <= '0';
251-
bf_dval <= '0';
252-
bf_dval_m1 <= '0';
253-
bf_dval_m2 <= '0';
254249
fram1_rd <= '0';
255250
fram1_rd_d <= (others => '0');
256251
start_int_d <= (others => '0');
@@ -270,10 +265,6 @@ begin
270265
cur_cmp_idx_d8 <= cur_cmp_idx_d7;
271266

272267
start_int <= '0';
273-
bf_dval_m3 <= bf_fifo_rd_s;
274-
bf_dval_m2 <= bf_dval_m3;
275-
bf_dval_m1 <= bf_dval_m2;
276-
bf_dval <= bf_dval_m1;
277268

278269
fram1_rd_d <= fram1_rd_d(fram1_rd_d'length-2 downto 0) & fram1_rd;
279270
start_int_d <= start_int_d(start_int_d'length-2 downto 0) & start_int;
@@ -324,8 +315,7 @@ begin
324315
----------------------------------------------------------------
325316
-- stall reading from input FIFO and writing to output FIFO
326317
-- when output FIFO is almost full
327-
if rd_en = '1' and unsigned(fifo1_count) < 512-64 and
328-
(bf_fifo_hf_full = '1' or cur_cmp_idx > 1) then
318+
if rd_en = '1' and unsigned(fifo1_count) < 512-64 then
329319
-- read request goes to BUF_FIFO only for component 0.
330320
if cur_cmp_idx < 2 then
331321
bf_fifo_rd_s <= '1';

‎gateware/encoder/vhdl/JPEG_PKG.vhd

-11
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,6 @@ package JPEG_PKG is
5757
-- do not change, constant
5858
constant C_HDR_SIZE : integer := 623;
5959

60-
-- warning! this parameter heavily affects memory size required
61-
-- if expected image width is known change this parameter to match this
62-
-- otherwise some onchip RAM will be wasted and never used
63-
constant C_MAX_LINE_WIDTH : integer := 1280;
64-
65-
-- memory/performance tradeoff
66-
-- 8 extra lines highest performance
67-
-- 0 extra lines lowest area
68-
constant C_EXTRA_LINES : integer := 8; -- from 0 to 8
69-
70-
7160
-- 24 bit format RGB 888 bits
7261
-- 16 bit format RGB 565 bits
7362
constant C_PIXEL_BITS : integer := 24;

‎gateware/encoder/vhdl/JpegEnc.vhd

+7-31
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,10 @@ entity JpegEnc is
8787
OPB_toutSup : out std_logic;
8888
OPB_errAck : out std_logic;
8989

90-
-- IMAGE RAM
91-
iram_wdata : in std_logic_vector(C_PIXEL_BITS-1 downto 0);
92-
iram_wren : in std_logic;
93-
iram_fifo_afull : out std_logic;
90+
-- FDCT INPUT DATA
91+
fdct_ack : out std_logic;
92+
fdct_data : in std_logic_vector(C_PIXEL_BITS-1 downto 0);
93+
fdct_stb : in std_logic;
9494

9595
-- OUT RAM
9696
ram_byte : out std_logic_vector(7 downto 0);
@@ -224,31 +224,7 @@ begin
224224
img_size_wr => img_size_wr,
225225
sof => sof
226226
);
227-
228-
-------------------------------------------------------------------
229-
-- BUF_FIFO
230-
-------------------------------------------------------------------
231-
U_BUF_FIFO : entity work.BUF_FIFO
232-
port map
233-
(
234-
CLK => CLK,
235-
RST => RST,
236-
-- HOST PROG
237-
img_size_x => img_size_x,
238-
img_size_y => img_size_y,
239-
sof => sof,
240-
241-
-- HOST DATA
242-
iram_wren => iram_wren,
243-
iram_wdata => iram_wdata,
244-
fifo_almost_full => iram_fifo_afull,
245227

246-
-- FDCT
247-
fdct_fifo_rd => fdct_fifo_rd,
248-
fdct_fifo_q => fdct_fifo_q,
249-
fdct_fifo_hf_full => fdct_fifo_hf_full
250-
);
251-
252228
-------------------------------------------------------------------
253229
-- Controller
254230
-------------------------------------------------------------------
@@ -321,9 +297,9 @@ begin
321297
fdct_sm_settings => fdct_sm_settings,
322298

323299
-- BUF_FIFO
324-
bf_fifo_rd => fdct_fifo_rd,
325-
bf_fifo_q => fdct_fifo_q,
326-
bf_fifo_hf_full => fdct_fifo_hf_full,
300+
bf_fifo_rd => fdct_ack,
301+
bf_fifo_q => fdct_data,
302+
bf_fifo_hf_full => fdct_stb,
327303

328304
-- ZIG ZAG
329305
zz_buf_sel => zz_buf_sel,

‎gateware/streamer/__init__.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@ def __init__(self, ip_address, udp_port, fifo_depth=1024):
1515

1616
# # #
1717

18+
self.submodules.async_fifo = async_fifo = RenameClockDomains(AsyncFIFO([("data", 8)], 4),
19+
{"write": "encoder", "read": "sys"})
1820
self.submodules.fifo = fifo = SyncFIFO([("data", 8)], fifo_depth)
19-
self.comb += Record.connect(sink, fifo.sink)
21+
self.comb += [
22+
Record.connect(sink, async_fifo.sink),
23+
Record.connect(async_fifo.source, fifo.sink)
24+
]
2025

2126
level = Signal(max=fifo_depth + 1)
2227
level_update = Signal()
@@ -87,7 +92,7 @@ def __init__(self, platform, pads):
8792
]
8893

8994
self.submodules.fifo = fifo = RenameClockDomains(AsyncFIFO([("data", 8)], 4),
90-
{"write": "sys", "read": "usb"})
95+
{"write": "encoder", "read": "usb"})
9196
self.comb += Record.connect(sink, fifo.sink)
9297

9398

‎targets/atlys_base.py

+3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def __init__(self, platform, clk_freq):
2828
self.clock_domains.cd_sdram_full_wr = ClockDomain()
2929
self.clock_domains.cd_sdram_full_rd = ClockDomain()
3030
self.clock_domains.cd_base50 = ClockDomain()
31+
self.clock_domains.cd_encoder = ClockDomain()
3132

3233
self.clk4x_wr_strb = Signal()
3334
self.clk4x_rd_strb = Signal()
@@ -109,6 +110,8 @@ def __init__(self, platform, clk_freq):
109110
self.specials += AsyncResetSynchronizer(self.cd_base50, self.cd_sys.rst | ~dcm_base50_locked)
110111
platform.add_period_constraint(self.cd_base50.clk, 20)
111112

113+
self.comb += self.cd_encoder.clk.eq(self.cd_sys.clk)
114+
self.specials += AsyncResetSynchronizer(self.cd_encoder, self.cd_sys.rst)
112115

113116
class BaseSoC(SDRAMSoC):
114117
default_platform = "atlys"

‎targets/atlys_hdmi2eth.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@
99

1010
from gateware.hdmi_in import HDMIIn
1111
from gateware.hdmi_out import HDMIOut
12-
from gateware.encoder import EncoderReader, Encoder
12+
from gateware.encoder import Encoder
13+
from gateware.encoder.dma import EncoderDMAReader
14+
from gateware.encoder.buffer import EncoderBuffer
1315
from gateware.streamer import UDPStreamer
16+
from migen.actorlib.fifo import AsyncFIFO, SyncFIFO
17+
from migen.flow.actor import *
18+
1419

1520
class EtherboneSoC(BaseSoC):
1621
csr_peripherals = (
@@ -115,15 +120,23 @@ class HDMI2ETHSoC(VideomixerSoC):
115120
def __init__(self, platform, **kwargs):
116121
VideomixerSoC.__init__(self, platform, **kwargs)
117122

118-
self.submodules.encoder_reader = EncoderReader(self.sdram.crossbar.get_master())
123+
lasmim = self.sdram.crossbar.get_master()
124+
self.submodules.encoder_reader = EncoderDMAReader(lasmim)
125+
self.submodules.encoder_cdc = RenameClockDomains(AsyncFIFO([("data", 128)], 4),
126+
{"write": "sys", "read": "encoder"})
127+
self.submodules.encoder_buffer = RenameClockDomains(EncoderBuffer(), "encoder")
128+
self.submodules.encoder_fifo = RenameClockDomains(SyncFIFO(EndpointDescription([("data", 16)], packetized=True), 128), "encoder")
119129
self.submodules.encoder = Encoder(platform)
120130
encoder_port = self.ethcore.udp.crossbar.get_port(8000, 8)
121131
self.submodules.encoder_streamer = UDPStreamer(convert_ip("192.168.1.15"), 8000)
122132

123133
self.comb += [
124134
platform.request("user_led", 0).eq(self.encoder_reader.source.stb),
125135
platform.request("user_led", 1).eq(self.encoder_reader.source.ack),
126-
Record.connect(self.encoder_reader.source, self.encoder.sink),
136+
Record.connect(self.encoder_reader.source, self.encoder_cdc.sink),
137+
Record.connect(self.encoder_cdc.source, self.encoder_buffer.sink),
138+
Record.connect(self.encoder_buffer.source, self.encoder_fifo.sink),
139+
Record.connect(self.encoder_fifo.source, self.encoder.sink),
127140
Record.connect(self.encoder.source, self.encoder_streamer.sink),
128141
Record.connect(self.encoder_streamer.source, encoder_port.sink)
129142
]

‎targets/atlys_hdmi2usb.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
from targets.common import *
12
from targets.atlys_base import *
23
from targets.atlys_base import default_subtarget as BaseSoC
34

45
from gateware.hdmi_in import HDMIIn
56
from gateware.hdmi_out import HDMIOut
6-
from gateware.encoder import EncoderReader, Encoder
7+
from gateware.encoder import Encoder
8+
from gateware.encoder.dma import EncoderDMAReader
9+
from gateware.encoder.buffer import EncoderBuffer
710
from gateware.streamer import USBStreamer
11+
from migen.actorlib.fifo import AsyncFIFO, SyncFIFO
12+
from migen.flow.actor import *
813

914
class VideomixerSoC(BaseSoC):
1015
csr_peripherals = (
@@ -68,15 +73,23 @@ class HDMI2USBSoC(VideomixerSoC):
6873
def __init__(self, platform, **kwargs):
6974
VideomixerSoC.__init__(self, platform, **kwargs)
7075

71-
self.submodules.encoder_reader = EncoderReader(self.sdram.crossbar.get_master())
76+
lasmim = self.sdram.crossbar.get_master()
77+
self.submodules.encoder_reader = EncoderDMAReader(lasmim)
78+
self.submodules.encoder_cdc = RenameClockDomains(AsyncFIFO([("data", 128)], 4),
79+
{"write": "sys", "read": "encoder"})
80+
self.submodules.encoder_buffer = RenameClockDomains(EncoderBuffer(), "encoder")
81+
self.submodules.encoder_fifo = RenameClockDomains(SyncFIFO(EndpointDescription([("data", 16)], packetized=True), 128), "encoder")
7282
self.submodules.encoder = Encoder(platform)
73-
self.submodules.usb_streamer = USBStreamer(platform, platform.request("fx2"))
83+
self.submodules.encoder_streamer = USBStreamer(platform, platform.request("fx2"))
7484

7585
self.comb += [
7686
platform.request("user_led", 0).eq(self.encoder_reader.source.stb),
7787
platform.request("user_led", 1).eq(self.encoder_reader.source.ack),
78-
Record.connect(self.encoder_reader.source, self.encoder.sink),
79-
Record.connect(self.encoder.source, self.usb_streamer.sink)
88+
Record.connect(self.encoder_reader.source, self.encoder_cdc.sink),
89+
Record.connect(self.encoder_cdc.source, self.encoder_buffer.sink),
90+
Record.connect(self.encoder_buffer.source, self.encoder_fifo.sink),
91+
Record.connect(self.encoder_fifo.source, self.encoder.sink),
92+
Record.connect(self.encoder.source, self.encoder_streamer.sink)
8093
]
8194
self.add_wb_slave(mem_decoder(self.mem_map["encoder"]), self.encoder.bus)
8295
self.add_memory_region("encoder", self.mem_map["encoder"]+self.shadow_base, 0x2000)

‎targets/opsis_base.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def __init__(self, platform, clk_freq):
3232
self.clock_domains.cd_sdram_full_wr = ClockDomain()
3333
self.clock_domains.cd_sdram_full_rd = ClockDomain()
3434
self.clock_domains.cd_base50 = ClockDomain()
35+
self.clock_domains.cd_encoder = ClockDomain()
3536

3637
self.clk8x_wr_strb = Signal()
3738
self.clk8x_rd_strb = Signal()
@@ -66,7 +67,7 @@ def __init__(self, platform, clk_freq):
6667
o_CLKOUT4=pll[4], p_CLKOUT4_DUTY_CYCLE=.5,
6768
o_CLKOUT5=pll[5], p_CLKOUT5_DUTY_CYCLE=.5,
6869
p_CLKOUT0_PHASE=0., p_CLKOUT0_DIVIDE=p//8, # sdram wr rd
69-
p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=p//8,
70+
p_CLKOUT1_PHASE=0., p_CLKOUT1_DIVIDE=6,
7071
p_CLKOUT2_PHASE=230., p_CLKOUT2_DIVIDE=p//4, # sdram dqs adr ctrl
7172
p_CLKOUT3_PHASE=210., p_CLKOUT3_DIVIDE=p//4, # off-chip ddr
7273
p_CLKOUT4_PHASE=0., p_CLKOUT4_DIVIDE=p//2,
@@ -115,6 +116,9 @@ def __init__(self, platform, clk_freq):
115116
self.specials += AsyncResetSynchronizer(self.cd_base50, self.cd_sys.rst | ~dcm_base50_locked)
116117
platform.add_period_constraint(self.cd_base50.clk, 20)
117118

119+
self.specials += Instance("BUFG", i_I=pll[1], o_O=self.cd_encoder.clk) # 66 MHz
120+
self.specials += AsyncResetSynchronizer(self.cd_encoder, self.cd_sys.rst)
121+
118122

119123
class BaseSoC(SDRAMSoC):
120124
default_platform = "opsis"

‎targets/opsis_hdmi2usb.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
from gateware.hdmi_in import HDMIIn
66
from gateware.hdmi_out import HDMIOut
7-
from gateware.encoder import EncoderReader, Encoder
7+
from gateware.encoder import Encoder
8+
from gateware.encoder.dma import EncoderDMAReader
9+
from gateware.encoder.buffer import EncoderBuffer
810
from gateware.streamer import USBStreamer
11+
from migen.actorlib.fifo import AsyncFIFO, SyncFIFO
12+
from migen.flow.actor import *
913

1014
class VideomixerSoC(BaseSoC):
1115
csr_peripherals = (
@@ -69,12 +73,20 @@ class HDMI2USBSoC(VideomixerSoC):
6973
def __init__(self, platform, **kwargs):
7074
VideomixerSoC.__init__(self, platform, **kwargs)
7175

72-
self.submodules.encoder_reader = EncoderReader(self.sdram.crossbar.get_master())
76+
lasmim = self.sdram.crossbar.get_master()
77+
self.submodules.encoder_reader = EncoderDMAReader(lasmim)
78+
self.submodules.encoder_cdc = RenameClockDomains(AsyncFIFO([("data", 128)], 4),
79+
{"write": "sys", "read": "encoder"})
80+
self.submodules.encoder_buffer = RenameClockDomains(EncoderBuffer(), "encoder")
81+
self.submodules.encoder_fifo = RenameClockDomains(SyncFIFO(EndpointDescription([("data", 16)], packetized=True), 128), "encoder")
7382
self.submodules.encoder = Encoder(platform)
7483
self.submodules.usb_streamer = USBStreamer(platform, platform.request("fx2"))
7584

7685
self.comb += [
77-
Record.connect(self.encoder_reader.source, self.encoder.sink),
86+
Record.connect(self.encoder_reader.source, self.encoder_cdc.sink),
87+
Record.connect(self.encoder_cdc.source, self.encoder_buffer.sink),
88+
Record.connect(self.encoder_buffer.source, self.encoder_fifo.sink),
89+
Record.connect(self.encoder_fifo.source, self.encoder.sink),
7890
Record.connect(self.encoder.source, self.usb_streamer.sink)
7991
]
8092
self.add_wb_slave(mem_decoder(self.mem_map["encoder"]), self.encoder.bus)

0 commit comments

Comments
 (0)
Please sign in to comment.