soc_core: convert cpu_type="None" string to None
[litex.git] / litex / soc / integration / soc_core.py
1 import struct
2 import inspect
3 from operator import itemgetter
4
5 from migen import *
6
7 from litex.soc.cores import identifier, timer, uart
8 from litex.soc.cores.cpu import *
9 from litex.soc.interconnect.csr import *
10 from litex.soc.interconnect import wishbone, csr_bus, wishbone2csr
11
12
13 __all__ = ["mem_decoder", "get_mem_data", "SoCCore", "soc_core_args", "soc_core_argdict"]
14
15
16 def version(with_time=True):
17 import datetime
18 import time
19 if with_time:
20 return datetime.datetime.fromtimestamp(
21 time.time()).strftime("%Y-%m-%d %H:%M:%S")
22 else:
23 return datetime.datetime.fromtimestamp(
24 time.time()).strftime("%Y-%m-%d")
25
26
27 def mem_decoder(address, start=26, end=29):
28 return lambda a: a[start:end] == ((address >> (start+2)) & (2**(end-start))-1)
29
30
31 def get_mem_data(filename, endianness="big", mem_size=None):
32 data = []
33 with open(filename, "rb") as mem_file:
34 while True:
35 w = mem_file.read(4)
36 if not w:
37 break
38 if endianness == "little":
39 data.append(struct.unpack("<I", w)[0])
40 else:
41 data.append(struct.unpack(">I", w)[0])
42 data_size = len(data)*4
43 assert data_size > 0
44 if mem_size is not None:
45 assert data_size < mem_size, (
46 "file is too big: {}/{} bytes".format(
47 data_size, mem_size))
48 return data
49
50
51 class ReadOnlyDict(dict):
52 def __readonly__(self, *args, **kwargs):
53 raise RuntimeError("Cannot modify ReadOnlyDict")
54 __setitem__ = __readonly__
55 __delitem__ = __readonly__
56 pop = __readonly__
57 popitem = __readonly__
58 clear = __readonly__
59 update = __readonly__
60 setdefault = __readonly__
61 del __readonly__
62
63
64 class SoCController(Module, AutoCSR):
65 def __init__(self):
66 self._reset = CSR()
67 self._scratch = CSRStorage(32, reset=0x12345678)
68 self._bus_errors = CSRStatus(32)
69
70 # # #
71
72 # reset
73 self.reset = Signal()
74 self.comb += self.reset.eq(self._reset.re)
75
76 # bus errors
77 self.bus_error = Signal()
78 bus_errors = Signal(32)
79 self.sync += \
80 If(bus_errors != (2**len(bus_errors)-1),
81 If(self.bus_error,
82 bus_errors.eq(bus_errors + 1)
83 )
84 )
85 self.comb += self._bus_errors.status.eq(bus_errors)
86
87
88 class SoCCore(Module):
89 csr_map = {
90 "ctrl": 0, # provided by default (optional)
91 "crg": 1, # user
92 "uart_phy": 2, # provided by default (optional)
93 "uart": 3, # provided by default (optional)
94 "identifier_mem": 4, # provided by default (optional)
95 "timer0": 5, # provided by default (optional)
96 "buttons": 6, # user
97 "leds": 7, # user
98 }
99 interrupt_map = {}
100 soc_interrupt_map = {
101 "timer0": 1, # LiteX Timer
102 "uart": 2, # LiteX UART (IRQ 2 for UART matches mor1k standard config).
103 }
104 mem_map = {
105 "rom": 0x00000000, # (default shadow @0x80000000)
106 "sram": 0x10000000, # (default shadow @0x90000000)
107 "main_ram": 0x40000000, # (default shadow @0xc0000000)
108 "csr": 0x60000000, # (default shadow @0xe0000000)
109 }
110 def __init__(self, platform, clk_freq,
111 cpu_type="lm32", cpu_reset_address=0x00000000, cpu_variant=None,
112 integrated_rom_size=0, integrated_rom_init=[],
113 integrated_sram_size=4096,
114 integrated_main_ram_size=0, integrated_main_ram_init=[],
115 shadow_base=0x80000000,
116 csr_data_width=8, csr_address_width=14, csr_expose=False,
117 with_uart=True, uart_name="serial", uart_baudrate=115200, uart_stub=False,
118 ident="", ident_version=False,
119 reserve_nmi_interrupt=True,
120 with_timer=True,
121 with_ctrl=True):
122 self.config = dict()
123
124 self.platform = platform
125 self.clk_freq = clk_freq
126
127 if cpu_type == "None":
128 cpu_type = None
129 self.cpu_type = cpu_type
130 self.cpu_variant = cpu_variant
131 if integrated_rom_size:
132 cpu_reset_address = self.mem_map["rom"]
133 self.cpu_reset_address = cpu_reset_address
134 self.config["CPU_RESET_ADDR"] = self.cpu_reset_address
135
136 self.integrated_rom_size = integrated_rom_size
137 self.integrated_rom_initialized = integrated_rom_init != []
138 self.integrated_sram_size = integrated_sram_size
139 self.integrated_main_ram_size = integrated_main_ram_size
140
141 self.with_uart = with_uart
142 self.uart_baudrate = uart_baudrate
143
144 self.shadow_base = shadow_base
145
146 self.csr_data_width = csr_data_width
147 self.csr_address_width = csr_address_width
148 self.csr_expose = csr_expose
149 if csr_expose:
150 self.csr = csr_bus.Interface(csr_data_width, csr_address_width)
151
152 self.with_ctrl = with_ctrl
153
154 self._memory_regions = [] # list of (name, origin, length)
155 self._csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
156 self._constants = [] # list of (name, value)
157
158 self._wb_masters = []
159 self._wb_slaves = []
160
161 if with_ctrl:
162 self.submodules.ctrl = SoCController()
163
164 if cpu_type is not None:
165 if cpu_type == "lm32":
166 self.add_cpu(lm32.LM32(platform, self.cpu_reset_address, self.cpu_variant))
167 elif cpu_type == "or1k":
168 self.add_cpu(mor1kx.MOR1KX(platform, self.cpu_reset_address, self.cpu_variant))
169 elif cpu_type == "picorv32":
170 self.add_cpu(picorv32.PicoRV32(platform, self.cpu_reset_address, self.cpu_variant))
171 elif cpu_type == "vexriscv":
172 self.add_cpu(vexriscv.VexRiscv(platform, self.cpu_reset_address, self.cpu_variant))
173 elif cpu_type == "minerva":
174 self.add_cpu(minerva.Minerva(platform, self.cpu_reset_address, self.cpu_variant))
175 else:
176 raise ValueError("Unsupported CPU type: {}".format(cpu_type))
177 self.add_wb_master(self.cpu.ibus)
178 self.add_wb_master(self.cpu.dbus)
179 if with_ctrl:
180 self.comb += self.cpu.reset.eq(self.ctrl.reset)
181 self.config["CPU_TYPE"] = str(cpu_type).upper()
182 if self.cpu_variant:
183 self.config["CPU_VARIANT"] = str(cpu_type).upper()
184
185 if integrated_rom_size:
186 self.submodules.rom = wishbone.SRAM(integrated_rom_size, read_only=True, init=integrated_rom_init)
187 self.register_rom(self.rom.bus, integrated_rom_size)
188
189 if integrated_sram_size:
190 self.submodules.sram = wishbone.SRAM(integrated_sram_size)
191 self.register_mem("sram", self.mem_map["sram"], self.sram.bus, integrated_sram_size)
192
193 # Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping.
194 if integrated_main_ram_size:
195 self.submodules.main_ram = wishbone.SRAM(integrated_main_ram_size, init=integrated_main_ram_init)
196 self.register_mem("main_ram", self.mem_map["main_ram"], self.main_ram.bus, integrated_main_ram_size)
197
198 self.submodules.wishbone2csr = wishbone2csr.WB2CSR(
199 bus_csr=csr_bus.Interface(csr_data_width, csr_address_width))
200 self.config["CSR_DATA_WIDTH"] = csr_data_width
201 self.add_constant("CSR_DATA_WIDTH", csr_data_width)
202 self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
203
204 if reserve_nmi_interrupt:
205 self.soc_interrupt_map["nmi"] = 0 # Reserve zero for "non-maskable interrupt"
206
207 if with_uart:
208 if uart_stub:
209 self.submodules.uart = uart.UARTStub()
210 else:
211 self.submodules.uart_phy = uart.RS232PHY(platform.request(uart_name), clk_freq, uart_baudrate)
212 self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy))
213
214 #else:
215 # del self.soc_interrupt_map["uart"]
216
217 if ident:
218 if ident_version:
219 ident = ident + " " + version()
220 self.submodules.identifier = identifier.Identifier(ident)
221 self.config["CLOCK_FREQUENCY"] = int(clk_freq)
222 self.add_constant("SYSTEM_CLOCK_FREQUENCY", int(clk_freq))
223
224 if with_timer:
225 self.submodules.timer0 = timer.Timer()
226 #else:
227 # del self.soc_interrupt_map["timer0"]
228
229 # Invert the interrupt map.
230 interrupt_rmap = {}
231 for mod_name, interrupt in self.interrupt_map.items():
232 assert interrupt not in interrupt_rmap, (
233 "Interrupt vector conflict for IRQ %s, user defined %s conflicts with user defined %s" % (
234 interrupt, mod_name, interrupt_rmap[interrupt]))
235
236 interrupt_rmap[interrupt] = mod_name
237
238 # Add the base SoC's interrupt map
239 for mod_name, interrupt in self.soc_interrupt_map.items():
240 assert interrupt not in interrupt_rmap or mod_name == interrupt_rmap[interrupt], (
241 "Interrupt vector conflict for IRQ %s, user defined %s conflicts with SoC inbuilt %s" % (
242 interrupt, mod_name, interrupt_rmap[interrupt]))
243
244 self.interrupt_map[mod_name] = interrupt
245 interrupt_rmap[interrupt] = mod_name
246
247 # Make sure other functions are not using this value.
248 self.soc_interrupt_map = None
249
250 # Make the interrupt vector read only
251 self.interrupt_map = ReadOnlyDict(self.interrupt_map)
252
253 # Save the interrupt reverse map
254 self.interrupt_rmap = ReadOnlyDict(interrupt_rmap)
255
256
257 def add_cpu(self, cpu):
258 if self.finalized:
259 raise FinalizeError
260 if hasattr(self, "cpu"):
261 raise NotImplementedError("More than one CPU is not supported")
262 self.submodules.cpu = cpu
263
264 def add_cpu_or_bridge(self, cpu_or_bridge):
265 print("[WARNING] Please update SoCCore's \"add_cpu_or_bridge\" call to \"add_cpu\"")
266 self.add_cpu(cpu_or_bridge)
267 self.cpu_or_bridge = self.cpu
268
269 def initialize_rom(self, data):
270 self.rom.mem.init = data
271
272 def add_wb_master(self, wbm):
273 if self.finalized:
274 raise FinalizeError
275 self._wb_masters.append(wbm)
276
277 def add_wb_slave(self, address_decoder, interface):
278 if self.finalized:
279 raise FinalizeError
280 self._wb_slaves.append((address_decoder, interface))
281
282 def add_memory_region(self, name, origin, length):
283 def in_this_region(addr):
284 return addr >= origin and addr < origin + length
285 for n, o, l in self._memory_regions:
286 if n == name or in_this_region(o) or in_this_region(o+l-1):
287 raise ValueError("Memory region conflict between {} and {}".format(n, name))
288
289 self._memory_regions.append((name, origin, length))
290
291 def register_mem(self, name, address, interface, size=None):
292 self.add_wb_slave(mem_decoder(address), interface)
293 if size is not None:
294 self.add_memory_region(name, address, size)
295
296 def register_rom(self, interface, rom_size=0xa000):
297 self.add_wb_slave(mem_decoder(self.mem_map["rom"]), interface)
298 self.add_memory_region("rom", self.cpu_reset_address, rom_size)
299
300 def get_memory_regions(self):
301 return self._memory_regions
302
303 def check_csr_range(self, name, addr):
304 if addr >= 1<<(self.csr_address_width+2):
305 raise ValueError("{} CSR out of range, increase csr_address_width".format(name))
306
307 def check_csr_region(self, name, origin):
308 for n, o, l, obj in self._csr_regions:
309 if n == name or o == origin:
310 raise ValueError("CSR region conflict between {} and {}".format(n, name))
311
312 def add_csr_region(self, name, origin, busword, obj):
313 self.check_csr_region(name, origin)
314 self._csr_regions.append((name, origin, busword, obj))
315
316 def get_csr_regions(self):
317 return self._csr_regions
318
319 def add_constant(self, name, value=None):
320 self._constants.append((name, value))
321
322 def get_constants(self):
323 r = []
324 for interrupt, name in sorted(self.interrupt_rmap.items()):
325 r.append((name.upper() + "_INTERRUPT", interrupt))
326 r += self._constants
327 return r
328
329 def get_csr_dev_address(self, name, memory):
330 if memory is not None:
331 name = name + "_" + memory.name_override
332 try:
333 return self.csr_map[name]
334 except KeyError as e:
335 msg = "Undefined \"{}\" CSR.\n".format(name)
336 msg += "Avalaible CSRs in {} ({}):\n".format(
337 self.__class__.__name__, inspect.getfile(self.__class__))
338 for k in sorted(self.csr_map.keys()):
339 msg += "- {}\n".format(k)
340 raise RuntimeError(msg)
341 except ValueError:
342 return None
343
344 def do_finalize(self):
345 registered_mems = {regions[0] for regions in self._memory_regions}
346 if self.cpu_type is not None:
347 for mem in "rom", "sram":
348 if mem not in registered_mems:
349 raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem))
350
351 if len(self._wb_masters):
352 # Wishbone
353 self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
354 self._wb_slaves, register=True)
355 if self.with_ctrl:
356 self.comb += self.ctrl.bus_error.eq(self.wishbonecon.timeout.error)
357
358 # CSR
359 self.submodules.csrbankarray = csr_bus.CSRBankArray(self,
360 self.get_csr_dev_address,
361 data_width=self.csr_data_width, address_width=self.csr_address_width)
362 if self.csr_expose:
363 self.submodules.csrcon = csr_bus.InterconnectShared(
364 [self.csr, self.wishbone2csr.csr], self.csrbankarray.get_buses())
365 else:
366 self.submodules.csrcon = csr_bus.Interconnect(
367 self.wishbone2csr.csr, self.csrbankarray.get_buses())
368 for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
369 self.check_csr_range(name, 0x800*mapaddr)
370 self.add_csr_region(name, (self.mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, self.csr_data_width, csrs)
371 for name, memory, mapaddr, mmap in self.csrbankarray.srams:
372 self.check_csr_range(name, 0x800*mapaddr)
373 self.add_csr_region(name + "_" + memory.name_override, (self.mem_map["csr"] + 0x800*mapaddr) | self.shadow_base, self.csr_data_width, memory)
374 for name, constant in self.csrbankarray.constants:
375 self._constants.append(((name + "_" + constant.name).upper(), constant.value.value))
376 for name, value in sorted(self.config.items(), key=itemgetter(0)):
377 self._constants.append(("CONFIG_" + name.upper(), value))
378
379 # Interrupts
380 if hasattr(self, "cpu"):
381 if hasattr(self.cpu, "interrupt"):
382 for interrupt, mod_name in sorted(self.interrupt_rmap.items()):
383 if mod_name == "nmi":
384 continue
385 if hasattr(self, mod_name):
386 mod_impl = getattr(self, mod_name)
387 assert hasattr(mod_impl, 'ev'), "Submodule %s does not have EventManager (xx.ev) module" % mod_name
388 self.comb += self.cpu.interrupt[interrupt].eq(mod_impl.ev.irq)
389
390 def build(self, *args, **kwargs):
391 return self.platform.build(self, *args, **kwargs)
392
393
394 def soc_core_args(parser):
395 parser.add_argument("--cpu-type", default=None,
396 help="select CPU: lm32, or1k, picorv32, vexriscv, minerva")
397 parser.add_argument("--cpu-variant", default=None,
398 help="select CPU variant")
399 parser.add_argument("--integrated-rom-size", default=None, type=int,
400 help="size/enable the integrated (BIOS) ROM")
401 parser.add_argument("--integrated-main-ram-size", default=None, type=int,
402 help="size/enable the integrated main RAM")
403 parser.add_argument("--uart-stub", default=False, type=bool,
404 help="enable uart stub")
405
406
407 def soc_core_argdict(args):
408 r = dict()
409 for a in [
410 "cpu_type",
411 "cpu_variant",
412 "integrated_rom_size",
413 "integrated_main_ram_size",
414 "uart_stub"]:
415 arg = getattr(args, a)
416 if arg is not None:
417 r[a] = arg
418 return r