X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fdecoder%2Fisa%2Fcaller.py;h=a57194bec41ab28490d0df91d75362b7f62d88f8;hb=f156f22024d462676949f799e475e9b3766ddec1;hp=504ab94a69e4960184a925e24e707f2de5e923d0;hpb=eac3182f4d2f0efd1e9bc6487e2ae72b08923352;p=soc.git diff --git a/src/soc/decoder/isa/caller.py b/src/soc/decoder/isa/caller.py index 504ab94a..a57194be 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,24 +187,44 @@ 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) + if isinstance(key, int): + info = spr_dict[key] + else: + info = spr_byname[key] + if not isinstance(v, SelectableInt): + v = SelectableInt(v, info.length) + self[key] = v def __getitem__(self, key): + print ("get spr", key) + print ("dict", self.items()) # if key in special_sprs get the special spr, otherwise return key if isinstance(key, SelectableInt): key = key.value + if isinstance(key, int): + key = spr_dict[key].SPR key = special_sprs.get(key, key) if key in self: - return dict.__getitem__(self, key) + res = dict.__getitem__(self, key) else: info = spr_dict[key] dict.__setitem__(self, key, SelectableInt(0, info.length)) - return dict.__getitem__(self, key) + res = dict.__getitem__(self, key) + print ("spr returning", key, res) + return res def __setitem__(self, key, value): if isinstance(key, SelectableInt): key = key.value + if isinstance(key, int): + key = spr_dict[key].SPR + print ("spr key", key) key = special_sprs.get(key, key) + print ("setting spr", key, value) dict.__setitem__(self, key, value) def __call__(self, ridx): @@ -226,13 +250,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 = {} @@ -240,12 +264,14 @@ class ISACaller: for i, code in enumerate(disassembly): self.disassembly[i*4 + self.fake_pc] = code + # set up registers, instruction memory, data memory, PC, SPRs, MSR self.gpr = GPR(decoder2, regfile) self.mem = Mem(row_bytes=8, initial_mem=initial_mem) self.imem = Mem(row_bytes=4, initial_mem=initial_insns) self.pc = PC() self.spr = SPR(decoder2, initial_sprs) self.msr = SelectableInt(initial_msr, 64) # underlying reg + # TODO, needed here: # FPR (same as GPR except for FP nums) # 4.2.2 p124 FPSCR (definitely "separate" - not in SPR) @@ -266,7 +292,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, @@ -277,7 +305,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 = [] @@ -292,6 +321,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 @@ -330,8 +363,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): @@ -339,13 +380,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] @@ -355,8 +399,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) @@ -371,11 +423,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] @@ -391,21 +443,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) @@ -447,10 +559,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) @@ -458,6 +580,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']: @@ -472,6 +596,8 @@ class ISACaller: self.spr[name] = output else: self.namespace[name].eq(output) + if name == 'MSR': + print ('msr written', hex(self.msr.value)) else: regnum = yield getattr(self.decoder, name) print('writing reg %d %s' % (regnum, str(output)))