adding option to include XICS external interrupts.
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 4 Sep 2020 15:11:10 +0000 (16:11 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Fri, 4 Sep 2020 15:11:10 +0000 (16:11 +0100)
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
src/soc/consts.py
src/soc/decoder/power_decoder2.py
src/soc/fu/trap/main_stage.py
src/soc/interrupts/xics.py
src/soc/litex/florent/sim.py
src/soc/simple/core.py
src/soc/simple/issuer.py
src/soc/simple/issuer_verilog.py

index 4035543e971aa676e6e3ec5e18c325790c541393..e4cef69cf85dedbf6d2c9b7a3b5ea2ceecfde0d3 100644 (file)
@@ -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
index ff204488e7bd7a8bd8daf055f7d63fa3fddcde30..505fce3d6fca2567545384e56183a8fa0fc35ce9 100644 (file)
@@ -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
index edbbf8783037c4d3a97c29be805cf26b88752822..f6b88a8510f92a7f5d5e82f021ca84c5d909c38f 100644 (file)
@@ -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
index fa802a6bb0fa732de99a4a24c3cafe3fa3df3a50..9de2d9a649e845a2732dc504daf2d55370b3c844 100644 (file)
@@ -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)
index 3cf2a1294f8b1e8f2cf69c38716c9f0d017a6f50..7709252c7c9678fb958cca8f38c0eae2c4a5e8dd 100644 (file)
@@ -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")
index 02d5e690d9da3440d7878bf896b11e87cd7c798d..01c11740e80ed43ca3917b820344b7ad1d773874 100755 (executable)
@@ -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"
 
index 8e70feac073e71e44d9fbef17124f77f4c09b938..90a1bf0c1d879049d322dac662743d3c9069e4f0 100644 (file)
@@ -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]
index d1bcd7cdac871853c1e9e911537743f724f038f3..ea76bbe14c0c0c9629fc9ed1b510d356414c140a 100644 (file)
@@ -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)
index 46d36e99a581d462628083c288fb480e5c46365c..1f7c7b370a90f5a98a131f551122d41f658fb6a4 100644 (file)
@@ -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)