NuBusFPGA/nubus-to-ztex-gateware/nubus_to_fpga_soc.py

515 lines
28 KiB
Python
Raw Permalink Normal View History

2021-12-21 07:26:30 +00:00
import os
import argparse
from migen import *
from migen.genlib.fifo import *
from migen.fhdl.specials import Tristate
import litex
from litex.build.generic_platform import *
from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict
from litex.soc.integration.soc import *
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.interconnect import wishbone
from litex.soc.cores.clock import *
from litex.soc.cores.led import LedChaser
import ztex213_nubus
2022-01-29 10:03:47 +00:00
import nubus_to_fpga_export
2021-12-21 07:26:30 +00:00
import nubus_full_unified
2022-06-04 16:56:41 +00:00
import nubus_stat
2021-12-21 07:26:30 +00:00
from litedram.frontend.dma import *
2023-04-16 07:04:21 +00:00
from liteeth.phy.rmii import LiteEthPHYRMII
2021-12-21 07:26:30 +00:00
from migen.genlib.cdc import BusSynchronizer
from migen.genlib.resetsync import AsyncResetSynchronizer
# Wishbone stuff
2022-10-31 14:45:24 +00:00
from VintageBusFPGA_Common.cdc_wb import WishboneDomainCrossingMaster
2022-10-31 14:58:47 +00:00
from VintageBusFPGA_Common.fpga_blk_dma import *
2023-09-16 13:14:35 +00:00
from VintageBusFPGA_Common.fpga_sd_dma import *
2023-11-18 10:10:46 +00:00
from VintageBusFPGA_Common.MacPeriphSoC import *
2022-10-31 14:58:47 +00:00
2021-12-21 07:26:30 +00:00
from nubus_mem_wb import NuBus2Wishbone
from nubus_memfifo_wb import NuBus2WishboneFIFO
2022-04-17 09:25:48 +00:00
from nubus_cpu_wb import Wishbone2NuBus
2021-12-21 07:26:30 +00:00
# CRG ----------------------------------------------------------------------------------------------
class _CRG(Module, AutoCSR): # AutoCSR for DRP
2023-01-14 10:03:01 +00:00
def __init__(self, platform, version, sys_clk_freq,
goblin=False,
2021-12-21 07:26:30 +00:00
hdmi=False,
2023-04-16 07:04:21 +00:00
pix_clk=0,
ethernet=False):
2021-12-21 07:26:30 +00:00
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)
self.clock_domains.cd_idelay = ClockDomain()
self.clock_domains.cd_native = ClockDomain(reset_less=True) # 48MHz native, non-reset'ed (for power-on long delay, never reset, we don't want the delay after a warm reset)
self.clock_domains.cd_nubus = ClockDomain() # 10 MHz NuBus, reset'ed by NuBus, native NuBus clock domain (25% duty cycle)
self.clock_domains.cd_nubus90 = ClockDomain() # 20 MHz NuBus90, reset'ed by NuBus, native NuBus90 clock domain (25% duty cycle)
if (goblin):
2021-12-21 07:26:30 +00:00
if (not hdmi):
self.clock_domains.cd_vga = ClockDomain(reset_less=True)
else:
self.clock_domains.cd_hdmi = ClockDomain()
self.clock_domains.cd_hdmi5x = ClockDomain()
2023-04-16 07:04:21 +00:00
if (ethernet):
self.clock_domains.cd_eth = ClockDomain()
2021-12-21 07:26:30 +00:00
# # #
clk48 = platform.request("clk48")
###### explanations from betrusted-io/betrusted-soc/betrusted_soc.py
# Note: below feature cannot be used because Litex appends this *after* platform commands! This causes the generated
# clock derived constraints immediately below to fail, because .xdc file is parsed in-order, and the main clock needs
# to be created before the derived clocks. Instead, we use the line afterwards.
platform.add_platform_command("create_clock -name clk48 -period 20.8333 [get_nets clk48]")
# The above constraint must strictly proceed the below create_generated_clock constraints in the .XDC file
# This allows PLLs/MMCMEs to be placed anywhere and reference the input clock
self.clk48_bufg = Signal()
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
2023-01-14 10:03:01 +00:00
##### V1.2 extra clock for B34
if (version == "V1.2"):
self.clock_domains.cd_bank34 = ClockDomain()
clk54 = platform.request("clk54")
2023-04-17 20:55:22 +00:00
platform.add_platform_command("create_clock -name clk54 -period 18.51851851851851851 [get_nets clk54]")
2023-01-14 10:03:01 +00:00
self.clk54_bufg = Signal()
self.specials += Instance("BUFG", i_I=clk54, o_O=self.clk54_bufg)
2023-04-17 20:55:22 +00:00
self.comb += self.cd_bank34.clk.eq(self.clk54_bufg)
2023-01-14 10:03:01 +00:00
else:
clk54 = None
2021-12-21 07:26:30 +00:00
clk_nubus = platform.request("clk_3v3_n")
if (clk_nubus is None):
print(" ***** ERROR ***** Can't find the NuBus Clock !!!!\n");
assert(false)
self.cd_nubus.clk = clk_nubus
rst_nubus_n = platform.request("reset_3v3_n")
self.comb += self.cd_nubus.rst.eq(~rst_nubus_n)
platform.add_platform_command("create_clock -name nubus_clk -period 100.0 -waveform {{0.0 75.0}} [get_ports clk_3v3_n]")
2022-01-29 10:03:47 +00:00
clk2x_nubus = platform.request("clk2x_3v3_n")
if (clk2x_nubus is None):
print(" ***** ERROR ***** Can't find the NuBus90 Clock !!!!\n");
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 25}} [get_ports clk2x_3v3_n]")
2021-12-21 07:26:30 +00:00
num_adv = 0
num_clk = 0
self.submodules.pll = pll = S7MMCM(speedgrade=platform.speedgrade)
#pll.register_clkin(clk48, 48e6)
pll.register_clkin(self.clk48_bufg, 48e6)
pll.create_clkout(self.cd_sys, sys_clk_freq)
platform.add_platform_command("create_generated_clock -name sysclk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk))
num_clk = num_clk + 1
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq)
platform.add_platform_command("create_generated_clock -name sys4xclk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk))
num_clk = num_clk + 1
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
2023-04-16 07:04:21 +00:00
if (ethernet):
pll.create_clkout(self.cd_eth, 50e6, phase=90) # fixme: what if sys_clk_feq != 100e6? # why phase ???
2023-04-16 07:04:21 +00:00
platform.add_platform_command("create_generated_clock -name ethclk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk))
num_clk = num_clk + 1
2021-12-21 07:26:30 +00:00
self.comb += pll.reset.eq(~rst_nubus_n) # | ~por_done
2023-01-14 10:03:01 +00:00
platform.add_false_path_constraints(clk48, self.cd_nubus.clk) # FIXME?
platform.add_false_path_constraints(self.cd_nubus.clk, clk48) # FIXME?
2021-12-21 07:26:30 +00:00
#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)
num_adv = num_adv + 1
num_clk = 0
self.submodules.pll_idelay = pll_idelay = S7MMCM(speedgrade=platform.speedgrade)
#pll_idelay.register_clkin(clk48, 48e6)
pll_idelay.register_clkin(self.clk48_bufg, 48e6)
pll_idelay.create_clkout(self.cd_idelay, 200e6, margin = 0)
platform.add_platform_command("create_generated_clock -name idelayclk [get_pins {{{{MMCME2_ADV_{}/CLKOUT{}}}}}]".format(num_adv, num_clk))
num_clk = num_clk + 1
self.comb += pll_idelay.reset.eq(~rst_nubus_n) # | ~por_done
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)
num_adv = num_adv + 1
num_clk = 0
if (goblin):
2021-12-21 07:26:30 +00:00
self.submodules.video_pll = video_pll = S7MMCM(speedgrade=platform.speedgrade)
2023-01-14 10:03:01 +00:00
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?
2021-12-21 07:26:30 +00:00
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))
num_clk = num_clk + 1
else:
2022-04-17 09:25:48 +00:00
video_pll.create_clkout(self.cd_hdmi, pix_clk, margin = 0.005)
video_pll.create_clkout(self.cd_hdmi5x, 5*pix_clk, margin = 0.005)
2021-12-21 07:26:30 +00:00
platform.add_platform_command("create_generated_clock -name hdmi_clk [get_pins {{{{MMCME2_ADV_{}/CLKOUT{}}}}}]".format(num_adv, num_clk))
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()
2023-01-08 14:11:22 +00:00
2021-12-21 07:26:30 +00:00
self.comb += video_pll.reset.eq(~rst_nubus_n)
#platform.add_false_path_constraints(self.cd_sys.clk, self.cd_vga.clk)
platform.add_false_path_constraints(self.cd_sys.clk, video_pll.clkin)
num_adv = num_adv + 1
num_clk = 0
2023-11-18 10:10:46 +00:00
class NuBusFPGA(MacPeriphSoC):
def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, use_goblin_alt, sdcard, flash, config_flash, ethernet, **kwargs):
2021-12-21 07:26:30 +00:00
print(f"Building NuBusFPGA for board version {version}")
self.platform = platform = ztex213_nubus.Platform(variant = variant, version = version)
2023-09-16 13:14:35 +00:00
if (flash and (version == "V1.2")):
platform.add_extension(ztex213_nubus._flashtemp_pmod_io_v1_2)
2021-12-21 07:26:30 +00:00
2023-04-16 07:04:21 +00:00
if (ethernet and (version == "V1.2")):
platform.add_extension(ztex213_nubus._rmii_eth_extpmod_io_v1_2)
2021-12-21 07:26:30 +00:00
2023-11-18 10:10:46 +00:00
MacPeriphSoC.__init__(self,
platform=platform,
sys_clk_freq=sys_clk_freq,
csr_paging=0x800, # default is 0x800
bus_interconnect = "crossbar",
goblin = goblin,
hdmi = hdmi,
goblin_res = goblin_res,
use_goblin_alt = use_goblin_alt,
**kwargs)
self.mem_map.update(self.wb_mem_map)
2023-04-16 07:04:21 +00:00
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)
2021-12-21 07:26:30 +00:00
## add our custom timings after the clocks have been defined
xdc_timings_filename = None;
2022-09-21 21:06:17 +00:00
#if (version == "V1.0"):
# xdc_timings_filename = "/home/dolbeau/nubus-to-ztex-gateware/nubus_fpga_V1_0_timings.xdc"
2023-09-16 13:14:35 +00:00
if (version == "V1.2"):
xdc_timings_filename = "nubus_fpga_V1_2_timings.xdc"
2021-12-21 07:26:30 +00:00
if (xdc_timings_filename != None):
xdc_timings_file = open(xdc_timings_filename)
2022-04-17 09:25:48 +00:00
2021-12-21 07:26:30 +00:00
xdc_timings_lines = xdc_timings_file.readlines()
for line in xdc_timings_lines:
if (line[0:3] == "set"):
fix_line = line.strip().replace("{", "{{").replace("}", "}}")
#print(fix_line)
platform.add_platform_command(fix_line)
2023-11-18 11:16:58 +00:00
MacPeriphSoC.mac_add_declrom(self, version = version, flash = flash, config_flash = config_flash)
MacPeriphSoC.mac_add_sdram(self, hwinit = False)
2023-11-18 11:52:35 +00:00
if (goblin):
2023-11-18 11:52:35 +00:00
MacPeriphSoC.mac_add_goblin_prelim(self)
2021-12-21 07:26:30 +00:00
# don't enable anything on the NuBus side for XX seconds after power up
# this avoids FPGA initialization messing with the cold boot process
# requires us to reset the Macintosh afterward so the FPGA board
# is properly identified
# This is in the 'native' ClockDomain that is never reset
2022-04-17 09:25:48 +00:00
# not needed, FPGA initializes fast enough, works on cold boots
2021-12-21 07:26:30 +00:00
#hold_reset_ctr = Signal(30, reset=960000000)
hold_reset_ctr = Signal(5, reset=31)
self.sync.native += If(hold_reset_ctr>0, hold_reset_ctr.eq(hold_reset_ctr - 1))
2023-04-17 20:55:22 +00:00
self.hold_reset = hold_reset = Signal() # in reset if high, out-of-reset if low
2021-12-21 07:26:30 +00:00
self.comb += hold_reset.eq(~(hold_reset_ctr == 0))
pad_nubus_oe = platform.request("nubus_oe")
self.comb += pad_nubus_oe.eq(hold_reset)
2022-04-17 09:25:48 +00:00
#pad_user_led_0 = platform.request("user_led", 0)
#self.comb += pad_user_led_0.eq(~hold_reset)
2021-12-21 07:26:30 +00:00
# Interface NuBus to wishbone
# we need to cross clock domains
2022-11-05 13:59:33 +00:00
# Xibus is the original VErilog implementation I used
# mostly only for testing now, it doesn't have block mode so doesn't support the DMA mode of the RAM disk
# Should be set to False unless for testing (usually with notsimul=False)
xibus=False
if (xibus):
wishbone_master_sys = wishbone.Interface(data_width=self.bus.data_width)
self.submodules.wishbone_master_nubus = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_master_sys, cd_master="nubus", cd_slave="sys")
self.bus.add_master(name="NuBusBridgeToWishbone", master=wishbone_master_sys)
2022-11-01 14:42:59 +00:00
if (version == "V1.0"):
from nubus_V1_0 import NuBus
elif (version == "V1.2"):
from nubus_V1_2 import NuBus
self.submodules.nubus = NuBus(platform=platform, cd_nubus="nubus")
#self.submodules.nubus2wishbone = ClockDomainsRenamer("nubus")(NuBus2Wishbone(nubus=self.nubus,wb=self.wishbone_master_nubus))
2022-11-01 14:31:34 +00:00
if (version == "V1.2"):
self.comb += self.nubus.nubus_oe.eq(hold_reset) # improveme
nubus_writemaster_sys = wishbone.Interface(data_width=self.bus.data_width)
self.submodules.nubus2wishbone = NuBus2WishboneFIFO(platform=self.platform,nubus=self.nubus,wb_read=self.wishbone_master_nubus,wb_write=nubus_writemaster_sys)
self.bus.add_master(name="NuBusBridgeToWishboneWrite", master=nubus_writemaster_sys)
wishbone_slave_nubus = wishbone.Interface(data_width=self.bus.data_width)
self.submodules.wishbone2nubus = ClockDomainsRenamer("nubus")(Wishbone2NuBus(nubus=self.nubus,wb=wishbone_slave_nubus))
self.submodules.wishbone_slave_sys = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_nubus, cd_master="sys", cd_slave="nubus")
self.bus.add_slave("DMA", self.wishbone_slave_sys, SoCRegion(origin=self.mem_map.get("master", None), size=0x40000000, cached=False))
2022-10-31 14:28:08 +00:00
irq_line = self.platform.request("nmrq_3v3_n") # active low
fb_irq = Signal() # active low
2022-11-01 11:41:58 +00:00
#led0 = platform.request("user_led", 0)
#self.comb += [
# led0.eq(~fb_irq),
#]
2022-10-31 14:28:08 +00:00
self.comb += irq_line.eq(fb_irq) # active low, enable if one is low
else:
2022-11-05 13:59:33 +00:00
# details for usesampling in the NuBus python object
2023-09-16 13:14:35 +00:00
usesampling = False
wishbone_master_sys = wishbone.Interface(data_width=self.bus.data_width)
if (not usesampling): # we need an extra CDC
2022-09-21 21:06:17 +00:00
self.submodules.wishbone_master_nubus = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_master_sys, cd_master="nubus", cd_slave="sys") # for non-sampling only
nubus_writemaster_sys = wishbone.Interface(data_width=self.bus.data_width)
wishbone_slave_nubus = wishbone.Interface(data_width=self.bus.data_width)
2023-09-16 13:14:35 +00:00
self.submodules.wishbone_slave_sys = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_nubus, cd_master="sys", cd_slave="nubus", force_delay=9) # force delay needed to avoid back-to-back transaction running into issue https://github.com/alexforencich/verilog-wishbone/issues/4
#led0 = platform.request("user_led", 0)
#led1 = platform.request("user_led", 1)
#self.comb += [ led0.eq(self.wishbone_slave_sys.stb),
# led1.eq(self.wishbone_slave_sys.cyc), ]
2022-07-14 15:17:53 +00:00
burst_size=4
data_width = burst_size * 4
data_width_bits = burst_size * 32
blk_addr_width = 32 - log2_int(data_width)
self.tosbus_layout = [
("address", 32),
("data", data_width_bits),
]
self.fromsbus_layout = [
("blkaddress", blk_addr_width),
("data", data_width_bits),
]
self.fromsbus_req_layout = [
("blkaddress", blk_addr_width),
("dmaaddress", 32),
]
2023-09-16 13:14:35 +00:00
2022-10-08 16:23:01 +00:00
irq_line = self.platform.request("nmrq_3v3_n") # active low
2023-01-08 14:11:22 +00:00
fb_irq = Signal(reset = 1) # active low
dma_irq = Signal(reset = 1) # active low
audio_irq = Signal(reset = 1) # active low
#led0 = platform.request("user_led", 0)
#led1 = platform.request("user_led", 1)
#self.comb += [
# led0.eq(~fb_irq),
# led1.eq(~dma_irq),
#]
2023-01-08 14:11:22 +00:00
self.comb += irq_line.eq(fb_irq & dma_irq & audio_irq) # active low, enable if one is low
2023-09-16 13:14:35 +00:00
2022-07-14 15:17:53 +00:00
2023-09-16 13:14:35 +00:00
self.submodules.tosbus_fifo = ClockDomainsRenamer({"read": "nubus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.tosbus_layout), depth=1024//data_width))
self.submodules.fromsbus_fifo = ClockDomainsRenamer({"write": "nubus", "read": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_layout), depth=512//data_width))
self.submodules.fromsbus_req_fifo = ClockDomainsRenamer({"read": "nubus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_req_layout), depth=512//data_width))
#if (not sdcard): # fixme: temporay exclusion
2022-07-14 15:17:53 +00:00
self.submodules.exchange_with_mem = ExchangeWithMem(soc=self,
platform=platform,
tosbus_fifo=self.tosbus_fifo,
fromsbus_fifo=self.fromsbus_fifo,
fromsbus_req_fifo=self.fromsbus_req_fifo,
dram_native_r=self.sdram.crossbar.get_port(mode="read", data_width=data_width_bits),
dram_native_w=self.sdram.crossbar.get_port(mode="write", data_width=data_width_bits),
2023-11-18 11:16:58 +00:00
mem_size=self.avail_sdram//1048576,
2022-07-14 15:17:53 +00:00
burst_size=burst_size,
2022-07-23 10:53:30 +00:00
do_checksum = False,
clock_domain="nubus")
self.comb += dma_irq.eq(self.exchange_with_mem.irq)
2023-09-16 13:14:35 +00:00
#else:
# self.add_sdcard_custom()
# self.submodules.exchange_with_sd = ExchangeWithSD(soc=self,
# platform=platform,
# tosbus_fifo=self.tosbus_fifo,
# fromsbus_fifo=self.fromsbus_fifo,
# fromsbus_req_fifo=self.fromsbus_req_fifo,
# sd_source=self.sdcore.source,
# sd_sink=self.sdcore.sink,
# burst_size=burst_size,
# clock_domain="nubus")
# self.comb += dma_irq.eq(self.exchange_with_sd.irq)
self.submodules.nubus = nubus_full_unified.NuBus(soc=self,
2023-01-14 10:03:01 +00:00
version=version,
burst_size=burst_size,
tosbus_fifo=self.tosbus_fifo,
fromsbus_fifo=self.fromsbus_fifo,
fromsbus_req_fifo=self.fromsbus_req_fifo,
wb_read=(wishbone_master_sys if usesampling else self.wishbone_master_nubus), # CDC or not
wb_write=nubus_writemaster_sys,
wb_dma=wishbone_slave_nubus,
usesampling=usesampling,
cd_nubus="nubus")
self.bus.add_master(name="NuBusBridgeToWishbone", master=wishbone_master_sys)
self.bus.add_slave("DMA", self.wishbone_slave_sys, SoCRegion(origin=self.mem_map.get("master", None), size=0x40000000, cached=False))
self.bus.add_master(name="NuBusBridgeToWishboneWrite", master=nubus_writemaster_sys)
2022-06-04 16:56:41 +00:00
self.submodules.stat = nubus_stat.NuBusStat(nubus=self.nubus, platform=platform)
self.bus.add_slave("Stat", self.stat.bus_slv, SoCRegion(origin=self.mem_map.get("stat", None), size=0x1000, cached=False))
if (goblin):
2023-11-18 11:52:35 +00:00
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)
2022-04-17 09:25:48 +00:00
if (sdcard): ### WIP WIP WIP WIP
2023-09-16 13:14:35 +00:00
self.add_sdcard()
# irq?
2023-11-18 10:10:46 +00:00
if (ethernet): ### WIP WIP WIP WIP
2023-09-16 13:14:35 +00:00
# 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,
2023-09-16 13:14:35 +00:00
pads = self.platform.request("eth"))
self.add_ethernet(phy=self.ethphy, data_width = 32)
print(f"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% {self.ethmac.interface.sram.ev.irq}") # FIXME HANDLEME
2023-11-18 10:10:46 +00:00
from mdio import MDIOCtrl
self.submodules.mdio_ctrl = MDIOCtrl(platform=platform)
2022-04-17 09:25:48 +00:00
# for testing
2023-04-16 07:04:21 +00:00
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)
2021-12-21 07:26:30 +00:00
def main():
2023-04-16 07:04:21 +00:00
parser = argparse.ArgumentParser(description="NuBusFPGA")
2021-12-21 07:26:30 +00:00
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")
2023-04-16 07:04:21 +00:00
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="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)")
2023-09-16 13:14:35 +00:00
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")
2023-04-16 07:04:21 +00:00
parser.add_argument("--ethernet", action="store_true", help="Add Ethernet (V1.2 w/ custom PMod only)")
2021-12-21 07:26:30 +00:00
builder_args(parser)
vivado_build_args(parser)
args = parser.parse_args()
2023-04-16 07:04:21 +00:00
2023-09-16 13:14:35 +00:00
if (args.sdcard and (args.version == "V1.0")):
print(" ***** ERROR ***** : Ethernet not supported on V1.0\n");
assert(False)
if (args.flash and (args.version == "V1.0")):
print(" ***** ERROR ***** : Flash not supported on V1.0\n");
assert(False)
2023-04-16 07:04:21 +00:00
if (args.ethernet and (args.version == "V1.0")):
print(" ***** ERROR ***** : Ethernet not supported on V1.0\n");
assert(False)
2023-09-16 13:14:35 +00:00
if (args.ethernet and args.flash):
print(" ***** ERROR ***** : Only one PMod usable on V1.2\n");
assert(False)
2023-04-16 07:04:21 +00:00
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()
2024-05-18 08:24:27 +00:00
if (True):
f = open("board.inc", "w+")
f.write(f" .string \"NuBusFPGA {args.version}\\0\" /* revision level */")
f.close()
2021-12-21 07:26:30 +00:00
soc = NuBusFPGA(**soc_core_argdict(args),
variant=args.variant,
version=args.version,
sys_clk_freq=int(float(args.sys_clk_freq)),
goblin=args.goblin,
2021-12-21 07:26:30 +00:00
hdmi=args.hdmi,
2023-04-16 07:04:21 +00:00
goblin_res=args.goblin_res,
use_goblin_alt=args.goblin_alt,
2023-09-16 13:14:35 +00:00
sdcard=args.sdcard,
flash=args.flash,
config_flash=args.config_flash,
2023-04-16 07:04:21 +00:00
ethernet=args.ethernet)
2021-12-21 07:26:30 +00:00
version_for_filename = args.version.replace(".", "_")
soc.platform.name += "_" + version_for_filename
builder = Builder(soc, **builder_argdict(args))
builder.build(**vivado_build_argdict(args), run=args.build)
# Generate modified CSR registers definitions/access functions to netbsd_csr.h.
# should be split per-device (and without base) to still work if we have identical devices in different configurations on multiple boards
# now it is split
2022-01-29 10:03:47 +00:00
csr_contents_dict = nubus_to_fpga_export.get_csr_header_split(
regions = soc.csr_regions,
constants = soc.constants,
csr_base = soc.mem_regions['csr'].origin)
for name in csr_contents_dict.keys():
write_to_file(os.path.join("nubusfpga_csr_{}.h".format(name)), csr_contents_dict[name])
2021-12-21 07:26:30 +00:00
if __name__ == "__main__":
main()