move unused directory out of src, to indicate "ignore completely"
[soc.git] / unused_please_ignore_completely / simulator / internalop_sim.py
diff --git a/unused_please_ignore_completely/simulator/internalop_sim.py b/unused_please_ignore_completely/simulator/internalop_sim.py
new file mode 100644 (file)
index 0000000..f7a4b26
--- /dev/null
@@ -0,0 +1,196 @@
+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)