move unused simulator code out the way
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 7 May 2020 18:35:32 +0000 (19:35 +0100)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Thu, 7 May 2020 18:36:01 +0000 (19:36 +0100)
src/soc/simulator/internalop_sim.py [deleted file]
src/soc/simulator/test_sim.py [deleted file]
src/unused/simulator/internalop_sim.py [new file with mode: 0644]
src/unused/simulator/test_sim.py [new file with mode: 0644]

diff --git a/src/soc/simulator/internalop_sim.py b/src/soc/simulator/internalop_sim.py
deleted file mode 100644 (file)
index f7a4b26..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-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)
diff --git a/src/soc/simulator/test_sim.py b/src/soc/simulator/test_sim.py
deleted file mode 100644 (file)
index 0a26380..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-from nmigen import Module, Signal
-from nmigen.back.pysim import Simulator, Delay
-from nmigen.test.utils import FHDLTestCase
-import unittest
-from soc.simulator.internalop_sim import InternalOpSimulator
-from soc.decoder.power_decoder import (create_pdecode)
-from soc.decoder.power_enums import (Function, InternalOp,
-                                     In1Sel, In2Sel, In3Sel,
-                                     OutSel, RC, LdstLen, CryIn,
-                                     single_bit_flags, Form, SPR,
-                                     get_signal_name, get_csv)
-from soc.decoder.power_decoder2 import (PowerDecode2)
-from soc.simulator.program import Program
-from soc.simulator.qemu import run_program
-
-
-class Register:
-    def __init__(self, num):
-        self.num = num
-
-
-class DecoderTestCase(FHDLTestCase):
-
-    def run_tst(self, generator, simulator):
-        m = Module()
-        comb = m.d.comb
-        instruction = Signal(32)
-
-        pdecode = create_pdecode()
-
-        m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
-        comb += pdecode2.dec.raw_opcode_in.eq(instruction)
-        sim = Simulator(m)
-        gen = generator.generate_instructions()
-
-        def process():
-            for ins in gen:
-
-                print("0x{:X}".format(ins & 0xffffffff))
-
-                # ask the decoder to decode this binary data (endian'd)
-                yield pdecode2.dec.bigendian.eq(0)  # little / big?
-                yield instruction.eq(ins)          # raw binary instr.
-                yield Delay(1e-6)
-                yield from simulator.execute_op(pdecode2)
-
-        sim.add_process(process)
-        with sim.write_vcd("simulator.vcd", "simulator.gtkw",
-                           traces=pdecode2.ports()):
-            sim.run()
-
-    def test_example(self):
-        lst = ["addi 1, 0, 0x1234",
-               "addi 2, 0, 0x5678",
-               "add  3, 1, 2",
-               "and  4, 1, 2"]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1, 2, 3, 4])
-
-    def test_ldst(self):
-        lst = ["addi 1, 0, 0x1234",
-               "addi 2, 0, 0x5678",
-               "stw  1, 0(2)",
-               "lwz  3, 0(2)"]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1, 2, 3])
-
-    def test_ldst_extended(self):
-        lst = ["addi 1, 0, 0x1234",
-               "addi 2, 0, 0x5678",
-               "addi 4, 0, 0x40",
-               "stw  1, 0x40(2)",
-               "lwzx  3, 4, 2"]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1, 2, 3])
-
-    def test_ldst_widths(self):
-        lst = [" lis 1, 0xdead",
-               "ori 1, 1, 0xbeef",
-               "addi 2, 0, 0x1000",
-               "std 1, 0(2)",
-               "lbz 1, 5(2)",
-               "lhz 3, 4(2)",
-               "lwz 4, 4(2)",
-               "addi 5, 0, 0x12",
-               "stb 5, 5(2)",
-               "ld  5, 0(2)"]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1, 2, 3, 4, 5])
-
-    def test_sub(self):
-        lst = ["addi 1, 0, 0x1234",
-               "addi 2, 0, 0x5678",
-               "subf 3, 1, 2",
-               "subfic 4, 1, 0x1337",
-               "neg 5, 1"]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1, 2, 3, 4, 5])
-
-    def test_add_with_carry(self):
-        lst = ["addi 1, 0, 5",
-               "neg 1, 1",
-               "addi 2, 0, 7",
-               "neg 2, 2",
-               "addc 3, 2, 1",
-               "addi 3, 3, 1"
-               ]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1, 2, 3])
-
-    def test_addis(self):
-        lst = ["addi 1, 0, 0x0FFF",
-               "addis 1, 1, 0x0F"
-               ]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1])
-
-    def test_mulli(self):
-        lst = ["addi 1, 0, 3",
-               "mulli 1, 1, 2"
-               ]
-        with Program(lst) as program:
-            self.run_tst_program(program, [1])
-
-    def run_tst_program(self, prog, reglist):
-        simulator = InternalOpSimulator()
-        self.run_tst(prog, simulator)
-        prog.reset()
-        with run_program(prog) as q:
-            qemu_register_compare(simulator, q, reglist)
-
-
-def qemu_register_compare(simulator, qemu, regs):
-    for reg in regs:
-        qemu_val = qemu.get_register(reg)
-        simulator.regfile.assert_gpr(reg, qemu_val)
-
-
-if __name__ == "__main__":
-    unittest.main()
diff --git a/src/unused/simulator/internalop_sim.py b/src/unused/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)
diff --git a/src/unused/simulator/test_sim.py b/src/unused/simulator/test_sim.py
new file mode 100644 (file)
index 0000000..0a26380
--- /dev/null
@@ -0,0 +1,140 @@
+from nmigen import Module, Signal
+from nmigen.back.pysim import Simulator, Delay
+from nmigen.test.utils import FHDLTestCase
+import unittest
+from soc.simulator.internalop_sim import InternalOpSimulator
+from soc.decoder.power_decoder import (create_pdecode)
+from soc.decoder.power_enums import (Function, InternalOp,
+                                     In1Sel, In2Sel, In3Sel,
+                                     OutSel, RC, LdstLen, CryIn,
+                                     single_bit_flags, Form, SPR,
+                                     get_signal_name, get_csv)
+from soc.decoder.power_decoder2 import (PowerDecode2)
+from soc.simulator.program import Program
+from soc.simulator.qemu import run_program
+
+
+class Register:
+    def __init__(self, num):
+        self.num = num
+
+
+class DecoderTestCase(FHDLTestCase):
+
+    def run_tst(self, generator, simulator):
+        m = Module()
+        comb = m.d.comb
+        instruction = Signal(32)
+
+        pdecode = create_pdecode()
+
+        m.submodules.pdecode2 = pdecode2 = PowerDecode2(pdecode)
+        comb += pdecode2.dec.raw_opcode_in.eq(instruction)
+        sim = Simulator(m)
+        gen = generator.generate_instructions()
+
+        def process():
+            for ins in gen:
+
+                print("0x{:X}".format(ins & 0xffffffff))
+
+                # ask the decoder to decode this binary data (endian'd)
+                yield pdecode2.dec.bigendian.eq(0)  # little / big?
+                yield instruction.eq(ins)          # raw binary instr.
+                yield Delay(1e-6)
+                yield from simulator.execute_op(pdecode2)
+
+        sim.add_process(process)
+        with sim.write_vcd("simulator.vcd", "simulator.gtkw",
+                           traces=pdecode2.ports()):
+            sim.run()
+
+    def test_example(self):
+        lst = ["addi 1, 0, 0x1234",
+               "addi 2, 0, 0x5678",
+               "add  3, 1, 2",
+               "and  4, 1, 2"]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1, 2, 3, 4])
+
+    def test_ldst(self):
+        lst = ["addi 1, 0, 0x1234",
+               "addi 2, 0, 0x5678",
+               "stw  1, 0(2)",
+               "lwz  3, 0(2)"]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1, 2, 3])
+
+    def test_ldst_extended(self):
+        lst = ["addi 1, 0, 0x1234",
+               "addi 2, 0, 0x5678",
+               "addi 4, 0, 0x40",
+               "stw  1, 0x40(2)",
+               "lwzx  3, 4, 2"]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1, 2, 3])
+
+    def test_ldst_widths(self):
+        lst = [" lis 1, 0xdead",
+               "ori 1, 1, 0xbeef",
+               "addi 2, 0, 0x1000",
+               "std 1, 0(2)",
+               "lbz 1, 5(2)",
+               "lhz 3, 4(2)",
+               "lwz 4, 4(2)",
+               "addi 5, 0, 0x12",
+               "stb 5, 5(2)",
+               "ld  5, 0(2)"]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1, 2, 3, 4, 5])
+
+    def test_sub(self):
+        lst = ["addi 1, 0, 0x1234",
+               "addi 2, 0, 0x5678",
+               "subf 3, 1, 2",
+               "subfic 4, 1, 0x1337",
+               "neg 5, 1"]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1, 2, 3, 4, 5])
+
+    def test_add_with_carry(self):
+        lst = ["addi 1, 0, 5",
+               "neg 1, 1",
+               "addi 2, 0, 7",
+               "neg 2, 2",
+               "addc 3, 2, 1",
+               "addi 3, 3, 1"
+               ]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1, 2, 3])
+
+    def test_addis(self):
+        lst = ["addi 1, 0, 0x0FFF",
+               "addis 1, 1, 0x0F"
+               ]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1])
+
+    def test_mulli(self):
+        lst = ["addi 1, 0, 3",
+               "mulli 1, 1, 2"
+               ]
+        with Program(lst) as program:
+            self.run_tst_program(program, [1])
+
+    def run_tst_program(self, prog, reglist):
+        simulator = InternalOpSimulator()
+        self.run_tst(prog, simulator)
+        prog.reset()
+        with run_program(prog) as q:
+            qemu_register_compare(simulator, q, reglist)
+
+
+def qemu_register_compare(simulator, qemu, regs):
+    for reg in regs:
+        qemu_val = qemu.get_register(reg)
+        simulator.regfile.assert_gpr(reg, qemu_val)
+
+
+if __name__ == "__main__":
+    unittest.main()