From c6e33c5caf668d7999bc275ad487a0a843c96a4e Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Sun, 16 Apr 2023 09:04:21 +0200 Subject: [PATCH] better qemu support, exp. add of Eth --- README.md | 2 +- nubus-to-ztex-gateware/DeclROM/Makefile | 4 ++ .../DeclROM/NuBusFPGAPrimaryInit_Primary.c | 4 +- nubus-to-ztex-gateware/VintageBusFPGA_Common | 2 +- nubus-to-ztex-gateware/do_V1.2 | 2 +- nubus-to-ztex-gateware/nubus_to_fpga_soc.py | 48 +++++++++++++++---- 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 378359e..8866e74 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This project was 'spun off' the [SBusFPGA](https://github.com/rdolbeau/SBusFPGA) ## Current status -First prototype is working in a Quadra 650, running MacOS 8.1. It implements a single-screen-resolution, windowboxed multi-resolution, depth-switchable (1/2/4/8/16/32 bits) framebuffer over DVI-in-HDMI-connector (will work with any HDMI-compliant monitor). The framebuffer can be used as secondary/primary/only framebuffer in the machine running OS8.1. Qemu tests indicate this should work with 7.1 & 7.5/7.6 as well. An alternate HDMI PHY also supports audio, enabled as a 8/16 bits, mono/stereo, 44.1 Hz output compoenent in MacOS. +First prototype is working in a Quadra 650, running MacOS 8.1. It implements a single-screen-resolution, windowboxed multi-resolution, depth-switchable (1/2/4/8/16/32 bits) framebuffer over DVI-in-HDMI-connector (will work with any HDMI-compliant monitor). The framebuffer can be used as secondary/primary/only framebuffer in the machine running OS8.1. Qemu tests indicate this should work with 7.1 & 7.5/7.6 as well. An alternate HDMI PHY also supports audio, enabled as a 8/16 bits, mono/stereo, 44.1 kHz output component in MacOS. Some basic acceleration now exists for 8/16/32 bits, doing rectangle screen-to-screen blits and pattern rectangle fills. 1/2/4 bits also has some acceleration, but only for byte-aligned cases. diff --git a/nubus-to-ztex-gateware/DeclROM/Makefile b/nubus-to-ztex-gateware/DeclROM/Makefile index edfcea3..cacdaef 100644 --- a/nubus-to-ztex-gateware/DeclROM/Makefile +++ b/nubus-to-ztex-gateware/DeclROM/Makefile @@ -17,6 +17,10 @@ APPLEINCS=${NS816DECLROMDIR}/atrap.inc ${NS816DECLROMDIR}/declrom.inc ${NS816DEC HRES=1920 VRES=1080 +QEMU=no +ifeq ($(QEMU),yes) + CFLAGS+=-DQEMU +endif CSRC_VIDEO=NuBusFPGADrvr_OpenClose.c NuBusFPGADrvr_Ctrl.c NuBusFPGADrvr_Status.c NuBusFPGAPrimaryInit_Primary.c NuBusFPGAPrimaryInit_RamInit.c NuBusFPGASecondaryInit_Secondary.c CSRC_RAMDSK=NuBusFPGARAMDskDrvr_OpenClose.c NuBusFPGARAMDskDrvr_Ctrl.c NuBusFPGARAMDskDrvr_Prime.c NuBusFPGARAMDskDrvr_Status.c myrle.c diff --git a/nubus-to-ztex-gateware/DeclROM/NuBusFPGAPrimaryInit_Primary.c b/nubus-to-ztex-gateware/DeclROM/NuBusFPGAPrimaryInit_Primary.c index 55b031d..6d3e585 100644 --- a/nubus-to-ztex-gateware/DeclROM/NuBusFPGAPrimaryInit_Primary.c +++ b/nubus-to-ztex-gateware/DeclROM/NuBusFPGAPrimaryInit_Primary.c @@ -34,8 +34,10 @@ UInt32 Primary(SEBlock* seblock) { vres = __builtin_bswap32((UInt32)PRIM_READREG(GOBOFB_VRES)); // fixme: endianness /* initialize DRAM controller */ +#ifndef QEMU sdram_init(a32); - +#endif + /* grey the screen */ /* should switch to HW ? */ a32_l0 = a32; diff --git a/nubus-to-ztex-gateware/VintageBusFPGA_Common b/nubus-to-ztex-gateware/VintageBusFPGA_Common index f93c95b..9e350c5 160000 --- a/nubus-to-ztex-gateware/VintageBusFPGA_Common +++ b/nubus-to-ztex-gateware/VintageBusFPGA_Common @@ -1 +1 @@ -Subproject commit f93c95ba1eda007ffce0cf5f9c5a3421afbcfdc6 +Subproject commit 9e350c5962f1dc8f43091a3f44a7c1f8071d2bff diff --git a/nubus-to-ztex-gateware/do_V1.2 b/nubus-to-ztex-gateware/do_V1.2 index e4b79fb..fd8f5dc 100644 --- a/nubus-to-ztex-gateware/do_V1.2 +++ b/nubus-to-ztex-gateware/do_V1.2 @@ -2,7 +2,7 @@ source /opt/Xilinx/Vivado/2020.1/settings64.sh export LD_LIBRARY_PATH=/opt/Xilinx/Vivado/2020.1/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 --hdmi +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 --ethernet #python3 nubus_to_fpga_soc.py --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6 diff --git a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py index 3ebe2b5..6c5975a 100644 --- a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py +++ b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py @@ -24,6 +24,8 @@ from litedram.phy import s7ddrphy from litedram.frontend.dma import * +from liteeth.phy.rmii import LiteEthPHYRMII + from migen.genlib.cdc import BusSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer @@ -45,7 +47,8 @@ class _CRG(Module): def __init__(self, platform, version, sys_clk_freq, goblin=False, hdmi=False, - pix_clk=0): + pix_clk=0, + ethernet=False): self.clock_domains.cd_sys = ClockDomain() # 100 MHz PLL, reset'ed by NuBus (via pll), SoC/Wishbone main clock self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) @@ -59,7 +62,9 @@ class _CRG(Module): else: self.clock_domains.cd_hdmi = ClockDomain() self.clock_domains.cd_hdmi5x = ClockDomain() - + if (ethernet): + self.clock_domains.cd_eth = ClockDomain() + # # # clk48 = platform.request("clk48") @@ -118,6 +123,11 @@ class _CRG(Module): pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) 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? + platform.add_platform_command("create_generated_clock -name ethclk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk)) + num_clk = num_clk + 1 + self.comb += pll.reset.eq(~rst_nubus_n) # | ~por_done platform.add_false_path_constraints(clk48, self.cd_nubus.clk) # FIXME? platform.add_false_path_constraints(self.cd_nubus.clk, clk48) # FIXME? @@ -171,7 +181,7 @@ class _CRG(Module): class NuBusFPGA(SoCCore): - def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, **kwargs): + def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, ethernet, **kwargs): print(f"Building NuBusFPGA for board version {version}") kwargs["cpu_type"] = "None" @@ -183,6 +193,9 @@ class NuBusFPGA(SoCCore): self.platform = platform = ztex213_nubus.Platform(variant = variant, version = version) + if (ethernet and (version == "V1.2")): + platform.add_extension(ztex213_nubus._rmii_eth_extpmod_io_v1_2) + use_goblin_alt = True if ((not use_goblin_alt) or (not hdmi)): from VintageBusFPGA_Common.goblin_fb import goblin_rounded_size, Goblin @@ -238,11 +251,12 @@ class NuBusFPGA(SoCCore): "goblin_audio_ram" : 0xF0920000, # audio for goblin (RAM buffers) "csr" : 0xF0A00000, # CSR "pingmaster": 0xF0B00000, + "ethmac": 0xF0C00000, "rom": 0xF0FF8000, # ROM at the end (32 KiB of it ATM) #"END OF SLOT SPACE": 0xF0FFFFFF, } self.mem_map.update(wb_mem_map) - self.submodules.crg = _CRG(platform=platform, version=version, sys_clk_freq=sys_clk_freq, goblin=goblin, hdmi=hdmi, pix_clk=litex.soc.cores.video.video_timings[goblin_res]["pix_clk"]) + self.submodules.crg = _CRG(platform=platform, version=version, sys_clk_freq=sys_clk_freq, goblin=goblin, hdmi=hdmi, pix_clk=litex.soc.cores.video.video_timings[goblin_res]["pix_clk"], ethernet=ethernet) ## add our custom timings after the clocks have been defined xdc_timings_filename = None; @@ -476,25 +490,42 @@ class NuBusFPGA(SoCCore): self.add_ram("goblin_accel_rom", origin=self.mem_map["goblin_accel_rom"], size=rounded_goblin_rom_len, contents=goblin_rom_data, mode="r") self.add_ram("goblin_accel_ram", origin=self.mem_map["goblin_accel_ram"], size=2**12, mode="rw") + if (ethernet): + # 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"), + pads = self.platform.request("eth")) + self.add_ethernet(phy=self.ethphy, data_width = 32) + print(f"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% {self.ethmac.interface.sram.ev.irq}") # FIXME HANDLEME + # for testing - if (True): + if (False): from nubus_master_tst import PingMaster self.submodules.pingmaster = PingMaster(nubus=self.nubus, platform=self.platform) self.bus.add_slave("pingmaster_slv", self.pingmaster.bus_slv, SoCRegion(origin=self.mem_map.get("pingmaster", None), size=0x010, cached=False)) self.bus.add_master(name="pingmaster_mst", master=self.pingmaster.bus_mst) def main(): - parser = argparse.ArgumentParser(description="SbusFPGA") + parser = argparse.ArgumentParser(description="NuBusFPGA") parser.add_argument("--build", action="store_true", help="Build bitstream") parser.add_argument("--variant", default="ztex2.13a", help="ZTex board variant (default ztex2.13a)") parser.add_argument("--version", default="V1.0", help="NuBusFPGA board version (default V1.0)") 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)") + 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("--ethernet", action="store_true", help="Add Ethernet (V1.2 w/ custom PMod only)") builder_args(parser) vivado_build_args(parser) args = parser.parse_args() + + if (args.ethernet and (args.version == "V1.0")): + print(" ***** ERROR ***** : Ethernet not supported on V1.0\n"); + assert(False) + + if ((not args.hdmi) and (args.version == "V1.2")): + print(" ***** ERROR ***** : VGA not supported on V1.2\n"); + assert(False) soc = NuBusFPGA(**soc_core_argdict(args), variant=args.variant, @@ -502,7 +533,8 @@ def main(): sys_clk_freq=int(float(args.sys_clk_freq)), goblin=args.goblin, hdmi=args.hdmi, - goblin_res=args.goblin_res) + goblin_res=args.goblin_res, + ethernet=args.ethernet) version_for_filename = args.version.replace(".", "_")