bug #672: pospopcount using sv.lbzu/pi/dw=8 error
[openpower-isa.git] / src / openpower / decoder / isa / caller.py
index 0c5199e2397471c78c8886d07b5983b42f361658..44c7a41e1e863df60dd38288892bc56716761f18 100644 (file)
@@ -18,6 +18,7 @@ from copy import deepcopy
 from functools import wraps
 import os
 import sys
 from functools import wraps
 import os
 import sys
+from elftools.elf.elffile import ELFFile  # for isinstance
 
 from nmigen.sim import Settle
 import openpower.syscalls
 
 from nmigen.sim import Settle
 import openpower.syscalls
@@ -25,7 +26,7 @@ from openpower.consts import (MSRb, PIb,  # big-endian (PowerISA versions)
                               SVP64CROffs, SVP64MODEb)
 from openpower.decoder.helpers import (ISACallerHelper, ISAFPHelpers, exts,
                                        gtu, undefined, copy_assign_rhs)
                               SVP64CROffs, SVP64MODEb)
 from openpower.decoder.helpers import (ISACallerHelper, ISAFPHelpers, exts,
                                        gtu, undefined, copy_assign_rhs)
-from openpower.decoder.isa.mem import Mem, MemMMap, MemException
+from openpower.decoder.isa.mem import Mem, MemMMap, MemException, LoadedELF
 from openpower.decoder.isa.radixmmu import RADIX
 from openpower.decoder.isa.svshape import SVSHAPE
 from openpower.decoder.isa.svstate import SVP64State
 from openpower.decoder.isa.radixmmu import RADIX
 from openpower.decoder.isa.svshape import SVSHAPE
 from openpower.decoder.isa.svstate import SVP64State
@@ -216,9 +217,13 @@ class GPR(dict):
             rnum = rnum.value
         dict.__setitem__(self, rnum, value)
 
             rnum = rnum.value
         dict.__setitem__(self, rnum, value)
 
-    def getz(self, rnum):
+    def getz(self, rnum, rvalue=None):
         # rnum = rnum.value # only SelectableInt allowed
         # rnum = rnum.value # only SelectableInt allowed
-        log("GPR getzero?", rnum)
+        log("GPR getzero?", rnum, rvalue)
+        if rvalue is not None:
+            if rnum == 0:
+                return SelectableInt(0, rvalue.bits)
+            return rvalue
         if rnum == 0:
             return SelectableInt(0, 64)
         return self[rnum]
         if rnum == 0:
             return SelectableInt(0, 64)
         return self[rnum]
@@ -245,13 +250,14 @@ class GPR(dict):
                 for j in range(8):
                     s.append("%08x" % res[i+j])
                 s = ' '.join(s)
                 for j in range(8):
                     s.append("%08x" % res[i+j])
                 s = ' '.join(s)
-                print("reg", "%2d" % i, s)
+                log("reg", "%2d" % i, s, kind=LogType.InstrInOuts)
         return res
 
 
 class SPR(dict):
         return res
 
 
 class SPR(dict):
-    def __init__(self, dec2, initial_sprs={}):
+    def __init__(self, dec2, initial_sprs={}, gpr=None):
         self.sd = dec2
         self.sd = dec2
+        self.gpr = gpr  # for SVSHAPE[0-3]
         dict.__init__(self)
         for key, v in initial_sprs.items():
             if isinstance(key, SelectableInt):
         dict.__init__(self)
         for key, v in initial_sprs.items():
             if isinstance(key, SelectableInt):
@@ -303,6 +309,8 @@ class SPR(dict):
             self.__setitem__('SRR1', value)
         if key == 1:
             value = XERState(value)
             self.__setitem__('SRR1', value)
         if key == 1:
             value = XERState(value)
+        if key in ('SVSHAPE0', 'SVSHAPE1', 'SVSHAPE2', 'SVSHAPE3'):
+            value = SVSHAPE(value, self.gpr)
         log("setting spr", key, value)
         dict.__setitem__(self, key, value)
 
         log("setting spr", key, value)
         dict.__setitem__(self, key, value)
 
@@ -1141,6 +1149,10 @@ class StepLoop:
         log("    new dststep", dststep)
 
 
         log("    new dststep", dststep)
 
 
+class ExitSyscallCalled(Exception):
+    pass
+
+
 class SyscallEmulator(openpower.syscalls.Dispatcher):
     def __init__(self, isacaller):
         self.__isacaller = isacaller
 class SyscallEmulator(openpower.syscalls.Dispatcher):
     def __init__(self, isacaller):
         self.__isacaller = isacaller
@@ -1155,6 +1167,17 @@ class SyscallEmulator(openpower.syscalls.Dispatcher):
         (identifier, *arguments) = map(int, (identifier, *arguments))
         return super().__call__(identifier, *arguments)
 
         (identifier, *arguments) = map(int, (identifier, *arguments))
         return super().__call__(identifier, *arguments)
 
+    def sys_exit_group(self, status, *rest):
+        self.__isacaller.halted = True
+        raise ExitSyscallCalled(status)
+
+    def sys_write(self, fd, buf, count, *rest):
+        buf = self.__isacaller.mem.get_ctypes(buf, count, is_write=False)
+        try:
+            return os.write(fd, buf)
+        except OSError as e:
+            return -e.errno
+
 
 class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
     # decoder2 - an instance of power_decoder2
 
 class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
     # decoder2 - an instance of power_decoder2
@@ -1175,7 +1198,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
                  initial_fpscr=0,
                  insnlog=None,
                  use_mmap_mem=False,
                  initial_fpscr=0,
                  insnlog=None,
                  use_mmap_mem=False,
-                 use_syscall_emu=False):
+                 use_syscall_emu=False,
+                 emulating_mmap=False):
         if use_syscall_emu:
             self.syscall = SyscallEmulator(isacaller=self)
             if not use_mmap_mem:
         if use_syscall_emu:
             self.syscall = SyscallEmulator(isacaller=self)
             if not use_mmap_mem:
@@ -1184,6 +1208,16 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         else:
             self.syscall = None
 
         else:
             self.syscall = None
 
+        # we will eventually be able to load ELF files without use_syscall_emu
+        # (e.g. the linux kernel), so do it in a separate if block
+        if isinstance(initial_insns, ELFFile):
+            if not use_mmap_mem:
+                log("forcing use_mmap_mem due to loading an ELF file")
+                use_mmap_mem = True
+            if not emulating_mmap:
+                log("forcing emulating_mmap due to loading an ELF file")
+                emulating_mmap = True
+
         # trace log file for model output. if None do nothing
         self.insnlog = insnlog
         self.insnlog_is_file = hasattr(insnlog, "write")
         # trace log file for model output. if None do nothing
         self.insnlog = insnlog
         self.insnlog_is_file = hasattr(insnlog, "write")
@@ -1239,23 +1273,30 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         initial_sprs = deepcopy(initial_sprs)  # so as not to get modified
         self.gpr = GPR(decoder2, self, self.svstate, regfile)
         self.fpr = GPR(decoder2, self, self.svstate, fpregfile)
         initial_sprs = deepcopy(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
+        # initialise SPRs before MMU
+        self.spr = SPR(decoder2, initial_sprs, gpr=self.gpr)
 
         # set up 4 dummy SVSHAPEs if they aren't already set up
         for i in range(4):
             sname = 'SVSHAPE%d' % i
             val = self.spr.get(sname, 0)
 
         # set up 4 dummy SVSHAPEs if they aren't already set up
         for i in range(4):
             sname = 'SVSHAPE%d' % i
             val = self.spr.get(sname, 0)
-            # make sure it's an SVSHAPE
-            self.spr[sname] = SVSHAPE(val, self.gpr)
+            # make sure it's an SVSHAPE -- conversion done by SPR.__setitem__
+            self.spr[sname] = val
         self.last_op_svshape = False
 
         # "raw" memory
         if use_mmap_mem:
             self.mem = MemMMap(row_bytes=8,
                                initial_mem=initial_mem,
         self.last_op_svshape = False
 
         # "raw" memory
         if use_mmap_mem:
             self.mem = MemMMap(row_bytes=8,
                                initial_mem=initial_mem,
-                               misaligned_ok=True)
+                               misaligned_ok=True,
+                               emulating_mmap=emulating_mmap)
             self.imem = self.mem
             self.imem = self.mem
-            self.mem.initialize(row_bytes=4, initial_mem=initial_insns)
+            lelf = self.mem.initialize(row_bytes=4, initial_mem=initial_insns)
+            if isinstance(lelf, LoadedELF):  # stuff parsed from ELF
+                initial_pc = lelf.pc
+                for k, v in lelf.gprs.items():
+                    self.gpr[k] = SelectableInt(v, 64)
+                initial_fpscr = lelf.fpscr
             self.mem.log_fancy(kind=LogType.InstrInOuts)
         else:
             self.mem = Mem(row_bytes=8, initial_mem=initial_mem,
             self.mem.log_fancy(kind=LogType.InstrInOuts)
         else:
             self.mem = Mem(row_bytes=8, initial_mem=initial_mem,
@@ -1357,6 +1398,11 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         TRAP function is callable from inside the pseudocode itself,
         hence the default arguments.  when calling from inside ISACaller
         it is best to use call_trap()
         TRAP function is callable from inside the pseudocode itself,
         hence the default arguments.  when calling from inside ISACaller
         it is best to use call_trap()
+
+        trap_addr: int | SelectableInt
+            the address to go to (before any modifications from `KAIVB`)
+        trap_bit: int | None
+            the bit in `SRR1` to set, `None` means don't set any bits.
         """
         if isinstance(trap_addr, SelectableInt):
             trap_addr = trap_addr.value
         """
         if isinstance(trap_addr, SelectableInt):
             trap_addr = trap_addr.value
@@ -1452,26 +1498,30 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         self.cr_backup = self.cr.value
 
         # sv.bc* need some extra fields
         self.cr_backup = self.cr.value
 
         # 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
-            # convert to SelectableInt before test
-            mode = SelectableInt(mode, 5)
-            bc_vlset = mode[SVP64MODEb.BC_VLSET] != 0
-            bc_vli = mode[SVP64MODEb.BC_VLI] != 0
-            bc_snz = mode[SVP64MODEb.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['mode'] = SelectableInt(mode, 5)
-            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)
+        if not self.is_svp64_mode or not insn_name.startswith("sv.bc"):
+            return
+
+        # blegh grab bits manually
+        mode = yield self.dec2.rm_dec.rm_in.mode
+        # convert to SelectableInt before test
+        mode = SelectableInt(mode, 5)
+        bc_vlset = mode[SVP64MODEb.BC_VLSET] != 0
+        bc_vli = mode[SVP64MODEb.BC_VLI] != 0
+        bc_snz = mode[SVP64MODEb.BC_SNZ] != 0
+        bc_vsb = yield self.dec2.rm_dec.bc_vsb
+        bc_ctrtest = yield self.dec2.rm_dec.bc_ctrtest
+        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['mode'] = SelectableInt(mode, 5)
+        self.namespace['ALL'] = SelectableInt(bc_gate, 1)
+        self.namespace['VSb'] = SelectableInt(bc_vsb, 1)
+        self.namespace['LRu'] = SelectableInt(bc_lru, 1)
+        self.namespace['CTRtest'] = SelectableInt(bc_ctrtest, 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 get_kludged_op_add_ca_ov(self, inputs, inp_ca_ov):
         """ this was not at all necessary to do.  this function massively
 
     def get_kludged_op_add_ca_ov(self, inputs, inp_ca_ov):
         """ this was not at all necessary to do.  this function massively
@@ -1564,6 +1614,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         return ca64, ca32, ov64, ov32
 
     def handle_carry_(self, inputs, output, ca, ca32, inp_ca_ov):
         return ca64, ca32, ov64, ov32
 
     def handle_carry_(self, inputs, output, ca, ca32, inp_ca_ov):
+        if ca is not None and ca32 is not None:
+            return
         op = yield self.dec2.e.do.insn_type
         if op == MicrOp.OP_ADD.value and ca is None and ca32 is None:
             retval = yield from self.get_kludged_op_add_ca_ov(
         op = yield self.dec2.e.do.insn_type
         if op == MicrOp.OP_ADD.value and ca is None and ca32 is None:
             retval = yield from self.get_kludged_op_add_ca_ov(
@@ -2004,8 +2056,6 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         # 2. Call the HDL implementation which invokes trap.
         # 3. Reroute the guest system call to host system call.
         # 4. Force return from the interrupt as if we had guest OS.
         # 2. Call the HDL implementation which invokes trap.
         # 3. Reroute the guest system call to host system call.
         # 4. Force return from the interrupt as if we had guest OS.
-        #    "executing" rfid requires putting 0x4c000024 temporarily
-        #    into the program at the PC. TODO investigate and remove
         if ((asmop in ("sc", "scv")) and
                 (self.syscall is not None) and
                 not syscall_emu_active):
         if ((asmop in ("sc", "scv")) and
                 (self.syscall is not None) and
                 not syscall_emu_active):
@@ -2023,10 +2073,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             self.gpr.write(3, result, False, self.namespace["XLEN"])
 
             # Return from interrupt
             self.gpr.write(3, result, False, self.namespace["XLEN"])
 
             # Return from interrupt
-            backup = self.imem.ld(pc, 4, False, True, instr_fetch=True)
-            self.imem.st(pc, 0x4c000024, width=4, swap=True)
             yield from self.call("rfid", syscall_emu_active=True)
             yield from self.call("rfid", syscall_emu_active=True)
-            self.imem.st(pc, backup, width=4, swap=True)
+            return
         elif ((name in ("rfid", "hrfid")) and syscall_emu_active):
             asmop = "rfid"
 
         elif ((name in ("rfid", "hrfid")) and syscall_emu_active):
             asmop = "rfid"
 
@@ -2044,7 +2092,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
                        "brh", "brw", "brd",
                        'setvl', 'svindex', 'svremap', 'svstep',
                        'svshape', 'svshape2',
                        "brh", "brw", "brd",
                        'setvl', 'svindex', 'svremap', 'svstep',
                        'svshape', 'svshape2',
-                       'ternlogi', 'bmask', 'cprop',
+                       'ternlogi', 'bmask', 'cprop', 'gbbd',
                        'absdu', 'absds', 'absdacs', 'absdacu', 'avgadd',
                        'fmvis', 'fishmv', 'pcdec', "maddedu", "divmod2du",
                        "dsld", "dsrd", "maddedus",
                        'absdu', 'absds', 'absdacs', 'absdacu', 'avgadd',
                        'fmvis', 'fishmv', 'pcdec', "maddedu", "divmod2du",
                        "dsld", "dsrd", "maddedus",
@@ -2060,6 +2108,11 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             illegal = False
             ins_name = dotstrp
 
             illegal = False
             ins_name = dotstrp
 
+        # match against instructions treated as nop, see nop below
+        if asmop.startswith("dcbt"):
+            illegal = False
+            ins_name = "nop"
+
         # branch-conditional redirects to sv.bc
         if asmop.startswith('bc') and self.is_svp64_mode:
             ins_name = 'sv.%s' % ins_name
         # branch-conditional redirects to sv.bc
         if asmop.startswith('bc') and self.is_svp64_mode:
             ins_name = 'sv.%s' % ins_name
@@ -2105,7 +2158,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             ew_src = 8 << (3-int(ew_src))  # convert to bitlength
             ew_dst = 8 << (3-int(ew_dst))  # convert to bitlength
             xlen = max(ew_src, ew_dst)
             ew_src = 8 << (3-int(ew_src))  # convert to bitlength
             ew_dst = 8 << (3-int(ew_dst))  # convert to bitlength
             xlen = max(ew_src, ew_dst)
-            log("elwdith", ew_src, ew_dst)
+            log("elwidth", ew_src, ew_dst)
         log("XLEN:", self.is_svp64_mode, xlen)
 
         # look up instruction in ISA.instrs, prepare namespace
         log("XLEN:", self.is_svp64_mode, xlen)
 
         # look up instruction in ISA.instrs, prepare namespace
@@ -2186,7 +2239,16 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             remap_active = yield self.dec2.remap_active
         else:
             remap_active = False
             remap_active = yield self.dec2.remap_active
         else:
             remap_active = False
-        log("remap active", bin(remap_active))
+        log("remap active", bin(remap_active), self.is_svp64_mode)
+
+        # LDST does *not* allow elwidth overrides on RA (Effective Address).
+        # this has to be detected. XXX TODO: RB for ldst-idx *may* need
+        # conversion (to 64-bit) also.
+        # see write reg this *HAS* to also override XLEN to 64 on LDST/Update
+        sv_mode = yield self.dec2.rm_dec.sv_mode
+        is_ldst = (sv_mode in [SVMode.LDST_IDX.value, SVMode.LDST_IMM.value] \
+                  and self.is_svp64_mode)
+        log("is_ldst", sv_mode, is_ldst)
 
         # main input registers (RT, RA ...)
         for name in input_names:
 
         # main input registers (RT, RA ...)
         for name in input_names:
@@ -2200,8 +2262,12 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
                 inputs[name] = self.crl[0]
             elif name in spr_byname:
                 inputs[name] = self.spr[name]
                 inputs[name] = self.crl[0]
             elif name in spr_byname:
                 inputs[name] = self.spr[name]
+            elif is_ldst and name == 'RA':
+                regval = (yield from self.get_input(name, ew_src, 64))
+                log("EA (RA) regval name", name, regval)
+                inputs[name] = regval
             else:
             else:
-                regval = (yield from self.get_input(name, ew_src))
+                regval = (yield from self.get_input(name, ew_src, xlen))
                 log("regval name", name, regval)
                 inputs[name] = regval
 
                 log("regval name", name, regval)
                 inputs[name] = regval
 
@@ -2233,10 +2299,11 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
 
         # 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
 
         # 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
+        # the ALL/ANY mode we can early-exit. note that BI (to test)
+        # is an input so there is no termination if BI is scalar
+        # (because early-termination is for *output* scalars)
         if self.is_svp64_mode and ins_name.startswith("sv.bc"):
         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
+            end_loop = srcstep == vl-1 or dststep == vl-1
             self.namespace['end_loop'] = SelectableInt(end_loop, 1)
 
         inp_ca_ov = (self.spr['XER'][XER_bits['CA']].value,
             self.namespace['end_loop'] = SelectableInt(end_loop, 1)
 
         inp_ca_ov = (self.spr['XER'][XER_bits['CA']].value,
@@ -2323,8 +2390,12 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         # XXX TODO: now that CR0 is supported, sort out svstep's pseudocode
         # to write directly to CR0 instead of in ISACaller. hooyahh.
         if rc_en and ins_name not in ['svstep']:
         # XXX TODO: now that CR0 is supported, sort out svstep's pseudocode
         # to write directly to CR0 instead of in ISACaller. hooyahh.
         if rc_en and ins_name not in ['svstep']:
+            if outs_ok.get('FPSCR', False):
+                FPSCR = outs['FPSCR']
+            else:
+                FPSCR = self.FPSCR
             yield from self.do_rc_ov(
             yield from self.do_rc_ov(
-                ins_name, results[0], overflow, cr0, cr1, output_names)
+                ins_name, results[0], overflow, cr0, cr1, FPSCR)
 
         # check failfirst
         ffirst_hit = False, False
 
         # check failfirst
         ffirst_hit = False, False
@@ -2332,6 +2403,9 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             sv_mode = yield self.dec2.rm_dec.sv_mode
             is_cr = sv_mode == SVMode.CROP.value
             chk = rc_en or is_cr
             sv_mode = yield self.dec2.rm_dec.sv_mode
             is_cr = sv_mode == SVMode.CROP.value
             chk = rc_en or is_cr
+            if outs_ok.get('CR', False):
+                # early write so check_ffirst can see value
+                self.namespace['CR'].eq(outs['CR'])
             ffirst_hit = (yield from self.check_ffirst(info, chk, srcstep))
 
         # any modified return results?
             ffirst_hit = (yield from self.check_ffirst(info, chk, srcstep))
 
         # any modified return results?
@@ -2382,7 +2456,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         yield Settle()  # let decoder update
         return True, vli_
 
         yield Settle()  # let decoder update
         return True, vli_
 
-    def do_rc_ov(self, ins_name, result, overflow, cr0, cr1, output_names):
+    def do_rc_ov(self, ins_name, result, overflow, cr0, cr1, FPSCR):
         cr_out = yield self.dec2.op.cr_out
         if cr_out == CROutSel.CR1.value:
             rc_reg = "CR1"
         cr_out = yield self.dec2.op.cr_out
         if cr_out == CROutSel.CR1.value:
             rc_reg = "CR1"
@@ -2398,10 +2472,10 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
 
         if rc_reg == "CR1":
             if cr1 is None:
 
         if rc_reg == "CR1":
             if cr1 is None:
-                cr1 = int(self.FPSCR.FX) << 3
-                cr1 |= int(self.FPSCR.FEX) << 2
-                cr1 |= int(self.FPSCR.VX) << 1
-                cr1 |= int(self.FPSCR.OX)
+                cr1 = int(FPSCR.FX) << 3
+                cr1 |= int(FPSCR.FEX) << 2
+                cr1 |= int(FPSCR.VX) << 1
+                cr1 |= int(FPSCR.OX)
                 log("default fp cr1", cr1)
             else:
                 log("explicit cr1", cr1)
                 log("default fp cr1", cr1)
             else:
                 log("explicit cr1", cr1)
@@ -2437,8 +2511,8 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             nia_update = True
         else:
             # check advancement of src/dst/sub-steps and if PC needs updating
             nia_update = True
         else:
             # check advancement of src/dst/sub-steps and if PC needs updating
-            nia_update = (yield from self.check_step_increment(rc_en,
-                                                               asmop, ins_name))
+            nia_update = (yield from self.check_step_increment(
+                rc_en, asmop, ins_name))
         if nia_update:
             self.update_pc_next()
 
         if nia_update:
             self.update_pc_next()
 
@@ -2493,7 +2567,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
             else:
                 self.namespace['D'] = imm
 
             else:
                 self.namespace['D'] = imm
 
-    def get_input(self, name, ew_src):
+    def get_input(self, name, ew_src, xlen):
         # using PowerDecoder2, first, find the decoder index.
         # (mapping name RA RB RC RS to in1, in2, in3)
         regnum, is_vec = yield from get_idx_in(self.dec2, name, True)
         # using PowerDecoder2, first, find the decoder index.
         # (mapping name RA RB RC RS to in1, in2, in3)
         regnum, is_vec = yield from get_idx_in(self.dec2, name, True)
@@ -2514,20 +2588,27 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         regname = "_" + name
         if not self.is_svp64_mode or ew_src == 64:
             self.namespace[regname] = regnum
         regname = "_" + name
         if not self.is_svp64_mode or ew_src == 64:
             self.namespace[regname] = regnum
-        elif regname in self.namespace:
-            del self.namespace[regname]
+        else:
+            # FIXME: we're trying to access a sub-register, plain register
+            # numbers don't work for that.  for now, just pass something that
+            # can be compared to 0 and probably will cause an error if misused.
+            # see https://bugs.libre-soc.org/show_bug.cgi?id=1221
+            self.namespace[regname] = regnum * 10000
 
         if not self.is_svp64_mode or not self.pred_src_zero:
             log('reading reg %s %s' % (name, str(regnum)), is_vec)
             if name in fregs:
 
         if not self.is_svp64_mode or not self.pred_src_zero:
             log('reading reg %s %s' % (name, str(regnum)), is_vec)
             if name in fregs:
-                reg_val = SelectableInt(self.fpr(base, is_vec, offs, ew_src))
-                log("read reg %d/%d: 0x%x" % (base, offs, reg_val.value),
-                    kind=LogType.InstrInOuts)
+                fval = self.fpr(base, is_vec, offs, ew_src)
+                reg_val = SelectableInt(fval)
+                assert ew_src == XLEN, "TODO fix elwidth conversion"
                 self.trace("r:FPR:%d:%d:%d " % (base, offs, ew_src))
                 self.trace("r:FPR:%d:%d:%d " % (base, offs, ew_src))
+                log("read fp reg %d/%d: 0x%x" % (base, offs, reg_val.value),
+                    kind=LogType.InstrInOuts)
             elif name is not None:
             elif name is not None:
-                reg_val = SelectableInt(self.gpr(base, is_vec, offs, ew_src))
+                gval = self.gpr(base, is_vec, offs, ew_src)
+                reg_val = SelectableInt(gval.value, bits=xlen)
                 self.trace("r:GPR:%d:%d:%d " % (base, offs, ew_src))
                 self.trace("r:GPR:%d:%d:%d " % (base, offs, ew_src))
-                log("read reg %d/%d: 0x%x" % (base, offs, reg_val.value),
+                log("read int reg %d/%d: 0x%x" % (base, offs, reg_val.value),
                     kind=LogType.InstrInOuts)
         else:
             log('zero input reg %s %s' % (name, str(regnum)), is_vec)
                     kind=LogType.InstrInOuts)
         else:
             log('zero input reg %s %s' % (name, str(regnum)), is_vec)
@@ -2656,9 +2737,24 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         if name in fregs:
             self.fpr.write(regnum, output, is_vec, ew_dst)
             self.trace("w:FPR:%d:%d:%d " % (rnum, offset, ew_dst))
         if name in fregs:
             self.fpr.write(regnum, output, is_vec, ew_dst)
             self.trace("w:FPR:%d:%d:%d " % (rnum, offset, ew_dst))
-        else:
-            self.gpr.write(regnum, output, is_vec, ew_dst)
-            self.trace("w:GPR:%d:%d:%d " % (rnum, offset, ew_dst))
+            return
+
+        # LDST/Update does *not* allow elwidths on RA (Effective Address).
+        # this has to be detected, and overridden.  see get_input (related)
+        sv_mode = yield self.dec2.rm_dec.sv_mode
+        is_ldst = (sv_mode in [SVMode.LDST_IDX.value, SVMode.LDST_IMM.value] \
+                  and self.is_svp64_mode)
+        if is_ldst and name in ['EA', 'RA']:
+            op = self.dec2.dec.op
+            if hasattr(op, "upd"):
+                # update mode LD/ST uses read-reg A also as an output
+                upd = yield op.upd
+                log("write is_ldst is_update", sv_mode, is_ldst, upd)
+                if upd == LDSTMode.update.value:
+                    ew_dst = 64 # override for RA (EA) to 64-bit
+
+        self.gpr.write(regnum, output, is_vec, ew_dst)
+        self.trace("w:GPR:%d:%d:%d " % (rnum, offset, ew_dst))
 
     def check_step_increment(self, rc_en, asmop, ins_name):
         # check if it is the SVSTATE.src/dest step that needs incrementing
 
     def check_step_increment(self, rc_en, asmop, ins_name):
         # check if it is the SVSTATE.src/dest step that needs incrementing
@@ -2817,6 +2913,9 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         vfirst = self.svstate.vfirst
         log("    SV Vertical First", vf, vfirst)
         if not vf and vfirst == 1:
         vfirst = self.svstate.vfirst
         log("    SV Vertical First", vf, vfirst)
         if not vf and vfirst == 1:
+            if insn_name.startswith("sv.bc"):
+                self.update_pc_next()
+                return False
             self.update_nia()
             return True
 
             self.update_nia()
             return True
 
@@ -2883,7 +2982,7 @@ class ISACaller(ISACallerHelper, ISAFPHelpers, StepLoop):
         # 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)
         # 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.pc.NIA.eq(self.pc.CIA)
         self.namespace['NIA'] = self.pc.NIA
         log("end of sub-pc call", self.namespace['CIA'], self.namespace['NIA'])
         return False  # DO NOT allow PC update whilst Sub-PC loop running
         self.namespace['NIA'] = self.pc.NIA
         log("end of sub-pc call", self.namespace['CIA'], self.namespace['NIA'])
         return False  # DO NOT allow PC update whilst Sub-PC loop running