SVP64 Remap Fields structures for ISACaller
[soc.git] / src / soc / decoder / isa / caller.py
index 293c81c655318931442118e2ed3785a36a16a137..bd516ebb6d0d985bdb136ec12134f0908d7599aa 100644 (file)
@@ -1,3 +1,7 @@
+# SPDX-License-Identifier: LGPLv3+
+# Copyright (C) 2020, 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+# Copyright (C) 2020 Michael Nolan
+# Funded by NLnet http://nlnet.nl
 """core of the python-based POWER9 simulator
 
 this is part of a cycle-accurate POWER9 simulator.  its primary purpose is
@@ -16,7 +20,7 @@ from soc.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
                                         selectconcat)
 from soc.decoder.power_enums import (spr_dict, spr_byname, XER_bits,
                                      insns, MicrOp)
-from soc.decoder.helpers import exts, gtu, ltu
+from soc.decoder.helpers import exts, gtu, ltu, undefined
 from soc.consts import PIb, MSRb  # big-endian (PowerISA versions)
 
 from collections import namedtuple
@@ -41,14 +45,31 @@ def swap_order(x, nbytes):
     return x
 
 
+REG_SORT_ORDER = {
+    # TODO (lkcl): adjust other registers that should be in a particular order
+    # probably CA, CA32, and CR
+    "RT": 0,
+    "RA": 0,
+    "RB": 0,
+    "RS": 0,
+    "CR": 0,
+    "LR": 0,
+    "CTR": 0,
+    "TAR": 0,
+    "CA": 0,
+    "CA32": 0,
+    "MSR": 0,
+
+    "overflow": 1,
+}
+
+
 def create_args(reglist, extra=None):
-    args = OrderedSet()
-    for reg in reglist:
-        args.add(reg)
-    args = list(args)
-    if extra:
-        args = [extra] + args
-    return args
+    retval = list(OrderedSet(reglist))
+    retval.sort(key=lambda reg: REG_SORT_ORDER[reg])
+    if extra is not None:
+        return [extra] + retval
+    return retval
 
 
 class Mem:
@@ -191,6 +212,45 @@ class PC:
         namespace['NIA'] = self.NIA
 
 
+# Simple-V: see https://libre-soc.org/openpower/sv
+# also soc.sv.svstate SVSTATEREC
+class SVP64State:
+    def __init__(self, init=0):
+        self.spr = SelectableInt(init, 32)
+        # fields of SVSTATE, see https://libre-soc.org/openpower/sv/sprs/
+        self.maxvl = FieldSelectableInt(self.spr, tuple(range(0,7))
+        self.vl = FieldSelectableInt(self.spr, tuple(range(7,14)))
+        self.srcstep = FieldSelectableInt(self.spr, tuple(range(14,21)))
+        self.dststep = FieldSelectableInt(self.spr, tuple(range(21,28)))
+        self.subvl = FieldSelectableInt(self.spr, tuple(range(28,30)))
+        self.svstep = FieldSelectableInt(self.spr, tuple(range(30,32)))
+
+
+# SVP64 ReMap field
+class SVP64RMFields:
+    def __init__(self, init=0):
+        self.spr = SelectableInt(init, 24)
+        # SVP64 RM fields: see https://libre-soc.org/openpower/sv/svp64/
+        self.mmode = FieldSelectableInt(self.spr, [0])
+        self.mask = FieldSelectableInt(self.spr, tuple(range(1,4)))
+        self.elwidth = FieldSelectableInt(self.spr, tuple(range(4,6)))
+        self.ewsrc = FieldSelectableInt(self.spr, tuple(range(6,8)))
+        self.subvl = FieldSelectableInt(self.spr, tuple(range(8,10)))
+        self.extra = FieldSelectableInt(self.spr, tuple(range(10,19)))
+        self.mode = FieldSelectableInt(self.spr, tuple(range(19,24)))
+
+
+# SVP64 Prefix fields: see https://libre-soc.org/openpower/sv/svp64/
+class SPP64PrefixFields:
+    def __init__(self):
+        self.insn = SelectableInt(0, 32)
+        # 6 bit major opcode EXT001, 2 bits "identifying" (7, 9), 24 SV ReMap
+        self.major = FieldSelectableInt(self.insn, tuple(range(0,6)))
+        self.pid = FieldSelectableInt(self.insn, (7, 9) # must be 0b11
+        rmfields = [6, 8] + list(range(10,32)) # SVP64 24-bit RM
+        self.rm = FieldSelectableInt(self.spr, rmfields)
+
+
 class SPR(dict):
     def __init__(self, dec2, initial_sprs={}):
         self.sd = dec2
@@ -216,9 +276,9 @@ class SPR(dict):
         if isinstance(key, int):
             key = spr_dict[key].SPR
         key = special_sprs.get(key, key)
-        if key == 'HSRR0': # HACK!
+        if key == 'HSRR0':  # HACK!
             key = 'SRR0'
-        if key == 'HSRR1': # HACK!
+        if key == 'HSRR1':  # HACK!
             key = 'SRR1'
         if key in self:
             res = dict.__getitem__(self, key)
@@ -239,9 +299,9 @@ class SPR(dict):
             key = spr_dict[key].SPR
             print("spr key", key)
         key = special_sprs.get(key, key)
-        if key == 'HSRR0': # HACK!
+        if key == 'HSRR0':  # HACK!
             self.__setitem__('SRR0', value)
-        if key == 'HSRR1': # HACK!
+        if key == 'HSRR1':  # HACK!
             self.__setitem__('SRR1', value)
         print("setting spr", key, value)
         dict.__setitem__(self, key, value)
@@ -257,6 +317,7 @@ class ISACaller:
     # respect_pc - tracks the program counter.  requires initial_insns
     def __init__(self, decoder2, regfile, initial_sprs=None, initial_cr=0,
                  initial_mem=None, initial_msr=0,
+                 initial_svstate=0,
                  initial_insns=None, respect_pc=False,
                  disassembly=None,
                  initial_pc=0,
@@ -297,6 +358,7 @@ class ISACaller:
         self.mem = Mem(row_bytes=8, initial_mem=initial_mem)
         self.imem = Mem(row_bytes=4, initial_mem=initial_insns)
         self.pc = PC()
+        self.svstate = SVSTATE(initial_svstate)
         self.spr = SPR(decoder2, initial_sprs)
         self.msr = SelectableInt(initial_msr, 64)  # underlying reg
 
@@ -319,7 +381,7 @@ class ISACaller:
         #self.cr = FieldSelectableInt(self._cr, list(range(32, 64)))
 
         # "undefined", just set to variable-bit-width int (use exts "max")
-        self.undefined = SelectableInt(0, 256)  # TODO, not hard-code 256!
+        #self.undefined = SelectableInt(0, 256)  # TODO, not hard-code 256!
 
         self.namespace = {}
         self.namespace.update(self.spr)
@@ -331,7 +393,7 @@ class ISACaller:
                                'CIA': self.pc.CIA,
                                'CR': self.cr,
                                'MSR': self.msr,
-                               'undefined': self.undefined,
+                               'undefined': undefined,
                                'mode_is_64bit': True,
                                'SO': XER_bits['SO']
                                })
@@ -431,7 +493,7 @@ class ISACaller:
             gts.append(gt)
         print(gts)
         cy = 1 if any(gts) else 0
-        print ("CA", cy, gts)
+        print("CA", cy, gts)
         if not (1 & already_done):
             self.spr['XER'][XER_bits['CA']] = cy
 
@@ -440,14 +502,14 @@ class ISACaller:
         # ARGH... different for OP_ADD... *sigh*...
         op = yield self.dec2.e.do.insn_type
         if op == MicrOp.OP_ADD.value:
-            res32 = (output.value & (1<<32)) != 0
-            a32 = (inputs[0].value & (1<<32)) != 0
+            res32 = (output.value & (1 << 32)) != 0
+            a32 = (inputs[0].value & (1 << 32)) != 0
             if len(inputs) >= 2:
-                b32 = (inputs[1].value & (1<<32)) != 0
+                b32 = (inputs[1].value & (1 << 32)) != 0
             else:
                 b32 = False
             cy32 = res32 ^ a32 ^ b32
-            print ("CA32 ADD", cy32)
+            print("CA32 ADD", cy32)
         else:
             gts = []
             for x in inputs:
@@ -457,14 +519,15 @@ class ISACaller:
                 gt = (gtu(x[32:64], output[32:64])) == SelectableInt(1, 1)
                 gts.append(gt)
             cy32 = 1 if any(gts) else 0
-            print ("CA32", cy32, gts)
+            print("CA32", cy32, gts)
         if not (2 & already_done):
             self.spr['XER'][XER_bits['CA32']] = cy32
 
     def handle_overflow(self, inputs, outputs, div_overflow):
-        inv_a = yield self.dec2.e.do.invert_in
-        if inv_a:
-            inputs[0] = ~inputs[0]
+        if hasattr(self.dec2.e.do, "invert_in"):
+            inv_a = yield self.dec2.e.do.invert_in
+            if inv_a:
+                inputs[0] = ~inputs[0]
 
         imm_ok = yield self.dec2.e.do.imm_data.ok
         if imm_ok:
@@ -504,7 +567,7 @@ class ISACaller:
     def handle_comparison(self, outputs):
         out = outputs[0]
         assert isinstance(out, SelectableInt), \
-                          "out zero not a SelectableInt %s" % repr(outputs)
+            "out zero not a SelectableInt %s" % repr(outputs)
         print("handle_comparison", out.bits, hex(out.value))
         # TODO - XXX *processor* in 32-bit mode
         # https://bugs.libre-soc.org/show_bug.cgi?id=424
@@ -567,19 +630,27 @@ class ISACaller:
         int_op = yield self.dec2.dec.op.internal_op
 
         # sigh reconstruct the assembly instruction name
-        ov_en = yield self.dec2.e.do.oe.oe
-        ov_ok = yield self.dec2.e.do.oe.ok
-        rc_en = yield self.dec2.e.do.rc.rc
-        rc_ok = yield self.dec2.e.do.rc.ok
+        if hasattr(self.dec2.e.do, "oe"):
+            ov_en = yield self.dec2.e.do.oe.oe
+            ov_ok = yield self.dec2.e.do.oe.ok
+        else:
+            ov_en = False
+            ov_ok = False
+        if hasattr(self.dec2.e.do, "rc"):
+            rc_en = yield self.dec2.e.do.rc.rc
+            rc_ok = yield self.dec2.e.do.rc.ok
+        else:
+            rc_en = False
+            rc_ok = False
         # grrrr have to special-case MUL op (see DecodeOE)
-        print("ov %d en %d rc %d en %d op %d" % \
-                        (ov_ok, ov_en, rc_ok, rc_en, int_op))
+        print("ov %d en %d rc %d en %d op %d" %
+              (ov_ok, ov_en, rc_ok, rc_en, int_op))
         if int_op in [MicrOp.OP_MUL_H64.value, MicrOp.OP_MUL_H32.value]:
             print("mul op")
             if rc_en & rc_ok:
                 asmop += "."
         else:
-            if not asmop.endswith("."): # don't add "." to "andis."
+            if not asmop.endswith("."):  # don't add "." to "andis."
                 if rc_en & rc_ok:
                     asmop += "."
         if hasattr(self.dec2.e.do, "lk"):
@@ -658,7 +729,7 @@ class ISACaller:
             illegal = name != asmop
 
         if illegal:
-            print ("illegal", name, asmop)
+            print("illegal", name, asmop)
             self.TRAP(0x700, PIb.ILLEG)
             self.namespace['NIA'] = self.trap_nia
             self.pc.update(self.namespace)
@@ -715,7 +786,10 @@ class ISACaller:
                     already_done |= 2
 
         print("carry already done?", bin(already_done))
-        carry_en = yield self.dec2.e.do.output_carry
+        if hasattr(self.dec2.e.do, "output_carry"):
+            carry_en = yield self.dec2.e.do.output_carry
+        else:
+            carry_en = False
         if carry_en:
             yield from self.handle_carry_(inputs, results, already_done)
 
@@ -726,13 +800,20 @@ class ISACaller:
                 if name == 'overflow':
                     overflow = output
 
-        ov_en = yield self.dec2.e.do.oe.oe
-        ov_ok = yield self.dec2.e.do.oe.ok
+        if hasattr(self.dec2.e.do, "oe"):
+            ov_en = yield self.dec2.e.do.oe.oe
+            ov_ok = yield self.dec2.e.do.oe.ok
+        else:
+            ov_en = False
+            ov_ok = False
         print("internal overflow", overflow, ov_en, ov_ok)
         if ov_en & ov_ok:
             yield from self.handle_overflow(inputs, results, overflow)
 
-        rc_en = yield self.dec2.e.do.rc.rc
+        if hasattr(self.dec2.e.do, "rc"):
+            rc_en = yield self.dec2.e.do.rc.rc
+        else:
+            rc_en = False
         if rc_en:
             self.handle_comparison(results)