1669 lines
53 KiB
Python
1669 lines
53 KiB
Python
import unittest
|
|
import struct
|
|
from functools import wraps
|
|
|
|
from manticore.core.cpu.arm import Armv7Cpu as Cpu, Mask, Interruption
|
|
from manticore.core.memory import Memory32, SMemory32
|
|
from manticore.core.smtlib import *
|
|
from manticore.core.state import Concretize
|
|
|
|
from capstone.arm import *
|
|
from capstone import CS_MODE_THUMB, CS_MODE_ARM
|
|
from keystone import Ks, KS_ARCH_ARM, KS_MODE_ARM, KS_MODE_THUMB
|
|
|
|
ks = Ks(KS_ARCH_ARM, KS_MODE_ARM)
|
|
ks_thumb = Ks(KS_ARCH_ARM, KS_MODE_THUMB)
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger("ARM_TESTS")
|
|
|
|
|
|
def assemble(asm, mode=CS_MODE_ARM):
|
|
if CS_MODE_ARM == mode:
|
|
ords = ks.asm(asm)[0]
|
|
elif CS_MODE_THUMB == mode:
|
|
ords = ks_thumb.asm(asm)[0]
|
|
else:
|
|
raise Exception('bad processor mode for assembly: {}'.format(mode))
|
|
if not ords:
|
|
raise Exception('bad assembly: {}'.format(asm))
|
|
return ''.join(map(chr, ords))
|
|
|
|
|
|
class Armv7CpuTest(unittest.TestCase):
|
|
_multiprocess_can_split_ = True
|
|
|
|
def setUp(self):
|
|
cs = ConstraintSet()
|
|
self.c = Cpu(SMemory32(cs))
|
|
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)
|
|
|
|
|
|
def itest_failing(asm):
|
|
def instr_dec(assertions_func):
|
|
@wraps(assertions_func)
|
|
def wrapper(self):
|
|
self._setupCpu(asm)
|
|
self.cpu.instruction = "\x00\x00\x00\x00"
|
|
# self.cpu.execute()
|
|
assertions_func(self)
|
|
|
|
return wrapper
|
|
|
|
return instr_dec
|
|
|
|
|
|
def itest(asm):
|
|
def instr_dec(assertions_func):
|
|
@wraps(assertions_func)
|
|
def wrapper(self):
|
|
self._setupCpu(asm)
|
|
self.cpu.execute()
|
|
assertions_func(self)
|
|
|
|
return wrapper
|
|
|
|
return instr_dec
|
|
|
|
|
|
def itest_setregs(*preds):
|
|
def instr_dec(custom_func):
|
|
@wraps(custom_func)
|
|
def wrapper(self):
|
|
for p in preds:
|
|
dest, src = p.split('=')
|
|
|
|
try:
|
|
src = int(src, 0)
|
|
except:
|
|
pass
|
|
|
|
self.rf.write(dest.upper(), src)
|
|
custom_func(self)
|
|
|
|
return wrapper
|
|
|
|
return instr_dec
|
|
|
|
def itest_custom(asm):
|
|
def instr_dec(custom_func):
|
|
@wraps(custom_func)
|
|
def wrapper(self):
|
|
self._setupCpu(asm)
|
|
custom_func(self)
|
|
|
|
return wrapper
|
|
|
|
return instr_dec
|
|
|
|
def itest_thumb(asm):
|
|
def instr_dec(assertions_func):
|
|
@wraps(assertions_func)
|
|
def wrapper(self):
|
|
self._setupCpu(asm, mode=CS_MODE_THUMB)
|
|
self.cpu.execute()
|
|
assertions_func(self)
|
|
|
|
return wrapper
|
|
|
|
return instr_dec
|
|
|
|
def itest_multiple(asms):
|
|
def instr_dec(assertions_func):
|
|
@wraps(assertions_func)
|
|
def wrapper(self):
|
|
self._setupCpu(asms, mode=CS_MODE_ARM, multiple_insts=True)
|
|
for i in range(len(asms)):
|
|
self.cpu.execute()
|
|
assertions_func(self)
|
|
|
|
return wrapper
|
|
|
|
return instr_dec
|
|
|
|
|
|
def itest_thumb_multiple(asms):
|
|
def instr_dec(assertions_func):
|
|
@wraps(assertions_func)
|
|
def wrapper(self):
|
|
self._setupCpu(asms, mode=CS_MODE_THUMB, multiple_insts=True)
|
|
for i in range(len(asms)):
|
|
self.cpu.execute()
|
|
assertions_func(self)
|
|
|
|
return wrapper
|
|
|
|
return instr_dec
|
|
|
|
|
|
class Armv7CpuInstructions(unittest.TestCase):
|
|
def setUp(self):
|
|
cs = ConstraintSet()
|
|
self.cpu = Cpu(SMemory32(cs))
|
|
self.mem = self.cpu.memory
|
|
self.rf = self.cpu.regfile
|
|
|
|
def _setupCpu(self, asm, mode=CS_MODE_ARM, multiple_insts=False):
|
|
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
|
|
if multiple_insts:
|
|
offset = 0
|
|
for asm_single in asm:
|
|
asm_inst = assemble(asm_single, mode)
|
|
self.mem.write(start+offset, asm_inst)
|
|
offset += len(asm_inst)
|
|
else:
|
|
self.mem.write(start, assemble(asm, mode))
|
|
self.rf.write('PC', start)
|
|
self.rf.write('SP', self.stack + 0x1000)
|
|
self.cpu.mode = mode
|
|
|
|
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_setregs("R3=0xfffffff6", "R4=10")
|
|
@itest_thumb("adcs r3, r4")
|
|
def test_thumb_adc_basic(self):
|
|
self.assertEqual(self.rf.read('R3'), 0)
|
|
|
|
@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)
|
|
|
|
@itest_setregs("R0=0")
|
|
@itest_thumb("adds r0, #4")
|
|
def test_adds_thumb_two_op(self):
|
|
self.assertEqual(self.rf.read('R0'), 4)
|
|
|
|
# UADD8
|
|
|
|
@itest_setregs("R2=0x00FF00FF", "R3=0x00010002")
|
|
@itest_thumb("uadd8 r2, r2, r3")
|
|
def test_uadd8(self):
|
|
self.assertEqual(self.rf.read('R2'), 1)
|
|
self.assertEqual(self.rf.read('APSR_GE'), 5)
|
|
|
|
# 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)
|
|
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
|
|
|
|
@itest_custom("ldr pc, [sp]")
|
|
def test_ldr_imm_off_none_to_thumb(self):
|
|
self.cpu.stack_push(43)
|
|
self.cpu.execute()
|
|
self.assertEqual(self.rf.read('R15'), 42)
|
|
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
|
|
|
|
@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("ldrd r2, [sp]")
|
|
def test_ldrd(self):
|
|
r2 = 0x41
|
|
r3 = 0x42
|
|
self.cpu.stack_push(r3)
|
|
self.cpu.stack_push(r2)
|
|
self.cpu.execute()
|
|
self.assertEqual(self.rf.read('R2'), r2)
|
|
self.assertEqual(self.rf.read('R3'), r3)
|
|
|
|
@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)
|
|
|
|
@itest_custom("strd R2, [R1]")
|
|
@itest_setregs("R1=0xD000", "R2=34", "R3=35")
|
|
def test_strd(self):
|
|
r1 = self.rf.read('R1')
|
|
r2 = self.rf.read('R2')
|
|
r3 = self.rf.read('R3')
|
|
self.cpu.execute()
|
|
dr2 = self.cpu.read_int(r1, self.cpu.address_bit_size)
|
|
dr3 = self.cpu.read_int(r1+4, self.cpu.address_bit_size)
|
|
self.assertEqual(dr2, r2)
|
|
self.assertEqual(dr3, r3)
|
|
|
|
@itest_custom("str R2, [R1]")
|
|
@itest_setregs("R1=0xD000", "R2=34")
|
|
def test_str(self):
|
|
r1 = self.rf.read('R1')
|
|
r2 = self.rf.read('R2')
|
|
self.cpu.execute()
|
|
dr2 = self.cpu.read_int(r1, self.cpu.address_bit_size)
|
|
self.assertEqual(dr2, r2)
|
|
|
|
# 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_setregs("R3=0xE")
|
|
@itest_thumb("sub r3, #12")
|
|
def test_thumb_sub_basic(self):
|
|
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_setregs("R0=0","R3=0xffffffff")
|
|
@itest_thumb("sbcs r0, r3")
|
|
def test_sbc_thumb(self):
|
|
self.assertEqual(self.rf.read('R0'), 0)
|
|
|
|
@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)
|
|
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
|
|
|
|
@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)
|
|
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
|
|
|
|
# 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_setregs("R3=0x1000")
|
|
@itest_thumb("orr r3, #5")
|
|
def test_thumb_orr_imm(self):
|
|
self.assertEqual(self.rf.read('R3'), 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)
|
|
|
|
# ORN
|
|
@itest_setregs("R2=0x0", "R5=0xFFFFFFFA")
|
|
@itest_thumb("orn r2, r2, r5")
|
|
def test_orn(self):
|
|
self.assertEqual(self.rf.read('R2'), 0x5)
|
|
|
|
# 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_setregs("R3=0xA")
|
|
@itest_thumb("eor r3, #5")
|
|
def test_thumb_eor_imm(self):
|
|
self.assertEqual(self.rf.read('R3'), 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)
|
|
|
|
@itest_setregs("R5=1", "R6=2")
|
|
@itest_thumb("lsl.w r5, r6, #3")
|
|
def test_lslw_thumb(self):
|
|
'''thumb mode specific behavior'''
|
|
self.assertEqual(self.cpu.R5, 0x2 << 3)
|
|
|
|
# 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("R1=0", "R2=3")
|
|
@itest_thumb("lsrs r1, r2")
|
|
def test_thumb_lsrs(self):
|
|
self.assertEqual(self.cpu.R1, 0)
|
|
|
|
@itest_setregs("R5=0", "R6=16")
|
|
@itest_thumb("lsr.w R5, R6, #3")
|
|
def test_lsrw_thumb(self):
|
|
self.assertEqual(self.cpu.R5, 16>>3)
|
|
|
|
@itest_setregs("R5=0", "R6=16")
|
|
@itest_thumb("asr.w R5, R6, #3")
|
|
def test_asrw_thumb(self):
|
|
self.assertEqual(self.cpu.R5, 16>>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.set_flags 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=0xFF")
|
|
@itest("BIC R1, #0x10")
|
|
def test_thumb_bic_reg_imm(self):
|
|
self.assertEqual(self.rf.read('R1'), 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)
|
|
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
|
|
|
|
@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)
|
|
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
|
|
|
|
@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)
|
|
|
|
@itest_setregs("R3=3")
|
|
@itest("movt R3, #9")
|
|
def test_movt(self):
|
|
self.assertEqual(self.cpu.R3, 0x90003)
|
|
|
|
@itest_custom("mrc p15, #0, r2, c13, c0, #3")
|
|
def test_mrc(self):
|
|
self.cpu.set_arm_tls(0x55555)
|
|
self.cpu.write_register('R2', 0)
|
|
self.cpu.execute()
|
|
self.assertEqual(self.cpu.R2, 0x55555)
|
|
|
|
@itest_setregs("R1=0x45", "R2=0x55555555")
|
|
@itest("uxtb r1, r2")
|
|
def test_uxtb(self):
|
|
self.assertEqual(self.cpu.R2, 0x55555555)
|
|
self.assertEqual(self.cpu.R1, 0x55)
|
|
|
|
@itest_setregs("R1=1","R2=0","R3=0","R4=0","R12=0x4141")
|
|
@itest_thumb_multiple(["cmp r1, #1", "itt ne", "mov r2, r12", "mov r3, r12", "mov r4, r12"])
|
|
def test_itt_ne_noexec(self):
|
|
self.assertEqual(self.rf.read('R2'), 0)
|
|
self.assertEqual(self.rf.read('R3'), 0)
|
|
self.assertEqual(self.rf.read('R4'), 0x4141)
|
|
|
|
|
|
@itest_setregs("R1=0","R2=0","R3=0","R4=0","R12=0x4141")
|
|
@itest_thumb_multiple(["cmp r1, #1", "itt ne", "mov r2, r12", "mov r3, r12", "mov r4, r12"])
|
|
def test_itt_ne_exec(self):
|
|
self.assertEqual(self.rf.read('R2'), 0x4141)
|
|
self.assertEqual(self.rf.read('R3'), 0x4141)
|
|
self.assertEqual(self.rf.read('R4'), 0x4141)
|
|
|
|
@itest_setregs("R1=0","R2=0","R3=0","R4=0","R12=0x4141")
|
|
@itest_thumb_multiple(["cmp r1, #1", "ite ne", "mov r2, r12", "mov r3, r12", "mov r4, r12"])
|
|
def test_ite_ne_exec(self):
|
|
self.assertEqual(self.rf.read('R2'), 0x4141)
|
|
self.assertEqual(self.rf.read('R3'), 0x0)
|
|
self.assertEqual(self.rf.read('R4'), 0x4141)
|
|
|
|
@itest_setregs("R1=0","R2=0","R3=0","R4=0")
|
|
@itest_thumb_multiple(["cmp r1, #1", "itete ne", "mov r1, #1", "mov r2, #1", "mov r3, #1", "mov r4, #4"])
|
|
def test_itete_exec(self):
|
|
self.assertEqual(self.rf.read('R1'), 1)
|
|
self.assertEqual(self.rf.read('R2'), 0)
|
|
self.assertEqual(self.rf.read('R3'), 1)
|
|
self.assertEqual(self.rf.read('R4'), 0)
|
|
|
|
@itest_setregs("APSR_GE=3","R4=0","R5=0x01020304","R6=0x05060708")
|
|
@itest_thumb("sel r4, r5, r6")
|
|
def test_sel(self):
|
|
self.assertEqual(self.rf.read('R4'), 0x05060304)
|
|
|
|
@itest_setregs("R2=0","R1=0x01020304")
|
|
@itest("rev r2, r1")
|
|
def test_rev(self):
|
|
self.assertEqual(self.rf.read('R1'), 0x01020304)
|
|
self.assertEqual(self.rf.read('R2'), 0x04030201)
|
|
|
|
@itest_setregs("R1=0x01020304","R2=0x05060708", "R3=0","R4=0xF001")
|
|
@itest_multiple(["sxth r1, r2", "sxth r3, r4", "sxth r5, r4, ROR #8"])
|
|
def test_sxth(self):
|
|
self.assertEqual(self.rf.read('R1'), 0x0708)
|
|
self.assertEqual(self.rf.read('R3'), 0xFFFFF001)
|
|
self.assertEqual(self.rf.read('R5'), 0xF0)
|
|
|
|
@itest_custom("blx r1")
|
|
def test_blx_reg_sym(self):
|
|
dest = BitVecVariable(32, 'dest')
|
|
self.cpu.memory.constraints.add(dest >= 0x1000)
|
|
self.cpu.memory.constraints.add(dest <= 0x1001)
|
|
self.cpu.R1 = dest
|
|
|
|
# First, make sure we raise when the mode is symbolic and ambiguous
|
|
with self.assertRaises(Concretize) as cm:
|
|
self.cpu.execute()
|
|
|
|
# Then, make sure we have the correct expression
|
|
e = cm.exception
|
|
all_modes = solver.get_all_values(self.cpu.memory.constraints, e.expression)
|
|
self.assertIn(CS_MODE_THUMB, all_modes)
|
|
self.assertIn(CS_MODE_ARM, all_modes)
|
|
|
|
# Assuming we're in ARM mode, ensure the callback toggles correctly.
|
|
self.assertEqual(self.cpu.mode, CS_MODE_ARM)
|
|
# The setstate callback expects a State as its first argument; since we
|
|
# don't have a state, the unit test itself is an okay approximation, since
|
|
# the cpu lives in self.cpu
|
|
e.setstate(self, CS_MODE_THUMB)
|
|
self.assertEqual(self.cpu.mode, CS_MODE_THUMB)
|
|
|
|
@itest_setregs("R1=0x00000008") # pc/r15 is set to 0x1004 in _setupCpu()
|
|
@itest("add pc, pc, r1")
|
|
def test_add_to_pc(self):
|
|
self.assertEqual(self.rf.read('R15'), 0x1014)
|
|
|
|
# Make sure a cpu will survive a round trip through pickling/unpickling
|
|
def test_arm_save_restore_cpu(self):
|
|
import pickle
|
|
dumped_s = pickle.dumps(self.cpu)
|
|
self.cpu = pickle.loads(dumped_s)
|
|
|