From 734cec9d5c35c2ece6e9910831460a3bcf55ebf7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Fran=C3=A7ois=20Nguyen?= Date: Fri, 29 Oct 2021 18:21:52 +0200 Subject: [PATCH] Add support for configuration constants. --- lambdasoc/cpu/minerva.py | 13 +++++++ lambdasoc/periph/intc.py | 9 +++++ lambdasoc/periph/sdram.py | 8 ++++ lambdasoc/periph/serial.py | 9 +++++ lambdasoc/periph/sram.py | 7 ++++ lambdasoc/periph/timer.py | 8 ++++ lambdasoc/soc/base.py | 75 +++++++++++++++++++++++++++++++++++++- 7 files changed, 127 insertions(+), 2 deletions(-) diff --git a/lambdasoc/cpu/minerva.py b/lambdasoc/cpu/minerva.py index a9abc49..2ffb11b 100644 --- a/lambdasoc/cpu/minerva.py +++ b/lambdasoc/cpu/minerva.py @@ -1,10 +1,13 @@ from nmigen import * from nmigen_soc import wishbone +from nmigen_soc.periph import ConstantMap from minerva.core import Minerva from . import CPU +from ..soc.cpu import ConstantAddr + __all__ = ["MinervaCPU"] @@ -32,6 +35,16 @@ class MinervaCPU(CPU, Elaboratable): def muldiv(self): return "hard" if self._cpu.with_muldiv else "soft" + @property + def constant_map(self): + return ConstantMap( + MINERVA = True, + RESET_ADDR = ConstantAddr(self.reset_addr), + ARCH_RISCV = True, + RISCV_MULDIV_SOFT = self.muldiv == "soft", + BYTEORDER_LITTLE = True, + ) + def elaborate(self, platform): m = Module() diff --git a/lambdasoc/periph/intc.py b/lambdasoc/periph/intc.py index 5d75ff9..428fcfc 100644 --- a/lambdasoc/periph/intc.py +++ b/lambdasoc/periph/intc.py @@ -1,4 +1,7 @@ from nmigen import * + +from nmigen_soc.periph import ConstantMap + from . import Peripheral, IRQLine @@ -12,6 +15,12 @@ class InterruptController(Peripheral): self.__irq_lines = set() self.__irq_map = dict() + @property + def constant_map(self): + return ConstantMap(**{ + line.name.upper(): index for index, line in self.iter_irqs() + }) + def add_irq(self, line, index): """Add an IRQ line. diff --git a/lambdasoc/periph/sdram.py b/lambdasoc/periph/sdram.py index 5c13ef9..5d8380b 100644 --- a/lambdasoc/periph/sdram.py +++ b/lambdasoc/periph/sdram.py @@ -4,6 +4,7 @@ from nmigen.utils import log2_int from nmigen_soc import wishbone from nmigen_soc.memory import MemoryMap +from nmigen_soc.periph import ConstantMap from . import Peripheral @@ -300,6 +301,13 @@ class SDRAMPeripheral(Peripheral, Elaboratable): self._bridge = self.bridge(data_width=data_width, granularity=granularity) self.bus = self._bridge.bus + @property + def constant_map(self): + return ConstantMap( + SIZE = self.core.size, + CACHE_SIZE = self._cache.size, + ) + def elaborate(self, platform): m = Module() diff --git a/lambdasoc/periph/serial.py b/lambdasoc/periph/serial.py index cd7974b..574f070 100644 --- a/lambdasoc/periph/serial.py +++ b/lambdasoc/periph/serial.py @@ -1,6 +1,8 @@ from nmigen import * from nmigen.lib.fifo import SyncFIFOBuffered +from nmigen_soc.periph import ConstantMap + from nmigen_stdio.serial import AsyncSerial from . import Peripheral @@ -92,6 +94,13 @@ class AsyncSerialPeripheral(Peripheral, Elaboratable): self.bus = self._bridge.bus self.irq = self._bridge.irq + @property + def constant_map(self): + return ConstantMap( + RX_DEPTH = self._rx_fifo.depth, + TX_DEPTH = self._tx_fifo.depth, + ) + def elaborate(self, platform): m = Module() m.submodules.bridge = self._bridge diff --git a/lambdasoc/periph/sram.py b/lambdasoc/periph/sram.py index 9f3b7e1..a21ab91 100644 --- a/lambdasoc/periph/sram.py +++ b/lambdasoc/periph/sram.py @@ -3,6 +3,7 @@ from nmigen.utils import log2_int from nmigen_soc import wishbone from nmigen_soc.memory import MemoryMap +from nmigen_soc.periph import ConstantMap from . import Peripheral @@ -64,6 +65,12 @@ class SRAMPeripheral(Peripheral, Elaboratable): def init(self, init): self._mem.init = init + @property + def constant_map(self): + return ConstantMap( + SIZE = self.size, + ) + def elaborate(self, platform): m = Module() diff --git a/lambdasoc/periph/timer.py b/lambdasoc/periph/timer.py index 7b0abdc..25fdf87 100644 --- a/lambdasoc/periph/timer.py +++ b/lambdasoc/periph/timer.py @@ -1,5 +1,7 @@ from nmigen import * +from nmigen_soc.periph import ConstantMap + from . import Peripheral @@ -59,6 +61,12 @@ class TimerPeripheral(Peripheral, Elaboratable): self.bus = self._bridge.bus self.irq = self._bridge.irq + @property + def constant_map(self): + return ConstantMap( + CTR_WIDTH = self.width, + ) + def elaborate(self, platform): m = Module() m.submodules.bridge = self._bridge diff --git a/lambdasoc/soc/base.py b/lambdasoc/soc/base.py index 1c48f12..c9a381e 100644 --- a/lambdasoc/soc/base.py +++ b/lambdasoc/soc/base.py @@ -3,15 +3,21 @@ import re import textwrap import jinja2 +from collections import OrderedDict +from collections.abc import Mapping + from nmigen import tracer -from nmigen_soc.memory import MemoryMap +from nmigen.utils import log2_int from nmigen.build.run import * +from nmigen_soc.memory import MemoryMap +from nmigen_soc.periph import ConstantMap, ConstantBool, ConstantInt + from .. import __version__, software from ..periph import Peripheral -__all__ = ["socproperty", "SoC", "ConfigBuilder"] +__all__ = ["socproperty", "ConstantAddr", "ConstantMapCollection", "SoC", "ConfigBuilder"] def socproperty(cls, *, weak=False, src_loc_at=0): @@ -36,8 +42,73 @@ def socproperty(cls, *, weak=False, src_loc_at=0): return property(getter, setter) +class ConstantAddr(ConstantInt): + def __init__(self, value, *, width=None): + return super().__init__(value, width=width, signed=False) + + def __repr__(self): + return "ConstantAddr({}, width={})".format(self.value, self.width) + + +class ConstantMapCollection(Mapping): + def __init__(self, **constant_maps): + self._storage = OrderedDict() + for key, value in constant_maps.items(): + if value is None: + pass + elif not isinstance(value, (ConstantMap, ConstantMapCollection)): + raise TypeError("Constant map must be an instance of ConstantMap or " + "ConstantMapCollection, not {!r}" + .format(value)) + self._storage[key] = value + + def flatten(self, *, prefix="", separator="_"): + if not isinstance(prefix, str): + raise TypeError("Prefix must be a string, not {!r}".format(prefix)) + if not isinstance(separator, str): + raise TypeError("Separator must be a string, not {!r}".format(separator)) + for key, value in self.items(): + if isinstance(value, ConstantMap): + for const_key, const_value in value.items(): + yield f"{prefix}{key}{separator}{const_key}", const_value + elif isinstance(value, ConstantMapCollection): + yield from value.flatten(prefix=f"{prefix}{key}{separator}", separator=separator) + + def union(self, **other): + union = OrderedDict() + for key in self.keys() | other.keys(): + self_value = self .get(key, None) + other_value = other.get(key, None) + if self_value is None or other_value is None: + union[key] = self_value or other_value + elif isinstance(self_value, ConstantMap): + if not isinstance(other_value, ConstantMap): + raise TypeError # TODO + union[key] = ConstantMap(**self_value, **other_value) + elif isinstance(self_value, ConstantMapCollection): + if not isinstance(other_value, ConstantMapCollection): + raise TypeError # TODO + union[key] = self_value.merge(**{key: other_value}) + else: + assert False + return ConstantMapCollection(**union) + + def __getitem__(self, prefix): + return self._storage[prefix] + + def __iter__(self): + yield from self._storage + + def __len__(self): + return len(self._storage) + + def __repr__(self): + return "ConstantMapCollection({})".format(list(self._storage.items())) + + class SoC: memory_map = socproperty(MemoryMap) + constants = socproperty(ConstantMapCollection, weak=True) def build(self, build_dir="build/soc", do_build=True, name=None): plan = ConfigBuilder().prepare(self, build_dir, name) -- 2.30.2