From 4baf007f31c29bb53d09a43031ed74c0ba5ad6d8 Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Sat, 17 Feb 2024 08:38:17 +0100 Subject: [PATCH] 'alt' hdmi from framebuffer, ROM config from gateware, settable pixel clock for non-alt hdmi --- nubus-to-ztex-gateware/VintageBusFPGA_Common | 2 +- nubus-to-ztex-gateware/do_V1.2 | 4 ++ nubus-to-ztex-gateware/mdio.py | 37 ++++++++------- nubus-to-ztex-gateware/nubus_to_fpga_soc.py | 50 ++++++++++++++++---- 4 files changed, 66 insertions(+), 27 deletions(-) diff --git a/nubus-to-ztex-gateware/VintageBusFPGA_Common b/nubus-to-ztex-gateware/VintageBusFPGA_Common index 06c4327..76527c0 160000 --- a/nubus-to-ztex-gateware/VintageBusFPGA_Common +++ b/nubus-to-ztex-gateware/VintageBusFPGA_Common @@ -1 +1 @@ -Subproject commit 06c4327335c34b0adaac18f9a3dc9c1badc19953 +Subproject commit 76527c00d957379c1111d6899516f1f90ef2f63b diff --git a/nubus-to-ztex-gateware/do_V1.2 b/nubus-to-ztex-gateware/do_V1.2 index 50b77a8..c9109c7 100644 --- a/nubus-to-ztex-gateware/do_V1.2 +++ b/nubus-to-ztex-gateware/do_V1.2 @@ -4,8 +4,12 @@ source /opt/Xilinx/Vivado/2023.2/settings64.sh export LD_LIBRARY_PATH=/opt/Xilinx/Vivado/2023.2/lib/lnx64.o/SuSE +# python3 nubus_to_fpga_soc.py --build --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6 --goblin --goblin-res 1920x1080@60Hz --goblin-alt --hdmi --config-flash # --ethernet # --sdcard # --flash + python3 nubus_to_fpga_soc.py --build --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6 --goblin --goblin-res 1920x1080@60Hz --hdmi --config-flash # --ethernet # --sdcard # --flash +#python3 nubus_to_fpga_soc.py --build --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6 --goblin --goblin-res 1280x1024@60Hz --hdmi --config-flash # --ethernet # --sdcard # --flash + #python3 nubus_to_fpga_soc.py --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6 ) 2>&1 | tee build_V1_2.log diff --git a/nubus-to-ztex-gateware/mdio.py b/nubus-to-ztex-gateware/mdio.py index 26a70a6..8102215 100644 --- a/nubus-to-ztex-gateware/mdio.py +++ b/nubus-to-ztex-gateware/mdio.py @@ -11,6 +11,8 @@ class MDIOCtrl(Module, AutoCSR): div_clk_begin = 39 div_clk_half = 20 + + div_clk_state_change = 2 sig_mdc = platform.request("sep_mdc"); sig_mdio = platform.request("sep_mdio"); @@ -100,7 +102,7 @@ class MDIOCtrl(Module, AutoCSR): in_preamble.eq(0), mdio_oe.eq(0), # don't drive #mdio_oe.eq(1), # drive 0 at idle ? - If(cmd_recv & (clk_div == 2), # CHECKME + If(cmd_recv & (clk_div == div_clk_state_change), # CHECKME NextValue(cmd_recv, 0), NextValue(write, mdio_command.fields.write), @@ -125,7 +127,7 @@ class MDIOCtrl(Module, AutoCSR): mdio_fsm.act("Preamble", in_preamble.eq(1), mdio_oe.eq(1), - If(clk_div == 2, # CHECKME + If(clk_div == div_clk_state_change, # CHECKME If(int_cnt == 0, NextValue(int_cnt, 31), in_preamble.eq(0), # switch mdio_o to MSb of output_data @@ -144,12 +146,12 @@ class MDIOCtrl(Module, AutoCSR): mdio_fsm.act("WData", in_preamble.eq(0), mdio_oe.eq(1), - If(clk_div == 2, + If(clk_div == div_clk_state_change, shift_od.eq(1), # so during clk_div == 1, output will move to the next bit NextValue(int_cnt, int_cnt - 1), If(int_cnt == 0, mdio_o.eq(1), # help pull-ups - mdio_oe.eq(0), # stop driving + # mdio_oe.eq(0), # stop driving NextValue(output_data, 0), # make sure it's zero NextState("Idle"), ## fixme: delay to idle by one MDC clok cycle? ) @@ -159,11 +161,11 @@ class MDIOCtrl(Module, AutoCSR): mdio_fsm.act("RData", in_preamble.eq(0), mdio_oe.eq(1), - If(clk_div == 2, - shift_od.eq(1), # so during clk_div == 2, output will move to the next bit + If(clk_div == div_clk_state_change, + shift_od.eq(1), # so during clk_div == div_clk_state_change, output will move to the next bit NextValue(int_cnt, int_cnt - 1), If(int_cnt == 18, - #mdio_o.eq(1), # help pull-ups + mdio_o.eq(1), # help pull-ups #mdio_oe.eq(0), # stop driving during TA NextState("TA"), ) @@ -172,7 +174,8 @@ class MDIOCtrl(Module, AutoCSR): mdio_fsm.act("TA", mdio_oe.eq(0), - If(clk_div == 2, + If(clk_div == div_clk_state_change, + # mdio_oe.eq(0), # stop driving NextValue(rdata[15], mdio_i), # DEBUG, will capture on 17 and 16, will be flushed by shifting shift_rd.eq(1), # DEBUG, shift in 2 cycles to make room NextValue(int_cnt, int_cnt - 1), @@ -185,10 +188,12 @@ class MDIOCtrl(Module, AutoCSR): mdio_fsm.act("Capture", mdio_oe.eq(0), - If(clk_div == 2, + If(clk_div == div_clk_state_change, NextValue(rdata[15], mdio_i), NextValue(int_cnt, int_cnt - 1), If(int_cnt == 0, + mdio_oe.eq(0), + mdio_o.eq(1), # help pull-ups NextState("Idle"), ).Else( shift_rd.eq(1), # shift in 2 cycles to make room @@ -196,10 +201,10 @@ class MDIOCtrl(Module, AutoCSR): ), ) - led0 = platform.request("user_led", 0) - led1 = platform.request("user_led", 1) - - self.comb += [ - led0.eq(~mdio_fsm.ongoing("Idle")), - #led1.eq(clk_div != 0), - ] + #led0 = platform.request("user_led", 0) + #led1 = platform.request("user_led", 1) + # + #self.comb += [ + # led0.eq(~mdio_fsm.ongoing("Idle")), + # #led1.eq(clk_div != 0), + #] diff --git a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py index c6dfd78..44fea24 100644 --- a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py +++ b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py @@ -37,7 +37,7 @@ from nubus_memfifo_wb import NuBus2WishboneFIFO from nubus_cpu_wb import Wishbone2NuBus # CRG ---------------------------------------------------------------------------------------------- -class _CRG(Module): +class _CRG(Module, AutoCSR): # AutoCSR for DRP def __init__(self, platform, version, sys_clk_freq, goblin=False, hdmi=False, @@ -101,7 +101,7 @@ class _CRG(Module): assert(false) self.cd_nubus90.clk = clk2x_nubus self.comb += self.cd_nubus90.rst.eq(~rst_nubus_n) - platform.add_platform_command("create_clock -name nubus90_clk -period 50.0 -waveform {{0.0 37.5}} [get_ports clk2x_3v3_n]") + platform.add_platform_command("create_clock -name nubus90_clk -period 50.0 -waveform {{0.0 25}} [get_ports clk2x_3v3_n]") num_adv = 0 num_clk = 0 @@ -119,7 +119,7 @@ class _CRG(Module): platform.add_platform_command("create_generated_clock -name sys4x90clk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk)) num_clk = num_clk + 1 if (ethernet): - pll.create_clkout(self.cd_eth, 50e6, phase=90) # fixme: what if sys_clk_feq != 100e6? + pll.create_clkout(self.cd_eth, 50e6, phase=90) # fixme: what if sys_clk_feq != 100e6? # why phase ??? platform.add_platform_command("create_generated_clock -name ethclk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk)) num_clk = num_clk + 1 @@ -166,6 +166,8 @@ class _CRG(Module): num_clk = num_clk + 1 platform.add_platform_command("create_generated_clock -name hdmi5x_clk [get_pins {{{{MMCME2_ADV_{}/CLKOUT{}}}}}]".format(num_adv, num_clk)) num_clk = num_clk + 1 + video_pll.expose_drp() + self.comb += video_pll.reset.eq(~rst_nubus_n) #platform.add_false_path_constraints(self.cd_sys.clk, self.cd_vga.clk) @@ -176,7 +178,7 @@ class _CRG(Module): class NuBusFPGA(MacPeriphSoC): - def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, sdcard, flash, config_flash, ethernet, **kwargs): + def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, use_goblin_alt, sdcard, flash, config_flash, ethernet, **kwargs): print(f"Building NuBusFPGA for board version {version}") self.platform = platform = ztex213_nubus.Platform(variant = variant, version = version) @@ -186,8 +188,6 @@ class NuBusFPGA(MacPeriphSoC): if (ethernet and (version == "V1.2")): platform.add_extension(ztex213_nubus._rmii_eth_extpmod_io_v1_2) - - use_goblin_alt = True MacPeriphSoC.__init__(self, platform=platform, @@ -380,7 +380,7 @@ class NuBusFPGA(MacPeriphSoC): if (goblin): MacPeriphSoC.mac_add_goblin(self, use_goblin_alt = use_goblin_alt, hdmi = hdmi, goblin_res = goblin_res, goblin_irq = fb_irq, audio_irq = audio_irq) - if (sdcard): + if (sdcard): ### WIP WIP WIP WIP self.add_sdcard() # irq? @@ -388,14 +388,13 @@ class NuBusFPGA(MacPeriphSoC): # we need the CRG to provide the cd_eth clock: "use refclk_cd as RMII reference clock (provided by user design) (no external clock). self.ethphy = LiteEthPHYRMII( clock_pads = self.platform.request("eth_clocks"), + #clock_pads = None, pads = self.platform.request("eth")) self.add_ethernet(phy=self.ethphy, data_width = 32) print(f"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% {self.ethmac.interface.sram.ev.irq}") # FIXME HANDLEME - from mdio import MDIOCtrl self.submodules.mdio_ctrl = MDIOCtrl(platform=platform) - # for testing if (False): from nubus_master_tst import PingMaster @@ -411,7 +410,8 @@ def main(): parser.add_argument("--sys-clk-freq", default=100e6, help="NuBusFPGA system clock (default 100e6 = 100 MHz)") parser.add_argument("--goblin", action="store_true", help="add a goblin framebuffer") parser.add_argument("--hdmi", action="store_true", help="The framebuffer uses HDMI (default to VGA, required for V1.2)") - parser.add_argument("--goblin-res", default="640x480@60Hz", help="Specify the goblin resolution") + parser.add_argument("--goblin-res", default="1920x1080@60Hz", help="Specify the goblin resolution") + parser.add_argument("--goblin-alt", action="store_true", help="Use alternate HDMI Phy with Audio support (requires Full HD resolution)") parser.add_argument("--sdcard", action="store_true", help="add a sdcard controller (V1.2 only)") parser.add_argument("--flash", action="store_true", help="add a Flash device [V1.2+FLASHTEMP PMod] and configure the ROM to it") parser.add_argument("--config-flash", action="store_true", help="Configure the ROM to the internal Flash used for FPGA config") @@ -439,10 +439,39 @@ def main(): if ((not args.hdmi) and (args.version == "V1.2")): print(" ***** ERROR ***** : VGA not supported on V1.2\n"); assert(False) + + if ((not args.hdmi) and args.goblin_alt): + print(" ***** ERROR ***** : VGA and Goblin Alt PHY don't make sense\n"); + assert(False) if (args.config_flash and args.flash): print(" ***** ERROR ***** : ROM-in-Flash can only use config OR PMod, not both\n"); assert(False) + + if (args.goblin_alt and (args.goblin_res != "1920x1080@60Hz")): + print(" ***** ERROR ***** : Goblin Alt PHY currently only supports Full HD\n"); + assert(False) + + if (True): + f = open("decl_rom_config.mak","w+") + hres = int(args.goblin_res.split("@")[0].split("x")[0]) + vres = int(args.goblin_res.split("@")[0].split("x")[1]) + f.write("TARGET=NUBUSFPGA\n") + f.write("FEATURES+= -DNUBUSFPGA") + f.write(" -DENABLE_RAMDSK") # only NuBusFPGA for now + if (args.goblin_alt): + f.write(" -DENABLE_HDMIAUDIO") # no audio in litex-style not-hdmi phy + else: + f.write(" -DENABLE_HDMI_ALT_CHANGE"); + if (args.version == "V1.0"): + f.write(" -DENABLE_HDMI_ALT_CHANGE_48MHZ"); + elif (args.version == "V1.2"): + f.write(" -DENABLE_HDMI_ALT_CHANGE_54MHZ"); + + f.write("\n"); + f.write(f"HRES={hres}\n"); + f.write(f"VRES={vres}\n"); + f.close() soc = NuBusFPGA(**soc_core_argdict(args), variant=args.variant, @@ -451,6 +480,7 @@ def main(): goblin=args.goblin, hdmi=args.hdmi, goblin_res=args.goblin_res, + use_goblin_alt=args.goblin_alt, sdcard=args.sdcard, flash=args.flash, config_flash=args.config_flash,