move FPDIV, FPMUL (etc) to ISAFPHelpers class
[openpower-isa.git] / src / openpower / decoder / isa / caller.py
index 3fabdec46b5ca836163f813af03e984f73e38938..e330fb28e03374732b96c4a8635834d19c90991c 100644 (file)
@@ -21,16 +21,19 @@ 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, bitrev)
+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 SVP64CROffs
+from openpower.consts import (SVP64MODE,
+                              SVP64CROffs,
+                             )
 from openpower.decoder.power_svp64 import SVP64RM, decode_extra
 
 from openpower.decoder.isa.radixmmu import RADIX
@@ -70,6 +73,7 @@ REG_SORT_ORDER = {
     "RB": 0,
     "RC": 0,
     "RS": 0,
+    "BI": 0,
     "CR": 0,
     "LR": 0,
     "CTR": 0,
@@ -439,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
@@ -532,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
@@ -593,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
@@ -655,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
@@ -720,7 +750,7 @@ class ISACaller:
     def memassign(self, ea, sz, val):
         self.mem.memassign(ea, sz, val)
 
-    def prep_namespace(self, formname, op_fields):
+    def prep_namespace(self, insn_name, formname, op_fields):
         # TODO: get field names from form in decoder*1* (not decoder2)
         # decoder2 is hand-created, and decoder1.sigform is auto-generated
         # from spec
@@ -729,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.
@@ -752,6 +793,25 @@ class ISACaller:
         self.namespace['VL'] = vl
         self.namespace['srcstep'] = srcstep
 
+        # sv.bc* need some extra fields
+        if self.is_svp64_mode and insn_name.startswith("sv.bc"):
+            # blegh grab bits manually
+            mode = yield self.dec2.rm_dec.rm_in.mode
+            bc_vlset = (mode & SVP64MODE.BC_VLSET) != 0
+            bc_vli = (mode & SVP64MODE.BC_VLI) != 0
+            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)
+            self.namespace['VLI'] = SelectableInt(bc_vli, 1)
+            self.namespace['sz'] = SelectableInt(sz, 1)
+            self.namespace['SNZ'] = SelectableInt(bc_snz, 1)
+
     def handle_carry_(self, inputs, outputs, already_done):
         inv_a = yield self.dec2.e.do.invert_in
         if inv_a:
@@ -964,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
@@ -1027,8 +1088,11 @@ class ISACaller:
         return asmop
 
     def get_remap_indices(self):
+        """WARNING, this function stores remap_idxs and remap_loopends
+        in the class for later use.  this to avoid problems with yield
+        """
         # go through all iterators in lock-step, advance to next remap_idx
-        srcstep, dststep = self.new_srcstep, self.new_dststep
+        srcstep, dststep = self.get_src_dststeps()
         # get four SVSHAPEs. here we are hard-coding
         SVSHAPE0 = self.spr['SVSHAPE0']
         SVSHAPE1 = self.spr['SVSHAPE1']
@@ -1157,6 +1221,13 @@ class ISACaller:
             illegal = False
             ins_name = 'ffadds'
 
+        # branch-conditional redirects to sv.bc
+        if asmop.startswith('bc') and self.is_svp64_mode:
+            ins_name = 'sv.%s' % ins_name
+
+        log("   post-processed name", ins_name, asmop)
+
+        # illegal instructions call TRAP at 0x700
         if illegal:
             print("illegal", ins_name, asmop)
             self.call_trap(0x700, PIb.ILLEG)
@@ -1176,8 +1247,9 @@ class ISACaller:
             self.update_pc_next()
             return
 
+        # look up instruction in ISA.instrs, prepare namespace
         info = self.instrs[ins_name]
-        yield from self.prep_namespace(info.form, info.op_fields)
+        yield from self.prep_namespace(ins_name, info.form, info.op_fields)
 
         # preserve order of register names
         input_names = create_args(list(info.read_regs) +
@@ -1194,7 +1266,7 @@ class ISACaller:
 
         # see if srcstep/dststep need skipping over masked-out predicate bits
         if (self.is_svp64_mode or ins_name == 'setvl' or
-           ins_name.startswith("sv")):
+           ins_name in ['svremap', 'svstate']):
             yield from self.svstate_pre_inc()
         if self.is_svp64_mode:
             pre = yield from self.update_new_svstate_steps()
@@ -1203,7 +1275,7 @@ class ISACaller:
                 self.update_nia()
                 self.update_pc_next()
                 return
-            srcstep, dststep = self.new_srcstep, self.new_dststep
+            srcstep, dststep = self.get_src_dststeps()
             pred_dst_zero = self.pred_dst_zero
             pred_src_zero = self.pred_src_zero
             vl = self.svstate.vl
@@ -1290,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
@@ -1313,13 +1385,13 @@ class ISACaller:
         replace_d = False # update / replace constant in pseudocode
         if self.is_svp64_mode:
             ldstmode = yield self.dec2.rm_dec.ldstmode
-            # bitreverse mode reads SVD (or SVDS - TODO)
+            # shift mode reads SVD (or SVDS - TODO)
             # *BUT*... because this is "overloading" of LD operations,
             # it gets *STORED* into D (or DS, TODO)
-            if ldstmode == SVP64LDSTmode.BITREVERSE.value:
+            if ldstmode == SVP64LDSTmode.SHIFT.value:
                 imm = yield self.dec2.dec.fields.FormSVD.SVD[0:11]
                 imm = exts(imm, 11) # sign-extend to integer
-                log ("bitrev SVD", imm)
+                log ("shift SVD", imm)
                 replace_d = True
             else:
                 if info.form == 'DS':
@@ -1332,19 +1404,26 @@ class ISACaller:
             op = yield self.dec2.e.do.insn_type
             offsmul = 0
             if op == MicrOp.OP_LOAD.value:
-                offsmul = srcstep
-                log("D-field src", imm, offsmul)
+                if remap_active:
+                    offsmul = yield self.dec2.in1_step
+                    log("D-field REMAP src", imm, offsmul)
+                else:
+                    offsmul = srcstep
+                    log("D-field src", imm, offsmul)
             elif op == MicrOp.OP_STORE.value:
+                # XXX NOTE! no bit-reversed STORE! this should not ever be used
                 offsmul = dststep
                 log("D-field dst", imm, offsmul)
-            # bit-reverse mode
-            if ldstmode == SVP64LDSTmode.BITREVERSE.value:
+            # bit-reverse mode, rev already done through get_src_dst_steps()
+            if ldstmode == SVP64LDSTmode.SHIFT.value:
                 # manually look up RC, sigh
                 RC = yield self.dec2.dec.RC[0:5]
                 RC = self.gpr(RC)
-                log ("RC", RC.value, "imm", imm, "offs", bin(offsmul),
-                     "rev", bin(bitrev(offsmul, vl)))
-                imm = SelectableInt((imm * bitrev(offsmul, vl)) << RC.value, 32)
+                log ("LD-SHIFT:", "VL", vl,
+                      "RC", RC.value, "imm", imm,
+                     "offs", bin(offsmul),
+                     )
+                imm = SelectableInt((imm * offsmul) << RC.value, 32)
             # Unit-Strided LD/ST adds offset*width to immediate
             elif ldstmode == SVP64LDSTmode.UNITSTRIDE.value:
                 ldst_len = yield self.dec2.e.do.data_len
@@ -1379,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)
@@ -1500,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)
@@ -1517,9 +1605,11 @@ 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
+                # use bit-reversed version
                 srcstep, dststep = self.new_srcstep, self.new_dststep
                 remaps = self.get_remap_indices()
                 remap_idxs = self.remap_idxs
@@ -1555,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,
@@ -1564,12 +1654,17 @@ 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
         "Vertical-First" mode.  this function is called from
         setvl pseudo-code, as a pseudo-op "svstep"
+
+        WARNING: this function uses information that was created EARLIER
+        due to it being in the middle of a yield, but this function is
+        *NOT* called from yield (it's called from compiled pseudocode).
         """
         self.allow_next_step_inc = submode.value + 1
         log("SVSTATE_NEXT mode", mode, submode, self.allow_next_step_inc)
@@ -1646,7 +1741,13 @@ class ISACaller:
         log ("    new srcstep", srcstep)
         log ("    new dststep", dststep)
 
+    def get_src_dststeps(self):
+        """gets srcstep and dststep 
+        """
+        return self.new_srcstep, self.new_dststep
+
     def update_new_svstate_steps(self):
+        # note, do not get the bit-reversed srcstep here!
         srcstep, dststep = self.new_srcstep, self.new_dststep
 
         # update SVSTATE with new srcstep
@@ -1666,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)
@@ -1703,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
@@ -1737,6 +1849,7 @@ class ISACaller:
         self.pc.update_nia(self.is_svp64_mode)
         self.namespace['NIA'] = self.pc.NIA
 
+
 def inject():
     """Decorator factory.
 
@@ -1766,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)