cleanup, CSR for prom & netbsd (preliminary)
This commit is contained in:
133
sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py
Normal file
133
sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py
Normal file
@@ -0,0 +1,133 @@
|
||||
import os
|
||||
import json
|
||||
import inspect
|
||||
from shutil import which
|
||||
from sysconfig import get_platform
|
||||
|
||||
from migen import *
|
||||
|
||||
from litex.soc.interconnect.csr import CSRStatus
|
||||
|
||||
from litex.build.tools import generated_banner
|
||||
|
||||
from litex.soc.doc.rst import reflow
|
||||
from litex.soc.doc.module import gather_submodules, ModuleNotDocumented, DocumentedModule, DocumentedInterrupts
|
||||
from litex.soc.doc.csr import DocumentedCSRRegion
|
||||
from litex.soc.interconnect.csr import _CompoundCSR
|
||||
|
||||
# for generating a timestamp in the description field, if none is otherwise given
|
||||
import datetime
|
||||
import time
|
||||
|
||||
def _get_rw_functions_c(name, csr_name, reg_base, area_base, nwords, busword, alignment, read_only, with_access_functions):
|
||||
reg_name = name + "_" + csr_name
|
||||
r = ""
|
||||
|
||||
addr_str = "CSR_{}_ADDR".format(reg_name.upper())
|
||||
size_str = "CSR_{}_SIZE".format(reg_name.upper())
|
||||
r += "#define {} (CSR_{}_BASE + {}L)\n".format(addr_str, name.upper(), hex(reg_base - area_base))
|
||||
r += "#define {} {}\n".format(size_str, nwords)
|
||||
|
||||
size = nwords*busword//8
|
||||
if size > 8:
|
||||
# downstream should select appropriate `csr_[rd|wr]_buf_uintX()` pair!
|
||||
return r
|
||||
elif size > 4:
|
||||
ctype = "uint64_t"
|
||||
elif size > 2:
|
||||
ctype = "uint32_t"
|
||||
elif size > 1:
|
||||
ctype = "uint16_t"
|
||||
else:
|
||||
ctype = "uint8_t"
|
||||
|
||||
stride = alignment//8;
|
||||
if with_access_functions:
|
||||
r += "static inline {} {}_read(struct sbusfpga_sdram_softc *sc) {{\n".format(ctype, reg_name)
|
||||
if nwords > 1:
|
||||
r += "\t{} r = bus_space_read_4(sc->sc_bustag, sc>sc_bhregs_{}, {}L);\n".format(ctype, name, hex(reg_base - area_base))
|
||||
for sub in range(1, nwords):
|
||||
r += "\tr <<= {};\n".format(busword)
|
||||
r += "\tr |= bus_space_read_4(sc->sc_bustag, sc>sc_bhregs_{}, {}L);\n".format(name, hex(reg_base - area_base + sub*stride))
|
||||
r += "\treturn r;\n}\n"
|
||||
else:
|
||||
r += "\treturn bus_space_read_4(sc->sc_bustag, sc>sc_bhregs_{}, {}L);\n}}\n".format(name, hex(reg_base - area_base))
|
||||
|
||||
if not read_only:
|
||||
r += "static inline void {}_write(struct sbusfpga_sdram_softc *sc, {} v) {{\n".format(reg_name, ctype)
|
||||
for sub in range(nwords):
|
||||
shift = (nwords-sub-1)*busword
|
||||
if shift:
|
||||
v_shift = "v >> {}".format(shift)
|
||||
else:
|
||||
v_shift = "v"
|
||||
r += "\tbus_space_write_4(sc->sc_bustag, sc>sc_bhregs_{}, {}L, {});\n".format(name, hex(reg_base - area_base + sub*stride), v_shift)
|
||||
r += "}\n"
|
||||
return r
|
||||
|
||||
|
||||
def get_csr_header(regions, constants, csr_base=None, with_access_functions=True):
|
||||
alignment = constants.get("CONFIG_CSR_ALIGNMENT", 32)
|
||||
r = generated_banner("//")
|
||||
#if with_access_functions: # FIXME
|
||||
# r += "#include <generated/soc.h>\n"
|
||||
r += "#ifndef __GENERATED_CSR_H\n#define __GENERATED_CSR_H\n"
|
||||
#if with_access_functions:
|
||||
# r += "#include <stdint.h>\n"
|
||||
# r += "#include <system.h>\n"
|
||||
# r += "#ifndef CSR_ACCESSORS_DEFINED\n"
|
||||
# r += "#include <hw/common.h>\n"
|
||||
# r += "#endif /* ! CSR_ACCESSORS_DEFINED */\n"
|
||||
csr_base = csr_base if csr_base is not None else regions[next(iter(regions))].origin
|
||||
r += "#ifndef CSR_BASE\n"
|
||||
r += "#define CSR_BASE {}L\n".format(hex(csr_base))
|
||||
r += "#endif\n"
|
||||
for name, region in regions.items():
|
||||
origin = region.origin - csr_base
|
||||
r += "\n/* "+name+" */\n"
|
||||
r += "#ifndef CSR_"+name.upper()+"_BASE\n"
|
||||
r += "#define CSR_"+name.upper()+"_BASE (CSR_BASE + "+hex(origin)+"L)\n"
|
||||
r += "#endif\n"
|
||||
if not isinstance(region.obj, Memory):
|
||||
for csr in region.obj:
|
||||
nr = (csr.size + region.busword - 1)//region.busword
|
||||
r += _get_rw_functions_c(name, csr.name, origin, region.origin - csr_base, nr, region.busword, alignment,
|
||||
getattr(csr, "read_only", False), with_access_functions)
|
||||
origin += alignment//8*nr
|
||||
if hasattr(csr, "fields"):
|
||||
for field in csr.fields.fields:
|
||||
offset = str(field.offset)
|
||||
size = str(field.size)
|
||||
r += "#define CSR_"+name.upper()+"_"+csr.name.upper()+"_"+field.name.upper()+"_OFFSET "+offset+"\n"
|
||||
r += "#define CSR_"+name.upper()+"_"+csr.name.upper()+"_"+field.name.upper()+"_SIZE "+size+"\n"
|
||||
if with_access_functions and csr.size <= 32: # FIXME: Implement extract/read functions for csr.size > 32-bit.
|
||||
reg_name = name + "_" + csr.name.lower()
|
||||
field_name = reg_name + "_" + field.name.lower()
|
||||
r += "static inline uint32_t " + field_name + "_extract(struct sbusfpga_sdram_softc *sc, uint32_t oldword) {\n"
|
||||
r += "\tuint32_t mask = ((1 << " + size + ")-1);\n"
|
||||
r += "\treturn ( (oldword >> " + offset + ") & mask );\n}\n"
|
||||
r += "static inline uint32_t " + field_name + "_read(struct sbusfpga_sdram_softc *sc) {\n"
|
||||
r += "\tuint32_t word = " + reg_name + "_read(sc);\n"
|
||||
r += "\treturn " + field_name + "_extract(word);\n"
|
||||
r += "}\n"
|
||||
if not getattr(csr, "read_only", False):
|
||||
r += "static inline uint32_t " + field_name + "_replace(struct sbusfpga_sdram_softc *sc, uint32_t oldword, uint32_t plain_value) {\n"
|
||||
r += "\tuint32_t mask = ((1 << " + size + ")-1);\n"
|
||||
r += "\treturn (oldword & (~(mask << " + offset + "))) | (mask & plain_value)<< " + offset + " ;\n}\n"
|
||||
r += "static inline void " + field_name + "_write(struct sbusfpga_sdram_softc *sc, uint32_t plain_value) {\n"
|
||||
r += "\tuint32_t oldword = " + reg_name + "_read(sc);\n"
|
||||
r += "\tuint32_t newword = " + field_name + "_replace(sc, oldword, plain_value);\n"
|
||||
r += "\t" + reg_name + "_write(sc, newword);\n"
|
||||
r += "}\n"
|
||||
|
||||
r += "\n#endif\n"
|
||||
return r
|
||||
|
||||
|
||||
def get_csr_forth_header(csr_regions, mem_regions, constants, csr_base=None):
|
||||
r = "\\ auto-generated base regions for CSRs in the PROM\n"
|
||||
for name, region in csr_regions.items():
|
||||
r += "h# " + hex(region.origin).replace("0x", "") + " constant " + "sbusfpga_csraddr_{}".format(name) + "\n"
|
||||
for name, region in mem_regions.items():
|
||||
r += "h# " + hex(region.origin).replace("0x", "") + " constant " + "sbusfpga_regionaddr_{}".format(name) + "\n"
|
||||
return r
|
||||
@@ -18,6 +18,8 @@ from litedram.phy import s7ddrphy
|
||||
|
||||
from sbus_to_fpga_fsm import *;
|
||||
|
||||
import sbus_to_fpga_export;
|
||||
|
||||
_sbus_sbus = [
|
||||
("SBUS_3V3_CLK", 0, Pins("D15"), IOStandard("lvttl")),
|
||||
("SBUS_3V3_ASs", 0, Pins("T4"), IOStandard("lvttl")),
|
||||
@@ -98,7 +100,7 @@ class _CRG(Module):
|
||||
|
||||
self.submodules.pll_idelay = pll_idelay = S7PLL(speedgrade=-1)
|
||||
pll_idelay.register_clkin(clk48, 48e6)
|
||||
pll_idelay.create_clkout(self.cd_idelay, 200e6)
|
||||
pll_idelay.create_clkout(self.cd_idelay, 200e6, margin = 0)
|
||||
self.comb += pll_idelay.reset.eq(~rst_sbus) # | ~por_done
|
||||
|
||||
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)
|
||||
@@ -122,6 +124,13 @@ class SBusFPGA(SoCCore):
|
||||
clk_freq=sys_clk_freq,
|
||||
csr_paging=0x1000, # default is 0x800
|
||||
**kwargs)
|
||||
|
||||
# This mem-map is also exposed in the FSM (matched prefixes)
|
||||
# and in the PROM (to tell NetBSD where everything is)
|
||||
# Currently it is a straight mapping between the two:
|
||||
# the physical address here are used as offset in the SBus
|
||||
# reserved area of 256 MiB
|
||||
# Anything at 0x10000000 is therefore unreachable directly
|
||||
wb_mem_map = {
|
||||
"prom": 0x00000000,
|
||||
"csr" : 0x00040000,
|
||||
@@ -180,66 +189,8 @@ class SBusFPGA(SoCCore):
|
||||
hold_reset = Signal(reset=1)
|
||||
self.comb += hold_reset.eq(~(hold_reset_ctr == 0))
|
||||
|
||||
|
||||
# FIFO to send data & address from SBus to the Wishbone
|
||||
##sbus_to_wishbone_wr_fifo = AsyncFIFOBuffered(width=32+30, depth=16)
|
||||
##sbus_to_wishbone_wr_fifo = ClockDomainsRenamer({"write": "sbus", "read": "sys"})(sbus_to_wishbone_wr_fifo)
|
||||
##self.submodules += sbus_to_wishbone_wr_fifo
|
||||
|
||||
# FIFOs to send address / receive data from SBus to the Wishbone
|
||||
##sbus_to_wishbone_rd_fifo_addr = AsyncFIFOBuffered(width=30, depth=16)
|
||||
##sbus_to_wishbone_rd_fifo_addr = ClockDomainsRenamer({"write": "sbus", "read": "sys"})(sbus_to_wishbone_rd_fifo_addr)
|
||||
##self.submodules += sbus_to_wishbone_rd_fifo_addr
|
||||
##sbus_to_wishbone_rd_fifo_data = AsyncFIFOBuffered(width=32+1, depth=16)
|
||||
##sbus_to_wishbone_rd_fifo_data = ClockDomainsRenamer({"write": "sys", "read": "sbus"})(sbus_to_wishbone_rd_fifo_data)
|
||||
##self.submodules += sbus_to_wishbone_rd_fifo_data
|
||||
|
||||
# SBus to Wishbone, 'Slave' on the SBus side, 'Master' on the Wishbone side
|
||||
##self.submodules.sbus_to_wishbone = SBusToWishbone(platform=self.platform,
|
||||
## wr_fifo=sbus_to_wishbone_wr_fifo,
|
||||
## rd_fifo_addr=sbus_to_wishbone_rd_fifo_addr,
|
||||
## rd_fifo_data=sbus_to_wishbone_rd_fifo_data,
|
||||
## wishbone=wishbone.Interface(data_width=self.bus.data_width))
|
||||
|
||||
|
||||
# FIFO to send data & address from Wishbone to the SBus
|
||||
##wishbone_to_sbus_wr_fifo = AsyncFIFOBuffered(width=32+30, depth=16)
|
||||
##wishbone_to_sbus_wr_fifo = ClockDomainsRenamer({"write": "sys", "read": "sbus"})(wishbone_to_sbus_wr_fifo)
|
||||
##self.submodules += wishbone_to_sbus_wr_fifo
|
||||
|
||||
# FIFOs to send address / receive data from Wishbone to the SBus
|
||||
##wishbone_to_sbus_rd_fifo_addr = AsyncFIFOBuffered(width=30, depth=4)
|
||||
##wishbone_to_sbus_rd_fifo_addr = ClockDomainsRenamer({"write": "sys", "read": "sbus"})(wishbone_to_sbus_rd_fifo_addr)
|
||||
##self.submodules += wishbone_to_sbus_rd_fifo_addr
|
||||
##wishbone_to_sbus_rd_fifo_data = AsyncFIFOBuffered(width=32+1, depth=4)
|
||||
##wishbone_to_sbus_rd_fifo_data = ClockDomainsRenamer({"write": "sbus", "read": "sys"})(wishbone_to_sbus_rd_fifo_data)
|
||||
##self.submodules += wishbone_to_sbus_rd_fifo_data
|
||||
|
||||
# Wishbone to SBus, 'Master' on the SBus side, 'Slave' on the Wishbone side
|
||||
##self.submodules.wishbone_to_sbus = WishboneToSBus(platform=self.platform,
|
||||
## soc=self,
|
||||
## wr_fifo=wishbone_to_sbus_wr_fifo,
|
||||
## rd_fifo_addr=wishbone_to_sbus_rd_fifo_addr,
|
||||
## rd_fifo_data=wishbone_to_sbus_rd_fifo_data,
|
||||
## wishbone=wishbone.Interface(data_width=self.bus.data_width))
|
||||
|
||||
##_sbus_bus = SBusFPGABus(platform=self.platform,
|
||||
## prom=prom,
|
||||
## hold_reset=hold_reset,
|
||||
## wr_fifo=sbus_to_wishbone_wr_fifo,
|
||||
## rd_fifo_addr=sbus_to_wishbone_rd_fifo_addr,
|
||||
## rd_fifo_data=sbus_to_wishbone_rd_fifo_data,
|
||||
## master_wr_fifo=wishbone_to_sbus_wr_fifo,
|
||||
## master_rd_fifo_addr=wishbone_to_sbus_rd_fifo_addr,
|
||||
## master_rd_fifo_data=wishbone_to_sbus_rd_fifo_data)
|
||||
##self.submodules.sbus_bus = ClockDomainsRenamer("sbus")(_sbus_bus)
|
||||
|
||||
#wishbone_slave = wishbone.Interface(data_width=self.bus.data_width)
|
||||
#wishbone_master = wishbone.Interface(data_width=self.bus.data_width)
|
||||
|
||||
#wishbone_slave = wishbone.Interface(data_width=self.bus.data_width)
|
||||
#wishbone_master = wishbone.Interface(data_width=self.bus.data_width)
|
||||
|
||||
# Interface SBus to wishbone
|
||||
# we need to cross clock domains
|
||||
wishbone_slave_sbus = wishbone.Interface(data_width=self.bus.data_width)
|
||||
wishbone_master_sys = wishbone.Interface(data_width=self.bus.data_width)
|
||||
self.submodules.wishbone_master_sbus = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_master_sys, cd_master="sbus", cd_slave="sys")
|
||||
@@ -253,11 +204,6 @@ class SBusFPGA(SoCCore):
|
||||
#self.submodules.sbus_bus = _sbus_bus
|
||||
self.submodules.sbus_bus = ClockDomainsRenamer("sbus")(_sbus_bus)
|
||||
|
||||
##self.bus.add_master(name="SBusBridgeToWishbone", master=self.sbus_to_wishbone.wishbone)
|
||||
##self.bus.add_slave(name="usb_fake_dma", slave=self.wishbone_to_sbus.wishbone, region=SoCRegion(origin=self.mem_map.get("usb_fake_dma", None), size=0x03ffffff, cached=False))
|
||||
|
||||
#self.bus.add_master(name="SBusBridgeToWishbone", master=self.sbus_bus.wishbone_master)
|
||||
#self.bus.add_slave(name="usb_fake_dma", slave=self.sbus_bus.wishbone_slave, region=SoCRegion(origin=self.mem_map.get("usb_fake_dma", None), size=0x03ffffff, cached=False))
|
||||
self.bus.add_master(name="SBusBridgeToWishbone", master=wishbone_master_sys)
|
||||
self.bus.add_slave(name="usb_fake_dma", slave=self.wishbone_slave_sys, region=SoCRegion(origin=self.mem_map.get("usb_fake_dma", None), size=0x03ffffff, cached=False))
|
||||
|
||||
@@ -273,18 +219,6 @@ class SBusFPGA(SoCCore):
|
||||
l2_cache_size = 0
|
||||
)
|
||||
|
||||
# self.soc = Module()
|
||||
# self.soc.mem_regions = self.mem_regions = {}
|
||||
# region = litex.soc.integration.soc.SoCRegion(origin=0x0, size=0x0)
|
||||
# region.length = 0
|
||||
# self.mem_regions['csr'] = region
|
||||
# self.soc.constants = self.constants = {}
|
||||
# self.soc.csr_regions = self.csr_regions = {}
|
||||
# self.soc.cpu_type = self.cpu_type = None
|
||||
|
||||
# def do_finalize(self):
|
||||
# self.platform.add_period_constraint(self.platform.lookup_request("SBUS_3V3_CLK", loose=True), 1e9/25e6)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="SbusFPGA")
|
||||
parser.add_argument("--build", action="store_true", help="Build bitstream")
|
||||
@@ -298,5 +232,20 @@ def main():
|
||||
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.
|
||||
csr_contents = sbus_to_fpga_export.get_csr_header(
|
||||
regions = soc.csr_regions,
|
||||
constants = soc.constants,
|
||||
csr_base = soc.mem_regions['csr'].origin)
|
||||
write_to_file(os.path.join("netbsd_csr.h"), csr_contents)
|
||||
|
||||
# tells the prom where to find what
|
||||
csr_forth_contents = sbus_to_fpga_export.get_csr_forth_header(
|
||||
csr_regions = soc.csr_regions,
|
||||
mem_regions = soc.mem_regions,
|
||||
constants = soc.constants,
|
||||
csr_base = soc.mem_regions['csr'].origin)
|
||||
write_to_file(os.path.join("prom_csr.fth"), csr_forth_contents)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user