1 from operator
import itemgetter
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
10 __all__
= ["mem_decoder", "SoCCore", "soc_core_args", "soc_core_argdict"]
13 def version(with_time
=True):
17 return datetime
.datetime
.fromtimestamp(
18 time
.time()).strftime("%Y-%m-%d %H:%M:%S")
20 return datetime
.datetime
.fromtimestamp(
21 time
.time()).strftime("%Y-%m-%d")
24 def mem_decoder(address
, start
=26, end
=29):
25 return lambda a
: a
[start
:end
] == ((address
>> (start
+2)) & (2**(end
-start
))-1)
28 class ReadOnlyDict(dict):
29 def __readonly__(self
, *args
, **kwargs
):
30 raise RuntimeError("Cannot modify ReadOnlyDict")
31 __setitem__
= __readonly__
32 __delitem__
= __readonly__
34 popitem
= __readonly__
37 setdefault
= __readonly__
41 class SoCCore(Module
):
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)
53 "timer0": 1, # LiteX Timer
54 "uart": 2, # LiteX UART (IRQ 2 for UART matches mor1k standard config).
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)
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,
75 self
.platform
= platform
76 self
.clk_freq
= clk_freq
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
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
90 self
.with_uart
= with_uart
91 self
.uart_baudrate
= uart_baudrate
93 self
.shadow_base
= shadow_base
95 self
.csr_data_width
= csr_data_width
96 self
.csr_address_width
= csr_address_width
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)
102 self
._wb
_masters
= []
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
))
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()
118 self
.config
["CPU_VARIANT"] = str(cpu_type
).upper()
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
)
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
)
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
)
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
)
139 if reserve_nmi_interrupt
:
140 self
.soc_interrupt_map
["nmi"] = 0 # Reserve zero for "non-maskable interrupt"
144 self
.submodules
.uart
= uart
.UARTStub()
146 self
.submodules
.uart_phy
= uart
.RS232PHY(platform
.request(uart_name
), clk_freq
, uart_baudrate
)
147 self
.submodules
.uart
= uart
.UART(self
.uart_phy
)
149 # del self.soc_interrupt_map["uart"]
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
))
159 self
.submodules
.timer0
= timer
.Timer()
161 del self
.soc_interrupt_map
["timer0"]
163 # Invert the interrupt map.
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
]))
170 interrupt_rmap
[interrupt
] = mod_name
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
]))
178 self
.interrupt_map
[mod_name
] = interrupt
179 interrupt_rmap
[interrupt
] = mod_name
181 # Make sure other functions are not using this value.
182 self
.soc_interrupt_map
= None
184 # Make the interrupt vector read only
185 self
.interrupt_map
= ReadOnlyDict(self
.interrupt_map
)
187 # Save the interrupt reverse map
188 self
.interrupt_rmap
= ReadOnlyDict(interrupt_rmap
)
191 def add_cpu_or_bridge(self
, cpu_or_bridge
):
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
198 def initialize_rom(self
, data
):
199 self
.rom
.mem
.init
= data
201 def add_wb_master(self
, wbm
):
204 self
._wb
_masters
.append(wbm
)
206 def add_wb_slave(self
, address_decoder
, interface
):
209 self
._wb
_slaves
.append((address_decoder
, interface
))
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
))
218 self
._memory
_regions
.append((name
, origin
, length
))
220 def register_mem(self
, name
, address
, interface
, size
=None):
221 self
.add_wb_slave(mem_decoder(address
), interface
)
223 self
.add_memory_region(name
, address
, size
)
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
)
229 def get_memory_regions(self
):
230 return self
._memory
_regions
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
))
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
))
241 def get_csr_regions(self
):
242 return self
._csr
_regions
244 def add_constant(self
, name
, value
=None):
245 self
._constants
.append((name
, value
))
247 def get_constants(self
):
249 for interrupt
, name
in sorted(self
.interrupt_rmap
.items()):
250 r
.append((name
.upper() + "_INTERRUPT", interrupt
))
254 def get_csr_dev_address(self
, name
, memory
):
255 if memory
is not None:
256 name
= name
+ "_" + memory
.name_override
258 return self
.csr_map
[name
]
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
))
269 if len(self
._wb
_masters
):
271 self
.submodules
.wishbonecon
= wishbone
.InterconnectShared(self
._wb
_masters
,
272 self
._wb
_slaves
, register
=True)
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
))
290 if hasattr(self
.cpu_or_bridge
, "interrupt"):
291 for interrupt
, mod_name
in sorted(self
.interrupt_rmap
.items()):
292 if mod_name
== "nmi":
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
)
299 def build(self
, *args
, **kwargs
):
300 return self
.platform
.build(self
, *args
, **kwargs
)
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")
312 def soc_core_argdict(args
):
314 for a
in "cpu_type", "integrated_rom_size", "integrated_main_ram_size":
315 arg
= getattr(args
, a
)