report dar on exception + test case
[soc.git] / src / soc / fu / ldst / loadstore.py
index e20a77966432cfce911cf56b9282782b4fde0277..e013f3c5163fd0ff5011232a4ecaad0ec9a35960 100644 (file)
@@ -21,7 +21,7 @@ from nmigen import (Elaboratable, Module, Signal, Shape, unsigned, Cat, Mux,
                     Record, Memory,
                     Const)
 from nmutil.iocontrol import RecordObject
-from nmutil.util import rising_edge
+from nmutil.util import rising_edge, Display
 from enum import Enum, unique
 
 from soc.experiment.dcache import DCache
@@ -88,7 +88,7 @@ class LoadStore1(PortInterfaceBase):
         # these are accessed by OP_MTSPR/OP_MFSPR, on behalf of LoadStore1.
         # by contrast microwatt has the spr set/get done *in* loadstore1.vhdl
         self.dsisr = Signal(64)
-        self.dar = Signal(64)
+        #self.dar = Signal(64)
 
         # state info for LD/ST
         self.done          = Signal()
@@ -119,13 +119,17 @@ class LoadStore1(PortInterfaceBase):
         #self.nia           = Signal(64)
         #self.srr1          = Signal(16)
 
-    def set_wr_addr(self, m, addr, mask, misalign, msr_pr):
+    def set_wr_addr(self, m, addr, mask, misalign, msr_pr, is_dcbz):
         m.d.comb += self.req.load.eq(0) # store operation
         m.d.comb += self.req.byte_sel.eq(mask)
         m.d.comb += self.req.addr.eq(addr)
         m.d.comb += self.req.priv_mode.eq(~msr_pr) # not-problem  ==> priv
         m.d.comb += self.req.virt_mode.eq(msr_pr) # problem-state ==> virt
         m.d.comb += self.req.align_intr.eq(misalign)
+        m.d.comb += self.req.dcbz.eq(is_dcbz)
+
+        # m.d.comb += Display("set_wr_addr %i dcbz %i",addr,is_dcbz)
+
         # option to disable the cache entirely for write
         if self.disable_cache:
             m.d.comb += self.req.nc.eq(1)
@@ -186,6 +190,8 @@ class LoadStore1(PortInterfaceBase):
         # a request when MMU_LOOKUP completes.
         m.d.comb += self.d_validblip.eq(rising_edge(m, self.d_valid))
         ldst_r = LDSTRequest("ldst_r")
+        
+        comb += Display("MMUTEST: LoadStore1 d_in.error=%i",d_in.error)
 
         # fsm skeleton
         with m.Switch(self.state):
@@ -194,11 +200,14 @@ class LoadStore1(PortInterfaceBase):
                     comb += self.busy.eq(1)
                     sync += self.state.eq(State.ACK_WAIT)
                     sync += ldst_r.eq(self.req) # copy of LDSTRequest on "blip"
+#                   sync += Display("validblip self.req.virt_mode=%i",
+#                   self.req.virt_mode)
                 with m.Else():
                     sync += ldst_r.eq(0)
 
             # waiting for completion
             with m.Case(State.ACK_WAIT):
+                comb += Display("MMUTEST: ACK_WAIT")
                 comb += self.busy.eq(~exc.happened)
 
                 with m.If(d_in.error):
@@ -207,6 +216,8 @@ class LoadStore1(PortInterfaceBase):
                     with m.If(d_in.cache_paradox):
                         comb += exception.eq(1)
                         sync += self.state.eq(State.IDLE)
+                        sync += ldst_r.eq(0)
+                        sync += Display("cache error -> update dsisr")
                         sync += self.dsisr[63 - 38].eq(~self.load)
                         # XXX there is no architected bit for this
                         # (probably should be a machine check in fact)
@@ -223,12 +234,14 @@ class LoadStore1(PortInterfaceBase):
                     with m.If(self.done):
                         sync += Display("ACK_WAIT, done %x", self.addr)
                     sync += self.state.eq(State.IDLE)
+                    sync += ldst_r.eq(0)
                     with m.If(self.load):
                         m.d.comb += self.load_data.eq(d_in.data)
 
             # waiting here for the MMU TLB lookup to complete.
             # either re-try the dcache lookup or throw MMU exception
             with m.Case(State.MMU_LOOKUP):
+                comb += Display("MMUTEST: MMU_LOOKUP")
                 comb += self.busy.eq(1)
                 with m.If(m_in.done):
                     with m.If(~self.instr_fault):
@@ -238,15 +251,18 @@ class LoadStore1(PortInterfaceBase):
                         # installed a TLB entry, if not exception raised
                         m.d.comb += self.d_out.valid.eq(~exception)
                         sync += self.state.eq(State.ACK_WAIT)
+                        sync += ldst_r.eq(0)
                     with m.Else():
                         sync += Display("MMU_LOOKUP, exception %x", self.addr)
                         # instruction lookup fault: store address in DAR
-                        comb += exc.happened.eq(1)
-                        sync += self.dar.eq(self.addr)
+                        comb += exc.happened.eq(1) # reason = MMU_LOOKUP
+                        # mark dar as updated ?
+                        sync += self.pi.dar_o.eq(self.addr)
 
                 with m.If(m_in.err):
                     # MMU RADIX exception thrown
                     comb += exception.eq(1)
+                    sync += Display("MMU RADIX exception thrown")
                     sync += self.dsisr[63 - 33].eq(m_in.invalid)
                     sync += self.dsisr[63 - 36].eq(m_in.perm_error)
                     sync += self.dsisr[63 - 38].eq(self.load)
@@ -258,8 +274,10 @@ class LoadStore1(PortInterfaceBase):
 
         # alignment error: store address in DAR
         with m.If(self.align_intr):
-            comb += exc.happened.eq(1)
-            sync += self.dar.eq(self.addr)
+            comb += exc.happened.eq(1) # reason = alignment
+            sync += Display("alignment error: store addr in DAR %x", self.addr)
+            sync += self.pi.dar_o.eq(self.addr)
+            # TODO report reason
 
         # happened, alignment, instr_fault, invalid.
         # note that all of these flow through - eventually to the TRAP
@@ -286,11 +304,12 @@ class LoadStore1(PortInterfaceBase):
         if hasattr(dbus, "stall"):
             comb += dcache.wb_in.stall.eq(dbus.stall)
 
-        # write out d data only when flag set
+        # update out d data when flag set
         with m.If(self.d_w_valid):
             m.d.sync += d_out.data.eq(self.store_data)
-        with m.Else():
-            m.d.sync += d_out.data.eq(0)
+        #with m.Else():
+        #    m.d.sync += d_out.data.eq(0)
+        # unit test passes with that change
 
         # this must move into the FSM, conditionally noticing that
         # the "blip" comes from self.d_validblip.
@@ -306,6 +325,9 @@ class LoadStore1(PortInterfaceBase):
             m.d.comb += d_out.priv_mode.eq(self.req.priv_mode)
             m.d.comb += d_out.virt_mode.eq(self.req.virt_mode)
             m.d.comb += self.align_intr.eq(self.req.align_intr)
+            #m.d.comb += Display("validblip dcbz=%i addr=%x",
+            #self.req.dcbz,self.req.addr)
+            m.d.comb += d_out.dcbz.eq(self.req.dcbz)
         with m.Else():
             m.d.comb += d_out.load.eq(ldst_r.load)
             m.d.comb += d_out.byte_sel.eq(ldst_r.byte_sel)
@@ -314,6 +336,9 @@ class LoadStore1(PortInterfaceBase):
             m.d.comb += d_out.priv_mode.eq(ldst_r.priv_mode)
             m.d.comb += d_out.virt_mode.eq(ldst_r.virt_mode)
             m.d.comb += self.align_intr.eq(ldst_r.align_intr)
+            #m.d.comb += Display("no_validblip dcbz=%i addr=%x",
+            #ldst_r.dcbz,ldst_r.addr)
+            m.d.comb += d_out.dcbz.eq(ldst_r.dcbz)
 
         # XXX these should be possible to remove but for some reason
         # cannot be... yet. TODO, investigate