add option Spec to XICS ICP/ICS to be able to activate (in a horrible
[soc.git] / src / soc / interrupts / xics.py
index 3bcb1cebb5dccec2c435f5484588c6675eb4ef02..a5ed8f0d7338a0fcbb70cceb7eac417dd235c804 100644 (file)
@@ -16,6 +16,9 @@
 # highest priority interrupt currently presented (which is allowed
 # via XICS)
 #
+# Bugreports:
+#
+# * https://bugs.libre-soc.org/show_bug.cgi?id=407
 """
 from nmigen import Elaboratable, Module, Signal, Cat, Const, Record, Array, Mux
 from nmutil.iocontrol import RecordObject
@@ -23,6 +26,8 @@ from nmigen.utils import log2_int
 from nmigen.cli import rtlil
 from soc.minerva.wishbone import make_wb_layout
 from nmutil.util import wrap
+from soc.bus.test.wb_rw import wb_read, wb_write
+
 
 cxxsim = False
 if cxxsim:
@@ -46,11 +51,11 @@ class ICS2ICP(RecordObject):
 # hardwire the hardware IRQ priority
 HW_PRIORITY = Const(0x80, 8)
 
-# 8 bit offsets for each presentation
-XIRR_POLL = 0x00
-XIRR      = 0x04
-RESV0     = 0x08
-MFRR      = 0x0c
+# 8 bit offsets for each presentation - all addresses are in "words"
+XIRR_POLL = 0x00  # 0x000
+XIRR      = 0x01  # 0x004
+RESV0     = 0x02  # 0x008
+MFRR      = 0x03  # 0x00c
 
 
 class RegInternal(RecordObject):
@@ -70,13 +75,14 @@ def bswap(v):
 
 class XICS_ICP(Elaboratable):
 
-    def __init__(self):
-        class Spec: pass
-        spec = Spec()
+    def __init__(self, spec=None):
+        if spec is None:
+            class Spec: pass
+            spec = Spec()
         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, cti=False), name="icp_wb")
         self.ics_i = ICS2ICP("ics_i")
         self.core_irq_o = Signal()
 
@@ -91,8 +97,9 @@ class XICS_ICP(Elaboratable):
         # We delay core_irq_out by a cycle to help with timing
         sync += self.core_irq_o.eq(r.irq)
 
-        comb += self.bus.dat_r.eq(r.wb_rd_data)
-        comb += self.bus.ack.eq(r.wb_ack)
+        comb += self.bus.ack.eq(r.wb_ack & self.bus.cyc)
+        with m.If(self.bus.ack):
+            comb += self.bus.dat_r.eq(r.wb_rd_data)
 
         v = RegInternal()
         xirr_accept_rd = Signal()
@@ -101,6 +108,7 @@ class XICS_ICP(Elaboratable):
         be_out = Signal(32)
 
         pending_priority = Signal(8)
+        min_pri = Signal(8)
 
         comb += v.eq(r) # start from the register (r)
         comb += v.wb_ack.eq(0)
@@ -114,7 +122,7 @@ class XICS_ICP(Elaboratable):
             comb += v.wb_ack.eq(1) # always ack
             with m.If(self.bus.we): # write
                 # writes to both XIRR are the same
-                with m.Switch( self.bus.adr[:8]):
+                with m.Switch(self.bus.adr[:6]):
                     with m.Case(XIRR_POLL):
                         # report "ICP XIRR_POLL write";
                         comb += v.cppr.eq(be_in[24:32])
@@ -132,7 +140,7 @@ class XICS_ICP(Elaboratable):
                             #report "ICP XIRR UNSUPPORTED write ! sel=" & \
                             #           to_hstring(self.bus.sel);
                             pass
-                    with m.Case(MFRR ):
+                    with m.Case(MFRR):
                         comb += v.mfrr.eq(be_in[24:32])
                         with m.If(self.bus.sel == 0xf): #  # 4 byte
                             # report "ICP MFRR write word:" & to_hstring(be_in);
@@ -148,10 +156,10 @@ class XICS_ICP(Elaboratable):
 
             with m.Else(): # read
 
-                with m.Switch(self.bus.adr[:8]):
+                with m.Switch(self.bus.adr[:6]):
                     with m.Case(XIRR_POLL):
                         # report "ICP XIRR_POLL read";
-                        comb += be_out.eq(r.xisr & r.cppr)
+                        comb += be_out.eq(Cat(r.xisr, r.cppr))
                     with m.Case(XIRR):
                         # report "ICP XIRR read";
                         comb += be_out.eq(Cat(r.xisr, r.cppr))
@@ -159,7 +167,7 @@ class XICS_ICP(Elaboratable):
                             comb += xirr_accept_rd.eq(1)
                     with m.Case(MFRR):
                         # report "ICP MFRR read";
-                        comb += be_out.eq(r.mfrr)
+                        comb += be_out[24:32].eq(r.mfrr)
 
         comb += pending_priority.eq(0xff)
         comb += v.xisr.eq(0x0)
@@ -172,8 +180,10 @@ class XICS_ICP(Elaboratable):
 
         # Check MFRR
         with m.If(r.mfrr < pending_priority):
-            comb += v.xisr.eq(Const(0x2)) # special XICS MFRR IRQ source number
-            comb += pending_priority.eq(r.mfrr)
+            comb += v.xisr.eq(Const(0x2, 24)) # special XICS MFRR IRQ src num
+            comb += min_pri.eq(r.mfrr)
+        with m.Else():
+            comb += min_pri.eq(pending_priority)
 
         # Accept the interrupt
         with m.If(xirr_accept_rd):
@@ -181,16 +191,16 @@ class XICS_ICP(Elaboratable):
             #    " cppr:" &  to_hstring(r.cppr) &
             #    " xisr:" & to_hstring(r.xisr) &
             #    " mfrr:" & to_hstring(r.mfrr);
-            comb += v.cppr.eq(pending_priority)
+            comb += v.cppr.eq(min_pri)
 
         comb += v.wb_rd_data.eq(bswap(be_out))
 
         # check if the core needs an interrupt notification (or clearing)
-        comb += v.irq.eq(pending_priority < v.cppr)
-        with m.If(v.irq):
+        with m.If(min_pri < v.cppr):
             with m.If(~r.irq):
                 #report "IRQ set";
                 pass
+            comb += v.irq.eq(1)
         with m.Elif(r.irq):
             #report "IRQ clr";
             pass
@@ -217,16 +227,17 @@ class Xive(RecordObject):
 
 
 class XICS_ICS(Elaboratable):
-    def __init__(self, SRC_NUM=16, PRIO_BITS=8):
+    def __init__(self, spec=None, SRC_NUM=16, PRIO_BITS=8):
         self.SRC_NUM = SRC_NUM
         self.PRIO_BITS = PRIO_BITS
         self.pri_masked = (1<<self.PRIO_BITS)-1
-        class Spec: pass
-        spec = Spec()
+        if spec is None:
+            class Spec: pass
+            spec = Spec()
         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, cti=False), name="ics_wb")
 
         self.int_level_i = Signal(SRC_NUM)
         self.icp_o = ICS2ICP("icp_o")
@@ -283,12 +294,12 @@ class XICS_ICS(Elaboratable):
 
         assert self.SRC_NUM == 16, "Fixup address decode with log2"
 
-        comb += reg_is_xive.eq(self.bus.adr[11])
-        comb += reg_is_config.eq(self.bus.adr[0:12] == 0x0)
-        comb += reg_is_debug.eq(self.bus.adr[0:12] == 0x4)
+        comb += reg_is_xive.eq(self.bus.adr[9])
+        comb += reg_is_config.eq(self.bus.adr[0:10] == 0x0)
+        comb += reg_is_debug.eq(self.bus.adr[0:10] == 0x4)
 
         # Register index XX FIXME: figure out bits from SRC_NUM
-        comb += reg_idx.eq(self.bus.adr[2:6])
+        comb += reg_idx.eq(self.bus.adr[:4])
 
         # Latch interrupt inputs for timing
         sync += int_level_l.eq(self.int_level_i)
@@ -384,93 +395,32 @@ class XICS_ICS(Elaboratable):
         return list(self)
 
 
-def wb_write(dut, addr, data, sel=True):
-
-    # read wb
-    yield dut.bus.we.eq(1)
-    yield dut.bus.cyc.eq(1)
-    yield dut.bus.stb.eq(1)
-    yield dut.bus.sel.eq(0b1111 if sel else 0b1) # 32-bit / 8-bit
-    yield dut.bus.adr.eq(addr)
-    yield dut.bus.dat_w.eq(data)
-
-    # wait for ack to go high
-    while True:
-        ack = yield dut.bus.ack
-        print ("ack", ack)
-        if ack:
-            break
-        yield # loop until ack
-
-    # leave cyc/stb valid for 1 cycle while writing
-    yield
-
-    # clear out before returning data
-    yield dut.bus.cyc.eq(0)
-    yield dut.bus.stb.eq(0)
-    yield dut.bus.we.eq(0)
-    yield dut.bus.adr.eq(0)
-    yield dut.bus.sel.eq(0)
-    yield dut.bus.dat_w.eq(0)
-
-
-def wb_read(dut, addr, sel=True):
-
-    # read wb
-    yield dut.bus.cyc.eq(1)
-    yield dut.bus.stb.eq(1)
-    yield dut.bus.we.eq(0)
-    yield dut.bus.sel.eq(0b1111 if sel else 0b1) # 32-bit / 8-bit
-    yield dut.bus.adr.eq(addr)
-
-    # wait for ack to go high
-    while True:
-        ack = yield dut.bus.ack
-        print ("ack", ack)
-        if ack:
-            break
-        yield # loop until ack
-
-    # get data on same cycle that ack raises
-    data = yield dut.bus.dat_r
-
-    # leave cyc/stb valid for 1 cycle while reading
-    yield
-
-    # clear out before returning data
-    yield dut.bus.cyc.eq(0)
-    yield dut.bus.stb.eq(0)
-    yield dut.bus.we.eq(0)
-    yield dut.bus.adr.eq(0)
-    yield dut.bus.sel.eq(0)
-    return data
-
 
 def sim_xics_icp(dut):
 
     # read wb XIRR_MFRR
-    data = yield from wb_read(dut, MFRR)
+    data = yield from wb_read(dut.bus, MFRR)
     print ("mfrr", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
     yield
 
     # read wb XIRR (8-bit)
-    data = yield from wb_read(dut, XIRR, False)
+    data = yield from wb_read(dut.bus, XIRR, False)
     print ("xirr", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
     yield
 
     # read wb XIRR (32-bit)
-    data = yield from wb_read(dut, XIRR)
+    data = yield from wb_read(dut.bus, XIRR)
     print ("xirr", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
     yield
 
     # read wb XIRR_POLL
-    data = yield from wb_read(dut, XIRR_POLL)
+    data = yield from wb_read(dut.bus, XIRR_POLL)
     print ("xirr poll", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
@@ -481,59 +431,51 @@ def sim_xics_icp(dut):
     yield dut.ics_i.pri.eq(0x1e)
 
     # read wb XIRR_MFRR
-    data = yield from wb_read(dut, MFRR)
+    data = yield from wb_read(dut.bus, MFRR)
     print ("mfrr", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
     yield
 
     # read wb XIRR (8-bit)
-    data = yield from wb_read(dut, XIRR, False)
+    data = yield from wb_read(dut.bus, XIRR, False)
     print ("xirr", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
     yield
 
     # read wb XIRR (32-bit)
-    data = yield from wb_read(dut, XIRR)
+    data = yield from wb_read(dut.bus, XIRR)
     print ("xirr", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
     yield
 
     # read wb XIRR_POLL
-    data = yield from wb_read(dut, XIRR_POLL)
+    data = yield from wb_read(dut.bus, XIRR_POLL)
     print ("xirr poll", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 0
 
     ######################
     # write XIRR
     data = 0xfe
-    yield from wb_write(dut, XIRR, data)
+    yield from wb_write(dut.bus, XIRR, data)
     print ("xirr written", hex(data), bin(data))
 
-    assert (yield dut.core_irq_o) == 0 # write takes 1 cycle to propagate
-    yield # wait for it...
     assert (yield dut.core_irq_o) == 1 # ok *now* it should be set
 
     # read wb XIRR_POLL
-    data = yield from wb_read(dut, XIRR_POLL, False)
+    data = yield from wb_read(dut.bus, XIRR_POLL, False)
     print ("xirr poll", hex(data), bin(data))
     assert (yield dut.core_irq_o) == 1 # should not clear
 
-    yield # XXX only works if there is a 2-clock delay between POLL and XIRR
-    yield
-
     # read wb XIRR (8-bit)
-    data = yield from wb_read(dut, XIRR, False)
+    data = yield from wb_read(dut.bus, XIRR, False)
     print ("xirr", hex(data), bin(data))
-    yield
     assert (yield dut.core_irq_o) == 1 # should not clear
 
-    yield
-
     # read wb XIRR (32-bit)
-    data = yield from wb_read(dut, XIRR)
+    data = yield from wb_read(dut.bus, XIRR)
     print ("xirr", hex(data), bin(data))
     yield
     assert (yield dut.core_irq_o) == 0
@@ -553,7 +495,7 @@ def get_field(x, wid, shift):
 def sim_xics(icp, ics):
 
     # read config
-    data = yield from wb_read(ics, 0)
+    data = yield from wb_read(ics.bus, 0)
     print ("config", hex(data), bin(data))
     data = swap32(data)
     base = get_field(data, 24, 0)
@@ -567,7 +509,7 @@ def sim_xics(icp, ics):
     yield
 
     # read XIVE0
-    data = yield from wb_read(ics, 0x800)
+    data = yield from wb_read(ics.bus, 0x800//4)
     print ("xive0", hex(data), bin(data))
     data = swap32(data)
     irq = get_field(data, 1, 31)
@@ -596,11 +538,10 @@ def sim_xics(icp, ics):
     # raise XIVE 1 (just for fun)
     yield ics.int_level_i.eq(1<<1)
 
-    yield
-    yield
+    yield # wait for interrupt to propagate through from ics to icp...
 
     # read XIVE1
-    data = yield from wb_read(ics, 0x804)
+    data = yield from wb_read(ics.bus, 0x804//4)
     print ("xive1", hex(data), bin(data))
     data = swap32(data)
     irq = get_field(data, 1, 31)
@@ -632,25 +573,19 @@ def sim_xics(icp, ics):
 
     # set XIVE1 priority to 0xf0
     data = swap32(0xf0)
-    yield from wb_write(ics, 0x804, data)
+    yield from wb_write(ics.bus, 0x804//4, data)
     print ("XIVE1 priority written", hex(data), bin(data))
 
-    yield
-    yield
-
     ######################
     # write XIRR
     data = 0xfe
-    yield from wb_write(icp, XIRR, data)
+    yield from wb_write(icp.bus, XIRR, data)
     print ("xirr written", hex(data), bin(data))
 
     assert (yield icp.core_irq_o) == 1 # ok *now* it should be set
 
-    yield
-    yield
-
     # read wb XIRR (32-bit)
-    data = yield from wb_read(icp, XIRR)
+    data = yield from wb_read(icp.bus, XIRR)
     print ("xirr", hex(data), bin(data))
     data = swap32(data)
     cppr = get_field(data, 8, 24)