-from soc.decoder.power_enums import (Function, Form, InternalOp,
- In1Sel, In2Sel, In3Sel, OutSel,
- RC, LdstLen, CryIn, get_csv,
- single_bit_flags,
- get_signal_name, default_values)
-import math
-
-
-class MemorySim:
- def __init__(self, bytes_per_word=8):
- self.mem = {}
- self.bytes_per_word = bytes_per_word
- self.word_log2 = math.ceil(math.log2(bytes_per_word))
-
- def _get_shifter_mask(self, width, remainder):
- shifter = ((self.bytes_per_word - width) - remainder) * \
- 8 # bits per byte
- mask = (1 << (width * 8)) - 1
- return shifter, mask
-
- # TODO: Implement ld/st of lesser width
- def ld(self, address, width=8):
- 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]
- else:
- val = 0
-
- if width != self.bytes_per_word:
- shifter, mask = self._get_shifter_mask(width, remainder)
- val = val & (mask << shifter)
- val >>= shifter
- print("Read {:x} from addr {:x}".format(val, address))
- return val
-
- def st(self, address, value, width=8):
- remainder = address & (self.bytes_per_word - 1)
- address = address >> self.word_log2
- assert remainder & (width - 1) == 0, "Unaligned access unsupported!"
- print("Writing {:x} to addr {:x}".format(value, address))
- if width != self.bytes_per_word:
- if address in self.mem:
- val = self.mem[address]
- else:
- val = 0
- shifter, mask = self._get_shifter_mask(width, remainder)
- val &= ~(mask << shifter)
- val |= value << shifter
- self.mem[address] = val
- else:
- self.mem[address] = value
-
-
-class RegFile:
- def __init__(self):
- self.regfile = [0] * 32
- self.sprs = {}
-
- def write_reg(self, regnum, value):
- all1s = (1 << 64)-1 # 64 bits worth of 1s
- value &= all1s
- print("Writing {:x} to reg r{}".format(value, regnum))
- self.regfile[regnum] = value
-
- def read_reg(self, regnum):
- val = self.regfile[regnum]
- print("Read {:x} from reg r{}".format(val, regnum))
- return val
-
- def assert_gpr(self, gpr, val):
- reg_val = self.read_reg(gpr)
- msg = "reg r{} got {:x}, expecting {:x}".format(
- gpr, reg_val, val)
- assert reg_val == val, msg
-
- def assert_gprs(self, gprs):
- for k, v in list(gprs.items()):
- self.assert_gpr(k, v)
-
- def set_xer(self, result, operanda, operandb):
- xer = 0
- if result & 1 << 64:
- xer |= XER.CA
-
- self.xer = xer
-
-
-class InternalOpSimulator:
- def __init__(self):
- self.mem_sim = MemorySim()
- self.regfile = RegFile()
-
- def execute_alu_op(self, op1, op2, internal_op, carry=0):
- print(internal_op)
- if internal_op == InternalOp.OP_ADD.value:
- return op1 + op2 + carry
- elif internal_op == InternalOp.OP_AND.value:
- return op1 & op2
- elif internal_op == InternalOp.OP_OR.value:
- return op1 | op2
- elif internal_op == InternalOp.OP_MUL_L64.value:
- return op1 * op2
- else:
- assert False, "Not implemented"
-
- def update_cr0(self, result):
- if result == 0:
- self.cr0 = 0b001
- elif result >> 63:
- self.cr0 = 0b100
- else:
- self.cr0 = 0b010
- print("update_cr0", self.cr0)
-
- def alu_op(self, pdecode2):
- all1s = (1 << 64)-1 # 64 bits worth of 1s
- internal_op = yield pdecode2.dec.op.internal_op
- operand1 = 0
- operand2 = 0
- result = 0
- carry = 0
- r1_ok = yield pdecode2.e.read_reg1.ok
- r2_ok = yield pdecode2.e.read_reg2.ok
- r3_ok = yield pdecode2.e.read_reg3.ok
- imm_ok = yield pdecode2.e.imm_data.ok
- if r1_ok:
- r1_sel = yield pdecode2.e.read_reg1.data
- operand1 = self.regfile.read_reg(r1_sel)
- elif r3_ok:
- r3_sel = yield pdecode2.e.read_reg3.data
- operand1 = self.regfile.read_reg(r3_sel)
- if r2_ok:
- r2_sel = yield pdecode2.e.read_reg2.data
- operand2 = self.regfile.read_reg(r2_sel)
- if imm_ok:
- operand2 = yield pdecode2.e.imm_data.data
-
- inv_a = yield pdecode2.dec.op.inv_a
- if inv_a:
- operand1 = (~operand1) & all1s
-
- cry_in = yield pdecode2.dec.op.cry_in
- if cry_in == CryIn.ONE.value:
- carry = 1
- elif cry_in == CryIn.CA.value:
- carry = self.carry_out
-
- # TODO rc_sel = yield pdecode2.dec.op.rc_sel
- result = self.execute_alu_op(operand1, operand2, internal_op,
- carry=carry)
-
- cry_out = yield pdecode2.dec.op.cry_out
- rc = yield pdecode2.e.rc.data
-
- if rc:
- self.update_cr0(result)
- if cry_out == 1:
- self.carry_out = (result >> 64)
- print("setting carry_out", self.carry_out)
-
- ro_ok = yield pdecode2.e.write_reg.ok
- if ro_ok:
- ro_sel = yield pdecode2.e.write_reg.data
- self.regfile.write_reg(ro_sel, result)
-
- def mem_op(self, pdecode2):
- internal_op = yield pdecode2.dec.op.internal_op
- addr_reg = yield pdecode2.e.read_reg1.data
- addr = self.regfile.read_reg(addr_reg)
-
- imm_ok = yield pdecode2.e.imm_data.ok
- r2_ok = yield pdecode2.e.read_reg2.ok
- width = yield pdecode2.e.data_len
- if imm_ok:
- imm = yield pdecode2.e.imm_data.data
- addr += imm
- elif r2_ok:
- r2_sel = yield pdecode2.e.read_reg2.data
- addr += self.regfile.read_reg(r2_sel)
- if internal_op == InternalOp.OP_STORE.value:
- val_reg = yield pdecode2.e.read_reg3.data
- val = self.regfile.read_reg(val_reg)
- self.mem_sim.st(addr, val, width)
- elif internal_op == InternalOp.OP_LOAD.value:
- dest_reg = yield pdecode2.e.write_reg.data
- val = self.mem_sim.ld(addr, width)
- self.regfile.write_reg(dest_reg, val)
-
- def execute_op(self, pdecode2):
- function = yield pdecode2.dec.op.function_unit
- if function == Function.ALU.value:
- yield from self.alu_op(pdecode2)
- elif function == Function.LDST.value:
- yield from self.mem_op(pdecode2)