5 from operator
import itemgetter
9 from litex
.soc
.cores
import identifier
, timer
, uart
10 from litex
.soc
.cores
.cpu
import *
11 from litex
.soc
.interconnect
.csr
import *
12 from litex
.soc
.interconnect
import wishbone
, csr_bus
, wishbone2csr
25 def version(with_time
=True):
29 return datetime
.datetime
.fromtimestamp(
30 time
.time()).strftime("%Y-%m-%d %H:%M:%S")
32 return datetime
.datetime
.fromtimestamp(
33 time
.time()).strftime("%Y-%m-%d")
36 def mem_decoder(address
, start
=26, end
=29):
37 return lambda a
: a
[start
:end
] == ((address
>> (start
+2)) & (2**(end
-start
))-1)
40 def get_mem_data(filename
, endianness
="big", mem_size
=None):
41 # create memory regions
42 _
, ext
= os
.path
.splitext(filename
)
44 f
= open(filename
, "r")
45 regions
= json
.load(f
)
48 regions
= {filename
: "0x00000000"}
52 for filename
, base
in regions
.items():
53 data_size
= max(int(base
, 16) + os
.path
.getsize(filename
), data_size
)
55 if mem_size
is not None:
56 assert data_size
< mem_size
, (
57 "file is too big: {}/{} bytes".format(
61 data
= [0]*(data_size
//4)
62 for filename
, base
in regions
.items():
63 with
open(filename
, "rb") as f
:
70 for i
in range(len(w
), 4):
72 if endianness
== "little":
73 data
[i
] = struct
.unpack("<I", w
)[0]
75 data
[i
] = struct
.unpack(">I", w
)[0]
79 class ReadOnlyDict(dict):
80 def __readonly__(self
, *args
, **kwargs
):
81 raise RuntimeError("Cannot modify ReadOnlyDict")
82 __setitem__
= __readonly__
83 __delitem__
= __readonly__
85 popitem
= __readonly__
88 setdefault
= __readonly__
92 def csr_map_update(csr_map
, csr_peripherals
):
93 csr_map
.update(dict((n
, v
)
94 for v
, n
in enumerate(csr_peripherals
, start
=max(csr_map
.values()) + 1)))
97 class SoCController(Module
, AutoCSR
):
100 self
._scratch
= CSRStorage(32, reset
=0x12345678)
101 self
._bus
_errors
= CSRStatus(32)
106 self
.reset
= Signal()
107 self
.comb
+= self
.reset
.eq(self
._reset
.re
)
110 self
.bus_error
= Signal()
111 bus_errors
= Signal(32)
113 If(bus_errors
!= (2**len(bus_errors
)-1),
115 bus_errors
.eq(bus_errors
+ 1)
118 self
.comb
+= self
._bus
_errors
.status
.eq(bus_errors
)
121 class SoCCore(Module
):
123 "ctrl": 0, # provided by default (optional)
125 "uart_phy": 2, # provided by default (optional)
126 "uart": 3, # provided by default (optional)
127 "identifier_mem": 4, # provided by default (optional)
128 "timer0": 5, # provided by default (optional)
133 soc_interrupt_map
= {
134 "timer0": 1, # LiteX Timer
135 "uart": 2, # LiteX UART (IRQ 2 for UART matches mor1k standard config).
138 "rom": 0x00000000, # (default shadow @0x80000000)
139 "sram": 0x10000000, # (default shadow @0x90000000)
140 "main_ram": 0x40000000, # (default shadow @0xc0000000)
141 "csr": 0x60000000, # (default shadow @0xe0000000)
143 def __init__(self
, platform
, clk_freq
,
144 cpu_type
="lm32", cpu_reset_address
=0x00000000, cpu_variant
=None,
145 integrated_rom_size
=0, integrated_rom_init
=[],
146 integrated_sram_size
=4096,
147 integrated_main_ram_size
=0, integrated_main_ram_init
=[],
148 shadow_base
=0x80000000,
149 csr_data_width
=8, csr_address_width
=14, csr_expose
=False,
150 with_uart
=True, uart_name
="serial", uart_baudrate
=115200, uart_stub
=False,
151 ident
="", ident_version
=False,
152 wishbone_timeout_cycles
=1e6
,
153 reserve_nmi_interrupt
=True,
158 self
.platform
= platform
159 self
.clk_freq
= clk_freq
161 if cpu_type
== "None":
163 self
.cpu_type
= cpu_type
164 self
.cpu_variant
= cpu_variant
165 if integrated_rom_size
:
166 cpu_reset_address
= self
.mem_map
["rom"]
167 self
.cpu_reset_address
= cpu_reset_address
168 self
.config
["CPU_RESET_ADDR"] = self
.cpu_reset_address
170 self
.integrated_rom_size
= integrated_rom_size
171 self
.integrated_rom_initialized
= integrated_rom_init
!= []
172 self
.integrated_sram_size
= integrated_sram_size
173 self
.integrated_main_ram_size
= integrated_main_ram_size
175 self
.with_uart
= with_uart
176 self
.uart_baudrate
= uart_baudrate
178 self
.shadow_base
= shadow_base
180 self
.wishbone_timeout_cycles
= wishbone_timeout_cycles
182 self
.csr_data_width
= csr_data_width
183 self
.csr_address_width
= csr_address_width
184 self
.csr_expose
= csr_expose
186 self
.csr
= csr_bus
.Interface(csr_data_width
, csr_address_width
)
188 self
.with_ctrl
= with_ctrl
190 self
._memory
_regions
= [] # list of (name, origin, length)
191 self
._csr
_regions
= [] # list of (name, origin, busword, csr_list/Memory)
192 self
._constants
= [] # list of (name, value)
194 self
._wb
_masters
= []
198 self
.submodules
.ctrl
= SoCController()
200 if cpu_type
is not None:
201 if cpu_type
== "lm32":
202 self
.add_cpu(lm32
.LM32(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
203 elif cpu_type
== "or1k":
204 self
.add_cpu(mor1kx
.MOR1KX(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
205 elif cpu_type
== "picorv32":
206 self
.add_cpu(picorv32
.PicoRV32(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
207 elif cpu_type
== "vexriscv":
208 self
.add_cpu(vexriscv
.VexRiscv(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
209 elif cpu_type
== "minerva":
210 self
.add_cpu(minerva
.Minerva(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
212 raise ValueError("Unsupported CPU type: {}".format(cpu_type
))
213 self
.add_wb_master(self
.cpu
.ibus
)
214 self
.add_wb_master(self
.cpu
.dbus
)
216 self
.comb
+= self
.cpu
.reset
.eq(self
.ctrl
.reset
)
217 self
.config
["CPU_TYPE"] = str(cpu_type
).upper()
219 self
.config
["CPU_VARIANT"] = str(cpu_type
).upper()
221 if integrated_rom_size
:
222 self
.submodules
.rom
= wishbone
.SRAM(integrated_rom_size
, read_only
=True, init
=integrated_rom_init
)
223 self
.register_rom(self
.rom
.bus
, integrated_rom_size
)
225 if integrated_sram_size
:
226 self
.submodules
.sram
= wishbone
.SRAM(integrated_sram_size
)
227 self
.register_mem("sram", self
.mem_map
["sram"], self
.sram
.bus
, integrated_sram_size
)
229 # Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping.
230 if integrated_main_ram_size
:
231 self
.submodules
.main_ram
= wishbone
.SRAM(integrated_main_ram_size
, init
=integrated_main_ram_init
)
232 self
.register_mem("main_ram", self
.mem_map
["main_ram"], self
.main_ram
.bus
, integrated_main_ram_size
)
234 self
.submodules
.wishbone2csr
= wishbone2csr
.WB2CSR(
235 bus_csr
=csr_bus
.Interface(csr_data_width
, csr_address_width
))
236 self
.config
["CSR_DATA_WIDTH"] = csr_data_width
237 self
.add_constant("CSR_DATA_WIDTH", csr_data_width
)
238 self
.register_mem("csr", self
.mem_map
["csr"], self
.wishbone2csr
.wishbone
)
240 if reserve_nmi_interrupt
:
241 self
.soc_interrupt_map
["nmi"] = 0 # Reserve zero for "non-maskable interrupt"
245 self
.submodules
.uart
= uart
.UARTStub()
247 self
.submodules
.uart_phy
= uart
.RS232PHY(platform
.request(uart_name
), clk_freq
, uart_baudrate
)
248 self
.submodules
.uart
= ResetInserter()(uart
.UART(self
.uart_phy
))
251 # del self.soc_interrupt_map["uart"]
255 ident
= ident
+ " " + version()
256 self
.submodules
.identifier
= identifier
.Identifier(ident
)
257 self
.config
["CLOCK_FREQUENCY"] = int(clk_freq
)
258 self
.add_constant("SYSTEM_CLOCK_FREQUENCY", int(clk_freq
))
261 self
.submodules
.timer0
= timer
.Timer()
263 # del self.soc_interrupt_map["timer0"]
265 # Invert the interrupt map.
267 for mod_name
, interrupt
in self
.interrupt_map
.items():
268 assert interrupt
not in interrupt_rmap
, (
269 "Interrupt vector conflict for IRQ %s, user defined %s conflicts with user defined %s" % (
270 interrupt
, mod_name
, interrupt_rmap
[interrupt
]))
272 interrupt_rmap
[interrupt
] = mod_name
274 # Add the base SoC's interrupt map
275 for mod_name
, interrupt
in self
.soc_interrupt_map
.items():
276 assert interrupt
not in interrupt_rmap
or mod_name
== interrupt_rmap
[interrupt
], (
277 "Interrupt vector conflict for IRQ %s, user defined %s conflicts with SoC inbuilt %s" % (
278 interrupt
, mod_name
, interrupt_rmap
[interrupt
]))
280 self
.interrupt_map
[mod_name
] = interrupt
281 interrupt_rmap
[interrupt
] = mod_name
283 # Make sure other functions are not using this value.
284 self
.soc_interrupt_map
= None
286 # Make the interrupt vector read only
287 self
.interrupt_map
= ReadOnlyDict(self
.interrupt_map
)
289 # Save the interrupt reverse map
290 self
.interrupt_rmap
= ReadOnlyDict(interrupt_rmap
)
293 def add_cpu(self
, cpu
):
296 if hasattr(self
, "cpu"):
297 raise NotImplementedError("More than one CPU is not supported")
298 self
.submodules
.cpu
= cpu
300 def add_cpu_or_bridge(self
, cpu_or_bridge
):
301 print("[WARNING] Please update SoCCore's \"add_cpu_or_bridge\" call to \"add_cpu\"")
302 self
.add_cpu(cpu_or_bridge
)
303 self
.cpu_or_bridge
= self
.cpu
305 def initialize_rom(self
, data
):
306 self
.rom
.mem
.init
= data
308 def add_wb_master(self
, wbm
):
311 self
._wb
_masters
.append(wbm
)
313 def add_wb_slave(self
, address_decoder
, interface
):
316 self
._wb
_slaves
.append((address_decoder
, interface
))
318 def add_memory_region(self
, name
, origin
, length
):
319 def in_this_region(addr
):
320 return addr
>= origin
and addr
< origin
+ length
321 for n
, o
, l
in self
._memory
_regions
:
322 if n
== name
or in_this_region(o
) or in_this_region(o
+l
-1):
323 raise ValueError("Memory region conflict between {} and {}".format(n
, name
))
325 self
._memory
_regions
.append((name
, origin
, length
))
327 def register_mem(self
, name
, address
, interface
, size
=None):
328 self
.add_wb_slave(mem_decoder(address
), interface
)
330 self
.add_memory_region(name
, address
, size
)
332 def register_rom(self
, interface
, rom_size
=0xa000):
333 self
.add_wb_slave(mem_decoder(self
.mem_map
["rom"]), interface
)
334 self
.add_memory_region("rom", self
.cpu_reset_address
, rom_size
)
336 def get_memory_regions(self
):
337 return self
._memory
_regions
339 def check_csr_range(self
, name
, addr
):
340 if addr
>= 1<<(self
.csr_address_width
+2):
341 raise ValueError("{} CSR out of range, increase csr_address_width".format(name
))
343 def check_csr_region(self
, name
, origin
):
344 for n
, o
, l
, obj
in self
._csr
_regions
:
345 if n
== name
or o
== origin
:
346 raise ValueError("CSR region conflict between {} and {}".format(n
, name
))
348 def add_csr_region(self
, name
, origin
, busword
, obj
):
349 self
.check_csr_region(name
, origin
)
350 self
._csr
_regions
.append((name
, origin
, busword
, obj
))
352 def get_csr_regions(self
):
353 return self
._csr
_regions
355 def add_constant(self
, name
, value
=None):
356 self
._constants
.append((name
, value
))
358 def get_constants(self
):
360 for interrupt
, name
in sorted(self
.interrupt_rmap
.items()):
361 r
.append((name
.upper() + "_INTERRUPT", interrupt
))
365 def get_csr_dev_address(self
, name
, memory
):
366 if memory
is not None:
367 name
= name
+ "_" + memory
.name_override
369 return self
.csr_map
[name
]
370 except KeyError as e
:
371 msg
= "Undefined \"{}\" CSR.\n".format(name
)
372 msg
+= "Avalaible CSRs in {} ({}):\n".format(
373 self
.__class
__.__name
__, inspect
.getfile(self
.__class
__))
374 for k
in sorted(self
.csr_map
.keys()):
375 msg
+= "- {}\n".format(k
)
376 raise RuntimeError(msg
)
380 def do_finalize(self
):
381 registered_mems
= {regions
[0] for regions
in self
._memory
_regions
}
382 if self
.cpu_type
is not None:
383 for mem
in "rom", "sram":
384 if mem
not in registered_mems
:
385 raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem
))
387 if len(self
._wb
_masters
):
389 self
.submodules
.wishbonecon
= wishbone
.InterconnectShared(self
._wb
_masters
,
390 self
._wb
_slaves
, register
=True, timeout_cycles
=self
.wishbone_timeout_cycles
)
391 if self
.with_ctrl
and (self
.wishbone_timeout_cycles
is not None):
392 self
.comb
+= self
.ctrl
.bus_error
.eq(self
.wishbonecon
.timeout
.error
)
395 self
.submodules
.csrbankarray
= csr_bus
.CSRBankArray(self
,
396 self
.get_csr_dev_address
,
397 data_width
=self
.csr_data_width
, address_width
=self
.csr_address_width
)
399 self
.submodules
.csrcon
= csr_bus
.InterconnectShared(
400 [self
.csr
, self
.wishbone2csr
.csr
], self
.csrbankarray
.get_buses())
402 self
.submodules
.csrcon
= csr_bus
.Interconnect(
403 self
.wishbone2csr
.csr
, self
.csrbankarray
.get_buses())
404 for name
, csrs
, mapaddr
, rmap
in self
.csrbankarray
.banks
:
405 self
.check_csr_range(name
, 0x800*mapaddr
)
406 self
.add_csr_region(name
, (self
.mem_map
["csr"] + 0x800*mapaddr
) | self
.shadow_base
, self
.csr_data_width
, csrs
)
407 for name
, memory
, mapaddr
, mmap
in self
.csrbankarray
.srams
:
408 self
.check_csr_range(name
, 0x800*mapaddr
)
409 self
.add_csr_region(name
+ "_" + memory
.name_override
, (self
.mem_map
["csr"] + 0x800*mapaddr
) | self
.shadow_base
, self
.csr_data_width
, memory
)
410 for name
, constant
in self
.csrbankarray
.constants
:
411 self
._constants
.append(((name
+ "_" + constant
.name
).upper(), constant
.value
.value
))
412 for name
, value
in sorted(self
.config
.items(), key
=itemgetter(0)):
413 self
._constants
.append(("CONFIG_" + name
.upper(), value
))
416 if hasattr(self
, "cpu"):
417 if hasattr(self
.cpu
, "interrupt"):
418 for interrupt
, mod_name
in sorted(self
.interrupt_rmap
.items()):
419 if mod_name
== "nmi":
421 if hasattr(self
, mod_name
):
422 mod_impl
= getattr(self
, mod_name
)
423 assert hasattr(mod_impl
, 'ev'), "Submodule %s does not have EventManager (xx.ev) module" % mod_name
424 self
.comb
+= self
.cpu
.interrupt
[interrupt
].eq(mod_impl
.ev
.irq
)
426 def build(self
, *args
, **kwargs
):
427 return self
.platform
.build(self
, *args
, **kwargs
)
430 def soc_core_args(parser
):
431 parser
.add_argument("--cpu-type", default
=None,
432 help="select CPU: lm32, or1k, picorv32, vexriscv, minerva")
433 parser
.add_argument("--cpu-variant", default
=None,
434 help="select CPU variant")
435 parser
.add_argument("--integrated-rom-size", default
=None, type=int,
436 help="size/enable the integrated (BIOS) ROM")
437 parser
.add_argument("--integrated-main-ram-size", default
=None, type=int,
438 help="size/enable the integrated main RAM")
439 parser
.add_argument("--uart-stub", default
=False, type=bool,
440 help="enable uart stub")
443 def soc_core_argdict(args
):
448 "integrated_rom_size",
449 "integrated_main_ram_size",
451 arg
= getattr(args
, a
)