From ffe70742b1fb287ba1766df8a8e55ec2190db797 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Fri, 4 Sep 2020 16:11:10 +0100 Subject: [PATCH] adding option to include XICS external interrupts. XICS ICP and ICS are included, the wishbone slave ports added to TestIssuer then if ext_irq is raised in core, execution jumps to 0x500 through a TRAP --- src/soc/config/state.py | 5 +++-- src/soc/consts.py | 5 +++-- src/soc/decoder/power_decoder2.py | 14 ++++++++---- src/soc/fu/trap/main_stage.py | 3 +++ src/soc/interrupts/xics.py | 4 ++-- src/soc/litex/florent/sim.py | 2 ++ src/soc/simple/core.py | 6 +++++ src/soc/simple/issuer.py | 37 ++++++++++++++++++++++--------- src/soc/simple/issuer_verilog.py | 1 + 9 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/soc/config/state.py b/src/soc/config/state.py index 4035543e..e4cef69c 100644 --- a/src/soc/config/state.py +++ b/src/soc/config/state.py @@ -5,5 +5,6 @@ from nmigen import Signal class CoreState(RecordObject): def __init__(self, name): super().__init__(name=name) - self.pc = Signal(64) # Program Counter (CIA, NIA) - self.msr = Signal(64) # Machine Status Register (MSR) + self.pc = Signal(64) # Program Counter (CIA, NIA) + self.msr = Signal(64) # Machine Status Register (MSR) + self.eint = Signal() # External Interrupt diff --git a/src/soc/consts.py b/src/soc/consts.py index ff204488..505fce3d 100644 --- a/src/soc/consts.py +++ b/src/soc/consts.py @@ -141,6 +141,7 @@ class TT: PRIV = 1<<1 TRAP = 1<<2 ADDR = 1<<3 - ILLEG = 1<<4 # currently the max, therefore traptype must be 5 bits + EINT = 1<<4 # external interrupt + ILLEG = 1<<5 # currently the max, therefore traptype must be 5 bits # TODO: support for TM_BAD_THING (not included yet in trap main_stage.py) - size = 5 # MUST update this to contain the full number of Trap Types + size = 6 # MUST update this to contain the full number of Trap Types diff --git a/src/soc/decoder/power_decoder2.py b/src/soc/decoder/power_decoder2.py index edbbf878..f6b88a85 100644 --- a/src/soc/decoder/power_decoder2.py +++ b/src/soc/decoder/power_decoder2.py @@ -634,7 +634,7 @@ class PowerDecode2(Elaboratable): m = Module() comb = m.d.comb e_out, op, do_out = self.e, self.dec.op, self.e.do - msr, cia = self.state.msr, self.state.pc + msr, cia, ext_irq = self.state.msr, self.state.pc, self.state.eint # fill in for a normal instruction (not an exception) # copy over if non-exception, non-privileged etc. is detected @@ -749,9 +749,15 @@ class PowerDecode2(Elaboratable): # rverything including destroying read of RA and RB. comb += do.trapaddr.eq(0x70) # addr=0x700 (strip first nibble) - # TODO: get msr, then can do privileged instruction - with m.If(instr_is_priv(m, op.internal_op, e.do.insn) & msr[MSR.PR]): - # privileged instruction trap + # check if instruction is privileged + is_priv_insn = instr_is_priv(m, op.internal_op, e.do.insn) + + # external interrupt? + with m.If(ext_irq & msr[MSR.EE]): + self.trap(m, TT.EINT, 0x500) + + # privileged instruction trap + with m.Elif(is_priv_insn & msr[MSR.PR]): self.trap(m, TT.PRIV, 0x700) # illegal instruction must redirect to trap. this is done by diff --git a/src/soc/fu/trap/main_stage.py b/src/soc/fu/trap/main_stage.py index fa802a6b..9de2d9a6 100644 --- a/src/soc/fu/trap/main_stage.py +++ b/src/soc/fu/trap/main_stage.py @@ -195,6 +195,9 @@ class TrapMainStage(PipeModBase): comb += srr1_o.data[PI.FP].eq(1) with m.If(traptype & TT.ADDR): comb += srr1_o.data[PI.ADR].eq(1) + with m.If(traptype & TT.EINT): + # do nothing unusual? see 3.0B Book III 6.5.7 p1073 + pass with m.If(traptype & TT.ILLEG): comb += srr1_o.data[PI.ILLEG].eq(1) comb += srr1_o.ok.eq(1) diff --git a/src/soc/interrupts/xics.py b/src/soc/interrupts/xics.py index 3cf2a129..7709252c 100644 --- a/src/soc/interrupts/xics.py +++ b/src/soc/interrupts/xics.py @@ -76,7 +76,7 @@ class XICS_ICP(Elaboratable): spec.addr_wid = 30 spec.mask_wid = 4 spec.reg_wid = 32 - self.bus = Record(make_wb_layout(spec)) + self.bus = Record(make_wb_layout(spec), name="icp_wb") self.ics_i = ICS2ICP("ics_i") self.core_irq_o = Signal() @@ -226,7 +226,7 @@ class XICS_ICS(Elaboratable): spec.addr_wid = 30 spec.mask_wid = 4 spec.reg_wid = 32 - self.bus = Record(make_wb_layout(spec)) + self.bus = Record(make_wb_layout(spec), name="ics_wb") self.int_level_i = Signal(SRC_NUM) self.icp_o = ICS2ICP("icp_o") diff --git a/src/soc/litex/florent/sim.py b/src/soc/litex/florent/sim.py index 02d5e690..01c11740 100755 --- a/src/soc/litex/florent/sim.py +++ b/src/soc/litex/florent/sim.py @@ -52,6 +52,8 @@ class LibreSoCSim(SoCSDRAM): "tests/3.bin" #ram_fname = "/tmp/test.bin" #ram_fname = None + #ram_fname = "/home/lkcl/src/libresoc/microwatt/" \ + # "micropython/firmware.bin" ram_fname = "/home/lkcl/src/libresoc/microwatt/" \ "hello_world/hello_world.bin" diff --git a/src/soc/simple/core.py b/src/soc/simple/core.py index 8e70feac..90a1bf0c 100644 --- a/src/soc/simple/core.py +++ b/src/soc/simple/core.py @@ -65,6 +65,12 @@ def sort_fuspecs(fuspecs): class NonProductionCore(Elaboratable): def __init__(self, pspec): + + # add external interrupt? + self.xics = hasattr(pspec, "xics") and pspec.xics == True + if self.xics: + self.ext_irq_i = Signal() + # single LD/ST funnel for memory access self.l0 = TstL0CacheBuffer(pspec, n_units=1) pi = self.l0.l0.dports[0] diff --git a/src/soc/simple/issuer.py b/src/soc/simple/issuer.py index d1bcd7cd..ea76bbe1 100644 --- a/src/soc/simple/issuer.py +++ b/src/soc/simple/issuer.py @@ -32,6 +32,7 @@ from soc.config.ifetch import ConfigFetchUnit from soc.decoder.power_enums import MicrOp from soc.debug.dmi import CoreDebug, DMIInterface from soc.config.state import CoreState +from soc.interrupts.xics import XICS_ICP, XICS_ICS from nmutil.util import rising_edge @@ -42,6 +43,13 @@ class TestIssuer(Elaboratable): efficiency and speed is not the main goal here: functional correctness is. """ def __init__(self, pspec): + + # add interrupt controller? + self.xics = hasattr(pspec, "xics") and pspec.xics == True + if self.xics: + self.xics_icp = XICS_ICP() + self.xics_ics = XICS_ICS() + # main instruction core self.core = core = NonProductionCore(pspec) @@ -91,6 +99,12 @@ class TestIssuer(Elaboratable): m.submodules.imem = imem = self.imem m.submodules.dbg = dbg = self.dbg + if self.xics: + m.submodules.xics_icp = icp = self.xics_icp + m.submodules.xics_ics = ics = self.xics_ics + comb += icp.ics_i.eq(ics.icp_o) # connect ICS to ICP + comb += core.ext_irq_i.eq(icp.core_irq_o) # connect ICP to core + # instruction decoder pdecode = create_pdecode() m.submodules.dec2 = pdecode2 = self.pdecode2 @@ -300,16 +314,19 @@ class TestIssuer(Elaboratable): return list(self) def external_ports(self): - return self.pc_i.ports() + [self.pc_o, - self.memerr_o, - self.core_bigendian_i, - ClockSignal(), - ResetSignal(), - self.busy_o, - ] + \ - list(self.dbg.dmi.ports()) + \ - list(self.imem.ibus.fields.values()) + \ - list(self.core.l0.cmpi.lsmem.lsi.slavebus.fields.values()) + ports = self.pc_i.ports() + ports += [self.pc_o, self.memerr_o, self.core_bigendian_i, self.busy_o, + ClockSignal(), ResetSignal(), + ] + ports += list(self.dbg.dmi.ports()) + ports += list(self.imem.ibus.fields.values()) + ports += list(self.core.l0.cmpi.lsmem.lsi.slavebus.fields.values()) + + if self.xics: + ports += list(self.xics_icp.bus.fields.values()) + ports += list(self.xics_ics.bus.fields.values()) + + return ports def ports(self): return list(self) diff --git a/src/soc/simple/issuer_verilog.py b/src/soc/simple/issuer_verilog.py index 46d36e99..1f7c7b37 100644 --- a/src/soc/simple/issuer_verilog.py +++ b/src/soc/simple/issuer_verilog.py @@ -27,6 +27,7 @@ if __name__ == '__main__': imem_reg_wid=64, # set to 32 to make data wishbone bus 32-bit #wb_data_wid=32, + xics=True, units=units) dut = TestIssuer(pspec) -- 2.30.2