from soc.decoder.orderedset import OrderedSet
from soc.decoder.selectable_int import (FieldSelectableInt, SelectableInt,
selectconcat)
-from soc.decoder.power_enums import spr_dict, XER_bits
-from soc.decoder.helpers import exts
+from soc.decoder.power_enums import (spr_dict, spr_byname, XER_bits,
+ insns, InternalOp)
+from soc.decoder.helpers import exts, trunc_div, trunc_rem
from collections import namedtuple
import math
+import sys
instruction_info = namedtuple('instruction_info',
'func read_regs uninit_regs write_regs ' + \
return shifter, mask
# TODO: Implement ld/st of lesser width
- def ld(self, address, width=8, swap=True):
+ def ld(self, address, width=8, swap=True, check_in_mem=False):
print("ld from addr 0x{:x} width {:d}".format(address, width))
remainder = address & (self.bytes_per_word - 1)
address = address >> self.word_log2
assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
if address in self.mem:
val = self.mem[address]
+ elif check_in_mem:
+ return None
else:
val = 0
print("mem @ 0x{:x} rem {:d} : 0x{:x}".format(address, remainder, val))
def __init__(self, dec2, initial_sprs={}):
self.sd = dec2
dict.__init__(self)
- self.update(initial_sprs)
+ for key, v in initial_sprs.items():
+ if isinstance(key, SelectableInt):
+ key = key.value
+ key = special_sprs.get(key, key)
+ info = spr_byname[key]
+ if not isinstance(v, SelectableInt):
+ v = SelectableInt(v, info.length)
+ self[key] = v
def __getitem__(self, key):
# if key in special_sprs get the special spr, otherwise return key
initial_insns = {}
assert self.respect_pc == False, "instructions required to honor pc"
+ print ("ISACaller insns", respect_pc, initial_insns, disassembly)
+
# "fake program counter" mode (for unit testing)
+ self.fake_pc = 0
if not respect_pc:
if isinstance(initial_mem, tuple):
self.fake_pc = initial_mem[0]
- else:
- self.fake_pc = 0
# disassembly: we need this for now (not given from the decoder)
self.disassembly = {}
# "undefined", just set to variable-bit-width int (use exts "max")
self.undefined = SelectableInt(0, 256) # TODO, not hard-code 256!
- self.namespace = {'GPR': self.gpr,
+ self.namespace = {}
+ self.namespace.update(self.spr)
+ self.namespace.update({'GPR': self.gpr,
'MEM': self.mem,
'SPR': self.spr,
'memassign': self.memassign,
'undefined': self.undefined,
'mode_is_64bit': True,
'SO': XER_bits['SO']
- }
+ })
+
# field-selectable versions of Condition Register TODO check bitranges?
self.crl = []
def TRAP(self, trap_addr=0x700):
print ("TRAP: TODO")
+ #self.namespace['NIA'] = trap_addr
+ #self.SRR0 = self.namespace['CIA'] + 4
+ #self.SRR1 = self.namespace['MSR']
+ #self.namespace['MSR'][45] = 1
# store CIA(+4?) in SRR0, set NIA to 0x700
# store MSR in SRR1, set MSR to um errr something, have to check spec
imm = yield self.dec2.e.imm_data.data
inputs.append(SelectableInt(imm, 64))
assert len(outputs) >= 1
- output = outputs[0]
- gts = [(x > output) for x in inputs]
+ print ("outputs", repr(outputs))
+ if isinstance(outputs, list) or isinstance(outputs, tuple):
+ output = outputs[0]
+ else:
+ output = outputs
+ gts = []
+ for x in inputs:
+ print ("gt input", x, output)
+ gt = (x > output)
+ gts.append(gt)
print(gts)
cy = 1 if any(gts) else 0
if not (1 & already_done):
print ("inputs", inputs)
# 32 bit carry
- gts = [(x[32:64] > output[32:64]) == SelectableInt(1, 1)
- for x in inputs]
+ gts = []
+ for x in inputs:
+ print ("input", x, output)
+ gt = (x[32:64] > output[32:64]) == SelectableInt(1, 1)
+ gts.append(gt)
cy32 = 1 if any(gts) else 0
if not (2 & already_done):
self.spr['XER'][XER_bits['CA32']] = cy32
- def handle_overflow(self, inputs, outputs):
+ def handle_overflow(self, inputs, outputs, div_overflow):
inv_a = yield self.dec2.e.invert_a
if inv_a:
inputs[0] = ~inputs[0]
imm = yield self.dec2.e.imm_data.data
inputs.append(SelectableInt(imm, 64))
assert len(outputs) >= 1
- print ("handle_overflow", inputs, outputs)
- if len(inputs) >= 2:
+ print ("handle_overflow", inputs, outputs, div_overflow)
+ if len(inputs) < 2 and div_overflow != 1:
+ return
+
+ # div overflow is different: it's returned by the pseudo-code
+ # because it's more complex than can be done by analysing the output
+ if div_overflow == 1:
+ ov, ov32 = 1, 1
+ # arithmetic overflow can be done by analysing the input and output
+ elif len(inputs) >= 2:
output = outputs[0]
# OV (64-bit)
ov32 = 1 if input32_sgn[0] == input32_sgn[1] and \
output32_sgn != input32_sgn[0] else 0
- self.spr['XER'][XER_bits['OV']] = ov
- self.spr['XER'][XER_bits['OV32']] = ov32
- so = self.spr['XER'][XER_bits['SO']]
- so = so | ov
- self.spr['XER'][XER_bits['SO']] = so
+ self.spr['XER'][XER_bits['OV']] = ov
+ self.spr['XER'][XER_bits['OV32']] = ov32
+ so = self.spr['XER'][XER_bits['SO']]
+ so = so | ov
+ self.spr['XER'][XER_bits['SO']] = so
def handle_comparison(self, outputs):
out = outputs[0]
pc = self.pc.CIA.value
else:
pc = self.fake_pc
- ins = yield self.imem.ld(pc, 4, False)
- yield self.pdecode2.dec.raw_opcode_in.eq(ins)
- yield self.pdecode2.dec.bigendian.eq(0) # little / big?
- self._pc
+ self._pc = pc
+ ins = self.imem.ld(pc, 4, False, True)
+ if ins is None:
+ raise KeyError("no instruction at 0x%x" % pc)
+ print("setup: 0x%x 0x%x %s" % (pc, ins & 0xffffffff, bin(ins)))
+ print ("NIA, CIA", self.pc.CIA.value, self.pc.NIA.value)
+
+ yield self.dec2.dec.raw_opcode_in.eq(ins & 0xffffffff)
+ yield self.dec2.dec.bigendian.eq(0) # little / big?
def execute_one(self):
"""execute one instruction
"""
# get the disassembly code for this instruction
code = self.disassembly[self._pc]
+ print("sim-execute", hex(self._pc), code)
opname = code.split(' ')[0]
- yield from call(opname)
+ yield from self.call(opname)
if not self.respect_pc:
self.fake_pc += 4
- #else:
- #self.pc.CIA.value = self.pc.NIA.value
+ print ("NIA, CIA", self.pc.CIA.value, self.pc.NIA.value)
+
+ def get_assembly_name(self):
+ # TODO, asmregs is from the spec, e.g. add RT,RA,RB
+ # see http://bugs.libre-riscv.org/show_bug.cgi?id=282
+ asmcode = yield self.dec2.dec.op.asmcode
+ asmop = insns.get(asmcode, None)
+
+ # sigh reconstruct the assembly instruction name
+ ov_en = yield self.dec2.e.oe.oe
+ ov_ok = yield self.dec2.e.oe.ok
+ if ov_en & ov_ok:
+ asmop += "."
+ lk = yield self.dec2.e.lk
+ if lk:
+ asmop += "l"
+ int_op = yield self.dec2.dec.op.internal_op
+ print ("int_op", int_op)
+ if int_op in [InternalOp.OP_B.value, InternalOp.OP_BC.value]:
+ AA = yield self.dec2.dec.fields.FormI.AA[0:-1]
+ print ("AA", AA)
+ if AA:
+ asmop += "a"
+ if int_op == InternalOp.OP_MFCR.value:
+ dec_insn = yield self.dec2.e.insn
+ if dec_insn & (1<<20) != 0: # sigh
+ asmop = 'mfocrf'
+ else:
+ asmop = 'mfcr'
+ # XXX TODO: for whatever weird reason this doesn't work
+ # https://bugs.libre-soc.org/show_bug.cgi?id=390
+ if int_op == InternalOp.OP_MTCRF.value:
+ dec_insn = yield self.dec2.e.insn
+ if dec_insn & (1<<20) != 0: # sigh
+ asmop = 'mtocrf'
+ else:
+ asmop = 'mtcrf'
+ return asmop
def call(self, name):
# TODO, asmregs is from the spec, e.g. add RT,RA,RB
# see http://bugs.libre-riscv.org/show_bug.cgi?id=282
+ asmop = yield from self.get_assembly_name()
+ print ("call", name, asmop)
+ if name not in ['mtcrf', 'mtocrf']:
+ assert name == asmop, "name %s != %s" % (name, asmop)
+
info = self.instrs[name]
yield from self.prep_namespace(info.form, info.op_fields)
carry_en = yield self.dec2.e.output_carry
if carry_en:
yield from self.handle_carry_(inputs, results, already_done)
+
+ # detect if overflow was in return result
+ overflow = None
+ if info.write_regs:
+ for name, output in zip(output_names, results):
+ if name == 'overflow':
+ overflow = output
+
ov_en = yield self.dec2.e.oe.oe
ov_ok = yield self.dec2.e.oe.ok
+ print ("internal overflow", overflow)
if ov_en & ov_ok:
- yield from self.handle_overflow(inputs, results)
+ yield from self.handle_overflow(inputs, results, overflow)
+
rc_en = yield self.dec2.e.rc.data
if rc_en:
self.handle_comparison(results)
# any modified return results?
if info.write_regs:
for name, output in zip(output_names, results):
+ if name == 'overflow': # ignore, done already (above)
+ continue
if isinstance(output, int):
output = SelectableInt(output, 256)
if name in ['CA', 'CA32']: