diff --git a/nubus-to-ztex-gateware/do b/nubus-to-ztex-gateware/do_V1.0 similarity index 100% rename from nubus-to-ztex-gateware/do rename to nubus-to-ztex-gateware/do_V1.0 diff --git a/nubus-to-ztex-gateware/do_V1.2 b/nubus-to-ztex-gateware/do_V1.2 new file mode 100644 index 0000000..e4b79fb --- /dev/null +++ b/nubus-to-ztex-gateware/do_V1.2 @@ -0,0 +1,13 @@ +( +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 --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 +# --goblin --goblin-res 1280x1024@60Hz +# --hdmi + +grep -A10 'Design Timing Summary' build/ztex213_nubus_V1_2/gateware/ztex213_nubus_V1_2_timing.rpt diff --git a/nubus-to-ztex-gateware/nubus_V1_2.py b/nubus-to-ztex-gateware/nubus_V1_2.py index 3f2fe46..c2a5a2a 100644 --- a/nubus-to-ztex-gateware/nubus_V1_2.py +++ b/nubus-to-ztex-gateware/nubus_V1_2.py @@ -60,7 +60,11 @@ class NuBus(Module): self.nubus_oe = nubus_oe = Signal() # improveme # those are needed in both Nubus and cpld integrated part now - broadcast_id_3v3_n = platform.request("id_3v3_n") + raw_broadcast_id_3v3_n = platform.request("id_3v3_n") + broadcast_id_3v3_n = Signal(4) + self.comb += [ + broadcast_id_3v3_n.eq(Cat(raw_broadcast_id_3v3_n, Signal(1, reset = 0))) # add missing ID3 in V1_2 + ] # those are 'return' signals (O part of IO separated in I and O) # the 3v3 signals 'see' the 5V signals from the external drivers internal_start_3v3_n = Signal() diff --git a/nubus-to-ztex-gateware/nubus_full_unified.py b/nubus-to-ztex-gateware/nubus_full_unified.py index bf88308..bcca333 100644 --- a/nubus-to-ztex-gateware/nubus_full_unified.py +++ b/nubus-to-ztex-gateware/nubus_full_unified.py @@ -7,14 +7,14 @@ import litex from litex.soc.interconnect import wishbone class NuBus(Module): - def __init__(self, soc, + def __init__(self, soc, version, burst_size, tosbus_fifo, fromsbus_fifo, fromsbus_req_fifo, wb_read, wb_write, wb_dma, usesampling=False, cd_nubus="nubus", cd_nubus90="nubus90"): platform = soc.platform - self.add_sources(platform) + self.add_sources(platform, version) #led0 = platform.request("user_led", 0) #led1 = platform.request("user_led", 1) @@ -714,54 +714,91 @@ class NuBus(Module): # stuff at this end so we don't use the signals inadvertantly # real NuBus signals - nub_tm0n = platform.request("tm0_3v3_n") - nub_tm1n = platform.request("tm1_3v3_n") - nub_startn = platform.request("start_3v3_n") - nub_ackn = platform.request("ack_3v3_n") - nub_adn = platform.request("ad_3v3_n") - nub_idn = platform.request("id_3v3_n") + nub_tm0n = platform.request("tm0_3v3_n") # V1.0: from CPLD ; V1.2: from shifters + nub_tm1n = platform.request("tm1_3v3_n") # V1.0: from CPLD ; V1.2: from shifters + nub_startn = platform.request("start_3v3_n") # V1.0: from CPLD ; V1.2: from shifters + nub_ackn = platform.request("ack_3v3_n") # V1.0: from CPLD ; V1.2: from shifters + nub_adn = platform.request("ad_3v3_n") # V1.0: from CPLD ; V1.2: from shifters + nub_idn = platform.request("id_3v3_n") # V1.0: from CPLD (4 bits) ; V1.2: from shifters (3 bits, /ID3 is always 0) # Tri-state - self.specials += Tristate(nub_tm0n, tm0_o_n, tmo_oe, tm0_i_n) - self.specials += Tristate(nub_tm1n, tm1_o_n, tmo_oe, tm1_i_n) - self.specials += Tristate(nub_ackn, ack_o_n, tmo_oe, ack_i_n) - self.specials += Tristate(nub_adn, ad_o_n, ad_oe, ad_i_n) - self.specials += Tristate(nub_startn, start_o_n, master_oe, start_i_n) - self.comb += [ - id_i_n.eq(nub_idn), - ] + if (version == "V1.0"): + # tri-state communication with CPLD + self.specials += Tristate(nub_tm0n, tm0_o_n, tmo_oe, tm0_i_n) + self.specials += Tristate(nub_tm1n, tm1_o_n, tmo_oe, tm1_i_n) + self.specials += Tristate(nub_ackn, ack_o_n, tmo_oe, ack_i_n) + self.specials += Tristate(nub_adn, ad_o_n, ad_oe, ad_i_n) + self.specials += Tristate(nub_startn, start_o_n, master_oe, start_i_n) + elif (version == "V1.2"): + # input only + self.comb += [ + tm0_i_n.eq(nub_tm0n), + tm1_i_n.eq(nub_tm1n), + ack_i_n.eq(nub_ackn), + ad_i_n.eq(nub_adn), + start_i_n.eq(nub_startn), + ] + else: + raise ValueError(f"Unsupported version {version}") + + # input only + if (version == "V1.0"): + self.comb += [ + id_i_n.eq(nub_idn), + ] + elif (version == "V1.2"): + self.comb += [ + id_i_n.eq(Cat(nub_idn, Signal(1, reset = 0))), + ] + else: + raise ValueError(f"Unsupported version {version}") + # NubusFPGA-only signals - nf_tmoen = platform.request("tmoen") - nf_nubus_ad_dir = platform.request("nubus_ad_dir") - + nf_nubus_ad_dir = platform.request("nubus_ad_dir") # to drivers self.comb += [ - nf_tmoen.eq(~tmo_oe), nf_nubus_ad_dir.eq(~ad_oe), ] + if (version == "V1.0"): + nf_tmoen = platform.request("tmoen") # to cpld + self.comb += [ + nf_tmoen.eq(~tmo_oe), + ] + # real Nubus signal, for master - nub_rqstn = platform.request("rqst_3v3_n") + nub_rqstn = platform.request("rqst_3v3_n") # V1.0: from CPLD ; V1.2: from shifters # Tri-state - self.specials += Tristate(nub_rqstn, rqst_o_n, rqst_oe, rqst_i_n) + if (version == "V1.0"): + # tri-state communication with CPLD + self.specials += Tristate(nub_rqstn, rqst_o_n, rqst_oe, rqst_i_n) + elif (version == "V1.2"): + # input only + self.comb += [ + rqst_i_n.eq(nub_rqstn), + ] + else: + raise ValueError(f"Unsupported version {version}") # NubusFPGA-only signals, for master - nub_arbcy_n = platform.request("arbcy_n") - nf_grant = platform.request("grant") - nf_nubus_master_dir = platform.request("nubus_master_dir") - nf_fpga_to_cpld_signal = platform.request("fpga_to_cpld_signal") + if (version == "V1.0"): + nub_arbcy_n = platform.request("arbcy_n") # V1.0: from cpld + nf_grant = platform.request("grant") # V1.0: from cpld + nf_nubus_master_dir = platform.request("nubus_master_dir") # V1.0: to cpld + nf_fpga_to_cpld_signal = platform.request("fpga_to_cpld_signal") # V1.0: to cpld, 'rqstoen' # NuBus90 signals, , for completeness nub_clk2xn = ClockSignal(cd_nubus90) - nub_tm2n = platform.request("tm2_3v3_n") + nub_tm2n = platform.request("tm2_3v3_n") # V1.0: from CPLD ; V1.2: from shifters - self.comb += [ - nf_nubus_master_dir.eq(master_oe), - nub_arbcy_n.eq(~start_arbitration), - grant.eq(nf_grant), - nf_fpga_to_cpld_signal.eq(~rqst_oe), - ] + if (version == "V1.0"): + self.comb += [ + nf_nubus_master_dir.eq(master_oe), + nub_arbcy_n.eq(~start_arbitration), + grant.eq(nf_grant), + nf_fpga_to_cpld_signal.eq(~rqst_oe), + ] if (usesampling): self.sync += [ @@ -771,6 +808,50 @@ class NuBus(Module): ) ] - def add_sources(self, platform): + + + if (version == "V1.2"): + self.nubus_oe = nubus_oe = Signal() # improveme + self.specials += Instance("nubus_cpldinfpga", + i_nubus_oe = nubus_oe, # improveme: handled in soc + i_tmoen = ~tmo_oe, + i_nubus_master_dir = master_oe, + i_rqst_oe_n = ~rqst_oe, + + i_id_n_3v3 = id_i_n, # input only + + i_arbcy_n = ~start_arbitration, + i_arb_n_3v3 = platform.request("arb_3v3_n"), # arb only seen by cpld + o_arb_o_n = platform.request("arb_o_n"), + o_grant = grant, + + i_tm0_n_3v3 = tm0_o_n, # tm0 driving controlled by tmoen + o_tm0_o_n = platform.request("tm0_o_n"), + + i_tm1_n_3v3 = tm1_o_n, # tm1 driving controlled by tmoen + o_tm1_o_n = platform.request("tm1_o_n"), + o_tmx_oe_n = platform.request("tmx_oe_n"), + + i_tm2_n_3v3 = nub_tm2n, # tm2 currently never driven + o_tm2_o_n = platform.request("tm2_o_n"), + o_tm2_oe_n = platform.request("tm2_oe_n"), + + i_start_n_3v3 = start_o_n, # start driving enabled by nubus_master_dir + o_start_o_n = platform.request("start_o_n"), + o_start_oe_n = platform.request("start_oe_n"), + + i_ack_n_3v3 = ack_o_n, # ack driving controlled by tmoen + o_ack_o_n = platform.request("ack_o_n"), + o_ack_oe_n = platform.request("ack_oe_n"), + + i_rqst_n_3v3 = rqst_o_n, # rqst driving controller by rqst_oe_n + o_rqst_o_n = platform.request("rqst_o_n") + ) + + def add_sources(self, platform, version): # sampling of data on falling edge of clock, done in verilog platform.add_source("nubus_sampling.v", "verilog") + if (version == "V1.2"): + platform.add_source("nubus_arbiter.v", "verilog") # for CPLDinfpga + platform.add_source("nubus_cpldinfpga.v", "verilog") # internal now + diff --git a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py index 9a559ae..e3bfc1d 100644 --- a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py +++ b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py @@ -42,7 +42,7 @@ from nubus_cpu_wb import Wishbone2NuBus # CRG ---------------------------------------------------------------------------------------------- class _CRG(Module): - def __init__(self, platform, sys_clk_freq, + def __init__(self, platform, version, sys_clk_freq, goblin=False, hdmi=False, pix_clk=0): @@ -74,6 +74,17 @@ class _CRG(Module): self.specials += Instance("BUFG", i_I=clk48, o_O=self.clk48_bufg) self.comb += self.cd_native.clk.eq(self.clk48_bufg) #self.cd_native.clk = clk48 + + ##### V1.2 extra clock for B34 + if (version == "V1.2"): + self.clock_domains.cd_bank34 = ClockDomain() + clk54 = platform.request("clk54") + self.clk54_bufg = Signal() + self.specials += Instance("BUFG", i_I=clk54, o_O=self.clk54_bufg) + self.comb += self.cd_native.clk.eq(self.clk54_bufg) + else: + clk54 = None + clk_nubus = platform.request("clk_3v3_n") if (clk_nubus is None): @@ -108,8 +119,8 @@ 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 self.comb += pll.reset.eq(~rst_nubus_n) # | ~por_done - platform.add_false_path_constraints(self.cd_native.clk, self.cd_nubus.clk) # FIXME? - platform.add_false_path_constraints(self.cd_nubus.clk, self.cd_native.clk) # FIXME? + platform.add_false_path_constraints(clk48, self.cd_nubus.clk) # FIXME? + platform.add_false_path_constraints(self.cd_nubus.clk, clk48) # FIXME? #platform.add_false_path_constraints(self.cd_sys.clk, self.cd_nubus.clk) #platform.add_false_path_constraints(self.cd_nubus.clk, self.cd_sys.clk) ##platform.add_false_path_constraints(self.cd_native.clk, self.cd_sys.clk) @@ -130,7 +141,15 @@ class _CRG(Module): if (goblin): self.submodules.video_pll = video_pll = S7MMCM(speedgrade=platform.speedgrade) - video_pll.register_clkin(self.clk48_bufg, 48e6) + if (clk54 is None): + # no 54 MHz clock, drive hdmi from the main clock + video_pll.register_clkin(self.clk48_bufg, 48e6) + else: + # drive hdmi from the 54 MHz clock, easier to generate e.g. 148.5 MHz + video_pll.register_clkin(self.clk54_bufg, 54e6) + platform.add_false_path_constraints(self.cd_bank34.clk, self.cd_nubus.clk) # FIXME? + platform.add_false_path_constraints(self.cd_bank34.clk, clk48) # FIXME? + if (not hdmi): video_pll.create_clkout(self.cd_vga, pix_clk, margin = 0.0005) platform.add_platform_command("create_generated_clock -name vga_clk [get_pins {{{{MMCME2_ADV_{}/CLKOUT{}}}}}]".format(num_adv, num_clk)) @@ -223,7 +242,7 @@ class NuBusFPGA(SoCCore): #"END OF SLOT SPACE": 0xF0FFFFFF, } self.mem_map.update(wb_mem_map) - self.submodules.crg = _CRG(platform=platform, 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"]) ## add our custom timings after the clocks have been defined xdc_timings_filename = None; @@ -404,6 +423,7 @@ class NuBusFPGA(SoCCore): self.comb += dma_irq.eq(self.exchange_with_mem.irq) self.submodules.nubus = nubus_full_unified.NuBus(soc=self, + version=version, burst_size=burst_size, tosbus_fifo=self.tosbus_fifo, fromsbus_fifo=self.fromsbus_fifo, diff --git a/nubus-to-ztex-gateware/ztex213_nubus.py b/nubus-to-ztex-gateware/ztex213_nubus.py index 1ea741c..5d6e1bd 100644 --- a/nubus-to-ztex-gateware/ztex213_nubus.py +++ b/nubus-to-ztex-gateware/ztex213_nubus.py @@ -101,6 +101,8 @@ _nubus_io_v1_0 = [ ] _nubus_io_v1_2 = [ + ## extra 54 MHz clock reference for bank 34 + ("clk54", 0, Pins("R3"), IOStandard("LVCMOS33")), ## leds on the NuBus board ("user_led", 0, Pins("U9"), IOStandard("lvcmos33")), #LED0 ("user_led", 1, Pins("V9"), IOStandard("lvcmos33")), #LED1; both are overlapping with serial TX/RX @@ -179,7 +181,7 @@ _nubus_nubus_v1_2 = [ ("ack_o_n", 0, Pins("H14"), IOStandard("lvttl")), ("ack_oe_n", 0, Pins("J13"), IOStandard("lvttl")), ("nmrq_3v3_n", 0, Pins("K16"), IOStandard("lvttl")), # 'irq' line, Output only direct to 74LVT125 - ("reset_3v3_n", 0, Pins("R3"), IOStandard("lvttl")), # Input only + ("reset_3v3_n", 0, Pins("U8"), IOStandard("lvttl")), # Input only ("rqst_3v3_n" , 0, Pins("J18"), IOStandard("lvttl")), # Open Collector ("rqst_o_n" , 0, Pins("K13"), IOStandard("lvttl")), ("start_3v3_n", 0, Pins("K15"), IOStandard("lvttl")), @@ -191,7 +193,7 @@ _nubus_nubus_v1_2 = [ "D17 D18 E17 E18 F15 F18 F16 G18 "), IOStandard("lvttl")), ("arb_3v3_n", 0, Pins("T8 V4 V5 U6"), IOStandard("lvttl")), # Open Collector ("arb_o_n", 0, Pins("J14 G16 G14 H17"), IOStandard("lvttl")), - ("id_3v3_n", 0, Pins("U7 V6 V7 U8"), IOStandard("lvttl")), + ("id_3v3_n", 0, Pins("U7 V6 V7"), IOStandard("lvttl")), ("tm0_3v3_n", 0, Pins("U2"), IOStandard("lvttl")), ("tm0_o_n", 0, Pins("T6"), IOStandard("lvttl")), ("tm1_3v3_n", 0, Pins("V2"), IOStandard("lvttl")),