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