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