From ea0503173da85f0930eded372a155ddca8ac75e4 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Wed, 18 Sep 2013 16:56:07 +0200 Subject: [PATCH] add DVI output --- make.py | 1 + milkymist/framebuffer/dvi.py | 70 +++++++++++++++++++++++++++++++++ milkymist/framebuffer/format.py | 4 +- milkymist/framebuffer/phy.py | 42 ++++++++++++-------- top.py | 5 ++- 5 files changed, 102 insertions(+), 20 deletions(-) diff --git a/make.py b/make.py index 879b5b9f0..f62dd0e93 100755 --- a/make.py +++ b/make.py @@ -17,6 +17,7 @@ def build(platform_name, build_bitstream, build_header, *soc_args, **soc_kwargs) INST "mxcrg/rd_bufpll" LOC = "BUFPLL_X0Y3"; PIN "mxcrg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE; +PIN "pix2x_bufg.O" CLOCK_DEDICATED_ROUTE = FALSE; """) if hasattr(soc, "fb"): diff --git a/milkymist/framebuffer/dvi.py b/milkymist/framebuffer/dvi.py index 953ac2806..5475857be 100644 --- a/milkymist/framebuffer/dvi.py +++ b/milkymist/framebuffer/dvi.py @@ -83,6 +83,76 @@ def __init__(self): cnt.eq(0) ) +class _EncoderSerializer(Module): + def __init__(self, serdesstrobe, pad_p, pad_n): + self.submodules.encoder = RenameClockDomains(Encoder(), "pix") + self.d, self.c, self.de = self.encoder.d, self.encoder.c, self.encoder.de + + ### + + # 2X soft serialization + ed_2x = Signal(5) + self.sync.pix2x += ed_2x.eq(Mux(ClockSignal("pix"), self.encoder.out[:5], self.encoder.out[5:])) + + # 5X hard serialization + cascade_di = Signal() + cascade_do = Signal() + cascade_ti = Signal() + cascade_to = Signal() + pad_se = Signal() + self.specials += [ + Instance("OSERDES2", + p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", + p_SERDES_MODE="MASTER", p_OUTPUT_MODE="DIFFERENTIAL", + + o_OQ=pad_se, + i_OCE=1, i_IOCE=serdesstrobe, i_RST=0, + i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"), + i_D1=ed_2x[4], i_D2=0, i_D3=0, i_D4=0, + i_T1=0, i_T2=0, i_T3=0, i_T4=0, + i_TRAIN=0, i_TCE=1, + i_SHIFTIN1=1, i_SHIFTIN2=1, + i_SHIFTIN3=cascade_do, i_SHIFTIN4=cascade_to, + o_SHIFTOUT1=cascade_di, o_SHIFTOUT2=cascade_ti), + Instance("OSERDES2", + p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR", + p_SERDES_MODE="SLAVE", p_OUTPUT_MODE="DIFFERENTIAL", + + i_OCE=1, i_IOCE=serdesstrobe, i_RST=0, + i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"), + i_D1=ed_2x[0], i_D2=ed_2x[1], i_D3=ed_2x[2], i_D4=ed_2x[3], + i_T1=0, i_T2=0, i_T3=0, i_T4=0, + i_TRAIN=0, i_TCE=1, + i_SHIFTIN1=cascade_di, i_SHIFTIN2=cascade_ti, + i_SHIFTIN3=1, i_SHIFTIN4=1, + o_SHIFTOUT3=cascade_do, o_SHIFTOUT4=cascade_to), + Instance("OBUFDS", i_I=pad_se, o_O=pad_p, o_OB=pad_n) + ] + + +class PHY(Module): + def __init__(self, serdesstrobe, pads): + self.hsync = Signal() + self.vsync = Signal() + self.de = Signal() + self.r = Signal(8) + self.g = Signal(8) + self.b = Signal(8) + + ### + + self.submodules.es0 = _EncoderSerializer(serdesstrobe, pads.data0_p, pads.data0_n) + self.submodules.es1 = _EncoderSerializer(serdesstrobe, pads.data1_p, pads.data1_n) + self.submodules.es2 = _EncoderSerializer(serdesstrobe, pads.data2_p, pads.data2_n) + self.comb += [ + self.es0.c.eq(Cat(self.hsync, self.vsync)), + self.es1.c.eq(0), + self.es2.c.eq(0), + self.es0.de.eq(self.de), + self.es1.de.eq(self.de), + self.es2.de.eq(self.de), + ] + class _EncoderTB(Module): def __init__(self, inputs): self.outs = [] diff --git a/milkymist/framebuffer/format.py b/milkymist/framebuffer/format.py index 96ac45432..7e4224533 100644 --- a/milkymist/framebuffer/format.py +++ b/milkymist/framebuffer/format.py @@ -28,6 +28,7 @@ phy_layout = [ ("hsync", 1), ("vsync", 1), + ("de", 1), ("p0", phy_layout_s), ("p1", phy_layout_s) ] @@ -75,7 +76,8 @@ def __init__(self): active.eq(hactive & vactive), If(active, [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:]) - for p in ["p0", "p1"] for c in ["r", "g", "b"]] + for p in ["p0", "p1"] for c in ["r", "g", "b"]], + self.phy.payload.de.eq(1) ), generate_en.eq(self.timing.stb & (~active | self.pixels.stb)), diff --git a/milkymist/framebuffer/phy.py b/milkymist/framebuffer/phy.py index 2515a918f..90de7b0a9 100644 --- a/milkymist/framebuffer/phy.py +++ b/milkymist/framebuffer/phy.py @@ -1,11 +1,11 @@ from migen.fhdl.std import * -from migen.genlib.record import Record from migen.genlib.fifo import AsyncFIFO from migen.genlib.cdc import MultiReg from migen.bank.description import * from migen.flow.actor import * from milkymist.framebuffer.format import bpc_phy, phy_layout +from milkymist.framebuffer import dvi class _FIFO(Module): def __init__(self): @@ -14,39 +14,37 @@ def __init__(self): self.pix_hsync = Signal() self.pix_vsync = Signal() + self.pix_de = Signal() self.pix_r = Signal(bpc_phy) self.pix_g = Signal(bpc_phy) self.pix_b = Signal(bpc_phy) ### - data_width = 2+2*3*bpc_phy - fifo = RenameClockDomains(AsyncFIFO(data_width, 512), + fifo = RenameClockDomains(AsyncFIFO(phy_layout, 512), {"write": "sys", "read": "pix"}) self.submodules += fifo - fifo_in = self.phy.payload - fifo_out = Record(phy_layout) self.comb += [ self.phy.ack.eq(fifo.writable), fifo.we.eq(self.phy.stb), - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout), + fifo.din.eq(self.phy.payload), self.busy.eq(0) ] pix_parity = Signal() self.sync.pix += [ pix_parity.eq(~pix_parity), - self.pix_hsync.eq(fifo_out.hsync), - self.pix_vsync.eq(fifo_out.vsync), + self.pix_hsync.eq(fifo.dout.hsync), + self.pix_vsync.eq(fifo.dout.vsync), + self.pix_de.eq(fifo.dout.de), If(pix_parity, - self.pix_r.eq(fifo_out.p1.r), - self.pix_g.eq(fifo_out.p1.g), - self.pix_b.eq(fifo_out.p1.b) + self.pix_r.eq(fifo.dout.p1.r), + self.pix_g.eq(fifo.dout.p1.g), + self.pix_b.eq(fifo.dout.p1.b) ).Else( - self.pix_r.eq(fifo_out.p0.r), - self.pix_g.eq(fifo_out.p0.g), - self.pix_b.eq(fifo_out.p0.b) + self.pix_r.eq(fifo.dout.p0.r), + self.pix_g.eq(fifo.dout.p0.g), + self.pix_b.eq(fifo.dout.p0.b) ) ] self.comb += fifo.re.eq(pix_parity) @@ -143,7 +141,7 @@ def __init__(self, pads_vga, pads_dvi): Instance("BUFPLL", p_DIVIDE=5, i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked, o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe), - Instance("BUFG", i_I=pll_clk1, o_O=self.cd_pix2x.clk), + Instance("BUFG", name="pix2x_bufg", i_I=pll_clk1, o_O=self.cd_pix2x.clk), Instance("BUFG", i_I=pll_clk2, o_O=self.cd_pix.clk), MultiReg(locked_async, mult_locked, "sys") ] @@ -166,7 +164,7 @@ def __init__(self, pads_vga, pads_dvi): i_C1=~ClockSignal("pix"), i_CE=1, i_D0=1, i_D1=0, i_R=0, i_S=0) - self.specials += Instance("OBUFTDS", i_I=dvi_clk_se, + self.specials += Instance("OBUFDS", i_I=dvi_clk_se, o_O=pads_dvi.clk_p, o_OB=pads_dvi.clk_n) class Driver(Module, AutoCSR): @@ -187,3 +185,13 @@ def __init__(self, pads_vga, pads_dvi): pads_vga.b.eq(fifo.pix_b), pads_vga.psave_n.eq(1) ] + if pads_dvi is not None: + self.submodules.dvi_phy = dvi.PHY(self.clocking.serdesstrobe, pads_dvi) + self.comb += [ + self.dvi_phy.hsync.eq(fifo.pix_hsync), + self.dvi_phy.vsync.eq(fifo.pix_vsync), + self.dvi_phy.de.eq(fifo.pix_de), + self.dvi_phy.r.eq(fifo.pix_r), + self.dvi_phy.g.eq(fifo.pix_g), + self.dvi_phy.b.eq(fifo.pix_b) + ] diff --git a/top.py b/top.py index 60f6b33c8..69181e5fb 100644 --- a/top.py +++ b/top.py @@ -161,13 +161,14 @@ def __init__(self, platform, platform_name, with_memtest): self.submodules.timer0 = timer.Timer() if platform_name == "mixxeo": self.submodules.leds = gpio.GPIOOut(platform.request("user_led")) - self.submodules.fb = framebuffer.MixFramebuffer(platform.request("vga_out"), None, lasmim_fb0, lasmim_fb1) + self.submodules.fb = framebuffer.MixFramebuffer(platform.request("vga_out"), platform.request("dvi_out"), + lasmim_fb0, lasmim_fb1) self.submodules.dvisampler0 = dvisampler.DVISampler(platform.request("dvi_in", 0), lasmim_dvi0) self.submodules.dvisampler1 = dvisampler.DVISampler(platform.request("dvi_in", 1), lasmim_dvi1) if platform_name == "m1": self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2))) self.submodules.leds = gpio.GPIOOut(Cat(*[platform.request("user_led", i) for i in range(2)])) - self.submodules.fb = framebuffer.Framebuffer(platform.request("vga"), lasmim_fb) + self.submodules.fb = framebuffer.Framebuffer(platform.request("vga"), None, lasmim_fb) if with_memtest: self.submodules.memtest_w = memtest.MemtestWriter(lasmim_mtw) self.submodules.memtest_r = memtest.MemtestReader(lasmim_mtr)