7 from operator
import itemgetter
11 from litex
.build
.tools
import deprecated_warning
13 from litex
.soc
.cores
import identifier
, timer
, uart
14 from litex
.soc
.cores
.cpu
import *
15 from litex
.soc
.interconnect
.csr
import *
16 from litex
.soc
.interconnect
import wishbone
, csr_bus
, wishbone2csr
30 # "official name": ["alias 1", "alias 2"],
32 "lite" : ["light", "zephyr", "nuttx"],
33 "standard": [None, "std"],
37 CPU_VARIANTS_EXTENSIONS
= ["debug"]
40 class InvalidCPUVariantError(ValueError):
41 def __init__(self
, variant
):
43 Invalid cpu_variant value: {}
47 for k
, v
in CPU_VARIANTS
.items():
48 msg
+= " - {} (aliases: {})\n".format(k
, ", ".join(str(s
) for s
in v
))
49 ValueError.__init
__(self
, msg
)
52 class InvalidCPUExtensionError(ValueError):
53 def __init__(self
, variant
):
55 Invalid extension in cpu_variant value: {}
59 for e
in CPU_VARIANTS_EXTENSIONS
:
60 msg
+= " - {}\n".format(e
)
61 ValueError.__init
__(self
, msg
)
65 def version(with_time
=True):
69 return datetime
.datetime
.fromtimestamp(
70 time
.time()).strftime("%Y-%m-%d %H:%M:%S")
72 return datetime
.datetime
.fromtimestamp(
73 time
.time()).strftime("%Y-%m-%d")
76 def mem_decoder(address
, start
=26, end
=29):
77 return lambda a
: a
[start
:end
] == ((address
>> (start
+2)) & (2**(end
-start
))-1)
80 def get_mem_data(filename_or_regions
, endianness
="big", mem_size
=None):
81 # create memory regions
82 if isinstance(filename_or_regions
, dict):
83 regions
= filename_or_regions
85 filename
= filename_or_regions
86 _
, ext
= os
.path
.splitext(filename
)
88 f
= open(filename
, "r")
89 regions
= json
.load(f
)
92 regions
= {filename
: "0x00000000"}
96 for filename
, base
in regions
.items():
97 data_size
= max(int(base
, 16) + os
.path
.getsize(filename
), data_size
)
99 if mem_size
is not None:
100 assert data_size
< mem_size
, (
101 "file is too big: {}/{} bytes".format(
102 data_size
, mem_size
))
105 data
= [0]*math
.ceil(data_size
/4)
106 for filename
, base
in regions
.items():
107 with
open(filename
, "rb") as f
:
114 for _
in range(len(w
), 4):
116 if endianness
== "little":
117 data
[int(base
, 16)//4 + i
] = struct
.unpack("<I", w
)[0]
119 data
[int(base
, 16)//4 + i
] = struct
.unpack(">I", w
)[0]
124 class ReadOnlyDict(dict):
125 def __readonly__(self
, *args
, **kwargs
):
126 raise RuntimeError("Cannot modify ReadOnlyDict")
127 __setitem__
= __readonly__
128 __delitem__
= __readonly__
130 popitem
= __readonly__
132 update
= __readonly__
133 setdefault
= __readonly__
137 def csr_map_update(csr_map
, csr_peripherals
):
138 csr_map
.update(dict((n
, v
)
139 for v
, n
in enumerate(csr_peripherals
, start
=max(csr_map
.values()) + 1)))
142 class SoCController(Module
, AutoCSR
):
145 self
._scratch
= CSRStorage(32, reset
=0x12345678)
146 self
._bus
_errors
= CSRStatus(32)
151 self
.reset
= Signal()
152 self
.comb
+= self
.reset
.eq(self
._reset
.re
)
155 self
.bus_error
= Signal()
156 bus_errors
= Signal(32)
158 If(bus_errors
!= (2**len(bus_errors
)-1),
160 bus_errors
.eq(bus_errors
+ 1)
163 self
.comb
+= self
._bus
_errors
.status
.eq(bus_errors
)
166 class SoCCore(Module
):
168 "ctrl": 0, # provided by default (optional)
170 "uart_phy": 2, # provided by default (optional)
171 "uart": 3, # provided by default (optional)
172 "identifier_mem": 4, # provided by default (optional)
173 "timer0": 5, # provided by default (optional)
179 "rom": 0x00000000, # (default shadow @0x80000000)
180 "sram": 0x10000000, # (default shadow @0x90000000)
181 "main_ram": 0x40000000, # (default shadow @0xc0000000)
182 "csr": 0x60000000, # (default shadow @0xe0000000)
184 def __init__(self
, platform
, clk_freq
,
185 cpu_type
="vexriscv", cpu_reset_address
=0x00000000, cpu_variant
=None,
186 integrated_rom_size
=0, integrated_rom_init
=[],
187 integrated_sram_size
=4096, integrated_sram_init
=[],
188 integrated_main_ram_size
=0, integrated_main_ram_init
=[],
189 shadow_base
=0x80000000,
190 csr_data_width
=8, csr_address_width
=14, csr_expose
=False,
191 with_uart
=True, uart_name
="serial", uart_baudrate
=115200, uart_stub
=False,
192 ident
="", ident_version
=False,
193 wishbone_timeout_cycles
=1e6
,
198 self
.platform
= platform
199 self
.clk_freq
= clk_freq
201 if cpu_type
== "None":
203 self
.cpu_type
= cpu_type
205 # Support the old style which used underscore for separator
206 if cpu_variant
is None:
207 cpu_variant
= "standard"
208 cpu_variant
= cpu_variant
.replace('_', '+')
209 # Check for valid CPU variants.
210 cpu_variant_processor
, *cpu_variant_ext
= cpu_variant
.split('+')
211 for key
, values
in CPU_VARIANTS
.items():
212 if cpu_variant_processor
not in [key
,]+values
:
214 self
.cpu_variant
= key
217 raise InvalidCPUVariantError(cpu_variant
)
219 # Check for valid CPU extensions.
220 for ext
in sorted(cpu_variant_ext
):
221 if ext
not in CPU_VARIANTS_EXTENSIONS
:
222 raise InvalidCPUExtensionError(cpu_variant
)
223 self
.cpu_variant
+= "+"+ext
225 if integrated_rom_size
:
226 cpu_reset_address
= self
.mem_map
["rom"]
227 self
.cpu_reset_address
= cpu_reset_address
228 self
.config
["CPU_RESET_ADDR"] = self
.cpu_reset_address
230 self
.integrated_rom_size
= integrated_rom_size
231 self
.integrated_rom_initialized
= integrated_rom_init
!= []
232 self
.integrated_sram_size
= integrated_sram_size
233 self
.integrated_main_ram_size
= integrated_main_ram_size
235 self
.with_uart
= with_uart
236 self
.uart_baudrate
= uart_baudrate
238 self
.shadow_base
= shadow_base
240 self
.wishbone_timeout_cycles
= wishbone_timeout_cycles
242 self
.csr_data_width
= csr_data_width
243 self
.csr_address_width
= csr_address_width
244 self
.csr_expose
= csr_expose
246 self
.csr
= csr_bus
.Interface(csr_data_width
, csr_address_width
)
248 self
.with_ctrl
= with_ctrl
250 self
._memory
_regions
= [] # list of (name, origin, length)
251 self
._csr
_regions
= [] # list of (name, origin, busword, csr_list/Memory)
252 self
._constants
= [] # list of (name, value)
254 self
._wb
_masters
= []
257 self
.soc_interrupt_map
= {}
260 self
.submodules
.ctrl
= SoCController()
262 if cpu_type
is not None:
263 if cpu_type
== "lm32":
264 self
.add_cpu(lm32
.LM32(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
265 elif cpu_type
== "mor1kx" or cpu_type
== "or1k":
266 if cpu_type
== "or1k":
267 deprecated_warning("SoCCore's \"cpu-type\" to \"mor1kx\"")
268 self
.add_cpu(mor1kx
.MOR1KX(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
269 elif cpu_type
== "picorv32":
270 self
.add_cpu(picorv32
.PicoRV32(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
271 elif cpu_type
== "vexriscv":
272 self
.add_cpu(vexriscv
.VexRiscv(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
273 elif cpu_type
== "minerva":
274 self
.add_cpu(minerva
.Minerva(platform
, self
.cpu_reset_address
, self
.cpu_variant
))
276 raise ValueError("Unsupported CPU type: {}".format(cpu_type
))
277 self
.add_wb_master(self
.cpu
.ibus
)
278 self
.add_wb_master(self
.cpu
.dbus
)
280 self
.comb
+= self
.cpu
.reset
.eq(self
.ctrl
.reset
)
281 # add cpu reserved interrupts
282 for name
, _id
in self
.cpu
.reserved_interrupts
.items():
283 self
.add_interrupt(name
, _id
)
285 # add user interrupts
286 for name
, _id
in self
.interrupt_map
.items():
287 self
.add_interrupt(name
, _id
)
289 self
.config
["CPU_TYPE"] = str(cpu_type
).upper()
291 self
.config
["CPU_VARIANT"] = str(cpu_type
).upper()
293 if integrated_rom_size
:
294 self
.submodules
.rom
= wishbone
.SRAM(integrated_rom_size
, read_only
=True, init
=integrated_rom_init
)
295 self
.register_rom(self
.rom
.bus
, integrated_rom_size
)
297 if integrated_sram_size
:
298 self
.submodules
.sram
= wishbone
.SRAM(integrated_sram_size
, init
=integrated_sram_init
)
299 self
.register_mem("sram", self
.mem_map
["sram"], self
.sram
.bus
, integrated_sram_size
)
301 # Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping.
302 if integrated_main_ram_size
:
303 self
.submodules
.main_ram
= wishbone
.SRAM(integrated_main_ram_size
, init
=integrated_main_ram_init
)
304 self
.register_mem("main_ram", self
.mem_map
["main_ram"], self
.main_ram
.bus
, integrated_main_ram_size
)
306 self
.submodules
.wishbone2csr
= wishbone2csr
.WB2CSR(
307 bus_csr
=csr_bus
.Interface(csr_data_width
, csr_address_width
))
308 self
.config
["CSR_DATA_WIDTH"] = csr_data_width
309 self
.add_constant("CSR_DATA_WIDTH", csr_data_width
)
310 self
.register_mem("csr", self
.mem_map
["csr"], self
.wishbone2csr
.wishbone
)
314 self
.submodules
.uart
= uart
.UARTStub()
316 self
.submodules
.uart_phy
= uart
.RS232PHY(platform
.request(uart_name
), clk_freq
, uart_baudrate
)
317 self
.submodules
.uart
= ResetInserter()(uart
.UART(self
.uart_phy
))
318 self
.add_interrupt("uart")
322 ident
= ident
+ " " + version()
323 self
.submodules
.identifier
= identifier
.Identifier(ident
)
324 self
.config
["CLOCK_FREQUENCY"] = int(clk_freq
)
325 self
.add_constant("SYSTEM_CLOCK_FREQUENCY", int(clk_freq
))
328 self
.submodules
.timer0
= timer
.Timer()
329 self
.add_interrupt("timer0")
331 def add_cpu(self
, cpu
):
334 if hasattr(self
, "cpu"):
335 raise NotImplementedError("More than one CPU is not supported")
336 self
.submodules
.cpu
= cpu
338 def add_cpu_or_bridge(self
, cpu_or_bridge
):
339 deprecated_warning("SoCCore's \"add_cpu_or_bridge\" call to \"add_cpu\"")
340 self
.add_cpu(cpu_or_bridge
)
341 self
.cpu_or_bridge
= self
.cpu
343 def add_interrupt(self
, interrupt_name
, interrupt_id
=None):
344 # check that interrupt_name is not already used
345 if interrupt_name
in self
.soc_interrupt_map
.keys():
346 print(self
.soc_interrupt_map
)
347 raise ValueError("Interrupt conflit, {} name already used".format(interrupt_name
))
349 # check that interrupt_id is in range
350 if interrupt_id
is not None and interrupt_id
> 31:
351 raise ValueError("{} Interrupt ID out of range ({}, max=31)".format(
352 interrupt_namename
, interrupt_id
))
354 # interrupt_id not provided: allocate interrupt to the first available id
355 if interrupt_id
is None:
357 if n
not in self
.soc_interrupt_map
.values():
358 self
.soc_interrupt_map
.update({interrupt_name
: n
})
360 raise ValueError("No more space to allocate {} interrupt".format(name
))
361 # interrupt_id provided: check that interrupt_id is not already used and add interrupt
363 for _name
, _id
in self
.soc_interrupt_map
.items():
364 if interrupt_id
== _id
:
365 raise ValueError("Interrupt conflict, {} already used by {} interrupt".format(
366 interrupt_id
, _name
))
367 self
.soc_interrupt_map
.update({interrupt_name
: interrupt_id
})
369 def initialize_rom(self
, data
):
370 self
.rom
.mem
.init
= data
372 def add_wb_master(self
, wbm
):
375 self
._wb
_masters
.append(wbm
)
377 def add_wb_slave(self
, address_decoder
, interface
):
380 self
._wb
_slaves
.append((address_decoder
, interface
))
382 def add_memory_region(self
, name
, origin
, length
):
383 def in_this_region(addr
):
384 return addr
>= origin
and addr
< origin
+ length
385 for n
, o
, l
in self
._memory
_regions
:
386 if n
== name
or in_this_region(o
) or in_this_region(o
+l
-1):
387 raise ValueError("Memory region conflict between {} and {}".format(n
, name
))
389 self
._memory
_regions
.append((name
, origin
, length
))
391 def register_mem(self
, name
, address
, interface
, size
=None):
392 self
.add_wb_slave(mem_decoder(address
), interface
)
394 self
.add_memory_region(name
, address
, size
)
396 def register_rom(self
, interface
, rom_size
=0xa000):
397 self
.add_wb_slave(mem_decoder(self
.mem_map
["rom"]), interface
)
398 self
.add_memory_region("rom", self
.cpu_reset_address
, rom_size
)
400 def get_memory_regions(self
):
401 return self
._memory
_regions
403 def check_csr_range(self
, name
, addr
):
404 if addr
>= 1<<(self
.csr_address_width
+2):
405 raise ValueError("{} CSR out of range, increase csr_address_width".format(name
))
407 def check_csr_region(self
, name
, origin
):
408 for n
, o
, l
, obj
in self
._csr
_regions
:
409 if n
== name
or o
== origin
:
410 raise ValueError("CSR region conflict between {} and {}".format(n
, name
))
412 def add_csr_region(self
, name
, origin
, busword
, obj
):
413 self
.check_csr_region(name
, origin
)
414 self
._csr
_regions
.append((name
, origin
, busword
, obj
))
416 def get_csr_regions(self
):
417 return self
._csr
_regions
419 def add_constant(self
, name
, value
=None):
420 self
._constants
.append((name
, value
))
422 def get_constants(self
):
424 for _name
, _id
in sorted(self
.soc_interrupt_map
.items()):
425 r
.append((_name
.upper() + "_INTERRUPT", _id
))
429 def get_csr_dev_address(self
, name
, memory
):
430 if memory
is not None:
431 name
= name
+ "_" + memory
.name_override
433 return self
.csr_map
[name
]
434 except KeyError as e
:
435 msg
= "Undefined \"{}\" CSR.\n".format(name
)
436 msg
+= "Avalaible CSRs in {} ({}):\n".format(
437 self
.__class
__.__name
__, inspect
.getfile(self
.__class
__))
438 for k
in sorted(self
.csr_map
.keys()):
439 msg
+= "- {}\n".format(k
)
440 raise RuntimeError(msg
)
444 def do_finalize(self
):
445 registered_mems
= {regions
[0] for regions
in self
._memory
_regions
}
446 if self
.cpu_type
is not None:
447 for mem
in "rom", "sram":
448 if mem
not in registered_mems
:
449 raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem
))
451 if len(self
._wb
_masters
):
453 self
.submodules
.wishbonecon
= wishbone
.InterconnectShared(self
._wb
_masters
,
454 self
._wb
_slaves
, register
=True, timeout_cycles
=self
.wishbone_timeout_cycles
)
455 if self
.with_ctrl
and (self
.wishbone_timeout_cycles
is not None):
456 self
.comb
+= self
.ctrl
.bus_error
.eq(self
.wishbonecon
.timeout
.error
)
459 self
.submodules
.csrbankarray
= csr_bus
.CSRBankArray(self
,
460 self
.get_csr_dev_address
,
461 data_width
=self
.csr_data_width
, address_width
=self
.csr_address_width
)
463 self
.submodules
.csrcon
= csr_bus
.InterconnectShared(
464 [self
.csr
, self
.wishbone2csr
.csr
], self
.csrbankarray
.get_buses())
466 self
.submodules
.csrcon
= csr_bus
.Interconnect(
467 self
.wishbone2csr
.csr
, self
.csrbankarray
.get_buses())
468 for name
, csrs
, mapaddr
, rmap
in self
.csrbankarray
.banks
:
469 self
.check_csr_range(name
, 0x800*mapaddr
)
470 self
.add_csr_region(name
, (self
.mem_map
["csr"] + 0x800*mapaddr
) | self
.shadow_base
, self
.csr_data_width
, csrs
)
471 for name
, memory
, mapaddr
, mmap
in self
.csrbankarray
.srams
:
472 self
.check_csr_range(name
, 0x800*mapaddr
)
473 self
.add_csr_region(name
+ "_" + memory
.name_override
, (self
.mem_map
["csr"] + 0x800*mapaddr
) | self
.shadow_base
, self
.csr_data_width
, memory
)
474 for name
, constant
in self
.csrbankarray
.constants
:
475 self
._constants
.append(((name
+ "_" + constant
.name
).upper(), constant
.value
.value
))
476 for name
, value
in sorted(self
.config
.items(), key
=itemgetter(0)):
477 self
._constants
.append(("CONFIG_" + name
.upper(), value
))
480 if hasattr(self
, "cpu"):
481 if hasattr(self
.cpu
, "interrupt"):
482 for _name
, _id
in sorted(self
.soc_interrupt_map
.items()):
483 if _name
in self
.cpu
.reserved_interrupts
.keys():
485 if hasattr(self
, _name
):
486 module
= getattr(self
, _name
)
487 assert hasattr(module
, 'ev'), "Submodule %s does not have EventManager (xx.ev) module" % _name
488 self
.comb
+= self
.cpu
.interrupt
[_id
].eq(module
.ev
.irq
)
490 def build(self
, *args
, **kwargs
):
491 return self
.platform
.build(self
, *args
, **kwargs
)
494 def soc_core_args(parser
):
495 parser
.add_argument("--cpu-type", default
=None,
496 help="select CPU: lm32, or1k, picorv32, vexriscv, minerva")
497 parser
.add_argument("--cpu-variant", default
=None,
498 help="select CPU variant")
499 parser
.add_argument("--integrated-rom-size", default
=None, type=int,
500 help="size/enable the integrated (BIOS) ROM")
501 parser
.add_argument("--integrated-main-ram-size", default
=None, type=int,
502 help="size/enable the integrated main RAM")
503 parser
.add_argument("--uart-stub", default
=False, type=bool,
504 help="enable uart stub")
507 def soc_core_argdict(args
):
512 "integrated_rom_size",
513 "integrated_main_ram_size",
515 arg
= getattr(args
, a
)