add srcstep and correct PC-advancing during Sub-PC looping in ISACaller
[soc.git] / src / soc / decoder / isa / caller.py
index 726fc638b76873359a8c5441d40c6415b3d71d06..4a38a1ede376a61c3402c20b46715dabfe4b92ce 100644 (file)
@@ -211,11 +211,17 @@ class GPR(dict):
 class PC:
     def __init__(self, pc_init=0):
         self.CIA = SelectableInt(pc_init, 64)
-        self.NIA = self.CIA + SelectableInt(4, 64)
+        self.NIA = self.CIA + SelectableInt(4, 64) # only true for v3.0B!
 
-    def update(self, namespace):
+    def update_nia(self, is_svp64):
+        increment = 8 if is_svp64 else 4
+        self.NIA = self.CIA + SelectableInt(increment, 64)
+
+    def update(self, namespace, is_svp64):
+        """updates the program counter (PC) by 4 if v3.0B mode or 8 if SVP64
+        """
         self.CIA = namespace['NIA'].narrow(64)
-        self.NIA = self.CIA + SelectableInt(4, 64)
+        self.update_nia(is_svp64)
         namespace['CIA'] = self.CIA
         namespace['NIA'] = self.NIA
 
@@ -425,7 +431,9 @@ class ISACaller:
 
         # set up registers, instruction memory, data memory, PC, SPRs, MSR
         self.svp64rm = SVP64RM()
-        self.svstate = SVP64State(initial_svstate)
+        if isinstance(initial_svstate, int):
+            initial_svstate = SVP64State(initial_svstate)
+        self.svstate = initial_svstate
         self.gpr = GPR(decoder2, self, self.svstate, regfile)
         self.mem = Mem(row_bytes=8, initial_mem=initial_mem)
         self.imem = Mem(row_bytes=4, initial_mem=initial_insns)
@@ -657,7 +665,7 @@ class ISACaller:
 
     def set_pc(self, pc_val):
         self.namespace['NIA'] = SelectableInt(pc_val, 64)
-        self.pc.update(self.namespace)
+        self.pc.update(self.namespace, self.is_svp64_mode)
 
     def setup_one(self):
         """set up one instruction
@@ -682,7 +690,7 @@ class ISACaller:
         # SVP64.  first, check if the opcode is EXT001, and SVP64 id bits set
         yield Settle()
         opcode = yield self.dec2.dec.opcode_in
-        pfx = SVP64PrefixFields()
+        pfx = SVP64PrefixFields() # TODO should probably use SVP64PrefixDecoder
         pfx.insn.value = opcode
         major = pfx.major.asint(msb0=True) # MSB0 inversion
         print ("prefix test: opcode:", major, bin(major),
@@ -690,11 +698,14 @@ class ISACaller:
         self.is_svp64_mode = ((major == 0b000001) and
                               pfx.insn[7].value == 0b1 and
                               pfx.insn[9].value == 0b1)
+        self.pc.update_nia(self.is_svp64_mode)
         if not self.is_svp64_mode:
             return
 
         # in SVP64 mode.  decode/print out svp64 prefix, get v3.0B instruction
         print ("svp64.rm", bin(pfx.rm.asint(msb0=True)))
+        print ("    svstate.vl", self.svstate.vl.asint(msb0=True))
+        print ("    svstate.mvl", self.svstate.maxvl.asint(msb0=True))
         sv_rm = pfx.rm.asint()
         ins = self.imem.ld(pc+4, 4, False, True)
         print("     svsetup: 0x%x 0x%x %s" % (pc+4, ins & 0xffffffff, bin(ins)))
@@ -715,8 +726,10 @@ class ISACaller:
         opname = code.split(' ')[0]
         yield from self.call(opname)
 
+        # don't use this except in special circumstances
         if not self.respect_pc:
             self.fake_pc += 4
+
         print("execute one, CIA NIA", self.pc.CIA.value, self.pc.NIA.value)
 
     def get_assembly_name(self):
@@ -816,7 +829,7 @@ class ISACaller:
         if instr_is_privileged and self.msr[MSRb.PR] == 1:
             self.TRAP(0x700, PIb.PRIV)
             self.namespace['NIA'] = self.trap_nia
-            self.pc.update(self.namespace)
+            self.pc.update(self.namespace, self.is_svp64_mode)
             return
 
         # check halted condition
@@ -833,7 +846,7 @@ class ISACaller:
             print("illegal", name, asmop)
             self.TRAP(0x700, PIb.ILLEG)
             self.namespace['NIA'] = self.trap_nia
-            self.pc.update(self.namespace)
+            self.pc.update(self.namespace, self.is_svp64_mode)
             print("name %s != %s - calling ILLEGAL trap, PC: %x" %
                   (name, asmop, self.pc.CIA.value))
             return
@@ -854,6 +867,9 @@ class ISACaller:
             dest_cr, src_cr, src_byname, dest_byname = False, False, {}, {}
         print ("sv rm", sv_rm, dest_cr, src_cr, src_byname, dest_byname)
 
+        # get SVSTATE srcstep.  TODO: dststep (twin predication)
+        srcstep = self.svstate.srcstep.asint(msb0=True)
+
         # main input registers (RT, RA ...)
         inputs = []
         for name in input_names:
@@ -864,6 +880,10 @@ class ISACaller:
                 # doing this is not part of svp64, it's because output
                 # registers, to be modified, need to be in the namespace.
                 regnum, is_vec = yield from get_pdecode_idx_out(self.dec2, name)
+            # here's where we go "vector".  TODO: zero-testing (RA_IS_ZERO)
+            if is_vec:
+                regnum += srcstep # TODO, elwidth overrides
+
             # in case getting the register number is needed, _RA, _RB
             regname = "_" + name
             self.namespace[regname] = regnum
@@ -934,6 +954,9 @@ class ISACaller:
         if rc_en:
             self.handle_comparison(results)
 
+        # svp64 loop can end early if the dest is scalar
+        svp64_dest_vector = False
+
         # any modified return results?
         if info.write_regs:
             for name, output in zip(output_names, results):
@@ -962,14 +985,42 @@ class ISACaller:
                         # temporary hack for not having 2nd output
                         regnum = yield getattr(self.decoder, name)
                         is_vec = False
+                    # here's where we go "vector".
+                    if is_vec:
+                        regnum += srcstep # TODO, elwidth overrides
+                        svp64_dest_vector = True
                     print('writing reg %d %s' % (regnum, str(output)), is_vec)
                     if output.bits > 64:
                         output = SelectableInt(output.value, 64)
                     self.gpr[regnum] = output
 
-        print("end of call", self.namespace['CIA'], self.namespace['NIA'])
+        # check if it is the SVSTATE.src/dest step that needs incrementing
+        # this is our Sub-Program-Counter loop from 0 to VL-1
+        if self.is_svp64_mode:
+            # XXX twin predication TODO
+            vl = self.svstate.vl.asint(msb0=True)
+            mvl = self.svstate.maxvl.asint(msb0=True)
+            srcstep = self.svstate.srcstep.asint(msb0=True)
+            print ("    svstate.vl", vl)
+            print ("    svstate.mvl", mvl)
+            print ("    svstate.srcstep", srcstep)
+            # check if srcstep needs incrementing by one, stop PC advancing
+            if svp64_dest_vector and srcstep != vl-1:
+                self.svstate.srcstep += SelectableInt(1, 7)
+                self.pc.NIA.value = self.pc.CIA.value
+                self.namespace['NIA'] = self.pc.NIA
+                print("end of sub-pc call", self.namespace['CIA'],
+                                     self.namespace['NIA'])
+                return # DO NOT allow PC to update whilst Sub-PC loop running
+            # reset to zero
+            self.svstate.srcstep[0:7] = 0
+            print ("    svstate.srcstep loop end (PC to update)")
+            self.pc.update_nia(self.is_svp64_mode)
+            self.namespace['NIA'] = self.pc.NIA
+
         # UPDATE program counter
-        self.pc.update(self.namespace)
+        self.pc.update(self.namespace, self.is_svp64_mode)
+        print("end of call", self.namespace['CIA'], self.namespace['NIA'])
 
 
 def inject():