X-Git-Url: https://git.libre-soc.org/?p=soc.git;a=blobdiff_plain;f=src%2Fsoc%2Fdecoder%2Fisa%2Fcaller.py;h=488df5ceeaa88289edbb157ccf6ab622060e4266;hp=ec6af39c8ed30fb79b373443a2c59d24cc3da73e;hb=0c3689e8f95c8b2d08100055c9b9c3711d366f1c;hpb=5d183e9ed2beef48bab5166139d3385d948b43b4 diff --git a/src/soc/decoder/isa/caller.py b/src/soc/decoder/isa/caller.py index ec6af39c..488df5ce 100644 --- a/src/soc/decoder/isa/caller.py +++ b/src/soc/decoder/isa/caller.py @@ -9,10 +9,12 @@ from functools import wraps 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 ' + \ @@ -76,13 +78,15 @@ class Mem: 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)) @@ -183,7 +187,14 @@ class SPR(dict): 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 @@ -226,13 +237,13 @@ class ISACaller: 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 = {} @@ -268,7 +279,9 @@ class ISACaller: # "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, @@ -279,7 +292,8 @@ class ISACaller: 'undefined': self.undefined, 'mode_is_64bit': True, 'SO': XER_bits['SO'] - } + }) + # field-selectable versions of Condition Register TODO check bitranges? self.crl = [] @@ -294,6 +308,10 @@ class ISACaller: 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 @@ -332,8 +350,16 @@ class ISACaller: 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): @@ -341,13 +367,16 @@ class ISACaller: 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] @@ -357,8 +386,16 @@ class ISACaller: 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) @@ -373,11 +410,11 @@ class ISACaller: 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] @@ -393,21 +430,81 @@ class ISACaller: self.namespace['NIA'] = SelectableInt(pc_val, 64) self.pc.update(self.namespace) - def execute_one(self): + def setup_one(self): + """set up one instruction + """ if self.respect_pc: pc = self.pc.CIA.value else: pc = self.fake_pc - self.fake_pc += 4 - 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 = 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 + 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) @@ -449,10 +546,20 @@ class ISACaller: 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) @@ -460,6 +567,8 @@ class ISACaller: # 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']: