Also, merge examples/{sdram,sram}_soc as minerva_soc.
--- /dev/null
+import argparse
+from collections import OrderedDict
+
+from nmigen import *
+from nmigen.lib.cdc import ResetSynchronizer
+from nmigen.build import *
+
+from nmigen_soc import wishbone
+from nmigen_soc.periph import ConstantMap
+
+from nmigen_stdio.serial import AsyncSerial
+
+from nmigen_boards.arty_a7 import ArtyA7_35Platform
+from nmigen_boards.ecpix5 import ECPIX545Platform, ECPIX585Platform
+
+from lambdasoc.cpu.minerva import MinervaCPU
+from lambdasoc.periph.intc import GenericInterruptController
+from lambdasoc.periph.serial import AsyncSerialPeripheral
+from lambdasoc.periph.sram import SRAMPeripheral
+from lambdasoc.periph.timer import TimerPeripheral
+from lambdasoc.periph.sdram import SDRAMPeripheral
+
+from lambdasoc.soc.cpu import CPUSoC, BIOSBuilder
+
+from lambdasoc.cores.pll.lattice_ecp5 import PLL_LatticeECP5
+from lambdasoc.cores.pll.xilinx_7series import PLL_Xilinx7Series
+from lambdasoc.cores import litedram
+from lambdasoc.cores.utils import request_bare
+
+from lambdasoc.sim.blackboxes.serial import AsyncSerial_Blackbox
+from lambdasoc.sim.platform import CXXRTLPlatform
+
+
+__all__ = ["MinervaSoC"]
+
+
+class _ClockResetGenerator(Elaboratable):
+ def __init__(self, *, sync_clk_freq, with_sdram):
+ if not isinstance(sync_clk_freq, (int, float)) or sync_clk_freq <= 0:
+ raise ValueError("Sync domain clock frequency must be a positive integer or float, "
+ "not {!r}"
+ .format(sync_clk_freq))
+ self.sync_clk_freq = sync_clk_freq
+ self.with_sdram = bool(with_sdram)
+
+ def elaborate(self, platform):
+ m = Module()
+
+ m.domains += [
+ ClockDomain("_ref", reset_less=platform.default_rst is None, local=True),
+ ClockDomain("sync"),
+ ]
+
+ m.d.comb += ClockSignal("_ref").eq(platform.request(platform.default_clk, 0).i)
+ if platform.default_rst is not None:
+ m.d.comb += ResetSignal("_ref").eq(platform.request(platform.default_rst, 0).i)
+
+ # The LiteDRAM core provides its own PLL, which drives the litedram_user clock domain.
+ # We reuse this clock domain as the sync domain, in order to avoid CDC between LiteDRAM
+ # and the SoC interconnect.
+ if self.with_sdram:
+ m.domains += ClockDomain("litedram_input")
+ m.d.comb += ClockSignal("litedram_input").eq(ClockSignal("_ref"))
+ if platform.default_rst is not None:
+ m.d.comb += ResetSignal("litedram_input").eq(ResetSignal("_ref"))
+
+ m.domains += ClockDomain("litedram_user")
+ m.d.comb += [
+ ClockSignal("sync").eq(ClockSignal("litedram_user")),
+ ResetSignal("sync").eq(ResetSignal("litedram_user")),
+ ]
+
+ # In simulation mode, the sync clock domain is directly driven by the platform clock.
+ elif isinstance(platform, CXXRTLPlatform):
+ assert self.sync_clk_freq == platform.default_clk_frequency
+ m.d.comb += ClockSignal("sync").eq(ClockSignal("_ref"))
+ if platform.default_rst is not None:
+ m.d.comb += ResetSignal("sync").eq(ResetSignal("_ref"))
+
+ # Otherwise, we use a PLL to drive the sync clock domain.
+ else:
+ if isinstance(platform, ArtyA7_35Platform):
+ sync_pll_params = PLL_Xilinx7Series.Parameters(
+ i_domain = "_ref",
+ i_freq = platform.default_clk_frequency,
+ i_reset_less = platform.default_rst is None,
+ o_domain = "sync",
+ o_freq = self.sync_clk_freq,
+ )
+ m.submodules.sync_pll = sync_pll = PLL_Xilinx7Series(sync_pll_params)
+ elif isinstance(platform, (ECPIX545Platform, ECPIX585Platform)):
+ sync_pll_params = PLL_LatticeECP5.Parameters(
+ i_domain = "_ref",
+ i_freq = platform.default_clk_frequency,
+ i_reset_less = platform.default_rst is None,
+ o_domain = "sync",
+ o_freq = self.sync_clk_freq,
+ )
+ m.submodules.sync_pll = sync_pll = PLL_LatticeECP5(sync_pll_params)
+ else:
+ assert False
+
+ if self.platform.default_rst is not None:
+ sync_pll_arst = ~sync_pll.locked | ResetSignal("_ref")
+ else:
+ sync_pll_arst = ~sync_pll.locked
+
+ m.submodules += ResetSynchronizer(sync_pll_arst, domain="sync")
+
+ return m
+
+
+class MinervaSoC(CPUSoC, Elaboratable):
+ def __init__(self,
+ sync_clk_freq,
+ cpu_core,
+ bootrom_addr,
+ bootrom_size,
+ scratchpad_addr,
+ scratchpad_size,
+ uart_core,
+ uart_addr,
+ uart_irqno,
+ timer_addr,
+ timer_width,
+ timer_irqno):
+ if not isinstance(sync_clk_freq, (int, float)) or sync_clk_freq <= 0:
+ raise ValueError("Sync domain clock frequency must be a positive integer or float, "
+ "not {!r}"
+ .format(sync_clk_freq))
+ self.sync_clk_freq = int(sync_clk_freq)
+
+ if not isinstance(cpu_core, MinervaCPU):
+ raise TypeError("CPU core must be an instance of MinervaCPU, not {!r}"
+ .format(cpu_core))
+ self.cpu = cpu_core
+
+ self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8,
+ features={"cti", "bte", "err"})
+ self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8,
+ features={"cti", "bte", "err"})
+
+ self._arbiter.add(self.cpu.ibus)
+ self._arbiter.add(self.cpu.dbus)
+
+ self.intc = GenericInterruptController(width=len(self.cpu.ip))
+
+ self.bootrom = SRAMPeripheral(size=bootrom_size, writable=False)
+ self._decoder.add(self.bootrom.bus, addr=bootrom_addr)
+
+ self.scratchpad = SRAMPeripheral(size=scratchpad_size)
+ self._decoder.add(self.scratchpad.bus, addr=scratchpad_addr)
+
+ self.uart = AsyncSerialPeripheral(core=uart_core)
+ self._decoder.add(self.uart.bus, addr=uart_addr)
+ self.intc.add_irq(self.uart.irq, index=uart_irqno)
+
+ self.timer = TimerPeripheral(width=timer_width)
+ self._decoder.add(self.timer.bus, addr=timer_addr)
+ self.intc.add_irq(self.timer.irq, index=timer_irqno)
+
+ self._sdram = None
+ self._sram = None
+
+ @property
+ def memory_map(self):
+ return self._decoder.bus.memory_map
+
+ @property
+ def constants(self):
+ return super().constants.union(
+ SDRAM = self.sdram .constant_map if self.sdram is not None else None,
+ SOC = ConstantMap(
+ WITH_SDRAM = self.sdram is not None,
+ MEMTEST_ADDR_SIZE = 8192,
+ MEMTEST_DATA_SIZE = 8192,
+ ),
+ )
+
+ @property
+ def mainram(self):
+ assert not (self._sdram and self.sram)
+ return self._sdram or self._sram
+
+ @property
+ def sdram(self):
+ return self._sdram
+
+ @property
+ def sram(self):
+ return self._sram
+
+ def add_sdram(self, core, *, addr, cache_size):
+ if self.mainram is not None:
+ raise AttributeError("Main RAM has already been set to {!r}".format(self.mainram))
+ if core.config.user_clk_freq != self.sync_clk_freq:
+ raise ValueError("LiteDRAM user domain clock frequency ({} MHz) must match sync "
+ "domain clock frequency ({} MHz)"
+ .format(core.config.user_clk_freq / 1e6, self.sync_clk_freq / 1e6))
+ self._sdram = SDRAMPeripheral(core=core, cache_size=cache_size)
+ self._decoder.add(self._sdram.bus, addr=addr)
+
+ def add_internal_sram(self, *, addr, size):
+ if self.mainram is not None:
+ raise AttributeError("Main RAM has already been set to {!r}".format(self.mainram))
+ self._sram = SRAMPeripheral(size=size)
+ self._decoder.add(self._sram.bus, addr=addr)
+
+ def elaborate(self, platform):
+ m = Module()
+
+ m.submodules.crg = _ClockResetGenerator(
+ sync_clk_freq = self.sync_clk_freq,
+ with_sdram = self.sdram is not None,
+ )
+
+ m.submodules.cpu = self.cpu
+ m.submodules.arbiter = self._arbiter
+ m.submodules.decoder = self._decoder
+ m.submodules.uart = self.uart
+ m.submodules.timer = self.timer
+ m.submodules.intc = self.intc
+ m.submodules.bootrom = self.bootrom
+ m.submodules.scratchpad = self.scratchpad
+
+ if self.sdram is not None:
+ m.submodules.sdram = self.sdram
+ if self.sram is not None:
+ m.submodules.sram = self.sram
+
+ m.d.comb += [
+ self._arbiter.bus.connect(self._decoder.bus),
+ self.cpu.ip.eq(self.intc.ip),
+ ]
+
+ return m
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--build-dir", type=str,
+ default="build/minerva_soc",
+ help="local build directory (default: 'build/sdram_soc')")
+ parser.add_argument("--platform", type=str,
+ choices=("sim", "arty_a7", "ecpix5_45", "ecpix5_85"),
+ default="sim",
+ help="target platform")
+ parser.add_argument("--sync-clk-freq", type=int,
+ default=75,
+ help="SoC clock frequency, in MHz. (default: 75)")
+ parser.add_argument("--with-sdram", action="store_true",
+ help="enable SDRAM")
+ parser.add_argument("--internal-sram-size", type=int,
+ default=8192,
+ help="Internal RAM size, in bytes. Ignored if --with-sdram is provided. "
+ "(default: 8192)")
+ parser.add_argument("--baudrate", type=int,
+ default=9600,
+ help="UART baudrate (default: 9600)")
+ args = parser.parse_args()
+
+ # Platform selection
+
+ if args.platform == "sim":
+ platform = CXXRTLPlatform()
+ elif args.platform == "arty_a7":
+ platform = ArtyA7_35Platform()
+ elif args.platform == "ecpix5_45":
+ platform = ECPIX545Platform()
+ elif args.platform == "ecpix5_85":
+ platform = ECPIX585Platform()
+ else:
+ assert False
+
+ # LiteDRAM
+
+ if args.with_sdram:
+ if isinstance(platform, CXXRTLPlatform):
+ litedram_config = litedram.ECP5Config(
+ memtype = "DDR3",
+ module_name = "MT41K256M16",
+ module_bytes = 2,
+ module_ranks = 1,
+ input_clk_freq = int(platform.default_clk_frequency),
+ user_clk_freq = int(platform.default_clk_frequency),
+ init_clk_freq = int(1e6),
+ )
+ elif isinstance(platform, ArtyA7_35Platform):
+ litedram_config = litedram.Artix7Config(
+ memtype = "DDR3",
+ speedgrade = "-1",
+ cmd_latency = 0,
+ module_name = "MT41K128M16",
+ module_bytes = 2,
+ module_ranks = 1,
+ rtt_nom = 60,
+ rtt_wr = 60,
+ ron = 34,
+ input_clk_freq = int(platform.default_clk_frequency),
+ user_clk_freq = int(args.sync_clk_freq * 1e6),
+ iodelay_clk_freq = int(200e6),
+ )
+ elif isinstance(platform, (ECPIX545Platform, ECPIX585Platform)):
+ litedram_config = litedram.ECP5Config(
+ memtype = "DDR3",
+ module_name = "MT41K256M16",
+ module_bytes = 2,
+ module_ranks = 1,
+ input_clk_freq = int(platform.default_clk_frequency),
+ user_clk_freq = int(args.sync_clk_freq * 1e6),
+ init_clk_freq = int(25e6),
+ )
+ else:
+ assert False
+
+ if isinstance(platform, CXXRTLPlatform):
+ litedram_pins = None
+ else:
+ litedram_pins = request_bare(platform, "ddr3", 0)
+
+ litedram_core = litedram.Core(litedram_config, pins=litedram_pins)
+ litedram_core.build(litedram.Builder(), platform, args.build_dir,
+ sim=isinstance(platform, CXXRTLPlatform))
+ mainram_size = litedram_core.size
+ else:
+ litedram_core = None
+ mainram_size = args.internal_sram_size
+
+ # UART
+
+ if isinstance(platform, CXXRTLPlatform):
+ uart_core = AsyncSerial_Blackbox(
+ data_bits = 8,
+ divisor = 1,
+ )
+ else:
+ uart_core = AsyncSerial(
+ data_bits = 8,
+ divisor = int(args.sync_clk_freq * 1e6 // args.baudrate),
+ pins = platform.request("uart", 0),
+ )
+
+ # SoC and BIOS
+
+ if isinstance(platform, CXXRTLPlatform):
+ sync_clk_freq = platform.default_clk_frequency
+ else:
+ sync_clk_freq = int(args.sync_clk_freq * 1e6)
+
+ soc = MinervaSoC(
+ sync_clk_freq = sync_clk_freq,
+
+ cpu_core = MinervaCPU(
+ reset_address = 0x00000000,
+ with_icache = True,
+ icache_nlines = 16,
+ icache_nwords = 4,
+ icache_nways = 1,
+ icache_base = 0x40000000,
+ icache_limit = 0x40000000 + mainram_size,
+ with_dcache = True,
+ dcache_nlines = 16,
+ dcache_nwords = 4,
+ dcache_nways = 1,
+ dcache_base = 0x40000000,
+ dcache_limit = 0x40000000 + mainram_size,
+ with_muldiv = True,
+ ),
+
+ bootrom_addr = 0x00000000,
+ bootrom_size = 0x8000,
+ scratchpad_addr = 0x00008000,
+ scratchpad_size = 0x1000,
+
+ uart_addr = 0x80000000,
+ uart_core = uart_core,
+ uart_irqno = 1,
+ timer_addr = 0x80001000,
+ timer_width = 32,
+ timer_irqno = 0,
+ )
+
+ if args.with_sdram:
+ soc.add_sdram(litedram_core, addr=0x40000000, cache_size=4096)
+ else:
+ soc.add_internal_sram(addr=0x40000000, size=args.internal_sram_size)
+
+ soc.build(build_dir=args.build_dir, do_init=True)
+
+ if isinstance(platform, CXXRTLPlatform):
+ platform.build(soc, build_dir=args.build_dir, blackboxes={
+ "lambdasoc.sim.blackboxes.serial": "serial_pty",
+ })
+ else:
+ platform.build(soc, build_dir=args.build_dir, do_program=True)
+++ /dev/null
-import argparse
-
-from nmigen import *
-from nmigen.build import *
-from nmigen_soc import wishbone
-
-from lambdasoc.cpu.minerva import MinervaCPU
-from lambdasoc.periph.intc import GenericInterruptController
-from lambdasoc.periph.serial import AsyncSerialPeripheral
-from lambdasoc.periph.sram import SRAMPeripheral
-from lambdasoc.periph.timer import TimerPeripheral
-from lambdasoc.periph.sdram import SDRAMPeripheral
-from lambdasoc.soc.cpu import CPUSoC
-
-from lambdasoc.cores import litedram
-
-
-__all__ = ["SDRAMSoC"]
-
-
-class SDRAMSoC(CPUSoC, Elaboratable):
- def __init__(self, *, reset_addr, clk_freq,
- rom_addr, rom_size,
- ram_addr, ram_size,
- uart_addr, uart_divisor, uart_pins,
- timer_addr, timer_width,
- sdram_addr, sdram_core, sdram_cache_size):
- self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8,
- features={"cti", "bte"})
- self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8,
- features={"cti", "bte"})
-
- self.cpu = MinervaCPU(
- reset_address=reset_addr,
- with_icache=True, icache_nlines=64, icache_nwords=4, icache_nways=1,
- icache_base=sdram_addr, icache_limit=sdram_addr + sdram_core.size,
- with_dcache=True, dcache_nlines=64, dcache_nwords=4, dcache_nways=1,
- dcache_base=sdram_addr, dcache_limit=sdram_addr + sdram_core.size,
- with_muldiv=True,
- )
- self._arbiter.add(self.cpu.ibus)
- self._arbiter.add(self.cpu.dbus)
-
- self.rom = SRAMPeripheral(size=rom_size, writable=False)
- self._decoder.add(self.rom.bus, addr=rom_addr)
-
- self.ram = SRAMPeripheral(size=ram_size)
- self._decoder.add(self.ram.bus, addr=ram_addr)
-
- self.sdram = SDRAMPeripheral(core=sdram_core, cache_size=sdram_cache_size)
- self._decoder.add(self.sdram.bus, addr=sdram_addr)
-
- self.uart = AsyncSerialPeripheral(divisor=uart_divisor, pins=uart_pins)
- self._decoder.add(self.uart.bus, addr=uart_addr)
-
- self.timer = TimerPeripheral(width=timer_width)
- self._decoder.add(self.timer.bus, addr=timer_addr)
-
- self.intc = GenericInterruptController(width=len(self.cpu.ip))
- self.intc.add_irq(self.timer.irq, 0)
- self.intc.add_irq(self.uart .irq, 1)
-
- self.memory_map = self._decoder.bus.memory_map
-
- self.clk_freq = clk_freq
-
- def elaborate(self, platform):
- m = Module()
-
- m.domains += [
- ClockDomain("litedram_input"),
- ClockDomain("litedram_user"),
- ClockDomain("sync"),
- ]
-
- m.d.comb += [
- ClockSignal("litedram_input").eq(platform.request("clk100", 0).i),
-
- ClockSignal("sync").eq(ClockSignal("litedram_user")),
- ResetSignal("sync").eq(ResetSignal("litedram_user")),
- ]
-
- m.submodules.arbiter = self._arbiter
- m.submodules.cpu = self.cpu
-
- m.submodules.decoder = self._decoder
- m.submodules.rom = self.rom
- m.submodules.ram = self.ram
- m.submodules.sdram = self.sdram
- m.submodules.uart = self.uart
- m.submodules.timer = self.timer
- m.submodules.intc = self.intc
-
- m.d.comb += [
- self._arbiter.bus.connect(self._decoder.bus),
- self.cpu.ip.eq(self.intc.ip),
- ]
-
- return m
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser()
- parser.add_argument("--platform", type=str,
- choices=("arty_a7", "ecpix5_85"),
- help="target platform")
- parser.add_argument("--baudrate", type=int,
- default=9600,
- help="UART baudrate (default: 9600)")
- parser.add_argument("--build-dir", type=str,
- default="build",
- help="local build directory (default: 'build')")
- args = parser.parse_args()
-
- if args.platform == "arty_a7":
- from nmigen_boards.arty_a7 import ArtyA7_35Platform
- platform = ArtyA7_35Platform()
- litedram_cfg = litedram.Artix7Config(
- memtype = "DDR3",
- speedgrade = "-1",
- cmd_latency = 0,
- module_name = "MT41K128M16",
- module_bytes = 2,
- module_ranks = 1,
- rtt_nom = 60,
- rtt_wr = 60,
- ron = 34,
- input_clk_freq = int(100e6),
- user_clk_freq = int(100e6),
- iodelay_clk_freq = int(200e6),
- )
- elif args.platform == "ecpix5_85":
- from nmigen_boards.ecpix5 import ECPIX585Platform
- platform = ECPIX585Platform()
- litedram_cfg = litedram.ECP5Config(
- memtype = "DDR3",
- module_name = "MT41K256M16",
- module_bytes = 2,
- module_ranks = 1,
- input_clk_freq = int(100e6),
- user_clk_freq = int(70e6),
- init_clk_freq = int(25e6),
- )
- else:
- assert False
-
- litedram_pins = litedram_cfg.request_pins(platform, "ddr3", 0)
- litedram_core = litedram.Core(litedram_cfg, pins=litedram_pins)
-
- litedram_builder = litedram.Builder()
- litedram_build_dir = f"{args.build_dir}/litedram"
- litedram_products = litedram_core.build(litedram_builder, build_dir=litedram_build_dir)
-
- litedram_core_v = f"{litedram_core.name}/{litedram_core.name}.v"
- platform.add_file(litedram_core_v, litedram_products.get(litedram_core_v, mode="t"))
-
- soc = SDRAMSoC(
- reset_addr=0x30000000, clk_freq=litedram_cfg.user_clk_freq,
- uart_addr=0x00005000, uart_divisor=int(litedram_cfg.user_clk_freq // args.baudrate),
- uart_pins=platform.request("uart", 0),
- timer_addr=0x00006000, timer_width=32,
-
- rom_addr=0x30000000, rom_size=0x8000,
- ram_addr=0x30008000, ram_size=0x1000,
- sdram_addr=0x40000000, sdram_core=litedram_core, sdram_cache_size=8192,
- )
-
- soc.build(build_dir=f"{args.build_dir}/soc", litedram_dir=litedram_build_dir, do_init=True)
-
- platform.build(soc, build_dir=args.build_dir, do_program=True)
+++ /dev/null
-import argparse
-import importlib
-
-from nmigen import *
-from nmigen_soc import wishbone
-
-from lambdasoc.cpu.minerva import MinervaCPU
-from lambdasoc.periph.intc import GenericInterruptController
-from lambdasoc.periph.serial import AsyncSerialPeripheral
-from lambdasoc.periph.sram import SRAMPeripheral
-from lambdasoc.periph.timer import TimerPeripheral
-from lambdasoc.soc.cpu import CPUSoC
-
-
-__all__ = ["SRAMSoC"]
-
-
-class SRAMSoC(CPUSoC, Elaboratable):
- def __init__(self, *, reset_addr, clk_freq,
- rom_addr, rom_size,
- ram_addr, ram_size,
- uart_addr, uart_divisor, uart_pins,
- timer_addr, timer_width):
- self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8,
- features={"cti", "bte"})
- self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8,
- features={"cti", "bte"})
-
- self.cpu = MinervaCPU(reset_address=reset_addr)
- self._arbiter.add(self.cpu.ibus)
- self._arbiter.add(self.cpu.dbus)
-
- self.rom = SRAMPeripheral(size=rom_size, writable=False)
- self._decoder.add(self.rom.bus, addr=rom_addr)
-
- self.ram = SRAMPeripheral(size=ram_size)
- self._decoder.add(self.ram.bus, addr=ram_addr)
-
- self.uart = AsyncSerialPeripheral(divisor=uart_divisor, pins=uart_pins)
- self._decoder.add(self.uart.bus, addr=uart_addr)
-
- self.timer = TimerPeripheral(width=timer_width)
- self._decoder.add(self.timer.bus, addr=timer_addr)
-
- self.intc = GenericInterruptController(width=len(self.cpu.ip))
- self.intc.add_irq(self.timer.irq, 0)
- self.intc.add_irq(self.uart .irq, 1)
-
- self.memory_map = self._decoder.bus.memory_map
-
- self.clk_freq = clk_freq
-
- def elaborate(self, platform):
- m = Module()
-
- m.submodules.arbiter = self._arbiter
- m.submodules.cpu = self.cpu
-
- m.submodules.decoder = self._decoder
- m.submodules.rom = self.rom
- m.submodules.ram = self.ram
- m.submodules.uart = self.uart
- m.submodules.timer = self.timer
- m.submodules.intc = self.intc
-
- m.d.comb += [
- self._arbiter.bus.connect(self._decoder.bus),
- self.cpu.ip.eq(self.intc.ip),
- ]
-
- return m
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser()
- parser.add_argument("platform", type=str,
- help="target platform (e.g. 'nmigen_boards.arty_a7.ArtyA7_35Platform')")
- parser.add_argument("--baudrate", type=int,
- default=9600,
- help="UART baudrate (default: 9600)")
- parser.add_argument("--build-dir", type=str,
- default="build",
- help="local build directory (default: 'build')")
- args = parser.parse_args()
-
- def get_platform(platform_name):
- module_name, class_name = platform_name.rsplit(".", 1)
- module = importlib.import_module(name=module_name)
- platform_class = getattr(module, class_name)
- return platform_class()
-
- platform = get_platform(args.platform)
-
- uart_divisor = int(platform.default_clk_frequency // args.baudrate)
- uart_pins = platform.request("uart", 0)
-
- soc = SRAMSoC(
- reset_addr=0x00000000, clk_freq=int(platform.default_clk_frequency),
- rom_addr=0x00000000, rom_size=0x4000,
- ram_addr=0x00004000, ram_size=0x1000,
- uart_addr=0x00005000, uart_divisor=uart_divisor, uart_pins=uart_pins,
- timer_addr=0x00006000, timer_width=32,
- )
-
- soc.build(build_dir=f"{args.build_dir}/soc", do_init=True)
-
- platform.build(soc, build_dir=args.build_dir, do_program=True)
from nmigen import *
from nmigen import tracer
+from nmigen.build.plat import Platform
from nmigen.build.run import BuildPlan, BuildProducts
from nmigen.utils import log2_int
assert module.memtype == self.memtype
return module
- def request_pins(self, platform, name, number):
- """Request DRAM pins.
-
- This helper requests the DRAM pins with `dir="-"` and `xdr=0`, because LiteDRAM already
- provides its own I/O buffers.
-
- Arguments
- ---------
- platform : :class:`nmigen.build.Platform`
- Target platform.
- name : str
- DRAM resource name.
- number : int
- DRAM resource number.
-
- Return value
- ------------
- A :class:`Record` providing raw access to DRAM pins.
- """
- res = platform.lookup(name, number)
- return platform.request(
- name, number,
- dir={io.name: "-" for io in res.ios},
- xdr={io.name: 0 for io in res.ios},
- )
-
class ECP5Config(Config):
phy_name = "ECP5DDRPHY"
)
self._ctrl_bus.memory_map = ctrl_map
- def build(self, builder, *, do_build=True, build_dir="build/litedram", sim=False,
- name_force=False):
+ def build(self, builder, platform, build_dir, *, do_build=True, sim=False, name_force=False):
"""Build the LiteDRAM core.
Arguments
---------
builder: :class:`litedram.Builder`
Builder instance.
+ platform: :class:`nmigen.build.Platform`
+ Target platform.
+ build_dir : str
+ Root build directory.
do_build : bool
Execute the build locally. Defaults to ``True``.
- build_dir : str
- Root build directory. Defaults to ``"build/litedram"``.
sim : bool
Do the build in simulation mode (i.e. by replacing the PHY with a model). Defaults to
``False``.
if not isinstance(builder, Builder):
raise TypeError("Builder must be an instance of litedram.Builder, not {!r}"
.format(builder))
+ if not isinstance(platform, Platform):
+ raise TypeError("Platform must be an instance of nmigen.build.Platform, not {!r}"
+ .format(platform))
plan = builder.prepare(self, sim=sim, name_force=name_force)
if not do_build:
return plan
- products = plan.execute_local(build_dir)
+ products = plan.execute_local(f"{build_dir}/{__package__}")
self._populate_ctrl_map(products)
+
+ core_src = f"{self.name}/{self.name}.v"
+ platform.add_file(core_src, products.get(core_src, mode="t"))
+
return products
def elaborate(self, platform):
--- /dev/null
+def request_bare(platform, name, number):
+ """Request bare pins.
+
+ This helper requests pins with `dir="-"` and `xdr=0`, for use cases where implicit I/O
+ buffers are undesirable.
+
+ Arguments
+ ---------
+ platform : :class:`nmigen.build.plat.Platform`
+ Target platform.
+ name : str
+ Resource name.
+ number : int
+ Resource number.
+
+ Return value
+ ------------
+ A :class:`Record` providing raw access to pins.
+ """
+ res = platform.lookup(name, number)
+ return platform.request(
+ name, number,
+ dir={io.name: "-" for io in res.ios},
+ xdr={io.name: 0 for io in res.ios},
+ )
"periph_size": periph_size,
"soc": soc,
"software_dir": os.path.dirname(software.__file__),
+ "constants": soc.constants,
+ "ConstantAddr": ConstantAddr,
**render_params,
})
import os
+from nmigen_soc.periph import ConstantMap, ConstantBool, ConstantInt
+
from .base import *
from ..cpu import CPU
+from ..cores import litedram
from ..periph.intc import InterruptController
from ..periph.sram import SRAMPeripheral
-from ..periph.sdram import SDRAMPeripheral
from ..periph.serial import AsyncSerialPeripheral
from ..periph.timer import TimerPeripheral
class CPUSoC(SoC):
- cpu = socproperty(CPU)
- intc = socproperty(InterruptController)
- rom = socproperty(SRAMPeripheral)
- ram = socproperty(SRAMPeripheral)
- sdram = socproperty(SDRAMPeripheral, weak=True)
- uart = socproperty(AsyncSerialPeripheral)
- timer = socproperty(TimerPeripheral)
+ cpu = socproperty(CPU)
+ intc = socproperty(InterruptController)
+ bootrom = socproperty(SRAMPeripheral)
+ scratchpad = socproperty(SRAMPeripheral)
+ uart = socproperty(AsyncSerialPeripheral)
+ timer = socproperty(TimerPeripheral)
# TODO: implement a CRG peripheral and expose clock frequencies through CSRs.
- clk_freq = socproperty(int)
-
- def build(self, name=None,
- litedram_dir="build/litedram",
- build_dir="build/soc", do_build=True,
- do_init=False):
+ sync_clk_freq = socproperty(int)
+
+ @property
+ def constants(self):
+ return ConstantMapCollection(
+ CPU = self.cpu.constant_map,
+ INTC = self.intc.constant_map,
+ BOOTROM = self.bootrom.constant_map,
+ SCRATCHPAD = self.scratchpad.constant_map,
+ UART = self.uart.constant_map,
+ TIMER = self.timer.constant_map,
+ SOC = ConstantMap(
+ CLOCK_FREQ = self.sync_clk_freq,
+ CSR_DATA_WIDTH = 32,
+ ),
+ )
+
+ def build(self, build_dir, name=None, do_build=True, do_init=False):
"""TODO
"""
- plan = BIOSBuilder().prepare(self, build_dir, name,
- litedram_dir=os.path.abspath(litedram_dir))
+ plan = BIOSBuilder().prepare(self, build_dir, name)
if not do_build:
return plan
if not do_init:
return products
- with products.extract("bios/bios.bin") as bios_filename:
+ with products.extract(f"{__name__}/bios/bios.bin") as bios_filename:
with open(bios_filename, "rb") as f:
words = iter(lambda: f.read(self.cpu.data_width // 8), b'')
bios = [int.from_bytes(w, self.cpu.byteorder) for w in words]
- self.rom.init = bios
+ self.bootrom.init = bios
+
+
+def kconfig_format(key, const, prefix="CONFIG_"):
+ if not isinstance(key, str) or not key:
+ raise ValueError("Key must be a non-empty string, not {!r}".format(key))
+ if isinstance(const, ConstantBool):
+ value = "y" if const.value else "n"
+ elif isinstance(const, ConstantAddr):
+ value = hex(const.value)
+ elif isinstance(const, ConstantInt):
+ value = const.value
+ else:
+ raise TypeError("Unsupported constant type, must be ConstantBool, ConstantAddr or "
+ "ConstantInt, not {!r}"
+ .format(const))
+ return "{}{}={}".format(prefix, key.upper(), value)
+
+
+def cpp_format(key, const, prefix=""):
+ if not isinstance(key, str) or not key:
+ raise ValueError("Key must be a non-empty string, not {!r}".format(key))
+ if isinstance(const, ConstantBool):
+ value = 1 if const.value else 0
+ elif isinstance(const, ConstantAddr):
+ value = "{:#x}UL".format(const.value)
+ elif isinstance(const, ConstantInt):
+ value = "{}{}".format(const.value, "U" if not const.signed else "")
+ else:
+ raise TypeError("Unsupported constant type, must be ConstantBool, ConstantAddr or "
+ "ConstantInt, not {!r}"
+ .format(const))
+ return "#define {}{} {}".format(prefix, key.upper(), value)
class BIOSBuilder(ConfigBuilder):
file_templates = {
**ConfigBuilder.file_templates,
- "{{name}}.config": r"""
+ "/".join([__name__, "{{name}}.config"]): r"""
# {{autogenerated}}
- CONFIG_CPU_{{soc.cpu.name.upper()}}=y
- CONFIG_CPU_RESET_ADDR={{hex(soc.cpu.reset_addr)}}
- CONFIG_CPU_BYTEORDER="{{soc.cpu.byteorder}}"
- CONFIG_ARCH_{{soc.cpu.arch.upper()}}=y
- {% if soc.cpu.muldiv == "soft" %}
- CONFIG_{{soc.cpu.arch.upper()}}_MULDIV_SOFT=y
- {% else %}
- CONFIG_{{soc.cpu.arch.upper()}}_MULDIV_SOFT=n
- {% endif %}
- CONFIG_ROM_START={{hex(periph_addr(soc.rom))}}
- CONFIG_ROM_SIZE={{hex(soc.rom.size)}}
- CONFIG_RAM_START={{hex(periph_addr(soc.ram))}}
- CONFIG_RAM_SIZE={{hex(soc.ram.size)}}
- CONFIG_UART_START={{hex(periph_addr(soc.uart))}}
- CONFIG_UART_IRQNO={{soc.intc.find_index(soc.uart.irq)}}
- CONFIG_UART_RX_RINGBUF_SIZE_LOG2=7
- CONFIG_UART_TX_RINGBUF_SIZE_LOG2=7
- CONFIG_TIMER_START={{hex(periph_addr(soc.timer))}}
- CONFIG_TIMER_IRQNO={{soc.intc.find_index(soc.timer.irq)}}
- CONFIG_TIMER_CTR_WIDTH={{soc.timer.width}}
- CONFIG_CLOCK_FREQ={{soc.clk_freq}}
- {% if soc.sdram is not none %}
- CONFIG_WITH_SDRAM=y
- CONFIG_SDRAM_START={{hex(periph_addr(soc.sdram))}}
- CONFIG_SDRAM_SIZE={{hex(soc.sdram.core.size)}}
- {% else %}
- CONFIG_WITH_SDRAM=n
- {% endif %}
+ # Configuration constants
+ {% for key, value in constants.flatten(separator="_") %}
+ {{kconfig_format(key, value)}}
+ {% endfor %}
+
+ # Memory regions
+ {% for window, (start, stop, step) in soc.memory_map.windows() %}
+ {% set window_name = window.name.upper() %}
+ {{kconfig_format(window_name + "_BASE", ConstantAddr(start))}}
+ {{kconfig_format(window_name + "_LIMIT", ConstantAddr(stop))}}
+ {% endfor %}
""",
- "litex_config.h": r"""
+ "/".join([__name__, "litex_config.h"]): r"""
// {{autogenerated}}
#ifndef __LITEX_CONFIG_H_LAMBDASOC
#define __LITEX_CONFIG_H_LAMBDASOC
- #define LX_CONFIG_TIMER_START {{hex(periph_addr(soc.timer))}}
+ // Configuration constants
+ {% for key, value in constants.flatten(separator="_") %}
+ {{cpp_format(key, value, prefix="LX_CONFIG_")}}
+ {% endfor %}
+
+ // Memory regions
+ {% for window, (start, stop, step) in soc.memory_map.windows() %}
+ {% set window_name = window.name.upper() %}
+ {{cpp_format(window_name + "_BASE", ConstantAddr(start), prefix="LX_CONFIG_")}}
+ {{cpp_format(window_name + "_LIMIT", ConstantAddr(stop), prefix="LX_CONFIG_")}}
+ {% endfor %}
{% if soc.sdram is not none %}
- #define LX_CONFIG_SDRAM_START {{hex(periph_addr(soc.sdram))}}UL
- #define LX_CONFIG_SDRAM_SIZE {{hex(soc.sdram.core.size)}}UL
- #define LX_CONFIG_SDRAM_CACHE_SIZE {{soc.sdram._cache.size}}
- #define LX_CONFIG_MEMTEST_DATA_SIZE 2*1024*1024
- #define LX_CONFIG_MEMTEST_ADDR_SIZE 65536
+ #define LX_CONFIG_MAIN_RAM_BASE LX_CONFIG_SDRAM_BASE
+ #define LX_CONFIG_MAIN_RAM_SIZE LX_CONFIG_SDRAM_SIZE
+ {% else %}
+ #define LX_CONFIG_MAIN_RAM_BASE LX_CONFIG_SRAM_BASE
+ #define LX_CONFIG_MAIN_RAM_SIZE LX_CONFIG_SRAM_SIZE
{% endif %}
#endif
*ConfigBuilder.command_templates,
r"""
{% if soc.sdram is not none %}
- litedram_dir={{litedram_dir}}/{{soc.sdram.core.name}}
+ litedram_dir={{build_dir}}/{{litedram_pkg}}/{{soc.sdram.core.name}}
{% endif %}
- build={{build_dir}}
- KCONFIG_CONFIG={{build_dir}}/{{name}}.config
+ build={{bios_dir}}
+ KCONFIG_CONFIG={{bios_dir}}/{{name}}.config
make -C {{software_dir}}/bios 1>&2
""",
]
- def prepare(self, soc, build_dir, name, litedram_dir):
+ def prepare(self, soc, build_dir, name, **render_params):
if not isinstance(soc, CPUSoC):
raise TypeError("SoC must be an instance of CPUSoC, not {!r}"
.format(soc))
- return super().prepare(soc, build_dir, name, litedram_dir=litedram_dir)
+
+ render_params.update({
+ "kconfig_format": kconfig_format,
+ "cpp_format": cpp_format,
+ "bios_dir": os.path.abspath(f"{build_dir}/{__name__}"),
+ "litedram_pkg": litedram.__name__,
+ })
+
+ return super().prepare(soc, build_dir, name, **render_params)
license="BSD",
setup_requires=["setuptools_scm"],
install_requires=[
+ "jinja2>=3.0",
"nmigen>=0.1,<0.5",
"nmigen-soc",
"nmigen-stdio",