store KAIVB SPR 850 in TRAP Pipeline
[soc.git] / src / soc / fu / trap / main_stage.py
index 5f711ff4cb11a522d2aa13e83e20423f051a4571..c47b396e7a6670a5de3ab3e773049c0136bd7b4d 100644 (file)
@@ -14,16 +14,18 @@ from nmutil.pipemodbase import PipeModBase
 from nmutil.extend import exts
 from soc.fu.trap.pipe_data import TrapInputData, TrapOutputData
 from soc.fu.branch.main_stage import br_ext
-from soc.decoder.power_enums import MicrOp
+from openpower.decoder.power_enums import MicrOp
+from soc.experiment.mem_types import LDSTException
 
-from soc.decoder.power_fields import DecodeFields
-from soc.decoder.power_fieldsn import SignalBitRange
+from openpower.decoder.power_fields import DecodeFields
+from openpower.decoder.power_fieldsn import SignalBitRange
 
-from soc.consts import MSR, PI, TT
+from openpower.consts import MSR, PI, TT, field, field_slice
 
 
 def msr_copy(msr_o, msr_i, zero_me=True):
-    """msr_copy
+    """msr_copy (also used to copy relevant bits into SRR1)
+
     ISA says this:
     Defined MSR bits are classified as either full func tion or partial
     function. Full function MSR bits are saved in SRR1 or HSRR1 when
@@ -41,11 +43,11 @@ def msr_copy(msr_o, msr_i, zero_me=True):
     return l
 
 
-def msr_check_pr(m, msr):
+def msr_check_pr(m, d_in, msr):
     """msr_check_pr: checks "problem state"
     """
     comb = m.d.comb
-    with m.If(msr[MSR.PR]):
+    with m.If(d_in[MSR.PR]):
         comb += msr[MSR.EE].eq(1) # set external interrupt bit
         comb += msr[MSR.IR].eq(1) # set instruction relocation bit
         comb += msr[MSR.DR].eq(1) # set data relocation bit
@@ -56,6 +58,7 @@ class TrapMainStage(PipeModBase):
         super().__init__(pspec, "main")
         self.fields = DecodeFields(SignalBitRange, [self.i.ctx.op.insn])
         self.fields.create_specs()
+        self.kaivb = Signal(64) # KAIVB SPR
 
     def trap(self, m, trap_addr, return_addr):
         """trap.  sets new PC, stores MSR and old PC in SRR1 and SRR0
@@ -63,7 +66,13 @@ class TrapMainStage(PipeModBase):
         comb  = m.d.comb
         op = self.i.ctx.op
         msr_i = op.msr
-        nia_o, srr0_o, srr1_o = self.o.nia, self.o.srr0, self.o.srr1
+        svstate_i = op.svstate
+
+        exc = LDSTException("trapexc")
+        comb += exc.eq(op.ldst_exc)
+        srr1_i = exc.srr1 # new SRR1 bits come from exception
+        nia_o = self.o.nia
+        svsrr0_o, srr0_o, srr1_o = self.o.svsrr0, self.o.srr0, self.o.srr1
 
         # trap address
         comb += nia_o.data.eq(trap_addr)
@@ -73,11 +82,24 @@ class TrapMainStage(PipeModBase):
         comb += srr0_o.data.eq(return_addr)
         comb += srr0_o.ok.eq(1)
 
-        # take a copy of the current MSR in SRR1
-        comb += msr_copy(srr1_o.data, msr_i) # old MSR
+        # take a copy of the current MSR into SRR1, but first copy old SRR1
+        # this preserves the bits of SRR1 that are not supposed to change:
+        # MSR.IR,DR,PMM,RI,LE (0-5) and MR,FP,ME,FE0 (11-14)
+        # i would suggest reading v3.0C p1063 Book III section 7.2.1 for
+        # advice but it's so obscure and indirect, that it's just easier
+        # to copy microwatt behaviour.  see writeback.vhdl
+        # IMPORTANT: PowerDecoder2 needed to actually read SRR1 for
+        # it to have the contents *of* SRR1 to copy over!
+        comb += msr_copy(srr1_o.data, msr_i, False)  # old MSR
+        comb += srr1_o.data[16:22].eq(srr1_i[0:6])   # IR,DR,PMM,RI,LE
+        comb += srr1_o.data[27:31].eq(srr1_i[11:15]) # MR,FP,ME,FE0
         comb += srr1_o.ok.eq(1)
 
-    def msr_exception(self, m, trap_addr):
+        # take a copy of the current SVSTATE into SVSRR0
+        comb += svsrr0_o.data.eq(svstate_i) # old SVSTATE
+        comb += svsrr0_o.ok.eq(1)
+
+    def msr_exception(self, m, trap_addr, msr_hv=None):
         """msr_exception - sets bits in MSR specific to an exception.
         the full list of what needs to be done is given in V3.0B
         Book III Section 6.5 p1063 however it turns out that for the
@@ -96,6 +118,18 @@ class TrapMainStage(PipeModBase):
         comb += msr_o.data[MSR.DR].eq(0)
         comb += msr_o.data[MSR.RI].eq(0)
         comb += msr_o.data[MSR.LE].eq(1)
+        comb += msr_o.data[MSR.FE0].eq(0)
+        comb += msr_o.data[MSR.FE1].eq(0)
+        comb += msr_o.data[MSR.VSX].eq(0)
+        comb += msr_o.data[MSR.TM].eq(0)
+        comb += msr_o.data[MSR.VEC].eq(0)
+        comb += msr_o.data[MSR.FP].eq(0)
+        comb += msr_o.data[MSR.PMM].eq(0)
+        comb += msr_o.data[MSR.TEs].eq(0) # this is only 2 bits
+        comb += msr_o.data[MSR.TEe].eq(0) # so just zero them both
+        comb += msr_o.data[MSR.UND].eq(0)
+        if msr_hv is not None:
+            comb += msr_o.data[MSR.HV].eq(msr_hv)
         comb += msr_o.ok.eq(1)
 
     def ispec(self):
@@ -106,14 +140,16 @@ class TrapMainStage(PipeModBase):
 
     def elaborate(self, platform):
         m = Module()
-        comb = m.d.comb
+        comb, sync = m.d.comb, m.d.sync
         op = self.i.ctx.op
 
         # convenience variables
-        a_i, b_i, cia_i, msr_i = self.i.a, self.i.b, op.cia, op.msr
-        srr0_i, srr1_i = self.i.srr0, self.i.srr1
-        o, msr_o, nia_o = self.o.o, self.o.msr, self.o.nia
-        srr0_o, srr1_o = self.o.srr0, self.o.srr1
+        a_i, b_i = self.i.a, self.i.b
+        cia_i, msr_i, svstate_i = op.cia, op.msr, op.svstate
+        srr0_i, srr1_i, svsrr0_i = self.i.srr0, self.i.srr1, self.i.svsrr0
+        o = self.o.o
+        msr_o, nia_o, svstate_o = self.o.msr, self.o.nia, self.o.svstate
+        srr0_o, srr1_o, svsrr0_o = self.o.srr0, self.o.srr1, self.o.svsrr0
         traptype, trapaddr = op.traptype, op.trapaddr
 
         # take copy of D-Form TO field
@@ -165,7 +201,20 @@ class TrapMainStage(PipeModBase):
 
         # TODO: some #defines for the bits n stuff.
         with m.Switch(op.insn_type):
-            #### trap ####
+
+            ##############
+            # KAIVB https://bugs.libre-soc.org/show_bug.cgi?id=859
+
+            with m.Case(MicrOp.OP_MTSPR):
+                sync += self.kaivb.eq(a_i)
+
+            with m.Case(MicrOp.OP_MFSPR):
+                comb += o.data.eq(self.kaivb)
+                comb += o.ok.eq(1)
+
+            ###############
+            # TDI/TWI/TD/TW.  v3.0B p90-91
+
             with m.Case(MicrOp.OP_TRAP):
                 # trap instructions (tw, twi, td, tdi)
                 with m.If(should_trap):
@@ -180,6 +229,23 @@ 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.MEMEXC).bool() &
+                              (trapaddr == 0x400)):
+                        # Instruction Storage Interrupt (ISI - 0x400)
+                        #           v3.0C Book III Chap 7.5.5 p1085
+                        # decode exception bits, store in SRR1
+                        exc = LDSTException("trapexc")
+                        comb += exc.eq(op.ldst_exc)
+                        comb += srr1_o.data[PI.INVALID].eq(exc.invalid)
+                        comb += srr1_o.data[PI.PERMERR].eq(exc.perm_error)
+                        comb += srr1_o.data[PI.ILLEG].eq(exc.badtree)
+                        comb += srr1_o.data[PI.PRIV].eq(exc.rc_error)
+                    with m.If(traptype & TT.EINT):
+                        # do nothing unusual? see 3.0B Book III 6.5.7 p1073
+                        pass
+                    with m.If(traptype & TT.DEC):
+                        # do nothing unusual?
+                        pass
                     with m.If(traptype & TT.ILLEG):
                         comb += srr1_o.data[PI.ILLEG].eq(1)
                     comb += srr1_o.ok.eq(1)
@@ -187,9 +253,16 @@ class TrapMainStage(PipeModBase):
                     # when SRR1 is written to, update MSR bits
                     self.msr_exception(m, trapaddr)
 
-            # move to MSR
+                    # and store SVSTATE in SVSRR0
+                    comb += svsrr0_o.data.eq(svstate_i)
+                    comb += svsrr0_o.ok.eq(1)
+
+            ###################
+            # MTMSR/D.  v3.0B p TODO - move to MSR
+
             with m.Case(MicrOp.OP_MTMSRD, MicrOp.OP_MTMSR):
-                L = self.fields.FormX.L[0:-1] # X-Form field L
+                # L => bit 16 in LSB0, bit 15 in MSB0 order
+                L = self.fields.FormX.L1[0:1] # X-Form field L1
                 # start with copy of msr
                 comb += msr_o.eq(msr_i)
                 with m.If(L):
@@ -200,60 +273,100 @@ class TrapMainStage(PipeModBase):
                     # Architecture says to leave out bits 3 (HV), 51 (ME)
                     # and 63 (LE) (IBM bit numbering)
                     with m.If(op.insn_type == MicrOp.OP_MTMSRD):
+                        # not MSB0 notation here!
                         for stt, end in [(1,12), (13, 60), (61, 64)]:
                             comb += msr_o.data[stt:end].eq(a_i[stt:end])
+                        # put *back* bits 29-31 (MSB0 notation)
+                        bits = field_slice(29, 31)
+                        with m.If((msr_i[bits] == Const(0b010, 3)) &
+                                  (a_i[bits] == Const(0b000, 3))):
+                            comb += msr_o.data[bits].eq(msr_i[bits])
+
                     with m.Else():
                         # mtmsr - 32-bit, only room for bottom 32 LSB flags
                         for stt, end in [(1,12), (13, 32)]:
                             comb += msr_o.data[stt:end].eq(a_i[stt:end])
-                    msr_check_pr(m, msr_o.data)
+                    # check problem state: if set, not permitted to set EE,IR,DR
+                    msr_check_pr(m, a_i, msr_o.data)
+
+                # Per https://bugs.libre-soc.org/show_bug.cgi?id=325#c123,
+                # this actually *is* in the microwatt code now.
+                #
+                # hypervisor stuff.  here: bits 3 (HV) and 51 (ME) were
+                # copied over by msr_copy but if HV was not set we need
+                # the *original* (msr_i) bits
+                # XXX taking this out to see what happens when running
+                # linux-5.7 microwatt buildroot.  microwatt does not
+                # implement HV, so this is unlikely to work.  0x900
+                # linux kernel exception handling tends to support this
+                # with m.If(~msr_i[MSR.HV]):
+                #     comb += msr_o.data[MSR.HV].eq(msr_i[MSR.HV])
+                #     comb += msr_o.data[MSR.ME].eq(msr_i[MSR.ME])
+
                 comb += msr_o.ok.eq(1)
 
-            # move from MSR
+            ###################
+            # MFMSR.  v3.0B p TODO - move from MSR
+
             with m.Case(MicrOp.OP_MFMSR):
-                # TODO: some of the bits need zeroing?  apparently not
+                # some of the bits need zeroing?  apparently not
                 comb += o.data.eq(msr_i)
                 comb += o.ok.eq(1)
 
+            ###################
+            # RFID.  v3.0B p955
+
             with m.Case(MicrOp.OP_RFID):
-                # XXX f_out.virt_mode <= b_in(MSR.IR) or b_in(MSR.PR);
-                # XXX f_out.priv_mode <= not b_in(MSR.PR);
 
                 # return addr was in srr0
                 comb += nia_o.data.eq(br_ext(srr0_i[2:]))
                 comb += nia_o.ok.eq(1)
 
+                # svstate was in svsrr0
+                comb += svstate_o.data.eq(svstate_i)
+                comb += svstate_o.ok.eq(1)
+
                 # MSR was in srr1: copy it over, however *caveats below*
                 comb += msr_copy(msr_o.data, srr1_i, zero_me=False) # don't zero
 
-                # check problem state
-                msr_check_pr(m, msr_o.data)
+                if False: # XXX no - not doing hypervisor yet
+                    with m.If(~self.i.ctx.op.insn[9]): # XXX BAD HACK! (hrfid)
+                        with m.If(field(msr_i, 3)): # HV
+                            comb += field(msr_o, 51).eq(field(srr1_i, 51)) # ME
+                        with m.Else():
+                            comb += field(msr_o, 51).eq(field(msr_i, 51)) # ME
+                else:
+                    # same as microwatt: treat MSR.ME rfid same as hrfid
+                    comb += field(msr_o, 51).eq(field(srr1_i, 51)) # ME
 
-                # hypervisor stuff.  here: bits 3 (HV) and 51 (ME) were
-                # copied over by msr_copy but if HV was not set we need
-                # the *original* (msr_i) bits
-                with m.If(~msr_i[MSR.HV]):
-                    comb += msr_o.data[MSR.HV].eq(msr_i[MSR.HV])
-                    comb += msr_o.data[MSR.ME].eq(msr_i[MSR.ME])
+                # check problem state: if set, not permitted to set EE,IR,DR
+                msr_check_pr(m, srr1_i, msr_o.data)
 
                 # don't understand but it's in the spec.  again: bits 32-34
                 # are copied from srr1_i and need *restoring* to msr_i
-                bits = slice(63-31,63-29+1) # bits 29, 30, 31 (Power notation)
+
+                bits = field_slice(29, 31)  # bits 29, 30, 31 (Power notation)
                 with m.If((msr_i[bits] == Const(0b010, 3)) &
                           (srr1_i[bits] == Const(0b000, 3))):
                     comb += msr_o.data[bits].eq(msr_i[bits])
 
                 comb += msr_o.ok.eq(1)
 
-            # OP_SC
+            #################
+            # SC.  v3.0B p952
+
             with m.Case(MicrOp.OP_SC):
                 # scv is not covered here. currently an illegal instruction.
                 # raising "illegal" is the decoder's job, not ours, here.
 
+                # According to V3.0B, Book II, section 3.3.1, the System Call
+                # instruction allows you to trap directly into the hypervisor
+                # if the opcode's LEV sub-field is equal to 1.
+                # however we are following *microwatt* - which has
+                # not implemented hypervisor.
+
                 # jump to the trap address, return at cia+4
                 self.trap(m, 0xc00, cia_i+4)
-
-                # and update several MSR bits
                 self.msr_exception(m, 0xc00)
 
             # TODO (later)