move FPDIV, FPMUL (etc) to ISAFPHelpers class
[openpower-isa.git] / src / openpower / decoder / isa / caller.py
index c0ef32f988dd7f9a5d05e8fde845bc7c35f78341..e330fb28e03374732b96c4a8635834d19c90991c 100644 (file)
@@ -21,14 +21,15 @@ from openpower.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
                                         selectconcat)
 from openpower.decoder.power_enums import (spr_dict, spr_byname, XER_bits,
                                      insns, MicrOp, In1Sel, In2Sel, In3Sel,
-                                     OutSel, CROutSel, LDSTMode,
+                                     OutSel, CRInSel, CROutSel, LDSTMode,
                                      SVP64RMMode, SVP64PredMode,
                                      SVP64PredInt, SVP64PredCR,
                                      SVP64LDSTmode)
 
 from openpower.decoder.power_enums import SVPtype
 
-from openpower.decoder.helpers import (exts, gtu, ltu, undefined)
+from openpower.decoder.helpers import (exts, gtu, ltu, undefined,
+                                       ISACallerHelper, ISAFPHelpers)
 from openpower.consts import PIb, MSRb  # big-endian (PowerISA versions)
 from openpower.consts import (SVP64MODE,
                               SVP64CROffs,
@@ -72,6 +73,7 @@ REG_SORT_ORDER = {
     "RB": 0,
     "RC": 0,
     "RS": 0,
+    "BI": 0,
     "CR": 0,
     "LR": 0,
     "CTR": 0,
@@ -441,6 +443,30 @@ def get_pdecode_idx_in(dec2, name):
     return None, False
 
 
+# TODO, really should just be using PowerDecoder2
+def get_pdecode_cr_in(dec2, name):
+    op = dec2.dec.op
+    in_sel = yield op.cr_in
+    in_bitfield = yield dec2.dec_cr_in.cr_bitfield.data
+    sv_cr_in = yield op.sv_cr_in
+    spec = yield dec2.crin_svdec.spec
+    sv_override = yield dec2.dec_cr_in.sv_override
+    # get the IN1/2/3 from the decoder (includes SVP64 remap and isvec)
+    in1 = yield dec2.e.read_cr1.data
+    cr_isvec = yield dec2.cr_in_isvec
+    log ("get_pdecode_cr_in", in_sel, CROutSel.CR0.value, in1, cr_isvec)
+    log ("    sv_cr_in", sv_cr_in)
+    log ("    cr_bf", in_bitfield)
+    log ("    spec", spec)
+    log ("    override", sv_override)
+    # identify which regnames map to in / o2
+    if name == 'BI':
+        if in_sel == CRInSel.BI.value:
+            return in1, cr_isvec
+    log ("get_pdecode_cr_in not found", name)
+    return None, False
+
+
 # TODO, really should just be using PowerDecoder2
 def get_pdecode_cr_out(dec2, name):
     op = dec2.dec.op
@@ -534,7 +560,7 @@ def get_pdecode_idx_out2(dec2, name):
     return None, False
 
 
-class ISACaller:
+class ISACaller(ISACallerHelper, ISAFPHelpers):
     # decoder2 - an instance of power_decoder2
     # regfile - a list of initial values for the registers
     # initial_{etc} - initial values for SPRs, Condition Register, Mem, MSR
@@ -595,6 +621,7 @@ class ISACaller:
         self.msr = SelectableInt(initial_msr, 64)  # underlying reg
         self.pc = PC()
         # GPR FPR SPR registers
+        initial_sprs = copy(initial_sprs) # so as not to get modified
         self.gpr = GPR(decoder2, self, self.svstate, regfile)
         self.fpr = GPR(decoder2, self, self.svstate, fpregfile)
         self.spr = SPR(decoder2, initial_sprs) # initialise SPRs before MMU
@@ -657,7 +684,8 @@ class ISACaller:
                                'MSR': self.msr,
                                'undefined': undefined,
                                'mode_is_64bit': True,
-                               'SO': XER_bits['SO']
+                               'SO': XER_bits['SO'],
+                               'XLEN': 64  # elwidth overrides, later
                                })
 
         # update pc to requested start point
@@ -731,11 +759,22 @@ class ISACaller:
         fields = self.decoder.sigforms[formname]
         log("prep_namespace", formname, op_fields)
         for name in op_fields:
-            if name == 'spr':
-                sig = getattr(fields, name.upper())
-            else:
+            # CR immediates. deal with separately.  needs modifying
+            # pseudocode 
+            if self.is_svp64_mode and name in ['BI']: # TODO, more CRs
+                # BI is a 5-bit, must reconstruct the value
+                regnum, is_vec = yield from get_pdecode_cr_in(self.dec2, name)
                 sig = getattr(fields, name)
-            val = yield sig
+                val = yield sig
+                # low 2 LSBs (CR field selector) remain same, CR num extended
+                assert regnum <= 7, "sigh, TODO, 128 CR fields"
+                val = (val & 0b11) | (regnum<<2)
+            else:
+                if name == 'spr':
+                    sig = getattr(fields, name.upper())
+                else:
+                    sig = getattr(fields, name)
+                val = yield sig
             # these are all opcode fields involved in index-selection of CR,
             # and need to do "standard" arithmetic.  CR[BA+32] for example
             # would, if using SelectableInt, only be 5-bit.
@@ -763,7 +802,9 @@ class ISACaller:
             bc_snz = (mode & SVP64MODE.BC_SNZ) != 0
             bc_vsb = yield self.dec2.rm_dec.bc_vsb
             bc_lru = yield self.dec2.rm_dec.bc_lru
+            bc_gate = yield self.dec2.rm_dec.bc_gate
             sz = yield self.dec2.rm_dec.pred_sz
+            self.namespace['ALL'] = SelectableInt(bc_gate, 1)
             self.namespace['VSb'] = SelectableInt(bc_vsb, 1)
             self.namespace['LRu'] = SelectableInt(bc_lru, 1)
             self.namespace['VLSET'] = SelectableInt(bc_vlset, 1)
@@ -983,7 +1024,8 @@ class ISACaller:
         if not self.respect_pc:
             self.fake_pc += 4
 
-        log("execute one, CIA NIA", self.pc.CIA.value, self.pc.NIA.value)
+        log("execute one, CIA NIA", hex(self.pc.CIA.value),
+                                    hex(self.pc.NIA.value))
 
     def get_assembly_name(self):
         # TODO, asmregs is from the spec, e.g. add RT,RA,RB
@@ -1320,9 +1362,9 @@ class ISACaller:
             if not self.is_svp64_mode or not pred_src_zero:
                 log('reading reg %s %s' % (name, str(regnum)), is_vec)
                 if name in fregs:
-                    reg_val = self.fpr(regnum)
+                    reg_val = SelectableInt(self.fpr(regnum))
                 elif name is not None:
-                    reg_val = self.gpr(regnum)
+                    reg_val = SelectableInt(self.gpr(regnum))
             else:
                 log('zero input reg %s %s' % (name, str(regnum)), is_vec)
                 reg_val = 0
@@ -1416,6 +1458,14 @@ class ISACaller:
         # clear trap (trap) NIA
         self.trap_nia = None
 
+        # check if this was an sv.bc* and create an indicator that
+        # this is the last check to be made as a loop.  combined with
+        # the ALL/ANY mode we can early-exit
+        if self.is_svp64_mode and ins_name.startswith("sv.bc"):
+            no_in_vec = yield self.dec2.no_in_vec # BI is scalar
+            end_loop = no_in_vec or srcstep == vl-1 or dststep == vl-1
+            self.namespace['end_loop'] = SelectableInt(end_loop, 1)
+
         # execute actual instruction here (finally)
         log("inputs", inputs)
         results = info.func(self, *inputs)
@@ -1537,6 +1587,7 @@ class ISACaller:
         # this is our Sub-Program-Counter loop from 0 to VL-1
         pre = False
         post = False
+        nia_update = True
         if self.allow_next_step_inc:
             log("SVSTATE_NEXT: inc requested, mode",
                     self.svstate_next_mode, self.allow_next_step_inc)
@@ -1554,7 +1605,7 @@ class ISACaller:
             else:
                 if self.allow_next_step_inc == 2:
                     log ("SVSTATE_NEXT: read")
-                    yield from self.svstate_post_inc()
+                    nia_update = (yield from self.svstate_post_inc(ins_name))
                 else:
                     log ("SVSTATE_NEXT: post-inc")
                 # use actual src/dst-step here to check end, do NOT
@@ -1594,7 +1645,7 @@ class ISACaller:
                     self.svstate.vfirst = 0
 
         elif self.is_svp64_mode:
-            yield from self.svstate_post_inc()
+            nia_update = (yield from self.svstate_post_inc(ins_name))
         else:
             # XXX only in non-SVP64 mode!
             # record state of whether the current operation was an svshape,
@@ -1603,7 +1654,8 @@ class ISACaller:
             # to interrupt in between. sigh.
             self.last_op_svshape = asmop == 'svremap'
 
-        self.update_pc_next()
+        if nia_update:
+            self.update_pc_next()
 
     def SVSTATE_NEXT(self, mode, submode):
         """explicitly moves srcstep/dststep on to next element, for
@@ -1715,7 +1767,7 @@ class ISACaller:
         # nothing needs doing (TODO zeroing): just do next instruction
         return srcstep == vl or dststep == vl
 
-    def svstate_post_inc(self, vf=0):
+    def svstate_post_inc(self, insn_name, vf=0):
         # check if SV "Vertical First" mode is enabled
         vfirst = self.svstate.vfirst
         log ("    SV Vertical First", vf, vfirst)
@@ -1752,12 +1804,23 @@ class ISACaller:
             svp64_is_vector = (out_vec or in_vec)
         else:
             svp64_is_vector = out_vec
+        # check if this was an sv.bc* and if so did it succeed
+        if self.is_svp64_mode and insn_name.startswith("sv.bc"):
+            end_loop = self.namespace['end_loop']
+            log("branch %s end_loop" % insn_name, end_loop)
+            if end_loop.value:
+                self.svp64_reset_loop()
+                self.update_pc_next()
+                return False
         if svp64_is_vector and srcstep != vl-1 and dststep != vl-1:
             self.svstate.srcstep += SelectableInt(1, 7)
             self.svstate.dststep += SelectableInt(1, 7)
+            self.namespace['SVSTATE'] = self.svstate
+            # not an SVP64 branch, so fix PC (NIA==CIA) for next loop
+            # (by default, NIA is CIA+4 if v3.0B or CIA+8 if SVP64)
+            # this way we keep repeating the same instruction (with new steps)
             self.pc.NIA.value = self.pc.CIA.value
             self.namespace['NIA'] = self.pc.NIA
-            self.namespace['SVSTATE'] = self.svstate
             log("end of sub-pc call", self.namespace['CIA'],
                                  self.namespace['NIA'])
             return False # DO NOT allow PC update whilst Sub-PC loop running
@@ -1786,6 +1849,7 @@ class ISACaller:
         self.pc.update_nia(self.is_svp64_mode)
         self.namespace['NIA'] = self.pc.NIA
 
+
 def inject():
     """Decorator factory.
 
@@ -1815,6 +1879,8 @@ def inject():
             log("args[0]", args[0].namespace['CIA'],
                   args[0].namespace['NIA'],
                   args[0].namespace['SVSTATE'])
+            if 'end_loop' in func_globals:
+                log("args[0] end_loop", func_globals['end_loop'])
             args[0].namespace = func_globals
             #exec (func.__code__, func_globals)