class Armv7CpuTest(unittest.TestCase): _multiprocess_can_split_ = True def setUp(self): self.c = Cpu(Memory32()) self.rf = self.c.regfile self._setupStack() def _setupStack(self): self.stack = self.c.memory.mmap(0xf000, 0x1000, 'rw') self.rf.write('SP', self.stack + 0x1000) def test_rd(self): self.assertEqual(self.rf.read('R0'), 0) def test_rd2(self): self.c.STACK = 0x1337 self.assertEqual(self.rf.read('SP'), 0x1337) def test_stack_set_get(self): self.c.STACK = 0x1337 self.assertEqual(self.c.STACK, 0x1337) def test_rd3(self): self.c.STACK = 0x1337 - 1 self.assertEqual(self.rf.read('SP'), 0x1336) def test_rd4(self): self.c.STACK = 0x1337 + 1 self.assertEqual(self.rf.read('SP'), 0x1338) def test_stack_push(self): self.c.stack_push(42) self.c.stack_push(44) self.assertItemsEqual(self.c.read(self.c.STACK, 4), '\x2c\x00\x00\x00') self.assertItemsEqual(self.c.read(self.c.STACK + 4, 4), '\x2a\x00\x00\x00') def test_stack_pop(self): v = 0x55 v_bytes = struct.pack('<I', v) self.c.stack_push(v) val = self.c.stack_pop() self.assertItemsEqual(self.c.read(self.c.STACK - 4, 4), v_bytes) def test_stack_peek(self): self.c.stack_push(42) self.assertItemsEqual(self.c.stack_peek(), '\x2a\x00\x00\x00') def test_readwrite_int(self): self.c.STACK -= 4 self.c.write_int(self.c.STACK, 0x4242, 32) self.assertEqual(self.c.read_int(self.c.STACK), 0x4242)
class Armv7CpuTest(unittest.TestCase): _multiprocess_can_split_ = True def setUp(self): self.c = Cpu(Memory32()) self.rf = self.c.regfile self._setupStack() def _setupStack(self): self.stack = self.c.memory.mmap(0xf000, 0x1000, 'rw') self.rf.write('SP', self.stack + 0x1000) def test_rd(self): self.assertEqual(self.rf.read('R0'), 0) def test_rd2(self): self.c.STACK = 0x1337 self.assertEqual(self.rf.read('SP'), 0x1337) def test_stack_set_get(self): self.c.STACK = 0x1337 self.assertEqual(self.c.STACK, 0x1337) def test_rd3(self): self.c.STACK = 0x1337 - 1 self.assertEqual(self.rf.read('SP'), 0x1336) def test_rd4(self): self.c.STACK = 0x1337 + 1 self.assertEqual(self.rf.read('SP'), 0x1338) def test_stack_push(self): self.c.stack_push(42) self.c.stack_push(44) self.assertItemsEqual(self.c.read(self.c.STACK, 4), '\x2c\x00\x00\x00') self.assertItemsEqual(self.c.read(self.c.STACK + 4, 4), '\x2a\x00\x00\x00') def test_stack_pop(self): v = 0x55 v_bytes = struct.pack('<I', v) self.c.stack_push(v) val = self.c.stack_pop() self.assertItemsEqual(self.c.read(self.c.STACK - 4, 4), v_bytes) def test_stack_peek(self): self.c.stack_push(42) self.assertItemsEqual(self.c.stack_peek(), '\x2a\x00\x00\x00') def test_readwrite_int(self): self.c.STACK -= 4 self.c.write_int(self.c.STACK, 0x4242, 32) self.assertEqual(self.c.read_int(self.c.STACK), 0x4242)
class Armv7CpuInstructions(unittest.TestCase): def setUp(self): self.cpu = Cpu(Memory32()) self.mem = self.cpu.memory self.rf = self.cpu.regfile def _setupCpu(self, asm): self.code = self.mem.mmap(0x1000, 0x1000, 'rwx') self.data = self.mem.mmap(0xd000, 0x1000, 'rw') self.stack = self.mem.mmap(0xf000, 0x1000, 'rw') start = self.code + 4 self.mem.write(start, assemble(asm)) self.rf.write('PC', start) self.rf.write('SP', self.stack + 0x1000) def _checkFlagsNZCV(self, n, z, c, v): self.assertEqual(self.rf.read('APSR_N'), n) self.assertEqual(self.rf.read('APSR_Z'), z) self.assertEqual(self.rf.read('APSR_C'), c) self.assertEqual(self.rf.read('APSR_V'), v) # MOV @itest("mov r0, 0x0") def test_mov_imm_min(self): self.assertEqual(self.rf.read('R0'), 0x0) @itest("mov r0, 42") def test_mov_imm_norm(self): self.assertEqual(self.rf.read('R0'), 42) @itest("mov r0, 0x100") def test_mov_imm_modified_imm_min(self): self.assertEqual(self.rf.read('R0'), 0x100) @itest("mov r0, 0xff000000") def test_mov_imm_modified_imm_max(self): self.assertEqual(self.rf.read('R0'), 0xff000000) @itest_custom("mov r0, r1") def test_mov_immreg(self): self.rf.write('R1', 0) self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0) @itest_custom("mov r0, r1") def test_mov_immreg1(self): self.rf.write('R1', 2**32) self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0) @itest_custom("mov r0, r1") def test_mov_immreg2(self): self.rf.write('R1', 0xffffffff) self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0xffffffff) @itest_custom("mov r0, r1") def test_mov_immreg3(self): self.rf.write('R1', 42) self.cpu.execute() self.assertEqual(self.rf.read('R0'), 42) # MOVW @itest("movw r0, 0") def test_movw_imm_min(self): self.assertEqual(self.rf.read('R0'), 0x0) @itest("movw r0, 0xffff") def test_movw_imm_max(self): self.assertEqual(self.rf.read('R0'), 0xffff) # MOVS @itest_custom("movs r0, 0") def test_movs_imm_min(self): pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0) self._checkFlagsNZCV(0, 1, pre_c, pre_v) @itest_custom("movs r0, 42") def test_movs_imm_norm(self): pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 42) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_custom("movs r0, 0x100") def test_movs_imm_modified_imm_min(self): pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0x100) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_custom("movs r0, 0xff000000") def test_movs_imm_modified_imm_max(self): pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0xff000000) self._checkFlagsNZCV(1, 0, 1, pre_v) @itest_custom("movs r0, 0x0e000000") def test_movs_imm_modified_imm_sans_carry(self): pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0x0e000000) self._checkFlagsNZCV(0, 0, 0, pre_v) @itest_custom("movs r0, r1") def test_movs_reg(self): self.rf.write('R1', 0) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0) self._checkFlagsNZCV(0, 1, pre_c, pre_v) @itest_custom("movs r0, r1") def test_movs_reg1(self): self.rf.write('R1', 2**32) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 0) self._checkFlagsNZCV(0, 1, pre_c, pre_v) @itest_custom("movs r0, r1") def test_movs_reg2(self): self.rf.write('R1', 2**32 - 1) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 2**32 - 1) self._checkFlagsNZCV(1, 0, pre_c, pre_v) @itest_custom("movs r0, r1") def test_movs_reg3(self): self.rf.write('R1', 42) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.cpu.execute() self.assertEqual(self.rf.read('R0'), 42) self._checkFlagsNZCV(0, 0, pre_c, pre_v) # ADD @itest_custom("add r3, r1, 55") def test_add_imm_norm(self): self.rf.write('R1', 44) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 99) @itest_custom("add r3, r1, 0x100") def test_add_imm_mod_imm_min(self): self.rf.write('R1', 44) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0x100) @itest_custom("add r3, r1, 0xff000000") def test_add_imm_mod_imm_max(self): self.rf.write('R1', 44) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) @itest_custom("add r3, r1, 0x1000000") def test_add_imm_carry(self): self.rf.write('R1', 0xff000001) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 1) @itest_custom("add r3, r1, 0x1") def test_add_imm_overflow(self): self.rf.write('R1', (2**31 - 1)) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0x80000000) @itest_custom("add r3, r1, r2") def test_add_reg_norm(self): self.rf.write('R1', 44) self.rf.write('R2', 55) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 99) @itest_custom("add r3, r1, r2") def test_add_reg_mod_imm_min(self): self.rf.write('R1', 44) self.rf.write('R2', 0x100) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0x100) @itest_custom("add r3, r1, r2") def test_add_reg_mod_imm_max(self): self.rf.write('R1', 44) self.rf.write('R2', 0xff000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) @itest_custom("add r3, r1, r2") def test_add_reg_carry(self): self.rf.write('R1', 0x1000000) self.rf.write('R2', 0xff000001) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 1) @itest_custom("add r3, r1, r2") def test_add_reg_overflow(self): self.rf.write('R1', (2**31 - 1)) self.rf.write('R2', 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (1 << 31)) @itest_custom("add r3, r1, r2, lsl #3") def test_add_reg_sft_lsl(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (1 << 3)) @itest_custom("add r3, r1, r2, lsr #3") def test_add_reg_sft_lsr(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x8) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (0x8 >> 3)) @itest_custom("add r3, r1, r2, asr #3") def test_add_reg_sft_asr(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x80000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0xf0000000) @itest_custom("add r3, r1, r2, asr #3") def test_add_reg_sft_asr2(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x40000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) @itest_custom("add r3, r1, r2, ror #3") def test_add_reg_sft_ror_norm(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x8) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0x1) @itest_custom("add r3, r1, r2, ror #3") def test_add_reg_sft_ror(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x3) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0x60000000) @itest_custom("adc r3, r1, r2") @itest_setregs("R1=1", "R2=2", "APSR_C=1") def test_adc_basic(self): self.cpu.execute() self.assertEqual(self.rf.read('R3'), 4) @itest_custom("adc r3, r1, r2, ror #3") @itest_setregs("R1=1", "R2=2", "APSR_C=1") def test_adc_reg_sft_ror(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x3) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0x60000001) # TODO what is shifter_carry_out in the manual, A8-291? it gets set to # Bit[0] presumably, but i have no clue what it is. Not mentioned again in # manual. @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx(self): self.rf.write('APSR_C', 0x0) self.rf.write('R1', 0x0) self.rf.write('R2', 2**32 - 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 2**31 - 1) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx2(self): self.rf.write('APSR_C', 0x1) self.rf.write('R1', 0x0) self.rf.write('R2', 2**32 - 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 2**32 - 1) @itest_custom("add r3, r1, r2, lsl r4") def test_add_reg_sft_lsl_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (1 << 3)) @itest_custom("add r3, r1, r2, lsr r4") def test_add_reg_sft_lsr_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x8) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (0x8 >> 3)) @itest_custom("add r3, r1, r2, asr r4") def test_add_reg_sft_asr_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x80000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0xf0000000) @itest_custom("add r3, r1, r2, asr r4") def test_add_reg_sft_asr2_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x40000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) @itest_custom("add r3, r1, r2, ror r4") def test_add_reg_sft_ror_norm_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x8) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 1) @itest_custom("add r3, r1, r2, ror r4") def test_add_reg_sft_ror_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x3) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0x60000000) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx_reg(self): self.rf.write('R1', 0x0) self.rf.write('APSR_C', 0x0) self.rf.write('R2', 2**32 - 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 2**31 - 1) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx2_reg(self): self.rf.write('R1', 0x0) self.rf.write('APSR_C', 0x1) self.rf.write('R2', 2**32 - 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 2**32 - 1) # ADDS @itest_custom("adds r3, r1, 55") def test_adds_imm_norm(self): self.rf.write('R1', 44) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 99) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, 0x100") def test_adds_imm_mod_imm_min(self): self.rf.write('R1', 44) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0x100) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, 0xff000000") def test_adds_imm_mod_imm_max(self): self.rf.write('R1', 44) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, 0x1000000") def test_adds_imm_carry(self): self.rf.write('R1', 0xff000001) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 0) @itest_custom("adds r3, r1, 0x80000000") def test_adds_imm_carry_overflow(self): self.rf.write('R1', 0x80000001) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 1) @itest_custom("adds r3, r1, 0x1") def test_adds_imm_overflow(self): self.rf.write('R1', (2**31 - 1)) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0x80000000) self._checkFlagsNZCV(1, 0, 0, 1) @itest_custom("adds r3, r3, 0x0") def test_adds_imm_zf(self): self.rf.write('R3', 0) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0) self._checkFlagsNZCV(0, 1, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_norm(self): self.rf.write('R1', 44) self.rf.write('R2', 55) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 99) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_mod_imm_min(self): self.rf.write('R1', 44) self.rf.write('R2', 0x100) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0x100) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_mod_imm_max(self): self.rf.write('R1', 44) self.rf.write('R2', 0xff000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_carry(self): self.rf.write('R1', 0x1000000) self.rf.write('R2', 0xff000001) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_overflow(self): self.rf.write('R1', (2**31 - 1)) self.rf.write('R2', 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (1 << 31)) self._checkFlagsNZCV(1, 0, 0, 1) @itest_custom("adds r3, r1, r2") def test_adds_reg_carry_overflow(self): self.rf.write('R1', 0x80000001) self.rf.write('R2', 0x80000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 1) @itest_custom("adds r3, r1, r2") def test_adds_reg_zf(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x0) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0) self._checkFlagsNZCV(0, 1, 0, 0) @itest_custom("adds r3, r1, r2, asr #3") def test_adds_reg_sft_asr(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x80000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 0xf0000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, r2, asr #3") def test_adds_reg_sft_asr2(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x40000000) self.cpu.execute() self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2, rrx") def test_adds_reg_sft_rrx(self): self.rf.write('APSR_C', 0x0) self.rf.write('R1', 0x0) self.rf.write('R2', 2**32 - 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 2**31 - 1) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2, rrx") def test_adds_reg_sft_rrx2(self): self.rf.write('APSR_C', 0x1) self.rf.write('R1', 0x0) self.rf.write('R2', 2**32 - 1) self.cpu.execute() self.assertEqual(self.rf.read('R3'), 2**32 - 1) self._checkFlagsNZCV(1, 0, 0, 0) # LDR imm @itest_custom("ldr r1, [sp]") def test_ldr_imm_off_none(self): self.cpu.stack_push(42) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, #4]") def test_ldr_imm_off_pos(self): self.cpu.stack_push(42) self.cpu.stack_push(41) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, #-4]") def test_ldr_imm_off_neg(self): self.cpu.stack_push(42) self.cpu.stack_push(41) self.cpu.STACK += 4 self.cpu.execute() self.assertEqual(self.rf.read('R1'), 41) @itest_custom("ldr r1, [sp, #4]!") def test_ldr_imm_preind_pos(self): self.cpu.stack_push(42) self.cpu.stack_push(41) pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp, #-4]!") def test_ldr_imm_preind_neg(self): self.cpu.stack_push(42) self.cpu.stack_push(41) self.cpu.STACK += 4 pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 41) self.assertEqual(self.rf.read('SP'), pre_stack - 4) @itest_custom("ldr r1, [sp], #5") def test_ldr_imm_postind_pos(self): self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 5) @itest_custom("ldr r1, [sp], #-5") def test_ldr_imm_postind_neg(self): self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack - 5) # LDR reg @itest_custom("ldr r1, [sp, r2]") def test_ldr_reg_off(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, -r2]") def test_ldr_reg_off_neg(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 4 self.cpu.execute() self.assertEqual(self.rf.read('R1'), 48) @itest_custom("ldr r1, [sp, r2, lsl #3]") def test_ldr_reg_off_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.stack_push(40) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, -r2, lsl #3]") def test_ldr_reg_off_neg_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 8 self.cpu.execute() self.assertEqual(self.rf.read('R1'), 48) @itest_custom("ldr r1, [sp, r2]!") def test_ldr_reg_preind(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp, -r2, lsl #3]!") def test_ldr_reg_preind_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 8 pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 48) self.assertEqual(self.rf.read('SP'), pre_stack - 8) @itest_custom("ldr r1, [sp], r2") def test_ldr_reg_postind(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp], -r2, lsl #3") def test_ldr_reg_postind_neg_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack - 8) @itest_custom("pop {r1}") def test_pop_one_reg(self): self.cpu.stack_push(0x55) pre_stack = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0x55) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("pop {r1, r2, r3}") def test_pop_multops(self): vals = [0x01, 0x55, 0xAA] for v in vals: self.cpu.stack_push(v) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0xAA) self.assertEqual(self.rf.read('R2'), 0x55) self.assertEqual(self.rf.read('R3'), 0x01) @itest_custom("push {r1}") @itest_setregs("R1=3") def test_push_one_reg(self): self.cpu.execute() self.assertItemsEqual(self.cpu.stack_peek(), struct.pack('<I', 3)) @itest_custom("push {r1, r2, r3}") @itest_setregs("R1=3", "R2=0x55", "R3=0xffffffff") def test_push_multi_reg(self): pre_sp = self.cpu.STACK self.cpu.execute() sp = self.cpu.STACK self.assertEqual(self.rf.read('SP'), pre_sp - (3 * 4)) self.assertItemsEqual(self.cpu.stack_peek(), struct.pack('<I', 3)) self.assertEqual(self.cpu.read_int(sp + 4, self.cpu.address_bit_size), 0x55) self.assertEqual(self.cpu.read_int(sp + 8, self.cpu.address_bit_size), 0xffffffff) @itest_custom("str SP, [R1]") @itest_setregs("R1=0xd000") def test_str_basic(self): r1 = self.rf.read('R1') sp = self.rf.read('SP') self.cpu.execute() dr1 = self.cpu.read_int(r1, self.cpu.address_bit_size) self.assertEqual(sp, dr1) @itest_custom("str R1, [R2, R3]") @itest_setregs("R1=34", "R2=0xD000", "R3=8") def test_str_index(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') r3 = self.rf.read('R3') self.cpu.execute() retrieved = self.cpu.read_int(r2 + r3, self.cpu.address_bit_size) self.assertEqual(retrieved, r1) @itest_custom("str R1, [R2, R3, LSL #3]") @itest_setregs("R1=34", "R2=0xD000", "R3=1") def test_str_index_w_shift(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') r3 = self.rf.read('R3') r3 = r3 << 3 self.cpu.execute() retrieved = self.cpu.read_int(r2 + r3, self.cpu.address_bit_size) self.assertEqual(retrieved, r1) @itest_custom("str R1, [R2], #3") @itest_setregs("R1=34", "R2=0xD000") def test_str_postindex(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') self.cpu.execute() # check store results data = self.cpu.read_int(r2, self.cpu.address_bit_size) self.assertEqual(data, r1) # check writeback results new_r2 = self.rf.read('R2') self.assertEqual(new_r2, r2 + 3) @itest_custom("str R1, [R2, #3]!") @itest_setregs("R1=34", "R2=0xD000") def test_str_index_writeback(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') self.cpu.execute() # check store results data = self.cpu.read_int(r2 + 3, self.cpu.address_bit_size) self.assertEqual(data, r1) # check writeback results new_r2 = self.rf.read('R2') self.assertEqual(new_r2, r2 + 3) # BL @itest_custom("bl 0x170") def test_bl(self): pre_pc = self.rf.read('PC') self.cpu.execute() self.assertEqual(self.rf.read('PC'), pre_pc + 0x170) self.assertEqual(self.rf.read('LR'), pre_pc + 4) @itest_custom("bl #-4") def test_bl_neg(self): pre_pc = self.rf.read('PC') self.cpu.execute() self.assertEqual(self.rf.read('PC'), pre_pc - 4) self.assertEqual(self.rf.read('LR'), pre_pc + 4) # CMP @itest_setregs("R0=3") @itest("cmp r0, 3") def test_cmp_eq(self): self._checkFlagsNZCV(0, 1, 1, 0) @itest_setregs("R0=3") @itest("cmp r0, 5") def test_cmp_lt(self): self._checkFlagsNZCV(1, 0, 0, 0) @itest_setregs("R0=3") @itest("cmp r0, 2") def test_cmp_gt(self): self._checkFlagsNZCV(0, 0, 1, 0) @itest_setregs("R0=0") @itest("cmp r0, 0") def test_cmp_carry(self): self._checkFlagsNZCV(0, 1, 1, 0) @itest_setregs("R0=0x40000000") @itest("cmp r0, 0xa0000000") def test_cmp_ovf(self): self._checkFlagsNZCV(1, 0, 0, 1) @itest_setregs("R0=0x80000000") @itest("cmp r0, 0x40000000") def test_cmp_carry_ovf(self): self._checkFlagsNZCV(0, 0, 1, 1) # CLZ @itest_custom("clz r1, r2") @itest_setregs("R2=0xFFFF") def test_clz_sixteen_zeroes(self): self.cpu.execute() self.assertEqual(self.rf.read('R1'), 16) @itest_custom("clz r1, r2") @itest_setregs("R2=0") def test_clz_all_zero(self): self.cpu.execute() self.assertEqual(self.rf.read('R1'), self.cpu.address_bit_size) @itest_custom("clz r1, r2") @itest_setregs("R2=0xffffffff") def test_clz_no_leading_zeroes(self): self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0) @itest_custom("clz r1, r2") @itest_setregs("R2=0x7fffffff") def test_clz_one_leading_zero(self): self.cpu.execute() self.assertEqual(self.rf.read('R1'), 1) @itest_custom("clz r1, r2") @itest_setregs("R2=0x7f7fffff") def test_clz_lead_zero_then_more_zeroes(self): self.cpu.execute() self.assertEqual(self.rf.read('R1'), 1) @itest_custom("sub r3, r1, r2") @itest_setregs("R1=4", "R2=2") def test_sub_basic(self): self.cpu.execute() self.assertEqual(self.rf.read('R3'), 2) @itest_custom("sub r3, r1, #5") @itest_setregs("R1=10") def test_sub_imm(self): self.cpu.execute() self.assertEqual(self.rf.read('R3'), 5) @itest_custom("sbc r3, r1, #5") @itest_setregs("R1=10") def test_sbc_imm(self): self.cpu.execute() self.assertEqual(self.rf.read('R3'), 4) @itest_custom("ldm sp, {r1, r2, r3}") def test_ldm(self): self.cpu.stack_push(0x41414141) self.cpu.stack_push(2) self.cpu.stack_push(42) pre_sp = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('R2'), 2) self.assertEqual(self.rf.read('R3'), 0x41414141) self.assertEqual(self.cpu.STACK, pre_sp) @itest_custom("ldm sp!, {r1, r2, r3}") def test_ldm_wb(self): self.cpu.stack_push(0x41414141) self.cpu.stack_push(2) self.cpu.stack_push(42) pre_sp = self.cpu.STACK self.cpu.execute() self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('R2'), 2) self.assertEqual(self.rf.read('R3'), 0x41414141) self.assertEqual(self.cpu.STACK, pre_sp + 12) @itest_setregs("R1=2", "R2=42", "R3=0x42424242") @itest_custom("stm sp, {r1, r2, r3}") def test_stm(self): self.cpu.STACK -= 12 pre_sp = self.cpu.STACK self.cpu.execute() self.assertEqual(self.cpu.read_int(pre_sp, self.cpu.address_bit_size), 2) self.assertEqual( self.cpu.read_int(pre_sp + 4, self.cpu.address_bit_size), 42) self.assertEqual( self.cpu.read_int(pre_sp + 8, self.cpu.address_bit_size), 0x42424242) self.assertEqual(self.cpu.STACK, pre_sp) @itest_setregs("R1=2", "R2=42", "R3=0x42424242") @itest_custom("stm sp!, {r1, r2, r3}") def test_stm_wb(self): self.cpu.STACK -= 12 pre_sp = self.cpu.STACK self.cpu.execute() self.assertEqual(self.cpu.read_int(pre_sp, self.cpu.address_bit_size), 2) self.assertEqual( self.cpu.read_int(pre_sp + 4, self.cpu.address_bit_size), 42) self.assertEqual( self.cpu.read_int(pre_sp + 8, self.cpu.address_bit_size), 0x42424242) self.assertEqual(self.cpu.STACK, pre_sp + 12) @itest_custom("stmib r3, {r2, r4}") @itest_setregs("R1=1", "R2=2", "R4=4", "R3=0xd100") def test_stmib_basic(self): self.cpu.execute() addr = self.rf.read('R3') self.assertEqual( self.cpu.read_int(addr + 4, self.cpu.address_bit_size), 2) self.assertEqual( self.cpu.read_int(addr + 8, self.cpu.address_bit_size), 4) @itest_custom("bx r1") @itest_setregs("R1=0x1008") def test_bx_basic(self): self.cpu.execute() self.assertEqual(self.rf.read('PC'), 0x1008) @itest_custom("bx r1") @itest_setregs("R1=0x1009") def test_bx_thumb(self): pre_pc = self.rf.read('PC') self.cpu.execute() self.assertEqual(self.rf.read('PC'), pre_pc + 4) # ORR @itest_custom("orr r2, r3, #5") @itest_setregs("R3=0x1000") def test_orr_imm(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0x1005) @itest_custom("orrs r2, r3") @itest_setregs("R2=0x5", "R3=0x80000000") def test_orrs_imm_flags(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0x80000005) self.assertEqual(self.rf.read('APSR_N'), True) @itest_custom("orr r2, r3") @itest_setregs("R2=0x5", "R3=0x80000000") def test_orr_reg_w_flags(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0x80000005) # self.assertEqual(self.rf.read('APSR_N'), 1) @itest_custom("orr r2, r3, r4") @itest_setregs("R3=0x5", "R4=0x80000000") def test_orr_reg_two_op(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0x80000005) # self.assertEqual(self.rf.read('APSR_N'), 1) @itest_custom("orr r2, r3, r4, LSL #4") @itest_setregs("R3=0x5", "R4=0xF") def test_orr_reg_two_op_shifted(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0xF5) # EOR @itest_custom("eor r2, r3, #5") @itest_setregs("R3=0xA") def test_eor_imm(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0xF) @itest_custom("eors r2, r3") @itest_setregs("R2=0xAA", "R3=0x80000000") def test_eors_imm_flags(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0x800000AA) self.assertEqual(self.rf.read('APSR_N'), True) @itest_custom("eors r2, r3") @itest_setregs("R2=0x5", "R3=0x80000005") def test_eor_reg_w_flags(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0x80000000) self.assertEqual(self.rf.read('APSR_N'), 1) @itest_custom("eor r2, r3, r4") @itest_setregs("R3=0x80000005", "R4=0x80000005") def test_eor_reg_two_op(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0) @itest_custom("eor r2, r3, r4, LSL #4") @itest_setregs("R3=0x55", "R4=0x5") def test_eor_reg_two_op_shifted(self): self.cpu.execute() self.assertEqual(self.rf.read('R2'), 0x5) # LDRH - see also LDR tests @itest_custom("ldrh r1, [sp]") def test_ldrh_imm_off_none(self): self.cpu.stack_push(0x41410041) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0x41) @itest_custom("ldrh r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrh_reg_off(self): self.cpu.stack_push(0x41410041) self.cpu.stack_push(48) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0x41) # LDRSH - see also LDR tests @itest_custom("ldrsh r1, [sp]") def test_ldrsh_imm_off_none_neg(self): self.cpu.stack_push(0x2ff0f) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0xffffff0f) @itest_custom("ldrsh r1, [sp]") def test_ldrsh_imm_off_none_pos(self): self.cpu.stack_push(0xff0fff) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0x0fff) @itest_custom("ldrsh r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsh_reg_off_neg(self): self.cpu.stack_push(0x2ff0f) self.cpu.stack_push(48) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0xffffff0f) @itest_custom("ldrsh r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsh_reg_off_pos(self): self.cpu.stack_push(0xff0fff) self.cpu.stack_push(48) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0x0fff) # LDRB - see also LDR tests @itest_custom("ldrb r1, [sp]") def test_ldrb_imm_off_none(self): self.cpu.stack_push(0x41) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0x41) @itest_custom("ldrb r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrb_reg_off(self): self.cpu.stack_push(0x41) self.cpu.stack_push(48) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0x41) # LDRSB - see also LDR tests @itest_custom("ldrsb r1, [sp]") def test_ldrsb_imm_off_none_neg(self): self.cpu.stack_push(0x2ff) self.cpu.execute() self.assertEqual(self.rf.read('R1'), Mask(32)) @itest_custom("ldrsb r1, [sp]") def test_ldrsb_imm_off_none_pos(self): self.cpu.stack_push(0xff0f) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0xf) @itest_custom("ldrsb r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsb_reg_off_neg(self): self.cpu.stack_push(0x2ff) self.cpu.stack_push(48) self.cpu.execute() self.assertEqual(self.rf.read('R1'), Mask(32)) @itest_custom("ldrsb r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsb_reg_off_pos(self): self.cpu.stack_push(0xff0f) self.cpu.stack_push(48) self.cpu.execute() self.assertEqual(self.rf.read('R1'), 0xf) # TST @itest_setregs("R1=1", "R3=0") @itest("tst r3, r1") def test_tst(self): self._checkFlagsNZCV(0, 1, 0, 0) # AND @itest_setregs("R2=5") @itest("and r2, r2, #1") def test_and_imm(self): self.assertEqual(self.rf.read('R2'), 1) @itest_setregs("R1=5", "R2=3") @itest("and r1, r1, r2") def test_and_reg(self): self.assertEqual(self.rf.read('R1'), 3 & 5) @itest_setregs("R1=5", "R2=3", "APSR_C=1") @itest("and r1, r1, r2") def test_and_reg_carry(self): self.assertEqual(self.rf.read('R1'), 3 & 5) self.assertEqual(self.rf.read('APSR_C'), 1) # svc def test_svc(self): with self.assertRaises(Interruption): self._setupCpu("svc #0") self.cpu.execute() # lsl @itest_setregs("R3=0x11") @itest("lsls r4, r3, 1") def test_lsl_imm_min(self): self.assertEqual(self.rf.read('R4'), 0x11 << 1) self._checkFlagsNZCV(0, 0, 0, 0) @itest_setregs("R3=0x11") @itest("lsls r4, r3, 31") def test_lsl_imm_max(self): self.assertEqual(self.rf.read('R4'), 1 << 31) self._checkFlagsNZCV(1, 0, 0, 0) @itest_setregs("R3=0x11", "R2=0xff01") @itest("lsls r4, r3, r2") def test_lsl_reg_min(self): self.assertEqual(self.rf.read('R4'), 0x11 << 1) self._checkFlagsNZCV(0, 0, 0, 0) @itest_setregs("R3=0x11", "R2=0xff1f") @itest("lsls r4, r3, r2") def test_lsl_reg_max(self): self.assertEqual(self.rf.read('R4'), 0x1 << 31) self._checkFlagsNZCV(1, 0, 0, 0) @itest_setregs("R2=0xffffffff") @itest("lsls r2, r2, #0x1f") def test_lsl_imm_carry(self): self.assertEqual(self.cpu.R2, 0x1 << 31) self._checkFlagsNZCV(1, 0, 1, 0) # lsr @itest_setregs("R0=0x1000", "R2=3") @itest("lsr r0, r0, r2") def test_lsr_reg(self): self.assertEqual(self.rf.read('R0'), 0x1000 >> 3) @itest_setregs("R0=0x1000") @itest("lsr r0, r0, #3") def test_lsr_reg_imm(self): self.assertEqual(self.rf.read('R0'), 0x1000 >> 3) @itest_setregs("R2=29") @itest("RSB r2, r2, #31") def test_rsb_imm(self): # Diverging instruction from trace self.assertEqual(self.rf.read('R2'), 2) @itest_setregs("R6=2", "R8=0xfffffffe") @itest("RSBS r8, r6, #0") def test_rsbs_carry(self): self.assertEqual(self.rf.read('R8'), 0xFFFFFFFE) self._checkFlagsNZCV(1, 0, 0, 0) def test_flag_state_continuity(self): '''If an instruction only partially updates flags, cpu.setFlags should ensure unupdated flags are preserved. For example: r1 = 2**31 - 1 add r2, r1, 0x1 // overflow = 1 mov r1, 1 mov r3, 0 tst r3, r1 // does not change overflow flag // ovf should still be 1 ''' self.rf.write('R1', (2**31 - 1)) self._setupCpu("adds r2, r1, #0x1") self.cpu.execute() self.rf.write('R1', 1) self.rf.write('R3', 0) self.mem.write(self.cpu.PC, assemble("tst r3, r1")) self.cpu.execute() self._checkFlagsNZCV(0, 1, 0, 1) @itest_setregs("R1=30", "R2=10") @itest("MUL R1, R2") def test_mul_reg(self): self.assertEqual(self.rf.read('R1'), 300) @itest_setregs("R1=30", "R2=10") @itest("MUL R3, R1, R2") def test_mul_reg_w_dest(self): self.assertEqual(self.rf.read('R3'), 300) @itest_setregs("R2=10", "R3=15", "R4=7") @itest("MLA R1, R2, R3, R4") def test_mla_reg(self): self.assertEqual(self.rf.read('R1'), 157) @itest_setregs("R1=0xFF") @itest("BIC R2, R1, #0x10") def test_bic_reg_imm(self): self.assertEqual(self.rf.read('R2'), 0xEF) @itest_setregs("R1=0x1008") @itest("BLX R1") def test_blx_reg(self): self.assertEqual(self.rf.read('PC'), 0x1008) self.assertEqual(self.rf.read('LR'), 0x1008) @itest_setregs("R1=0x1009") @itest("BLX R1") def test_blx_reg_thumb(self): self.assertEqual(self.rf.read('PC'), 0x1008) self.assertEqual(self.rf.read('LR'), 0x1008) @itest_setregs("R1=0xffffffff", "R2=2") @itest("UMULLS R1, R2, R1, R2") def test_umull(self): mul = 0xffffffff * 2 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_setregs("R1=2", "R2=2") @itest("UMULLS R1, R2, R1, R2") def test_umull_still32(self): mul = 2 * 2 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_setregs("R1=0xfffffffe", "R2=0xfffffffe") @itest("UMULLS R1, R2, R1, R2") def test_umull_max(self): mul = 0xfffffffe**2 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(1, 0, pre_c, pre_v) @itest_setregs("R1=3", "R2=0") @itest("UMULLS R1, R2, R1, R2") def test_umull_z(self): mul = 3 * 0 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), (mul >> 32) & Mask(32)) self._checkFlagsNZCV(0, 1, pre_c, pre_v) @itest("dmb ish") def test_dmb(self): # This is a nop, ensure that the instruction exists self.assertTrue(True) @itest_custom("vldmia r1, {d8, d9, d10}") def test_vldmia(self): self.cpu.stack_push(20, 8) self.cpu.stack_push(21, 8) self.cpu.stack_push(22, 8) self.cpu.R1 = self.cpu.SP pre = self.cpu.R1 self.cpu.execute() self.assertEqual(self.cpu.D8, 22) self.assertEqual(self.cpu.D9, 21) self.assertEqual(self.cpu.D10, 20) self.assertEqual(self.cpu.R1, pre) @itest_custom("vldmia r1!, {d8, d9, d10}") def test_vldmia_wb(self): pre = self.cpu.SP self.cpu.stack_push(20, 8) self.cpu.stack_push(21, 8) self.cpu.stack_push(22, 8) self.cpu.R1 = self.cpu.SP self.cpu.execute() self.assertEqual(self.cpu.D8, 22) self.assertEqual(self.cpu.D9, 21) self.assertEqual(self.cpu.D10, 20) self.assertEqual(self.cpu.R1, pre)
class Armv7UnicornInstructions(unittest.TestCase): ''' Import all of the tests from ARM, but execute with Unicorn to verify that all semantics match. ''' _multiprocess_can_split_ = True def setUp(self): self.cpu = Cpu(Memory32()) self.mem = self.cpu.memory self.rf = self.cpu.regfile def _setupCpu(self, asm): self.code = self.mem.mmap(0x1000, 0x1000, 'rwx') self.data = self.mem.mmap(0xd000, 0x1000, 'rw') self.stack = self.mem.mmap(0xf000, 0x1000, 'rw') start = self.code + 4 self.mem.write(start, assemble(asm)) self.rf.write('PC', start) self.rf.write('SP', self.stack + 0x1000) def _checkFlagsNZCV(self, n, z, c, v): self.assertEqual(self.rf.read('APSR_N'), n) self.assertEqual(self.rf.read('APSR_Z'), z) self.assertEqual(self.rf.read('APSR_C'), c) self.assertEqual(self.rf.read('APSR_V'), v) # MOV @itest("mov r0, 0x0") def test_mov_imm_min(self): self.assertEqual(self.rf.read('R0'), 0x0) @itest("mov r0, 42") def test_mov_imm_norm(self): self.assertEqual(self.rf.read('R0'), 42) @itest("mov r0, 0x100") def test_mov_imm_modified_imm_min(self): self.assertEqual(self.rf.read('R0'), 0x100) @itest("mov r0, 0xff000000") def test_mov_imm_modified_imm_max(self): self.assertEqual(self.rf.read('R0'), 0xff000000) @itest_custom("mov r0, r1") def test_mov_immreg(self): self.rf.write('R1', 0) emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0) @itest_custom("mov r0, r1") def test_mov_immreg1(self): self.rf.write('R1', 2 ** 32) emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0) @itest_custom("mov r0, r1") def test_mov_immreg2(self): self.rf.write('R1', 0xffffffff) emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0xffffffff) @itest_custom("mov r0, r1") def test_mov_immreg3(self): self.rf.write('R1', 42) emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 42) # MOVW @itest("movw r0, 0") def test_movw_imm_min(self): self.assertEqual(self.rf.read('R0'), 0x0) @itest("movw r0, 0xffff") def test_movw_imm_max(self): self.assertEqual(self.rf.read('R0'), 0xffff) # MOVS @itest_custom("movs r0, 0") def test_movs_imm_min(self): pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0) self._checkFlagsNZCV(0, 1, pre_c, pre_v) @itest_custom("movs r0, 42") def test_movs_imm_norm(self): pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 42) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_custom("movs r0, 0x100") def test_movs_imm_modified_imm_min(self): pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0x100) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_custom("movs r0, 0xff000000") def test_movs_imm_modified_imm_max(self): pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0xff000000) self._checkFlagsNZCV(1, 0, 1, pre_v) @itest_custom("movs r0, 0x0e000000") def test_movs_imm_modified_imm_sans_carry(self): pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0x0e000000) self._checkFlagsNZCV(0, 0, 0, pre_v) @itest_custom("movs r0, r1") def test_movs_reg(self): self.rf.write('R1', 0) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0) self._checkFlagsNZCV(0, 1, pre_c, pre_v) @itest_custom("movs r0, r1") def test_movs_reg1(self): self.rf.write('R1', 2 ** 32) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 0) self._checkFlagsNZCV(0, 1, pre_c, pre_v) @itest_custom("movs r0, r1") def test_movs_reg2(self): self.rf.write('R1', 2 ** 32 - 1) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 2 ** 32 - 1) self._checkFlagsNZCV(1, 0, pre_c, pre_v) @itest_custom("movs r0, r1") def test_movs_reg3(self): self.rf.write('R1', 42) pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') emulate_next(self.cpu) self.assertEqual(self.rf.read('R0'), 42) self._checkFlagsNZCV(0, 0, pre_c, pre_v) # ADD @itest_custom("add r3, r1, 55") def test_add_imm_norm(self): self.rf.write('R1', 44) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 99) @itest_custom("add r3, r1, 0x100") def test_add_imm_mod_imm_min(self): self.rf.write('R1', 44) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0x100) @itest_custom("add r3, r1, 0xff000000") def test_add_imm_mod_imm_max(self): self.rf.write('R1', 44) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) @itest_custom("add r3, r1, 0x1000000") def test_add_imm_carry(self): self.rf.write('R1', 0xff000001) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 1) @itest_custom("add r3, r1, 0x1") def test_add_imm_overflow(self): self.rf.write('R1', (2 ** 31 - 1)) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0x80000000) @itest_custom("add r3, r1, r2") def test_add_reg_norm(self): self.rf.write('R1', 44) self.rf.write('R2', 55) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 99) @itest_custom("add r3, r1, r2") def test_add_reg_mod_imm_min(self): self.rf.write('R1', 44) self.rf.write('R2', 0x100) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0x100) @itest_custom("add r3, r1, r2") def test_add_reg_mod_imm_max(self): self.rf.write('R1', 44) self.rf.write('R2', 0xff000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) @itest_custom("add r3, r1, r2") def test_add_reg_carry(self): self.rf.write('R1', 0x1000000) self.rf.write('R2', 0xff000001) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 1) @itest_custom("add r3, r1, r2") def test_add_reg_overflow(self): self.rf.write('R1', (2 ** 31 - 1)) self.rf.write('R2', 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (1 << 31)) @itest_custom("add r3, r1, r2, lsl #3") def test_add_reg_sft_lsl(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (1 << 3)) @itest_custom("add r3, r1, r2, lsr #3") def test_add_reg_sft_lsr(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x8) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (0x8 >> 3)) @itest_custom("add r3, r1, r2, asr #3") def test_add_reg_sft_asr(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x80000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0xf0000000) @itest_custom("add r3, r1, r2, asr #3") def test_add_reg_sft_asr2(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x40000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) @itest_custom("add r3, r1, r2, ror #3") def test_add_reg_sft_ror_norm(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x8) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0x1) @itest_custom("add r3, r1, r2, ror #3") def test_add_reg_sft_ror(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x3) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0x60000000) @itest_custom("adc r3, r1, r2") @itest_setregs("R1=1", "R2=2", "APSR_C=1") def test_adc_basic(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 4) @itest_custom("adc r3, r1, r2, ror #3") @itest_setregs("R1=1", "R2=2", "APSR_C=1") def test_adc_reg_sft_ror(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x3) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0x60000001) # TODO what is shifter_carry_out in the manual, A8-291? it gets set to # Bit[0] presumably, but i have no clue what it is. Not mentioned again in # manual. @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx(self): self.rf.write('APSR_C', 0x0) self.rf.write('R1', 0x0) self.rf.write('R2', 2 ** 32 - 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 2 ** 31 - 1) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx2(self): self.rf.write('APSR_C', 0x1) self.rf.write('R1', 0x0) self.rf.write('R2', 2 ** 32 - 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1) @itest_custom("add r3, r1, r2, lsl r4") def test_add_reg_sft_lsl_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (1 << 3)) @itest_custom("add r3, r1, r2, lsr r4") def test_add_reg_sft_lsr_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x8) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (0x8 >> 3)) @itest_custom("add r3, r1, r2, asr r4") def test_add_reg_sft_asr_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x80000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0xf0000000) @itest_custom("add r3, r1, r2, asr r4") def test_add_reg_sft_asr2_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x40000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) @itest_custom("add r3, r1, r2, ror r4") def test_add_reg_sft_ror_norm_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x8) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 1) @itest_custom("add r3, r1, r2, ror r4") def test_add_reg_sft_ror_reg(self): self.rf.write('R1', 0x0) self.rf.write('R4', 0x3) self.rf.write('R2', 0x3) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0x60000000) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx_reg(self): self.rf.write('R1', 0x0) self.rf.write('APSR_C', 0x0) self.rf.write('R2', 2 ** 32 - 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 2 ** 31 - 1) @itest_custom("add r3, r1, r2, rrx") def test_add_reg_sft_rrx2_reg(self): self.rf.write('R1', 0x0) self.rf.write('APSR_C', 0x1) self.rf.write('R2', 2 ** 32 - 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1) # ADDS @itest_custom("adds r3, r1, 55") def test_adds_imm_norm(self): self.rf.write('R1', 44) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 99) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, 0x100") def test_adds_imm_mod_imm_min(self): self.rf.write('R1', 44) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0x100) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, 0xff000000") def test_adds_imm_mod_imm_max(self): self.rf.write('R1', 44) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, 0x1000000") def test_adds_imm_carry(self): self.rf.write('R1', 0xff000001) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 0) @itest_custom("adds r3, r1, 0x80000000") def test_adds_imm_carry_overflow(self): self.rf.write('R1', 0x80000001) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 1) @itest_custom("adds r3, r1, 0x1") def test_adds_imm_overflow(self): self.rf.write('R1', (2 ** 31 - 1)) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0x80000000) self._checkFlagsNZCV(1, 0, 0, 1) @itest_custom("adds r3, r3, 0x0") def test_adds_imm_zf(self): self.rf.write('R3', 0) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0) self._checkFlagsNZCV(0, 1, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_norm(self): self.rf.write('R1', 44) self.rf.write('R2', 55) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 99) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_mod_imm_min(self): self.rf.write('R1', 44) self.rf.write('R2', 0x100) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0x100) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_mod_imm_max(self): self.rf.write('R1', 44) self.rf.write('R2', 0xff000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 44 + 0xff000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_carry(self): self.rf.write('R1', 0x1000000) self.rf.write('R2', 0xff000001) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 0) @itest_custom("adds r3, r1, r2") def test_adds_reg_overflow(self): self.rf.write('R1', (2 ** 31 - 1)) self.rf.write('R2', 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (1 << 31)) self._checkFlagsNZCV(1, 0, 0, 1) @itest_custom("adds r3, r1, r2") def test_adds_reg_carry_overflow(self): self.rf.write('R1', 0x80000001) self.rf.write('R2', 0x80000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 1) self._checkFlagsNZCV(0, 0, 1, 1) @itest_custom("adds r3, r1, r2") def test_adds_reg_zf(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x0) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0) self._checkFlagsNZCV(0, 1, 0, 0) @itest_custom("adds r3, r1, r2, asr #3") def test_adds_reg_sft_asr(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x80000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 0xf0000000) self._checkFlagsNZCV(1, 0, 0, 0) @itest_custom("adds r3, r1, r2, asr #3") def test_adds_reg_sft_asr2(self): self.rf.write('R1', 0x0) self.rf.write('R2', 0x40000000) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), (0x40000000 >> 3)) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2, rrx") def test_adds_reg_sft_rrx(self): self.rf.write('APSR_C', 0x0) self.rf.write('R1', 0x0) self.rf.write('R2', 2 ** 32 - 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 2 ** 31 - 1) self._checkFlagsNZCV(0, 0, 0, 0) @itest_custom("adds r3, r1, r2, rrx") def test_adds_reg_sft_rrx2(self): self.rf.write('APSR_C', 0x1) self.rf.write('R1', 0x0) self.rf.write('R2', 2 ** 32 - 1) emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 2 ** 32 - 1) self._checkFlagsNZCV(1, 0, 0, 0) # LDR imm @itest_custom("ldr r1, [sp]") def test_ldr_imm_off_none(self): self.cpu.stack_push(42) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, #4]") def test_ldr_imm_off_pos(self): self.cpu.stack_push(42) self.cpu.stack_push(41) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, #-4]") def test_ldr_imm_off_neg(self): self.cpu.stack_push(42) self.cpu.stack_push(41) self.cpu.STACK += 4 emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 41) @itest_custom("ldr r1, [sp, #4]!") def test_ldr_imm_preind_pos(self): self.cpu.stack_push(42) self.cpu.stack_push(41) pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp, #-4]!") def test_ldr_imm_preind_neg(self): self.cpu.stack_push(42) self.cpu.stack_push(41) self.cpu.STACK += 4 pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 41) self.assertEqual(self.rf.read('SP'), pre_stack - 4) @itest_custom("ldr r1, [sp], #5") def test_ldr_imm_postind_pos(self): self.cpu.stack_push(42) pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 5) @itest_custom("ldr r1, [sp], #-5") def test_ldr_imm_postind_neg(self): self.cpu.stack_push(42) pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack - 5) # LDR reg @itest_custom("ldr r1, [sp, r2]") def test_ldr_reg_off(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, -r2]") def test_ldr_reg_off_neg(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 4 emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 48) @itest_custom("ldr r1, [sp, r2, lsl #3]") def test_ldr_reg_off_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.stack_push(40) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) @itest_custom("ldr r1, [sp, -r2, lsl #3]") def test_ldr_reg_off_neg_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 8 emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 48) @itest_custom("ldr r1, [sp, r2]!") def test_ldr_reg_preind(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) self.cpu.stack_push(48) pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp, -r2, lsl #3]!") def test_ldr_reg_preind_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) self.cpu.stack_push(48) self.cpu.STACK += 8 pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 48) self.assertEqual(self.rf.read('SP'), pre_stack - 8) @itest_custom("ldr r1, [sp], r2") def test_ldr_reg_postind(self): self.cpu.regfile.write('R2', 4) self.cpu.stack_push(42) pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("ldr r1, [sp], -r2, lsl #3") def test_ldr_reg_postind_neg_shift(self): self.cpu.regfile.write('R2', 1) self.cpu.stack_push(42) pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('SP'), pre_stack - 8) @itest_custom("pop {r1}") def test_pop_one_reg(self): self.cpu.stack_push(0x55) pre_stack = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0x55) self.assertEqual(self.rf.read('SP'), pre_stack + 4) @itest_custom("pop {r1, r2, r3}") def test_pop_multops(self): vals = [0x01, 0x55, 0xAA] for v in vals: self.cpu.stack_push(v) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0xAA) self.assertEqual(self.rf.read('R2'), 0x55) self.assertEqual(self.rf.read('R3'), 0x01) @itest_custom("push {r1}") @itest_setregs("R1=3") def test_push_one_reg(self): emulate_next(self.cpu) self.assertItemsEqual(self.cpu.stack_peek(), struct.pack('<I', 3)) @itest_custom("push {r1, r2, r3}") @itest_setregs("R1=3", "R2=0x55", "R3=0xffffffff") def test_push_multi_reg(self): pre_sp = self.cpu.STACK emulate_next(self.cpu) sp = self.cpu.STACK self.assertEqual(self.rf.read('SP'), pre_sp - (3 * 4)) self.assertItemsEqual(self.cpu.stack_peek(), struct.pack('<I', 3)) self.assertEqual(self.cpu.read_int(sp + 4, self.cpu.address_bit_size), 0x55) self.assertEqual(self.cpu.read_int(sp + 8, self.cpu.address_bit_size), 0xffffffff) @itest_custom("str SP, [R1]") @itest_setregs("R1=0xd000") def test_str_basic(self): r1 = self.rf.read('R1') sp = self.rf.read('SP') emulate_next(self.cpu) dr1 = self.cpu.read_int(r1, self.cpu.address_bit_size) self.assertEqual(sp, dr1) @itest_custom("str R1, [R2, R3]") @itest_setregs("R1=34", "R2=0xD000", "R3=8") def test_str_index(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') r3 = self.rf.read('R3') emulate_next(self.cpu) retrieved = self.cpu.read_int(r2 + r3, self.cpu.address_bit_size) self.assertEqual(retrieved, r1) @itest_custom("str R1, [R2, R3, LSL #3]") @itest_setregs("R1=34", "R2=0xD000", "R3=1") def test_str_index_w_shift(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') r3 = self.rf.read('R3') r3 = r3 << 3 emulate_next(self.cpu) retrieved = self.cpu.read_int(r2 + r3, self.cpu.address_bit_size) self.assertEqual(retrieved, r1) @itest_custom("str R1, [R2], #3") @itest_setregs("R1=34", "R2=0xD000") def test_str_postindex(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') emulate_next(self.cpu) # check store results data = self.cpu.read_int(r2, self.cpu.address_bit_size) self.assertEqual(data, r1) # check writeback results new_r2 = self.rf.read('R2') self.assertEqual(new_r2, r2 + 3) @itest_custom("str R1, [R2, #3]!") @itest_setregs("R1=34", "R2=0xD000") def test_str_index_writeback(self): r1 = self.rf.read('R1') r2 = self.rf.read('R2') emulate_next(self.cpu) # check store results data = self.cpu.read_int(r2 + 3, self.cpu.address_bit_size) self.assertEqual(data, r1) # check writeback results new_r2 = self.rf.read('R2') self.assertEqual(new_r2, r2 + 3) # BL @itest_custom("bl 0x170") def test_bl(self): pre_pc = self.rf.read('PC') emulate_next(self.cpu) self.assertEqual(self.rf.read('PC'), pre_pc + 0x170) self.assertEqual(self.rf.read('LR'), pre_pc + 4) @itest_custom("bl #-4") def test_bl_neg(self): pre_pc = self.rf.read('PC') emulate_next(self.cpu) self.assertEqual(self.rf.read('PC'), pre_pc - 4) self.assertEqual(self.rf.read('LR'), pre_pc + 4) # CMP @itest_setregs("R0=3") @itest("cmp r0, 3") def test_cmp_eq(self): self._checkFlagsNZCV(0, 1, 1, 0) @itest_setregs("R0=3") @itest("cmp r0, 5") def test_cmp_lt(self): self._checkFlagsNZCV(1, 0, 0, 0) @itest_setregs("R0=3") @itest("cmp r0, 2") def test_cmp_gt(self): self._checkFlagsNZCV(0, 0, 1, 0) @itest_setregs("R0=0") @itest("cmp r0, 0") def test_cmp_carry(self): self._checkFlagsNZCV(0, 1, 1, 0) @itest_setregs("R0=0x40000000") @itest("cmp r0, 0xa0000000") def test_cmp_ovf(self): self._checkFlagsNZCV(1, 0, 0, 1) @itest_setregs("R0=0x80000000") @itest("cmp r0, 0x40000000") def test_cmp_carry_ovf(self): self._checkFlagsNZCV(0, 0, 1, 1) # CLZ @itest_custom("clz r1, r2") @itest_setregs("R2=0xFFFF") def test_clz_sixteen_zeroes(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 16) @itest_custom("clz r1, r2") @itest_setregs("R2=0") def test_clz_all_zero(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), self.cpu.address_bit_size) @itest_custom("clz r1, r2") @itest_setregs("R2=0xffffffff") def test_clz_no_leading_zeroes(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0) @itest_custom("clz r1, r2") @itest_setregs("R2=0x7fffffff") def test_clz_one_leading_zero(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 1) @itest_custom("clz r1, r2") @itest_setregs("R2=0x7f7fffff") def test_clz_lead_zero_then_more_zeroes(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 1) @itest_custom("sub r3, r1, r2") @itest_setregs("R1=4", "R2=2") def test_sub_basic(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 2) @itest_custom("sub r3, r1, #5") @itest_setregs("R1=10") def test_sub_imm(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 5) @itest_custom("sbc r3, r1, #5") @itest_setregs("R1=10") def test_sbc_imm(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R3'), 4) @itest_custom("ldm sp, {r1, r2, r3}") def test_ldm(self): self.cpu.stack_push(0x41414141) self.cpu.stack_push(2) self.cpu.stack_push(42) pre_sp = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('R2'), 2) self.assertEqual(self.rf.read('R3'), 0x41414141) self.assertEqual(self.cpu.STACK, pre_sp) @itest_custom("ldm sp!, {r1, r2, r3}") def test_ldm_wb(self): self.cpu.stack_push(0x41414141) self.cpu.stack_push(2) self.cpu.stack_push(42) pre_sp = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 42) self.assertEqual(self.rf.read('R2'), 2) self.assertEqual(self.rf.read('R3'), 0x41414141) self.assertEqual(self.cpu.STACK, pre_sp + 12) @itest_setregs("R1=2", "R2=42", "R3=0x42424242") @itest_custom("stm sp, {r1, r2, r3}") def test_stm(self): self.cpu.STACK -= 12 pre_sp = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.cpu.read_int(pre_sp, self.cpu.address_bit_size), 2) self.assertEqual(self.cpu.read_int(pre_sp + 4, self.cpu.address_bit_size), 42) self.assertEqual(self.cpu.read_int(pre_sp + 8, self.cpu.address_bit_size), 0x42424242) self.assertEqual(self.cpu.STACK, pre_sp) @itest_setregs("R1=2", "R2=42", "R3=0x42424242") @itest_custom("stm sp!, {r1, r2, r3}") def test_stm_wb(self): self.cpu.STACK -= 12 pre_sp = self.cpu.STACK emulate_next(self.cpu) self.assertEqual(self.cpu.read_int(pre_sp, self.cpu.address_bit_size), 2) self.assertEqual(self.cpu.read_int(pre_sp + 4, self.cpu.address_bit_size), 42) self.assertEqual(self.cpu.read_int(pre_sp + 8, self.cpu.address_bit_size), 0x42424242) self.assertEqual(self.cpu.STACK, pre_sp + 12) @itest_custom("stmib r3, {r2, r4}") @itest_setregs("R1=1", "R2=2", "R4=4", "R3=0xd100") def test_stmib_basic(self): emulate_next(self.cpu) addr = self.rf.read('R3') self.assertEqual(self.cpu.read_int(addr + 4, self.cpu.address_bit_size), 2) self.assertEqual(self.cpu.read_int(addr + 8, self.cpu.address_bit_size), 4) @itest_custom("bx r1") @itest_setregs("R1=0x1008") def test_bx_basic(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('PC'), 0x1008) @itest_custom("bx r1") @itest_setregs("R1=0x1009") def test_bx_thumb(self): pre_pc = self.rf.read('PC') emulate_next(self.cpu) self.assertEqual(self.rf.read('PC'), pre_pc + 4) # ORR @itest_custom("orr r2, r3, #5") @itest_setregs("R3=0x1000") def test_orr_imm(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0x1005) @itest_custom("orrs r2, r3") @itest_setregs("R2=0x5", "R3=0x80000000") def test_orrs_imm_flags(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0x80000005) self.assertEqual(self.rf.read('APSR_N'), True) @itest_custom("orr r2, r3") @itest_setregs("R2=0x5", "R3=0x80000000") def test_orr_reg_w_flags(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0x80000005) # self.assertEqual(self.rf.read('APSR_N'), 1) @itest_custom("orr r2, r3, r4") @itest_setregs("R3=0x5", "R4=0x80000000") def test_orr_reg_two_op(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0x80000005) # self.assertEqual(self.rf.read('APSR_N'), 1) @itest_custom("orr r2, r3, r4, LSL #4") @itest_setregs("R3=0x5", "R4=0xF") def test_orr_reg_two_op_shifted(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0xF5) # EOR @itest_custom("eor r2, r3, #5") @itest_setregs("R3=0xA") def test_eor_imm(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0xF) @itest_custom("eors r2, r3") @itest_setregs("R2=0xAA", "R3=0x80000000") def test_eors_imm_flags(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0x800000AA) self.assertEqual(self.rf.read('APSR_N'), True) @itest_custom("eors r2, r3") @itest_setregs("R2=0x5", "R3=0x80000005") def test_eor_reg_w_flags(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0x80000000) self.assertEqual(self.rf.read('APSR_N'), 1) @itest_custom("eor r2, r3, r4") @itest_setregs("R3=0x80000005", "R4=0x80000005") def test_eor_reg_two_op(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0) @itest_custom("eor r2, r3, r4, LSL #4") @itest_setregs("R3=0x55", "R4=0x5") def test_eor_reg_two_op_shifted(self): emulate_next(self.cpu) self.assertEqual(self.rf.read('R2'), 0x5) # LDRH - see also LDR tests @itest_custom("ldrh r1, [sp]") def test_ldrh_imm_off_none(self): self.cpu.stack_push(0x41410041) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0x41) @itest_custom("ldrh r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrh_reg_off(self): self.cpu.stack_push(0x41410041) self.cpu.stack_push(48) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0x41) # LDRSH - see also LDR tests @itest_custom("ldrsh r1, [sp]") def test_ldrsh_imm_off_none_neg(self): self.cpu.stack_push(0x2ff0f) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0xffffff0f) @itest_custom("ldrsh r1, [sp]") def test_ldrsh_imm_off_none_pos(self): self.cpu.stack_push(0xff0fff) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0x0fff) @itest_custom("ldrsh r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsh_reg_off_neg(self): self.cpu.stack_push(0x2ff0f) self.cpu.stack_push(48) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0xffffff0f) @itest_custom("ldrsh r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsh_reg_off_pos(self): self.cpu.stack_push(0xff0fff) self.cpu.stack_push(48) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0x0fff) # LDRB - see also LDR tests @itest_custom("ldrb r1, [sp]") def test_ldrb_imm_off_none(self): self.cpu.stack_push(0x41) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0x41) @itest_custom("ldrb r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrb_reg_off(self): self.cpu.stack_push(0x41) self.cpu.stack_push(48) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0x41) # LDRSB - see also LDR tests @itest_custom("ldrsb r1, [sp]") def test_ldrsb_imm_off_none_neg(self): self.cpu.stack_push(0x2ff) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), Mask(32)) @itest_custom("ldrsb r1, [sp]") def test_ldrsb_imm_off_none_pos(self): self.cpu.stack_push(0xff0f) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0xf) @itest_custom("ldrsb r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsb_reg_off_neg(self): self.cpu.stack_push(0x2ff) self.cpu.stack_push(48) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), Mask(32)) @itest_custom("ldrsb r1, [sp, r2]") @itest_setregs("R2=4") def test_ldrsb_reg_off_pos(self): self.cpu.stack_push(0xff0f) self.cpu.stack_push(48) emulate_next(self.cpu) self.assertEqual(self.rf.read('R1'), 0xf) # TST @itest_setregs("R1=1", "R3=0") @itest("tst r3, r1") def test_tst(self): self._checkFlagsNZCV(0, 1, 0, 0) # AND @itest_setregs("R2=5") @itest("and r2, r2, #1") def test_and_imm(self): self.assertEqual(self.rf.read('R2'), 1) @itest_setregs("R1=5", "R2=3") @itest("and r1, r1, r2") def test_and_reg(self): self.assertEqual(self.rf.read('R1'), 3 & 5) @itest_setregs("R1=5", "R2=3", "APSR_C=1") @itest("and r1, r1, r2") def test_and_reg_carry(self): self.assertEqual(self.rf.read('R1'), 3 & 5) self.assertEqual(self.rf.read('APSR_C'), 1) # svc def test_svc(self): with self.assertRaises(Interruption): self._setupCpu("svc #0") emulate_next(self.cpu) # lsl @itest_setregs("R3=0x11") @itest("lsls r4, r3, 1") def test_lsl_imm_min(self): self.assertEqual(self.rf.read('R4'), 0x11 << 1) self._checkFlagsNZCV(0, 0, 0, 0) @itest_setregs("R3=0x11") @itest("lsls r4, r3, 31") def test_lsl_imm_max(self): self.assertEqual(self.rf.read('R4'), 1 << 31) self._checkFlagsNZCV(1, 0, 0, 0) @itest_setregs("R3=0x11", "R2=0xff01") @itest("lsls r4, r3, r2") def test_lsl_reg_min(self): self.assertEqual(self.rf.read('R4'), 0x11 << 1) self._checkFlagsNZCV(0, 0, 0, 0) @itest_setregs("R3=0x11", "R2=0xff1f") @itest("lsls r4, r3, r2") def test_lsl_reg_max(self): self.assertEqual(self.rf.read('R4'), 0x1 << 31) self._checkFlagsNZCV(1, 0, 0, 0) # lsr @itest_setregs("R0=0x1000", "R2=3") @itest("lsr r0, r0, r2") def test_lsr_reg(self): self.assertEqual(self.rf.read('R0'), 0x1000 >> 3) @itest_setregs("R0=0x1000") @itest("lsr r0, r0, #3") def test_lsr_reg_imm(self): self.assertEqual(self.rf.read('R0'), 0x1000 >> 3) @itest_setregs("R2=29") @itest("RSB r2, r2, #31") def test_rsb_imm(self): # Diverging instruction from trace self.assertEqual(self.rf.read('R2'), 2) def test_flag_state_continuity(self): '''If an instruction only partially updates flags, cpu.setFlags should ensure unupdated flags are preserved. For example: r1 = 2**31 - 1 add r2, r1, 0x1 // overflow = 1 mov r1, 1 mov r3, 0 tst r3, r1 // does not change overflow flag // ovf should still be 1 ''' self.rf.write('R1', (2 ** 31 - 1)) self._setupCpu("adds r2, r1, #0x1") emulate_next(self.cpu) self.rf.write('R1', 1) self.rf.write('R3', 0) self.mem.write(self.cpu.PC, assemble("tst r3, r1")) emulate_next(self.cpu) self._checkFlagsNZCV(0, 1, 0, 1) @itest_setregs("R1=30", "R2=10") @itest("MUL R1, R2") def test_mul_reg(self): self.assertEqual(self.rf.read('R1'), 300) @itest_setregs("R1=30", "R2=10") @itest("MUL R3, R1, R2") def test_mul_reg_w_dest(self): self.assertEqual(self.rf.read('R3'), 300) @itest_setregs("R2=10", "R3=15", "R4=7") @itest("MLA R1, R2, R3, R4") def test_mla_reg(self): self.assertEqual(self.rf.read('R1'), 157) @itest_setregs("R1=0xFF") @itest("BIC R2, R1, #0x10") def test_bic_reg_imm(self): self.assertEqual(self.rf.read('R2'), 0xEF) @itest_setregs("R1=0x1008") @itest("BLX R1") def test_blx_reg(self): self.assertEqual(self.rf.read('PC'), 0x1008) self.assertEqual(self.rf.read('LR'), 0x1008) @itest_setregs("R1=0x1009") @itest("BLX R1") def test_blx_reg_thumb(self): self.assertEqual(self.rf.read('PC'), 0x1008) self.assertEqual(self.rf.read('LR'), 0x1008) @itest_setregs("R1=0xffffffff", "R2=2") @itest("UMULLS R1, R2, R1, R2") def test_umull(self): mul = 0xffffffff * 2 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_setregs("R1=2", "R2=2") @itest("UMULLS R1, R2, R1, R2") def test_umull_still32(self): mul = 2 * 2 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(0, 0, pre_c, pre_v) @itest_setregs("R1=0xfffffffe", "R2=0xfffffffe") @itest("UMULLS R1, R2, R1, R2") def test_umull_max(self): mul = 0xfffffffe ** 2 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), mul >> 32) self._checkFlagsNZCV(1, 0, pre_c, pre_v) @itest_setregs("R1=3", "R2=0") @itest("UMULLS R1, R2, R1, R2") def test_umull_z(self): mul = 3 * 0 pre_c = self.rf.read('APSR_C') pre_v = self.rf.read('APSR_V') self.assertEqual(self.rf.read('R1'), mul & Mask(32)) self.assertEqual(self.rf.read('R2'), (mul >> 32) & Mask(32)) self._checkFlagsNZCV(0, 1, pre_c, pre_v)