integration/soc_core: rework interrupt assignation/reservation
The CPUs can now reserve specific interrupts with reserved_interrupts property. User can still define interrupts in SoCCore.interrupt_map (old way) or use add_interrupt method. Interrupts specific to SoCCore internal modules are allocated automatically on the remaining free interrupt ids. Priority for the interrupts allocation: - 1) CPU reserved interrupts. - 2) User interrupts. - 3) SoCCore interrupts.
This commit is contained in:
parent
3ee9ce0529
commit
47dc87584f
|
@ -49,7 +49,7 @@ class MOR1KX(Module):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reserved_interrupts(self):
|
def reserved_interrupts(self):
|
||||||
return { "nmi": 0 }
|
return {"nmi": 0}
|
||||||
|
|
||||||
def __init__(self, platform, reset_pc, variant="standard"):
|
def __init__(self, platform, reset_pc, variant="standard"):
|
||||||
assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant
|
assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant
|
||||||
|
|
|
@ -47,7 +47,11 @@ class PicoRV32(Module):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def reserved_interrupts(self):
|
def reserved_interrupts(self):
|
||||||
return { "picorv32_timer": 0, "picorv32_ebreak_ecall_illegal": 1, "picorv32_bus_error": 2 }
|
return {
|
||||||
|
"timer": 0,
|
||||||
|
"ebreak_ecall_illegal": 1,
|
||||||
|
"bus_error": 2
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, platform, progaddr_reset, variant="standard"):
|
def __init__(self, platform, progaddr_reset, variant="standard"):
|
||||||
assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant
|
assert variant in CPU_VARIANTS, "Unsupported variant %s" % variant
|
||||||
|
|
|
@ -175,10 +175,6 @@ class SoCCore(Module):
|
||||||
"leds": 7, # user
|
"leds": 7, # user
|
||||||
}
|
}
|
||||||
interrupt_map = {}
|
interrupt_map = {}
|
||||||
soc_interrupt_map = {
|
|
||||||
"timer0": 1, # LiteX Timer
|
|
||||||
"uart": 2, # LiteX UART (IRQ 2 for UART matches mor1k standard config).
|
|
||||||
}
|
|
||||||
mem_map = {
|
mem_map = {
|
||||||
"rom": 0x00000000, # (default shadow @0x80000000)
|
"rom": 0x00000000, # (default shadow @0x80000000)
|
||||||
"sram": 0x10000000, # (default shadow @0x90000000)
|
"sram": 0x10000000, # (default shadow @0x90000000)
|
||||||
|
@ -195,7 +191,6 @@ class SoCCore(Module):
|
||||||
with_uart=True, uart_name="serial", uart_baudrate=115200, uart_stub=False,
|
with_uart=True, uart_name="serial", uart_baudrate=115200, uart_stub=False,
|
||||||
ident="", ident_version=False,
|
ident="", ident_version=False,
|
||||||
wishbone_timeout_cycles=1e6,
|
wishbone_timeout_cycles=1e6,
|
||||||
reserve_nmi_interrupt=True,
|
|
||||||
with_timer=True,
|
with_timer=True,
|
||||||
with_ctrl=True):
|
with_ctrl=True):
|
||||||
self.config = dict()
|
self.config = dict()
|
||||||
|
@ -259,6 +254,8 @@ class SoCCore(Module):
|
||||||
self._wb_masters = []
|
self._wb_masters = []
|
||||||
self._wb_slaves = []
|
self._wb_slaves = []
|
||||||
|
|
||||||
|
self.soc_interrupt_map = {}
|
||||||
|
|
||||||
if with_ctrl:
|
if with_ctrl:
|
||||||
self.submodules.ctrl = SoCController()
|
self.submodules.ctrl = SoCController()
|
||||||
|
|
||||||
|
@ -281,6 +278,14 @@ class SoCCore(Module):
|
||||||
self.add_wb_master(self.cpu.dbus)
|
self.add_wb_master(self.cpu.dbus)
|
||||||
if with_ctrl:
|
if with_ctrl:
|
||||||
self.comb += self.cpu.reset.eq(self.ctrl.reset)
|
self.comb += self.cpu.reset.eq(self.ctrl.reset)
|
||||||
|
# add cpu reserved interrupts
|
||||||
|
for name, _id in self.cpu.reserved_interrupts.items():
|
||||||
|
self.add_interrupt(name, _id)
|
||||||
|
|
||||||
|
# add user interrupts
|
||||||
|
for name, _id in self.interrupt_map.items():
|
||||||
|
self.add_interrupt(name, _id)
|
||||||
|
|
||||||
self.config["CPU_TYPE"] = str(cpu_type).upper()
|
self.config["CPU_TYPE"] = str(cpu_type).upper()
|
||||||
if self.cpu_variant:
|
if self.cpu_variant:
|
||||||
self.config["CPU_VARIANT"] = str(cpu_type).upper()
|
self.config["CPU_VARIANT"] = str(cpu_type).upper()
|
||||||
|
@ -304,18 +309,13 @@ class SoCCore(Module):
|
||||||
self.add_constant("CSR_DATA_WIDTH", csr_data_width)
|
self.add_constant("CSR_DATA_WIDTH", csr_data_width)
|
||||||
self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
|
self.register_mem("csr", self.mem_map["csr"], self.wishbone2csr.wishbone)
|
||||||
|
|
||||||
if reserve_nmi_interrupt:
|
|
||||||
self.soc_interrupt_map["nmi"] = 0 # Reserve zero for "non-maskable interrupt"
|
|
||||||
|
|
||||||
if with_uart:
|
if with_uart:
|
||||||
if uart_stub:
|
if uart_stub:
|
||||||
self.submodules.uart = uart.UARTStub()
|
self.submodules.uart = uart.UARTStub()
|
||||||
else:
|
else:
|
||||||
self.submodules.uart_phy = uart.RS232PHY(platform.request(uart_name), clk_freq, uart_baudrate)
|
self.submodules.uart_phy = uart.RS232PHY(platform.request(uart_name), clk_freq, uart_baudrate)
|
||||||
self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy))
|
self.submodules.uart = ResetInserter()(uart.UART(self.uart_phy))
|
||||||
|
self.add_interrupt("uart")
|
||||||
#else:
|
|
||||||
# del self.soc_interrupt_map["uart"]
|
|
||||||
|
|
||||||
if ident:
|
if ident:
|
||||||
if ident_version:
|
if ident_version:
|
||||||
|
@ -326,36 +326,7 @@ class SoCCore(Module):
|
||||||
|
|
||||||
if with_timer:
|
if with_timer:
|
||||||
self.submodules.timer0 = timer.Timer()
|
self.submodules.timer0 = timer.Timer()
|
||||||
#else:
|
self.add_interrupt("timer0")
|
||||||
# del self.soc_interrupt_map["timer0"]
|
|
||||||
|
|
||||||
# Invert the interrupt map.
|
|
||||||
interrupt_rmap = {}
|
|
||||||
for mod_name, interrupt in self.interrupt_map.items():
|
|
||||||
assert interrupt not in interrupt_rmap, (
|
|
||||||
"Interrupt vector conflict for IRQ %s, user defined %s conflicts with user defined %s" % (
|
|
||||||
interrupt, mod_name, interrupt_rmap[interrupt]))
|
|
||||||
|
|
||||||
interrupt_rmap[interrupt] = mod_name
|
|
||||||
|
|
||||||
# Add the base SoC's interrupt map
|
|
||||||
for mod_name, interrupt in self.soc_interrupt_map.items():
|
|
||||||
assert interrupt not in interrupt_rmap or mod_name == interrupt_rmap[interrupt], (
|
|
||||||
"Interrupt vector conflict for IRQ %s, user defined %s conflicts with SoC inbuilt %s" % (
|
|
||||||
interrupt, mod_name, interrupt_rmap[interrupt]))
|
|
||||||
|
|
||||||
self.interrupt_map[mod_name] = interrupt
|
|
||||||
interrupt_rmap[interrupt] = mod_name
|
|
||||||
|
|
||||||
# Make sure other functions are not using this value.
|
|
||||||
self.soc_interrupt_map = None
|
|
||||||
|
|
||||||
# Make the interrupt vector read only
|
|
||||||
self.interrupt_map = ReadOnlyDict(self.interrupt_map)
|
|
||||||
|
|
||||||
# Save the interrupt reverse map
|
|
||||||
self.interrupt_rmap = ReadOnlyDict(interrupt_rmap)
|
|
||||||
|
|
||||||
|
|
||||||
def add_cpu(self, cpu):
|
def add_cpu(self, cpu):
|
||||||
if self.finalized:
|
if self.finalized:
|
||||||
|
@ -369,6 +340,32 @@ class SoCCore(Module):
|
||||||
self.add_cpu(cpu_or_bridge)
|
self.add_cpu(cpu_or_bridge)
|
||||||
self.cpu_or_bridge = self.cpu
|
self.cpu_or_bridge = self.cpu
|
||||||
|
|
||||||
|
def add_interrupt(self, interrupt_name, interrupt_id=None):
|
||||||
|
# check that interrupt_name is not already used
|
||||||
|
if interrupt_name in self.soc_interrupt_map.keys():
|
||||||
|
print(self.soc_interrupt_map)
|
||||||
|
raise ValueError("Interrupt conflit, {} name already used".format(interrupt_name))
|
||||||
|
|
||||||
|
# check that interrupt_id is in range
|
||||||
|
if interrupt_id is not None and interrupt_id > 31:
|
||||||
|
raise ValueError("{} Interrupt ID out of range ({}, max=31)".format(
|
||||||
|
interrupt_namename, interrupt_id))
|
||||||
|
|
||||||
|
# interrupt_id not provided: allocate interrupt to the first available id
|
||||||
|
if interrupt_id is None:
|
||||||
|
for n in range(32):
|
||||||
|
if n not in self.soc_interrupt_map.values():
|
||||||
|
self.soc_interrupt_map.update({interrupt_name: n})
|
||||||
|
return
|
||||||
|
raise ValueError("No more space to allocate {} interrupt".format(name))
|
||||||
|
# interrupt_id provided: check that interrupt_id is not already used and add interrupt
|
||||||
|
else:
|
||||||
|
for _name, _id in self.soc_interrupt_map.items():
|
||||||
|
if interrupt_id == _id:
|
||||||
|
raise ValueError("Interrupt conflict, {} already used by {} interrupt".format(
|
||||||
|
interrupt_id, _name))
|
||||||
|
self.soc_interrupt_map.update({interrupt_name: interrupt_id})
|
||||||
|
|
||||||
def initialize_rom(self, data):
|
def initialize_rom(self, data):
|
||||||
self.rom.mem.init = data
|
self.rom.mem.init = data
|
||||||
|
|
||||||
|
@ -424,8 +421,8 @@ class SoCCore(Module):
|
||||||
|
|
||||||
def get_constants(self):
|
def get_constants(self):
|
||||||
r = []
|
r = []
|
||||||
for interrupt, name in sorted(self.interrupt_rmap.items()):
|
for _name, _id in sorted(self.soc_interrupt_map.items()):
|
||||||
r.append((name.upper() + "_INTERRUPT", interrupt))
|
r.append((_name.upper() + "_INTERRUPT", _id))
|
||||||
r += self._constants
|
r += self._constants
|
||||||
return r
|
return r
|
||||||
|
|
||||||
|
@ -482,13 +479,13 @@ class SoCCore(Module):
|
||||||
# Interrupts
|
# Interrupts
|
||||||
if hasattr(self, "cpu"):
|
if hasattr(self, "cpu"):
|
||||||
if hasattr(self.cpu, "interrupt"):
|
if hasattr(self.cpu, "interrupt"):
|
||||||
for interrupt, mod_name in sorted(self.interrupt_rmap.items()):
|
for _name, _id in sorted(self.soc_interrupt_map.items()):
|
||||||
if mod_name == "nmi":
|
if _name in self.cpu.reserved_interrupts.keys():
|
||||||
continue
|
continue
|
||||||
if hasattr(self, mod_name):
|
if hasattr(self, _name):
|
||||||
mod_impl = getattr(self, mod_name)
|
module = getattr(self, _name)
|
||||||
assert hasattr(mod_impl, 'ev'), "Submodule %s does not have EventManager (xx.ev) module" % mod_name
|
assert hasattr(module, 'ev'), "Submodule %s does not have EventManager (xx.ev) module" % _name
|
||||||
self.comb += self.cpu.interrupt[interrupt].eq(mod_impl.ev.irq)
|
self.comb += self.cpu.interrupt[_id].eq(module.ev.irq)
|
||||||
|
|
||||||
def build(self, *args, **kwargs):
|
def build(self, *args, **kwargs):
|
||||||
return self.platform.build(self, *args, **kwargs)
|
return self.platform.build(self, *args, **kwargs)
|
||||||
|
|
|
@ -124,6 +124,7 @@ class SimSoC(SoCSDRAM):
|
||||||
# serial
|
# serial
|
||||||
self.submodules.uart_phy = uart.RS232PHYModel(platform.request("serial"))
|
self.submodules.uart_phy = uart.RS232PHYModel(platform.request("serial"))
|
||||||
self.submodules.uart = uart.UART(self.uart_phy)
|
self.submodules.uart = uart.UART(self.uart_phy)
|
||||||
|
self.add_interrupt("uart")
|
||||||
|
|
||||||
# sdram
|
# sdram
|
||||||
if with_sdram:
|
if with_sdram:
|
||||||
|
|
Loading…
Reference in New Issue