Add support for configuration constants.
authorJean-François Nguyen <jf@lambdaconcept.com>
Fri, 29 Oct 2021 16:21:52 +0000 (18:21 +0200)
committerJean-François Nguyen <jf@lambdaconcept.com>
Fri, 29 Oct 2021 16:21:52 +0000 (18:21 +0200)
lambdasoc/cpu/minerva.py
lambdasoc/periph/intc.py
lambdasoc/periph/sdram.py
lambdasoc/periph/serial.py
lambdasoc/periph/sram.py
lambdasoc/periph/timer.py
lambdasoc/soc/base.py

index a9abc496a993f0af129b2dcce77498803aa50f5c..2ffb11b3fec676f8859a530cae4ad2779e4de7d1 100644 (file)
@@ -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()
 
index 5d75ff974927fe76720c48117bf73b10afe5b9b7..428fcfcbd858de213cf6658e521c4a278334b4d5 100644 (file)
@@ -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.
 
index 5c13ef94e1a0c60403d85cb042eb85bb710cd239..5d8380bc70699a25a6c6a9d529c44ae17a447d51 100644 (file)
@@ -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()
 
index cd7974b349b1a7766d44cf3e9cbed8e9e87a6002..574f070e68a2aaaa732ac3ee606c6a23a93f22d9 100644 (file)
@@ -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
index 9f3b7e11214ccc38a9286a0c6d65f531d88cd361..a21ab913e79dc7a9b4c59c877ae1439c04df915f 100644 (file)
@@ -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()
 
index 7b0abdc0ba9ef9c1fde7a0f0b003db2e5f729e7f..25fdf87a49f4289a825d78a130c78b3039a9f045 100644 (file)
@@ -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
index 1c48f12b9aec795b03cd33c68109485fd985a38c..c9a381e1763cf2630ee34252ae0132243ed93536 100644 (file)
@@ -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)