mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
93de581931
When don't necessary want to have shadow memories and be able to start CSR at address 0x00000000(for example with an X86 CPU)
204 lines
8.3 KiB
Python
204 lines
8.3 KiB
Python
from operator import itemgetter
|
|
|
|
from migen.fhdl.std import *
|
|
from migen.bank import csrgen
|
|
from migen.bus import wishbone, csr, wishbone2csr
|
|
|
|
from misoclib.com.uart.phy import UARTPHY
|
|
from misoclib.com import uart
|
|
from misoclib.cpu import lm32, mor1kx
|
|
from misoclib.cpu.peripherals import identifier, timer
|
|
|
|
|
|
def mem_decoder(address, start=26, end=29):
|
|
return lambda a: a[start:end] == ((address >> (start+2)) & (2**(end-start))-1)
|
|
|
|
|
|
class SoC(Module):
|
|
csr_map = {
|
|
"crg": 0, # user
|
|
"uart_phy": 1, # provided by default (optional)
|
|
"uart": 2, # provided by default (optional)
|
|
"identifier": 3, # provided by default (optional)
|
|
"timer0": 4, # provided by default (optional)
|
|
"buttons": 5, # user
|
|
"leds": 6, # user
|
|
}
|
|
interrupt_map = {
|
|
"uart": 0,
|
|
"timer0": 1,
|
|
}
|
|
mem_map = {
|
|
"rom": 0x00000000, # (default shadow @0x80000000)
|
|
"sram": 0x10000000, # (default shadow @0x90000000)
|
|
"main_ram": 0x40000000, # (default shadow @0xc0000000)
|
|
"csr": 0x60000000, # (default shadow @0xe0000000)
|
|
}
|
|
def __init__(self, platform, clk_freq,
|
|
cpu_type="lm32", cpu_reset_address=0x00000000,
|
|
integrated_rom_size=0,
|
|
integrated_sram_size=4096,
|
|
integrated_main_ram_size=0,
|
|
shadow_address=0x80000000,
|
|
with_csr=True, csr_data_width=8, csr_address_width=14,
|
|
with_uart=True, uart_baudrate=115200,
|
|
with_identifier=True,
|
|
with_timer=True):
|
|
self.platform = platform
|
|
self.clk_freq = clk_freq
|
|
|
|
self.cpu_type = cpu_type
|
|
if integrated_rom_size:
|
|
cpu_reset_address = 0
|
|
self.cpu_reset_address = cpu_reset_address
|
|
|
|
self.integrated_rom_size = integrated_rom_size
|
|
self.integrated_sram_size = integrated_sram_size
|
|
self.integrated_main_ram_size = integrated_main_ram_size
|
|
|
|
self.with_uart = with_uart
|
|
self.uart_baudrate = uart_baudrate
|
|
|
|
self.with_identifier = with_identifier
|
|
|
|
self.shadow_address = shadow_address
|
|
|
|
self.with_csr = with_csr
|
|
self.csr_data_width = csr_data_width
|
|
self.csr_address_width = csr_address_width
|
|
|
|
self._memory_regions = [] # list of (name, origin, length)
|
|
self._csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
|
|
self._constants = [] # list of (name, value)
|
|
|
|
self._wb_masters = []
|
|
self._wb_slaves = []
|
|
|
|
if cpu_type != "none":
|
|
if cpu_type == "lm32":
|
|
self.add_cpu_or_bridge(lm32.LM32(platform, self.cpu_reset_address))
|
|
elif cpu_type == "or1k":
|
|
self.add_cpu_or_bridge(mor1kx.MOR1KX(platform, self.cpu_reset_address))
|
|
else:
|
|
raise ValueError("Unsupported CPU type: {}".format(cpu_type))
|
|
self.add_wb_master(self.cpu_or_bridge.ibus)
|
|
self.add_wb_master(self.cpu_or_bridge.dbus)
|
|
|
|
if integrated_rom_size:
|
|
self.submodules.rom = wishbone.SRAM(integrated_rom_size, read_only=True)
|
|
self.register_rom(self.rom.bus, integrated_rom_size)
|
|
|
|
if integrated_sram_size:
|
|
self.submodules.sram = wishbone.SRAM(integrated_sram_size)
|
|
self.register_mem("sram", self.mem_map["sram"], self.sram.bus, integrated_sram_size)
|
|
|
|
# Note: Main Ram can be used when no external SDRAM is available and use SDRAM mapping.
|
|
if integrated_main_ram_size:
|
|
self.submodules.main_ram = wishbone.SRAM(integrated_main_ram_size)
|
|
self.register_mem("main_ram", self.mem_map["main_ram"], self.main_ram.bus, integrated_main_ram_size)
|
|
|
|
if with_csr:
|
|
self.submodules.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(csr_data_width, csr_address_width))
|
|
self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
|
|
|
|
if with_uart:
|
|
self.submodules.uart_phy = UARTPHY(platform.request("serial"), clk_freq, uart_baudrate)
|
|
self.submodules.uart = uart.UART(self.uart_phy)
|
|
|
|
if with_identifier:
|
|
platform_id = 0x554E if not hasattr(platform, "identifier") else platform.identifier
|
|
self.submodules.identifier = identifier.Identifier(platform_id, int(clk_freq))
|
|
|
|
if with_timer:
|
|
self.submodules.timer0 = timer.Timer()
|
|
|
|
def add_cpu_or_bridge(self, cpu_or_bridge):
|
|
if self.finalized:
|
|
raise FinalizeError
|
|
if hasattr(self, "cpu_or_bridge"):
|
|
raise NotImplementedError("More than one CPU is not supported")
|
|
self.submodules.cpu_or_bridge = cpu_or_bridge
|
|
|
|
def init_rom(self, data):
|
|
self.rom.mem.init = data
|
|
|
|
def add_wb_master(self, wbm):
|
|
if self.finalized:
|
|
raise FinalizeError
|
|
self._wb_masters.append(wbm)
|
|
|
|
def add_wb_slave(self, address_decoder, interface):
|
|
if self.finalized:
|
|
raise FinalizeError
|
|
self._wb_slaves.append((address_decoder, interface))
|
|
|
|
def add_memory_region(self, name, origin, length):
|
|
def in_this_region(addr):
|
|
return addr >= origin and addr < origin + length
|
|
for n, o, l in self._memory_regions:
|
|
if n == name or in_this_region(o) or in_this_region(o+l-1):
|
|
raise ValueError("Memory region conflict between {} and {}".format(n, name))
|
|
|
|
self._memory_regions.append((name, origin, length))
|
|
|
|
def register_mem(self, name, address, interface, size=None):
|
|
self.add_wb_slave(mem_decoder(address), interface)
|
|
if size is not None:
|
|
self.add_memory_region(name, address, size)
|
|
|
|
def register_rom(self, interface, rom_size=0xa000):
|
|
self.add_wb_slave(mem_decoder(self.mem_map["rom"]), interface)
|
|
self.add_memory_region("rom", self.cpu_reset_address, rom_size)
|
|
|
|
def get_memory_regions(self):
|
|
return self._memory_regions
|
|
|
|
def check_csr_region(self, name, origin):
|
|
for n, o, l, obj in self._csr_regions:
|
|
if n == name or o == origin:
|
|
raise ValueError("CSR region conflict between {} and {}".format(n, name))
|
|
|
|
def add_csr_region(self, name, origin, busword, obj):
|
|
self.check_csr_region(name, origin)
|
|
self._csr_regions.append((name, origin, busword, obj))
|
|
|
|
def get_csr_regions(self):
|
|
return self._csr_regions
|
|
|
|
def add_constant(self, name, value):
|
|
self._constants.append((name, value))
|
|
|
|
def get_constants(self):
|
|
r = []
|
|
for name, interrupt in sorted(self.interrupt_map.items(), key=itemgetter(1)):
|
|
r.append((name.upper() + "_INTERRUPT", interrupt))
|
|
r += self._constants
|
|
return r
|
|
|
|
def do_finalize(self):
|
|
registered_mems = {regions[0] for regions in self._memory_regions}
|
|
if self.cpu_type != "none":
|
|
for mem in "rom", "sram":
|
|
if mem not in registered_mems:
|
|
raise FinalizeError("CPU needs a {} to be registered with SoC.register_mem()".format(mem))
|
|
|
|
# Wishbone
|
|
self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
|
|
self._wb_slaves, register=True)
|
|
|
|
# CSR
|
|
if self.with_csr:
|
|
self.submodules.csrbankarray = csrgen.BankArray(self,
|
|
lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
|
|
data_width=self.csr_data_width, address_width=self.csr_address_width)
|
|
self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
|
|
for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
|
|
self.add_csr_region(name, self.mem_map["csr"]+self.shadow_address+0x800*mapaddr, self.csr_data_width, csrs)
|
|
for name, memory, mapaddr, mmap in self.csrbankarray.srams:
|
|
self.add_csr_region(name + "_" + memory.name_override, self.mem_map["csr"]+self.shadow_address+0x800*mapaddr, self.csr_data_width, memory)
|
|
|
|
# Interrupts
|
|
if hasattr(self.cpu_or_bridge, "interrupt"):
|
|
for k, v in sorted(self.interrupt_map.items(), key=itemgetter(1)):
|
|
if hasattr(self, k):
|
|
self.comb += self.cpu_or_bridge.interrupt[v].eq(getattr(self, k).ev.irq)
|