add micro-sd HW support

This commit is contained in:
Romain Dolbeau 2023-09-16 15:14:35 +02:00
parent 77852b8d40
commit f9886f7280
3 changed files with 129 additions and 28 deletions

View File

@ -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 # --ethernet
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 --sdcard --flash # --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
@ -11,3 +11,15 @@ python3 nubus_to_fpga_soc.py --build --csr-csv csr.csv --csr-json csr.json --var
# --hdmi
grep -A10 'Design Timing Summary' build/ztex213_nubus_V1_2/gateware/ztex213_nubus_V1_2_timing.rpt
###
# For 16 MiB Flash NOR (W25Q128.V):
# truncate -s $((16*1024*1024)) vid_decl_rom.bin
# flashrom -c W25Q128.V -p linux_spi:dev=/dev/spidev0.0,spispeed=2000 -l nubus_prom.layout -i ROM -w vid_decl_rom.bin
#
# where nubus_prom.layout contains:
###
# 00000000:00007fff ROM
# 00008000:00ffffff VDISK
###

View File

@ -37,6 +37,7 @@ from VintageBusFPGA_Common.goblin_accel import *
# Wishbone stuff
from VintageBusFPGA_Common.cdc_wb import WishboneDomainCrossingMaster
from VintageBusFPGA_Common.fpga_blk_dma import *
from VintageBusFPGA_Common.fpga_sd_dma import *
from nubus_mem_wb import NuBus2Wishbone
from nubus_memfifo_wb import NuBus2WishboneFIFO
@ -181,8 +182,26 @@ class _CRG(Module):
class NuBusFPGA(SoCCore):
def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, ethernet, **kwargs):
class NuBusFPGA(SoCCore): # Add SDCard -----------------------------------------------------------------------------------
# WiP
def add_sdcard_custom(self, name="sdcard", mode="read+write"):
# Imports.
from litesdcard.phy import SDPHY
from litesdcard.core import SDCore
# Checks.
assert mode in ["read", "write", "read+write"]
# Pads.
sdcard_pads = self.platform.request(name)
# Core.
self.check_if_exists("sdphy")
self.check_if_exists("sdcore")
self.sdphy = SDPHY(sdcard_pads, self.platform.device, self.clk_freq, cmd_timeout=10e-1, data_timeout=10e-1)
self.sdcore = SDCore(self.sdphy)
def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, sdcard, flash, ethernet, **kwargs):
print(f"Building NuBusFPGA for board version {version}")
kwargs["cpu_type"] = "None"
@ -193,6 +212,9 @@ class NuBusFPGA(SoCCore):
self.sys_clk_freq = sys_clk_freq
self.platform = platform = ztex213_nubus.Platform(variant = variant, version = version)
if (flash and (version == "V1.2")):
platform.add_extension(ztex213_nubus._flashtemp_pmod_io_v1_2)
if (ethernet and (version == "V1.2")):
platform.add_extension(ztex213_nubus._rmii_eth_extpmod_io_v1_2)
@ -253,7 +275,9 @@ class NuBusFPGA(SoCCore):
"csr" : 0xF0A00000, # CSR
"pingmaster": 0xF0B00000,
"ethmac": 0xF0C00000,
#"spiflash": 0xF0D00000, # testing
"rom": 0xF0FF8000, # ROM at the end (32 KiB of it ATM)
"spiflash": 0xF0FF8000, # FIXME currently the flash is in the ROM spot, limited to 32 KiB
#"END OF SLOT SPACE": 0xF0FFFFFF,
}
self.mem_map.update(wb_mem_map)
@ -263,6 +287,8 @@ class NuBusFPGA(SoCCore):
xdc_timings_filename = None;
#if (version == "V1.0"):
# xdc_timings_filename = "/home/dolbeau/nubus-to-ztex-gateware/nubus_fpga_V1_0_timings.xdc"
if (version == "V1.2"):
xdc_timings_filename = "nubus_fpga_V1_2_timings.xdc"
if (xdc_timings_filename != None):
xdc_timings_file = open(xdc_timings_filename)
@ -274,14 +300,25 @@ class NuBusFPGA(SoCCore):
#print(fix_line)
platform.add_platform_command(fix_line)
rom_file = "rom_{}.bin".format(version.replace(".", "_"))
rom_data = soc_core.get_mem_data(filename_or_regions=rom_file, endianness="little") # "big"
# rom = Array(rom_data)
#print("\n****************************************\n")
#for i in range(len(rom)):
# print(hex(rom[i]))
#print("\n****************************************\n")
self.add_ram("rom", origin=self.mem_map["rom"], size=2**15, contents=rom_data, mode="r") ## 32 KiB, must match mmap
if (not flash):
rom_file = "rom_{}.bin".format(version.replace(".", "_"))
rom_data = soc_core.get_mem_data(filename_or_regions=rom_file, endianness="little") # "big"
# rom = Array(rom_data)
#print("\n****************************************\n")
#for i in range(len(rom)):
# print(hex(rom[i]))
#print("\n****************************************\n")
self.add_ram("rom", origin=self.mem_map["rom"], size=2**15, contents=rom_data, mode="r") ## 32 KiB, must match mmap
if (flash):
from litespi.modules.generated_modules import W25Q128JV
from litespi.opcodes import SpiNorFlashOpCodes as Codes
self.add_spi_flash(mode="4x",
clk_freq = sys_clk_freq/4, # Fixme; PHY freq ?
module=W25Q128JV(Codes.READ_1_1_4),
region_size = 0x00008000, # 32 KiB
with_mmap=True, with_master=False)
#from wb_test import WA2D
#self.submodules.wa2d = WA2D(self.platform)
@ -379,15 +416,18 @@ class NuBusFPGA(SoCCore):
self.comb += irq_line.eq(fb_irq) # active low, enable if one is low
else:
# details for usesampling in the NuBus python object
usesampling = True
usesampling = False
wishbone_master_sys = wishbone.Interface(data_width=self.bus.data_width)
if (not usesampling): # we need an extra CDC
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)
self.submodules.wishbone_slave_sys = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_nubus, cd_master="sys", cd_slave="nubus", force_delay=6) # force delay needed to avoid back-to-back transaction running into issue https://github.com/alexforencich/verilog-wishbone/issues/4
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), ]
burst_size=4
data_width = burst_size * 4
@ -407,9 +447,7 @@ class NuBusFPGA(SoCCore):
("dmaaddress", 32),
]
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))
irq_line = self.platform.request("nmrq_3v3_n") # active low
fb_irq = Signal(reset = 1) # active low
dma_irq = Signal(reset = 1) # active low
@ -422,7 +460,13 @@ class NuBusFPGA(SoCCore):
#]
self.comb += irq_line.eq(fb_irq & dma_irq & audio_irq) # active low, enable if one is low
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
self.submodules.exchange_with_mem = ExchangeWithMem(soc=self,
platform=platform,
tosbus_fifo=self.tosbus_fifo,
@ -434,8 +478,20 @@ class NuBusFPGA(SoCCore):
burst_size=burst_size,
do_checksum = False,
clock_domain="nubus")
self.comb += dma_irq.eq(self.exchange_with_mem.irq)
#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,
version=version,
@ -491,13 +547,17 @@ 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
if (sdcard):
self.add_sdcard()
# irq?
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 (False):
@ -515,14 +575,28 @@ def main():
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("--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]")
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.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)
if (args.ethernet and (args.version == "V1.0")):
print(" ***** ERROR ***** : Ethernet not supported on V1.0\n");
assert(False)
if (args.ethernet and args.flash):
print(" ***** ERROR ***** : Only one PMod usable on V1.2\n");
assert(False)
if ((not args.hdmi) and (args.version == "V1.2")):
print(" ***** ERROR ***** : VGA not supported on V1.2\n");
@ -535,6 +609,8 @@ def main():
goblin=args.goblin,
hdmi=args.hdmi,
goblin_res=args.goblin_res,
sdcard=args.sdcard,
flash=args.flash,
ethernet=args.ethernet)
version_for_filename = args.version.replace(".", "_")

View File

@ -214,17 +214,30 @@ connectors_v1_2 = [
("P1", "M1 L1 N2 N1 R2 P2 T1 R1 P4 P3 P5 N5"), # check sequence! currently in pmod-* order
]
# Extension
def flashtemp_pmod_io(pmod):
return [
# completely inconsistent with the SBus entry as P1 is in a different order...
("spiflash4x", 0,
Subsignal("cs_n", Pins(f"{pmod}:2")),
Subsignal("clk", Pins(f"{pmod}:5")),
Subsignal("dq", Pins(f"{pmod}:7 {pmod}:4 {pmod}:6 {pmod}:3")),
IOStandard("LVCMOS33")
),
]
_flashtemp_pmod_io_v1_2 = flashtemp_pmod_io("P1")
# Ethernet ----------------------------------------------------------------------------------------------
# custom not-quite-pmod
def rmii_eth_extpmod_io(extpmod):
return [
("eth_clocks", 0,
Subsignal("ref_clk", Pins(f"{extpmod}:10")),
Subsignal("ref_clk", Pins(f"{extpmod}:8")),
IOStandard("LVCMOS33"),
),
("eth", 0,
Subsignal("rst_n", Pins(f"{extpmod}:3")),
Subsignal("rx_data", Pins(f"{extpmod}:8 {extpmod}:11")),
Subsignal("rx_data", Pins(f"{extpmod}:11 {extpmod}:10")),
Subsignal("crs_dv", Pins(f"{extpmod}:6")),
Subsignal("tx_en", Pins(f"{extpmod}:2")),
Subsignal("tx_data", Pins(f"{extpmod}:0 {extpmod}:1")),