Add LiteEth support.
[lambdasoc.git] / lambdasoc / soc / cpu.py
1 import os
2
3 from nmigen_soc.periph import ConstantMap, ConstantBool, ConstantInt
4
5 from .base import *
6 from ..cpu import CPU
7 from ..cores import litedram, liteeth
8 from ..periph.intc import InterruptController
9 from ..periph.sram import SRAMPeripheral
10 from ..periph.serial import AsyncSerialPeripheral
11 from ..periph.timer import TimerPeripheral
12
13
14 __all__ = ["CPUSoC", "BIOSBuilder"]
15
16
17 class CPUSoC(SoC):
18 cpu = socproperty(CPU)
19 intc = socproperty(InterruptController)
20 bootrom = socproperty(SRAMPeripheral)
21 scratchpad = socproperty(SRAMPeripheral)
22 uart = socproperty(AsyncSerialPeripheral)
23 timer = socproperty(TimerPeripheral)
24
25 # TODO: implement a CRG peripheral and expose clock frequencies through CSRs.
26 sync_clk_freq = socproperty(int)
27
28 @property
29 def constants(self):
30 return ConstantMapCollection(
31 CPU = self.cpu.constant_map,
32 INTC = self.intc.constant_map,
33 BOOTROM = self.bootrom.constant_map,
34 SCRATCHPAD = self.scratchpad.constant_map,
35 UART = self.uart.constant_map,
36 TIMER = self.timer.constant_map,
37 SOC = ConstantMap(
38 CLOCK_FREQ = self.sync_clk_freq,
39 CSR_DATA_WIDTH = 32,
40 ),
41 )
42
43 def build(self, build_dir, name=None, do_build=True, do_init=False):
44 """TODO
45 """
46 plan = BIOSBuilder().prepare(self, build_dir, name)
47 if not do_build:
48 return plan
49
50 products = plan.execute_local(build_dir)
51 if not do_init:
52 return products
53
54 with products.extract(f"{__name__}/bios/bios.bin") as bios_filename:
55 with open(bios_filename, "rb") as f:
56 words = iter(lambda: f.read(self.cpu.data_width // 8), b'')
57 bios = [int.from_bytes(w, self.cpu.byteorder) for w in words]
58 self.bootrom.init = bios
59
60
61 def kconfig_format(key, const, prefix="CONFIG_"):
62 if not isinstance(key, str) or not key:
63 raise ValueError("Key must be a non-empty string, not {!r}".format(key))
64 if isinstance(const, ConstantBool):
65 value = "y" if const.value else "n"
66 elif isinstance(const, ConstantAddr):
67 value = hex(const.value)
68 elif isinstance(const, ConstantInt):
69 value = const.value
70 else:
71 raise TypeError("Unsupported constant type, must be ConstantBool, ConstantAddr or "
72 "ConstantInt, not {!r}"
73 .format(const))
74 return "{}{}={}".format(prefix, key.upper(), value)
75
76
77 def cpp_format(key, const, prefix=""):
78 if not isinstance(key, str) or not key:
79 raise ValueError("Key must be a non-empty string, not {!r}".format(key))
80 if isinstance(const, ConstantBool):
81 value = 1 if const.value else 0
82 elif isinstance(const, ConstantAddr):
83 value = "{:#x}UL".format(const.value)
84 elif isinstance(const, ConstantInt):
85 value = "{}{}".format(const.value, "U" if not const.signed else "")
86 else:
87 raise TypeError("Unsupported constant type, must be ConstantBool, ConstantAddr or "
88 "ConstantInt, not {!r}"
89 .format(const))
90 return "#define {}{} {}".format(prefix, key.upper(), value)
91
92
93 class BIOSBuilder(ConfigBuilder):
94 file_templates = {
95 **ConfigBuilder.file_templates,
96 "/".join([__name__, "{{name}}.config"]): r"""
97 # {{autogenerated}}
98
99 # Configuration constants
100 {% for key, value in constants.flatten(separator="_") %}
101 {{kconfig_format(key, value)}}
102 {% endfor %}
103
104 # Memory regions
105 {% for window, (start, stop, step) in soc.memory_map.windows() %}
106 {% set window_name = window.name.upper() %}
107 {{kconfig_format(window_name + "_BASE", ConstantAddr(start))}}
108 {{kconfig_format(window_name + "_LIMIT", ConstantAddr(stop))}}
109 {% endfor %}
110 """,
111 "/".join([__name__, "litex_config.h"]): r"""
112 // {{autogenerated}}
113 #ifndef __LITEX_CONFIG_H_LAMBDASOC
114 #define __LITEX_CONFIG_H_LAMBDASOC
115
116 // Configuration constants
117 {% for key, value in constants.flatten(separator="_") %}
118 {{cpp_format(key, value, prefix="LX_CONFIG_")}}
119 {% endfor %}
120
121 // Memory regions
122 {% for window, (start, stop, step) in soc.memory_map.windows() %}
123 {% set window_name = window.name.upper() %}
124 {{cpp_format(window_name + "_BASE", ConstantAddr(start), prefix="LX_CONFIG_")}}
125 {{cpp_format(window_name + "_LIMIT", ConstantAddr(stop), prefix="LX_CONFIG_")}}
126 {% endfor %}
127
128 {% if soc.sdram is not none %}
129 #define LX_CONFIG_MAIN_RAM_BASE LX_CONFIG_SDRAM_BASE
130 #define LX_CONFIG_MAIN_RAM_SIZE LX_CONFIG_SDRAM_SIZE
131 {% else %}
132 #define LX_CONFIG_MAIN_RAM_BASE LX_CONFIG_SRAM_BASE
133 #define LX_CONFIG_MAIN_RAM_SIZE LX_CONFIG_SRAM_SIZE
134 {% endif %}
135
136 #endif
137 """,
138 }
139 command_templates = [
140 *ConfigBuilder.command_templates,
141 r"""
142 {% if soc.sdram is not none %}
143 litedram_dir={{build_dir}}/{{litedram_pkg}}/{{soc.sdram.core.name}}
144 {% endif %}
145 {% if soc.ethmac is not none %}
146 liteeth_dir={{build_dir}}/{{liteeth_pkg}}/{{soc.ethmac.core.name}}
147 {% endif %}
148 build={{bios_dir}}
149 KCONFIG_CONFIG={{bios_dir}}/{{name}}.config
150 make -C {{software_dir}}/bios 1>&2
151 """,
152 ]
153
154 def prepare(self, soc, build_dir, name, **render_params):
155 if not isinstance(soc, CPUSoC):
156 raise TypeError("SoC must be an instance of CPUSoC, not {!r}"
157 .format(soc))
158
159 render_params.update({
160 "kconfig_format": kconfig_format,
161 "cpp_format": cpp_format,
162 "bios_dir": os.path.abspath(f"{build_dir}/{__name__}"),
163 "litedram_pkg": litedram.__name__,
164 "liteeth_pkg": liteeth.__name__,
165 })
166
167 return super().prepare(soc, build_dir, name, **render_params)