soc.cpu: generate BIOS configuration from SoC constants.
[lambdasoc.git] / lambdasoc / soc / cpu.py
index 5f26054582886a070d6414694035fa604780ebcf..24149f4a98987f63ed016ff15d9cf951b6124e50 100644 (file)
@@ -1,10 +1,12 @@
 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
 
@@ -13,25 +15,35 @@ __all__ = ["CPUSoC", "BIOSBuilder"]
 
 
 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
 
@@ -39,61 +51,86 @@ class CPUSoC(SoC):
         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
@@ -103,16 +140,24 @@ class BIOSBuilder(ConfigBuilder):
         *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)