From e6e04a2e3a8fd08a150ce5a2302f1ffa8a728465 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Tue, 17 Sep 2013 18:15:22 +0200 Subject: [PATCH] framebuffer: prepare for DVI out --- make.py | 4 +- milkymist/framebuffer/__init__.py | 60 +++------- milkymist/framebuffer/format.py | 111 ++++++++++++++++++ milkymist/framebuffer/lib.py | 166 --------------------------- milkymist/framebuffer/phy.py | 182 ++++++++++++++++++++++++++++++ milkymist/mxcrg/__init__.py | 56 +-------- software/videomixer/fb.c | 12 +- top.py | 3 +- verilog/mxcrg/mxcrg.v | 60 +--------- 9 files changed, 328 insertions(+), 326 deletions(-) create mode 100644 milkymist/framebuffer/format.py delete mode 100644 milkymist/framebuffer/lib.py create mode 100644 milkymist/framebuffer/phy.py diff --git a/make.py b/make.py index c5cce7eb..879b5b9f 100755 --- a/make.py +++ b/make.py @@ -21,11 +21,11 @@ PIN "mxcrg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE; if hasattr(soc, "fb"): platform.add_platform_command(""" -NET "vga_clk" TNM_NET = "GRPvga_clk"; +NET "{vga_clk}" TNM_NET = "GRPvga_clk"; NET "sys_clk" TNM_NET = "GRPsys_clk"; TIMESPEC "TSise_sucks1" = FROM "GRPvga_clk" TO "GRPsys_clk" TIG; TIMESPEC "TSise_sucks2" = FROM "GRPsys_clk" TO "GRPvga_clk" TIG; -""") +""", vga_clk=soc.fb.driver.clocking.cd_pix.clk) for d in ["mxcrg", "minimac3"]: platform.add_source_dir(os.path.join("verilog", d)) diff --git a/milkymist/framebuffer/__init__.py b/milkymist/framebuffer/__init__.py index 7911b32a..eb64208f 100644 --- a/milkymist/framebuffer/__init__.py +++ b/milkymist/framebuffer/__init__.py @@ -4,52 +4,35 @@ from migen.flow.network import * from migen.bank.description import CSRStorage, AutoCSR from migen.actorlib import dma_lasmi, structuring, sim, spi -from milkymist.framebuffer.lib import bpp, pixel_layout, dac_layout, FrameInitiator, VTG, FIFO +from milkymist.framebuffer.format import bpp, pixel_layout, FrameInitiator, VTG +from milkymist.framebuffer.phy import Driver -class Framebuffer(Module): - def __init__(self, pads, lasmim, simulation=False): +class Framebuffer(Module, AutoCSR): + def __init__(self, pads_vga, pads_dvi, lasmim, simulation=False): pack_factor = lasmim.dw//(2*bpp) packed_pixels = structuring.pack_layout(pixel_layout, pack_factor) - fi = FrameInitiator() - dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4) + self._enable = CSRStorage() + self.fi = FrameInitiator() + self.dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4) + self.driver = Driver(pads_vga, pads_dvi) + cast = structuring.Cast(lasmim.dw, packed_pixels, reverse_to=True) unpack = structuring.Unpack(pack_factor, pixel_layout) vtg = VTG() - if simulation: - fifo = sim.SimActor(sim_fifo_gen(), ("dac", Sink, dac_layout)) - else: - fifo = FIFO() g = DataFlowGraph() - g.add_connection(fi, vtg, sink_ep="timing") - g.add_connection(dma, cast) + g.add_connection(self.fi, vtg, sink_ep="timing") + g.add_connection(self.dma, cast) g.add_connection(cast, unpack) g.add_connection(unpack, vtg, sink_ep="pixels") - g.add_connection(vtg, fifo) + g.add_connection(vtg, self.driver) self.submodules += CompositeActor(g) - self._enable = CSRStorage() self.comb += [ - fi.trigger.eq(self._enable.storage), - dma.generator.trigger.eq(self._enable.storage), + self.fi.trigger.eq(self._enable.storage), + self.dma.generator.trigger.eq(self._enable.storage), ] - self._fi = fi - self._dma = dma - - # Drive pads - if not simulation: - self.comb += [ - pads.hsync_n.eq(fifo.vga_hsync_n), - pads.vsync_n.eq(fifo.vga_vsync_n), - pads.r.eq(fifo.vga_r), - pads.g.eq(fifo.vga_g), - pads.b.eq(fifo.vga_b) - ] - self.comb += pads.psave_n.eq(1) - - def get_csrs(self): - return [self._enable] + self._fi.get_csrs() + self._dma.get_csrs() class Blender(PipelinedActor, AutoCSR): def __init__(self, nimages, latency): @@ -97,13 +80,14 @@ class Blender(PipelinedActor, AutoCSR): self.comb += self.source.payload.eq(outval) class MixFramebuffer(Module, AutoCSR): - def __init__(self, pads, *lasmims, blender_latency=5): + def __init__(self, pads_vga, pads_dvi, *lasmims, blender_latency=5): pack_factor = lasmims[0].dw//(2*bpp) packed_pixels = structuring.pack_layout(pixel_layout, pack_factor) self._enable = CSRStorage() self.fi = FrameInitiator() self.blender = Blender(len(lasmims), blender_latency) + self.driver = Driver(pads_vga, pads_dvi) self.comb += self.fi.trigger.eq(self._enable.storage) g = DataFlowGraph() @@ -120,17 +104,7 @@ class MixFramebuffer(Module, AutoCSR): setattr(self, "dma"+str(n), dma) vtg = VTG() - fifo = FIFO() g.add_connection(self.fi, vtg, sink_ep="timing") g.add_connection(self.blender, vtg, sink_ep="pixels") - g.add_connection(vtg, fifo) + g.add_connection(vtg, self.driver) self.submodules += CompositeActor(g) - - self.comb += [ - pads.hsync_n.eq(fifo.vga_hsync_n), - pads.vsync_n.eq(fifo.vga_vsync_n), - pads.r.eq(fifo.vga_r), - pads.g.eq(fifo.vga_g), - pads.b.eq(fifo.vga_b), - pads.psave_n.eq(1) - ] diff --git a/milkymist/framebuffer/format.py b/milkymist/framebuffer/format.py new file mode 100644 index 00000000..96ac4543 --- /dev/null +++ b/milkymist/framebuffer/format.py @@ -0,0 +1,111 @@ +from migen.fhdl.std import * +from migen.flow.actor import * +from migen.bank.description import CSRStorage +from migen.actorlib import spi + +_hbits = 11 +_vbits = 12 + +bpp = 32 +bpc = 10 +pixel_layout_s = [ + ("pad", bpp-3*bpc), + ("r", bpc), + ("g", bpc), + ("b", bpc) +] +pixel_layout = [ + ("p0", pixel_layout_s), + ("p1", pixel_layout_s) +] + +bpc_phy = 8 +phy_layout_s = [ + ("r", bpc_phy), + ("g", bpc_phy), + ("b", bpc_phy) +] +phy_layout = [ + ("hsync", 1), + ("vsync", 1), + ("p0", phy_layout_s), + ("p1", phy_layout_s) +] + +class FrameInitiator(spi.SingleGenerator): + def __init__(self): + layout = [ + ("hres", _hbits, 640, 1), + ("hsync_start", _hbits, 656, 1), + ("hsync_end", _hbits, 752, 1), + ("hscan", _hbits, 800, 1), + + ("vres", _vbits, 480), + ("vsync_start", _vbits, 492), + ("vsync_end", _vbits, 494), + ("vscan", _vbits, 525) + ] + spi.SingleGenerator.__init__(self, layout, spi.MODE_EXTERNAL) + +class VTG(Module): + def __init__(self): + self.timing = Sink([ + ("hres", _hbits), + ("hsync_start", _hbits), + ("hsync_end", _hbits), + ("hscan", _hbits), + ("vres", _vbits), + ("vsync_start", _vbits), + ("vsync_end", _vbits), + ("vscan", _vbits)]) + self.pixels = Sink(pixel_layout) + self.phy = Source(phy_layout) + self.busy = Signal() + + hactive = Signal() + vactive = Signal() + active = Signal() + + generate_en = Signal() + hcounter = Signal(_hbits) + vcounter = Signal(_vbits) + + skip = bpc - bpc_phy + self.comb += [ + 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"]] + ), + + generate_en.eq(self.timing.stb & (~active | self.pixels.stb)), + self.pixels.ack.eq(self.phy.ack & active), + self.phy.stb.eq(generate_en), + self.busy.eq(generate_en) + ] + tp = self.timing.payload + self.sync += [ + self.timing.ack.eq(0), + If(generate_en & self.phy.ack, + hcounter.eq(hcounter + 1), + + If(hcounter == 0, hactive.eq(1)), + If(hcounter == tp.hres, hactive.eq(0)), + If(hcounter == tp.hsync_start, self.phy.payload.hsync.eq(1)), + If(hcounter == tp.hsync_end, self.phy.payload.hsync.eq(0)), + If(hcounter == tp.hscan, + hcounter.eq(0), + If(vcounter == tp.vscan, + vcounter.eq(0), + self.timing.ack.eq(1) + ).Else( + vcounter.eq(vcounter + 1) + ) + ), + + If(vcounter == 0, vactive.eq(1)), + If(vcounter == tp.vres, vactive.eq(0)), + If(vcounter == tp.vsync_start, self.phy.payload.vsync.eq(1)), + If(vcounter == tp.vsync_end, self.phy.payload.vsync.eq(0)) + ) + ] diff --git a/milkymist/framebuffer/lib.py b/milkymist/framebuffer/lib.py deleted file mode 100644 index 81bfa44b..00000000 --- a/milkymist/framebuffer/lib.py +++ /dev/null @@ -1,166 +0,0 @@ -from migen.fhdl.std import * -from migen.genlib.record import Record -from migen.genlib.fifo import AsyncFIFO -from migen.flow.actor import * -from migen.flow.network import * -from migen.flow.transactions import * -from migen.bank.description import CSRStorage -from migen.actorlib import spi - -_hbits = 11 -_vbits = 12 - -bpp = 32 -bpc = 10 -pixel_layout_s = [ - ("pad", bpp-3*bpc), - ("r", bpc), - ("g", bpc), - ("b", bpc) -] -pixel_layout = [ - ("p0", pixel_layout_s), - ("p1", pixel_layout_s) -] - -bpc_dac = 8 -dac_layout_s = [ - ("r", bpc_dac), - ("g", bpc_dac), - ("b", bpc_dac) -] -dac_layout = [ - ("hsync", 1), - ("vsync", 1), - ("p0", dac_layout_s), - ("p1", dac_layout_s) -] - -class FrameInitiator(spi.SingleGenerator): - def __init__(self): - layout = [ - ("hres", _hbits, 640, 1), - ("hsync_start", _hbits, 656, 1), - ("hsync_end", _hbits, 752, 1), - ("hscan", _hbits, 800, 1), - - ("vres", _vbits, 480), - ("vsync_start", _vbits, 492), - ("vsync_end", _vbits, 494), - ("vscan", _vbits, 525) - ] - spi.SingleGenerator.__init__(self, layout, spi.MODE_EXTERNAL) - -class VTG(Module): - def __init__(self): - self.timing = Sink([ - ("hres", _hbits), - ("hsync_start", _hbits), - ("hsync_end", _hbits), - ("hscan", _hbits), - ("vres", _vbits), - ("vsync_start", _vbits), - ("vsync_end", _vbits), - ("vscan", _vbits)]) - self.pixels = Sink(pixel_layout) - self.dac = Source(dac_layout) - self.busy = Signal() - - hactive = Signal() - vactive = Signal() - active = Signal() - - generate_en = Signal() - hcounter = Signal(_hbits) - vcounter = Signal(_vbits) - - skip = bpc - bpc_dac - self.comb += [ - active.eq(hactive & vactive), - If(active, - [getattr(getattr(self.dac.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:]) - for p in ["p0", "p1"] for c in ["r", "g", "b"]] - ), - - generate_en.eq(self.timing.stb & (~active | self.pixels.stb)), - self.pixels.ack.eq(self.dac.ack & active), - self.dac.stb.eq(generate_en), - self.busy.eq(generate_en) - ] - tp = self.timing.payload - self.sync += [ - self.timing.ack.eq(0), - If(generate_en & self.dac.ack, - hcounter.eq(hcounter + 1), - - If(hcounter == 0, hactive.eq(1)), - If(hcounter == tp.hres, hactive.eq(0)), - If(hcounter == tp.hsync_start, self.dac.payload.hsync.eq(1)), - If(hcounter == tp.hsync_end, self.dac.payload.hsync.eq(0)), - If(hcounter == tp.hscan, - hcounter.eq(0), - If(vcounter == tp.vscan, - vcounter.eq(0), - self.timing.ack.eq(1) - ).Else( - vcounter.eq(vcounter + 1) - ) - ), - - If(vcounter == 0, vactive.eq(1)), - If(vcounter == tp.vres, vactive.eq(0)), - If(vcounter == tp.vsync_start, self.dac.payload.vsync.eq(1)), - If(vcounter == tp.vsync_end, self.dac.payload.vsync.eq(0)) - ) - ] - -class FIFO(Module): - def __init__(self): - self.dac = Sink(dac_layout) - self.busy = Signal() - - self.vga_hsync_n = Signal() - self.vga_vsync_n = Signal() - self.vga_r = Signal(bpc_dac) - self.vga_g = Signal(bpc_dac) - self.vga_b = Signal(bpc_dac) - - ### - - data_width = 2+2*3*bpc_dac - fifo = RenameClockDomains(AsyncFIFO(data_width, 512), - {"write": "sys", "read": "vga"}) - self.submodules += fifo - fifo_in = self.dac.payload - fifo_out = Record(dac_layout) - self.comb += [ - self.dac.ack.eq(fifo.writable), - fifo.we.eq(self.dac.stb), - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout), - self.busy.eq(0) - ] - - pix_parity = Signal() - self.sync.vga += [ - pix_parity.eq(~pix_parity), - self.vga_hsync_n.eq(~fifo_out.hsync), - self.vga_vsync_n.eq(~fifo_out.vsync), - If(pix_parity, - self.vga_r.eq(fifo_out.p1.r), - self.vga_g.eq(fifo_out.p1.g), - self.vga_b.eq(fifo_out.p1.b) - ).Else( - self.vga_r.eq(fifo_out.p0.r), - self.vga_g.eq(fifo_out.p0.g), - self.vga_b.eq(fifo_out.p0.b) - ) - ] - self.comb += fifo.re.eq(pix_parity) - -def sim_fifo_gen(): - while True: - t = Token("dac") - yield t - print("H/V:" + str(t.value["hsync"]) + str(t.value["vsync"]) - + " " + str(t.value["r"]) + " " + str(t.value["g"]) + " " + str(t.value["b"])) diff --git a/milkymist/framebuffer/phy.py b/milkymist/framebuffer/phy.py new file mode 100644 index 00000000..c8a0699d --- /dev/null +++ b/milkymist/framebuffer/phy.py @@ -0,0 +1,182 @@ +from migen.fhdl.std import * +from migen.genlib.record import Record +from migen.genlib.fifo import AsyncFIFO +from migen.bank.description import * +from migen.flow.actor import * + +from milkymist.framebuffer.format import bpc_phy, phy_layout + +class _FIFO(Module): + def __init__(self): + self.phy = Sink(phy_layout) + self.busy = Signal() + + self.pix_hsync = Signal() + self.pix_vsync = 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), + {"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), + 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), + 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) + ).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.comb += fifo.re.eq(pix_parity) + +# This assumes a 50MHz base clock +class _Clocking(Module, AutoCSR): + def __init__(self, pads_vga, pads_dvi): + self._r_cmd_data = CSRStorage(10) + self._r_send_cmd_data = CSR() + self._r_send_go = CSR() + self._r_status = CSRStatus(4) + + self.clock_domains.cd_pix = ClockDomain(reset_less=True) + if pads_dvi is not None: + self.clock_domains.cd_pix2x = ClockDomain(reset_less=True) + self.clock_domains.cd_pix10x = ClockDomain(reset_less=True) + self.serdesstrobe = Signal() + + ### + + # Generate 1x pixel clock + clk_pix_unbuffered = Signal() + pix_progdata = Signal() + pix_progen = Signal() + pix_progdone = Signal() + pix_locked = Signal() + self.specials += Instance("DCM_CLKGEN", + p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=3.0, p_CLKFX_MULTIPLY=2, + p_CLKIN_PERIOD=20.0, p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE", + + i_CLKIN=ClockSignal("base50"), o_CLKFX=clk_pix_unbuffered, + i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen, + o_PROGDONE=pix_progdone, o_LOCKED=pix_locked, + i_FREEZEDCM=0, i_RST=ResetSignal()) + + remaining_bits = Signal(max=11) + transmitting = Signal() + self.comb += transmitting.eq(remaining_bits != 0) + sr = Signal(10) + self.sync += [ + If(self._r_send_cmd_data.re, + remaining_bits.eq(10), + sr.eq(self._r_cmd_data.storage) + ).Elif(transmitting, + remaining_bits.eq(remaining_bits - 1), + sr.eq(sr[1:]) + ) + ] + self.comb += [ + pix_progdata.eq(transmitting & sr[0]), + pix_progen.eq(transmitting | self._r_send_go.re) + ] + + # enforce gap between commands + busy_counter = Signal(max=14) + busy = Signal() + self.comb += busy.eq(busy_counter != 0) + self.sync += If(self._r_send_cmd_data.re, + busy_counter.eq(13) + ).Elif(busy, + busy_counter.eq(busy_counter - 1) + ) + + mult_locked = Signal() + self.comb += self._r_status.status.eq(Cat(busy, pix_progdone, pix_locked, mult_locked)) + + # Clock multiplication and buffering + if pads_dvi is None: + # Just buffer 1x pixel clock + self.specials += Instance("BUFG", i_I=clk_pix_unbuffered, o_O=self.cd_pix.clk) + self.comb += mult_locked.eq(pix_locked) + else: + # Route unbuffered 1x pixel clock to PLL + # Generate 1x, 2x and 10x IO pixel clocks + clkfbout = Signal() + pll_locked = Signal() + pll_clk0 = Signal() + pll_clk1 = Signal() + pll_clk2 = Signal() + locked_async = Signal() + self.specials += [ + Instance("PLL_BASE", + p_CLKIN_PERIOD=26.7, + p_CLKFBOUT_MULT=20, + p_CLKOUT0_DIVIDE=2, # pix10x + p_CLKOUT1_DIVIDE=10, # pix2x + p_CLKOUT2_DIVIDE=20, # pix + p_COMPENSATION="INTERNAL", + + i_CLKIN=clk_pix_unbuffered, + o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2, + o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout, + o_LOCKED=pll_locked, i_RST=~pix_locked), + 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", i_I=pll_clk2, o_O=self.cd_pix.clk), + MultiReg(locked_async, mult_locked, "sys") + ] + + # Drive VGA/DVI clock pads + pix_clk_io = Signal() + self.specials += Instance("ODDR2", + p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC", + o_Q=pix_clk_io, + i_C0=ClockSignal("pix"), + i_C1=~ClockSignal("pix"), + i_CE=1, i_D0=1, i_D1=0, + i_R=0, i_S=0) + if pads_vga is not None: + self.comb += pads_vga.clk.eq(pix_clk_io) + if pads_dvi is not None: + self.specials += Instance("OBUFDS", i_I=pix_clk_io, + o_O=pads.clk_p, o_OB=pads.clk_n) + +class Driver(Module, AutoCSR): + def __init__(self, pads_vga, pads_dvi): + fifo = _FIFO() + self.submodules += fifo + self.phy = fifo.phy + self.busy = fifo.busy + + self.submodules.clocking = _Clocking(pads_vga, pads_dvi) + + if pads_vga is not None: + self.comb += [ + pads_vga.hsync_n.eq(~fifo.pix_hsync), + pads_vga.vsync_n.eq(~fifo.pix_vsync), + pads_vga.r.eq(fifo.pix_r), + pads_vga.g.eq(fifo.pix_g), + pads_vga.b.eq(fifo.pix_b), + pads_vga.psave_n.eq(1) + ] diff --git a/milkymist/mxcrg/__init__.py b/milkymist/mxcrg/__init__.py index c487f07a..ab110018 100644 --- a/milkymist/mxcrg/__init__.py +++ b/milkymist/mxcrg/__init__.py @@ -1,9 +1,8 @@ from fractions import Fraction from migen.fhdl.std import * -from migen.bank.description import * -class MXCRG(Module, AutoCSR): +class MXCRG(Module): def __init__(self, pads, outfreq1x): self.clock_domains.cd_sys = ClockDomain() self.clock_domains.cd_sdram_half = ClockDomain() @@ -11,27 +10,17 @@ class MXCRG(Module, AutoCSR): self.clock_domains.cd_sdram_full_rd = ClockDomain() self.clock_domains.cd_eth_rx = ClockDomain() self.clock_domains.cd_eth_tx = ClockDomain() - self.clock_domains.cd_vga = ClockDomain(reset_less=True) + self.clock_domains.cd_base50 = ClockDomain(reset_less=True) self.clk4x_wr_strb = Signal() self.clk4x_rd_strb = Signal() - self._r_cmd_data = CSRStorage(10) - self._r_send_cmd_data = CSR() - self._r_send_go = CSR() - self._r_status = CSRStatus(3) - ### infreq = 50*1000000 ratio = Fraction(outfreq1x)/Fraction(infreq) in_period = float(Fraction(1000000000)/Fraction(infreq)) - vga_progdata = Signal() - vga_progen = Signal() - vga_progdone = Signal() - vga_locked = Signal() - self.specials += Instance("mxcrg", Instance.Parameter("in_period", in_period), Instance.Parameter("f_mult", ratio.numerator), @@ -49,48 +38,11 @@ class MXCRG(Module, AutoCSR): Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk), Instance.Output("eth_rx_clk", self.cd_eth_rx.clk), Instance.Output("eth_tx_clk", self.cd_eth_tx.clk), - Instance.Output("vga_clk", self.cd_vga.clk), + Instance.Output("base50_clk", self.cd_base50.clk), Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb), Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb), Instance.Output("norflash_rst_n", pads.norflash_rst_n), Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p), Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n), - Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk), - Instance.Output("vga_clk_pad", pads.vga_clk), - - Instance.Input("vga_progclk", ClockSignal()), - Instance.Input("vga_progdata", vga_progdata), - Instance.Input("vga_progen", vga_progen), - Instance.Output("vga_progdone", vga_progdone), - Instance.Output("vga_locked", vga_locked)) - - remaining_bits = Signal(max=11) - transmitting = Signal() - self.comb += transmitting.eq(remaining_bits != 0) - sr = Signal(10) - self.sync += [ - If(self._r_send_cmd_data.re, - remaining_bits.eq(10), - sr.eq(self._r_cmd_data.storage) - ).Elif(transmitting, - remaining_bits.eq(remaining_bits - 1), - sr.eq(sr[1:]) - ) - ] - self.comb += [ - vga_progdata.eq(transmitting & sr[0]), - vga_progen.eq(transmitting | self._r_send_go.re) - ] - - # enforce gap between commands - busy_counter = Signal(max=14) - busy = Signal() - self.comb += busy.eq(busy_counter != 0) - self.sync += If(self._r_send_cmd_data.re, - busy_counter.eq(13) - ).Elif(busy, - busy_counter.eq(busy_counter - 1) - ) - - self.comb += self._r_status.status.eq(Cat(busy, vga_progdone, vga_locked)) + Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk)) diff --git a/software/videomixer/fb.c b/software/videomixer/fb.c index 58b90bca..094cc1f8 100644 --- a/software/videomixer/fb.c +++ b/software/videomixer/fb.c @@ -13,9 +13,9 @@ static void fb_clkgen_write(int cmd, int data) int word; word = (data << 2) | cmd; - crg_cmd_data_write(word); - crg_send_cmd_data_write(1); - while(crg_status_read() & CLKGEN_STATUS_BUSY); + fb_driver_clocking_cmd_data_write(word); + fb_driver_clocking_send_cmd_data_write(1); + while(fb_driver_clocking_status_read() & CLKGEN_STATUS_BUSY); } void fb_set_mode(int mode) @@ -86,12 +86,12 @@ void fb_set_mode(int mode) fb_clkgen_write(0x1, clock_d-1); fb_clkgen_write(0x3, clock_m-1); - crg_send_go_write(1); + fb_driver_clocking_send_go_write(1); printf("waiting for PROGDONE..."); - while(!(crg_status_read() & CLKGEN_STATUS_PROGDONE)); + while(!(fb_driver_clocking_status_read() & CLKGEN_STATUS_PROGDONE)); printf("ok\n"); printf("waiting for LOCKED..."); - while(!(crg_status_read() & CLKGEN_STATUS_LOCKED)); + while(!(fb_driver_clocking_status_read() & CLKGEN_STATUS_LOCKED)); printf("ok\n"); printf("VGA: mode set to %dx%d\n", fb_hres, fb_vres); diff --git a/top.py b/top.py index 03e0b19a..60f6b33c 100644 --- a/top.py +++ b/top.py @@ -51,7 +51,6 @@ class MXClockPads: except ConstraintError: pass self.norflash_rst_n = platform.request("norflash_rst_n") - self.vga_clk = platform.request("vga_clock") ddram_clock = platform.request("ddram_clock") self.ddr_clk_p = ddram_clock.p self.ddr_clk_n = ddram_clock.n @@ -162,7 +161,7 @@ class SoC(Module): 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"), lasmim_fb0, lasmim_fb1) + self.submodules.fb = framebuffer.MixFramebuffer(platform.request("vga_out"), None, 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": diff --git a/verilog/mxcrg/mxcrg.v b/verilog/mxcrg/mxcrg.v index a7dee56a..63052eef 100644 --- a/verilog/mxcrg/mxcrg.v +++ b/verilog/mxcrg/mxcrg.v @@ -31,16 +31,8 @@ module mxcrg #( output eth_rx_clk, output eth_tx_clk, - /* VGA clock */ - output vga_clk, /* < buffered, to internal clock network */ - output vga_clk_pad, /* < forwarded through ODDR2, to I/O */ - - /* VGA clock control */ - input vga_progclk, - input vga_progdata, - input vga_progen, - output vga_progdone, - output vga_locked + /* Base clock, buffered */ + output base50_clk ); /* @@ -213,10 +205,10 @@ BUFG bufg_x1( .O(sys_clk) ); -wire clk50g; +wire base50_clk; BUFG bufg_50( .I(pllout4), - .O(clk50g) + .O(base50_clk) ); wire clk2x_off; @@ -263,53 +255,11 @@ ODDR2 #( * Ethernet PHY */ -always @(posedge clk50g) +always @(posedge base50_clk) eth_phy_clk_pad <= ~eth_phy_clk_pad; /* Let the synthesizer insert the appropriate buffers */ assign eth_rx_clk = eth_rx_clk_pad; assign eth_tx_clk = eth_tx_clk_pad; - -/* - * VGA clock - */ - -DCM_CLKGEN #( - .CLKFXDV_DIVIDE(2), - .CLKFX_DIVIDE(4), - .CLKFX_MD_MAX(3.0), - .CLKFX_MULTIPLY(2), - .CLKIN_PERIOD(20.0), - .SPREAD_SPECTRUM("NONE"), - .STARTUP_WAIT("FALSE") -) vga_clock_gen ( - .CLKFX(vga_clk), - .CLKFX180(), - .CLKFXDV(), - .STATUS(), - .CLKIN(clk50g), - .FREEZEDCM(1'b0), - .PROGCLK(vga_progclk), - .PROGDATA(vga_progdata), - .PROGEN(vga_progen), - .PROGDONE(vga_progdone), - .LOCKED(vga_locked), - .RST(~pll_lckd | sys_rst) -); - -ODDR2 #( - .DDR_ALIGNMENT("NONE"), - .INIT(1'b0), - .SRTYPE("SYNC") -) vga_clock_forward ( - .Q(vga_clk_pad), - .C0(vga_clk), - .C1(~vga_clk), - .CE(1'b1), - .D0(1'b1), - .D1(1'b0), - .R(1'b0), - .S(1'b0) -); endmodule -- 2.30.2