mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 06:50:29 +02:00
The old disarm handled the integer instructions but only a fraction of VFP and NEON, and got several of those wrong. The new one decodes ARMv7-A ARM state with VFPv4 and NEON, printing UAL with upper case mnemonics. The new ArmDisasm test runs every ARM emitter function through it, two examples each. Tools/arm_disasm_check.py compares the test's output with llvm-mc; they agree on all of it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
768 lines
37 KiB
C++
768 lines
37 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
// Runs every instruction the ARM32 emitter can produce through our disassembler (ext/disarm.cpp),
|
|
// two examples each. The expected strings were checked against llvm-mc, which
|
|
// Tools/arm_disasm_check.py automates: it sets ARM_DISASM_DUMP to make this test print every line.
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#include "Common/ArmEmitter.h"
|
|
#include "Common/CPUDetect.h"
|
|
#include "ext/disarm.h"
|
|
|
|
#include "UnitTest.h"
|
|
|
|
#undef ADD
|
|
#undef RET
|
|
|
|
using namespace ArmGen;
|
|
|
|
namespace {
|
|
|
|
struct DisasmChecker {
|
|
ARMXEmitter &emit;
|
|
const u8 *base;
|
|
const u8 *start = nullptr;
|
|
int failures = 0;
|
|
int checks = 0;
|
|
bool dumpAll = getenv("ARM_DISASM_DUMP") != nullptr;
|
|
|
|
void Begin() {
|
|
start = emit.GetCodePointer();
|
|
}
|
|
|
|
// Multiple instructions are joined with "; ".
|
|
void Check(const char *expected, const char *code, int line) {
|
|
std::string actual;
|
|
std::string words;
|
|
for (const u8 *p = start; p < emit.GetCodePointer(); p += 4) {
|
|
u32 w;
|
|
memcpy(&w, p, 4);
|
|
char buf[256];
|
|
// Addresses are relative to the start of the buffer, which keeps branch targets stable.
|
|
ArmDis((u32)(p - base), w, buf, sizeof(buf), false);
|
|
if (!actual.empty()) {
|
|
actual += "; ";
|
|
words += " ";
|
|
}
|
|
actual += buf;
|
|
snprintf(buf, sizeof(buf), "%08x", w);
|
|
words += buf;
|
|
}
|
|
checks++;
|
|
bool fail = actual != expected;
|
|
if (fail || dumpAll) {
|
|
// Machine readable, for Tools/arm_disasm_check.py.
|
|
printf("DIS|%d|%x|%s|%s|%s|%s\n", line, (int)(start - base), words.c_str(), actual.c_str(), expected, code);
|
|
}
|
|
if (fail) {
|
|
failures++;
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
#define DIS(expected, ...) do { c.Begin(); __VA_ARGS__; c.Check(expected, #__VA_ARGS__, __LINE__); } while (false)
|
|
|
|
static void TestIntegerInstructions(DisasmChecker &c, ARMXEmitter &e, const u8 *base) {
|
|
// Branches. The buffer is at address 0 as far as the disassembler is concerned.
|
|
e.SetCodePointer((u8 *)base + 0x100, (u8 *)base + 0x100);
|
|
DIS("B 0x00000180", e.B(base + 0x180));
|
|
DIS("B 0x00000040", e.B(base + 0x40));
|
|
DIS("BL 0x00002000", e.BL(base + 0x2000));
|
|
DIS("BL 0x00000000", e.BL(base));
|
|
DIS("BEQ 0x00000200", e.B_CC(CC_EQ, base + 0x200));
|
|
DIS("BLE 0x00000080", e.B_CC(CC_LE, base + 0x80));
|
|
DIS("B 0x0000011c", FixupBranch b = e.B(); e.SetJumpTarget(b));
|
|
DIS("BL 0x00000120", FixupBranch b = e.BL(); e.SetJumpTarget(b));
|
|
DIS("BHI 0x00000124", FixupBranch b = e.B_CC(CC_HI); e.SetJumpTarget(b));
|
|
DIS("BLLT 0x0000012c; MOV r0, r0", FixupBranch b = e.BL_CC(CC_LT); e.NOP(); e.SetJumpTarget(b));
|
|
DIS("BX r0", e.B(R0));
|
|
DIS("BX lr", e.B(R_LR));
|
|
DIS("BLX r3", e.BL(R3));
|
|
DIS("BLX r12", e.BL(R12));
|
|
DIS("BL 0x00001000", e.QuickCallFunction(R12, base + 0x1000));
|
|
DIS("MOV r0, r4; BL 0x00001000", e.QuickCallFunctionR(R12, base + 0x1000, R4));
|
|
DIS("BNE 0x00000200", e.SetCC(CC_NEQ); e.B(base + 0x200); e.SetCC());
|
|
DIS("BLXGE r2", e.SetCC(CC_GE); e.BL(R2); e.SetCC());
|
|
|
|
// Misc
|
|
DIS("MOV r0, r0", e.NOP());
|
|
DIS("MOV r0, r0; MOV r0, r0", e.NOP(2));
|
|
DIS("SETEND be", e.SETEND(true));
|
|
DIS("SETEND le", e.SETEND(false));
|
|
DIS("BKPT #1", e.BKPT(1));
|
|
DIS("BKPT #4660", e.BKPT(0x1234));
|
|
DIS("YIELD", e.YIELD());
|
|
DIS("YIELDEQ", e.SetCC(CC_EQ); e.YIELD(); e.SetCC());
|
|
DIS("SVC #0x0", e.SVC(IMM(0)));
|
|
DIS("SVC #0x123456", e.SVC(IMM(0x123456)));
|
|
DIS("DMB st", e.DMB());
|
|
DIS("MRS r0, apsr", e.MRS(R0));
|
|
DIS("MRS r11, apsr", e.MRS(R11));
|
|
DIS("MSR APSR_nzcvq, r1", e._MSR(true, false, R1));
|
|
DIS("MSR APSR_nzcvqg, r9", e._MSR(true, true, R9));
|
|
DIS("MSR APSR_nzcvq, #0xf0000000", e._MSR(true, false, Operand2(0xF0, 4)));
|
|
DIS("MSR APSR_g, #7", e._MSR(false, true, IMM(7)));
|
|
|
|
// Data processing, every operation with an immediate, a register and a shifted register.
|
|
DIS("AND r0, r1, #255", e.AND(R0, R1, IMM(0xFF)));
|
|
DIS("AND r2, r3, r4, lsl #3", e.AND(R2, R3, Operand2(R4, ST_LSL, 3)));
|
|
DIS("ANDS r0, r1, r2", e.ANDS(R0, R1, R2));
|
|
DIS("ANDS r5, r6, #0xff000000", e.ANDS(R5, R6, Operand2(0xFF, 4)));
|
|
DIS("EOR r0, r1, #1", e.EOR(R0, R1, IMM(1)));
|
|
DIS("EOR r10, r11, r12, asr r1", e.EOR(R10, R11, Operand2(R12, ST_ASR, R1)));
|
|
DIS("EORS r0, r1, r2", e.EORS(R0, R1, R2));
|
|
DIS("EORS r3, r3, r4, ror #7", e.EORS(R3, R3, Operand2(R4, ST_ROR, 7)));
|
|
DIS("SUB r0, r1, #4", e.SUB(R0, R1, IMM(4)));
|
|
DIS("SUB sp, sp, #0x100", e.SUB(R_SP, R_SP, Operand2(0x40, 15)));
|
|
DIS("SUBS r0, r0, #1", e.SUBS(R0, R0, IMM(1)));
|
|
DIS("SUBS r1, r2, r3", e.SUBS(R1, R2, Operand2(R3, ST_LSR, 32)));
|
|
DIS("RSB r0, r1, #0", e.RSB(R0, R1, IMM(0)));
|
|
DIS("RSB r0, r1, r2, lsl r3", e.RSB(R0, R1, Operand2(R2, ST_LSL, R3)));
|
|
DIS("RSBS r4, r5, #32", e.RSBS(R4, R5, IMM(32)));
|
|
DIS("RSBS r4, r5, r6", e.RSBS(R4, R5, R6));
|
|
DIS("ADD r0, r1, r2", e.ADD(R0, R1, R2));
|
|
DIS("ADD r0, pc, #8", e.ADD(R0, R_PC, IMM(8)));
|
|
DIS("ADDS r0, r1, r2, rrx", e.ADDS(R0, R1, Operand2(R2, ST_RRX, 0)));
|
|
DIS("ADDS r8, r9, #255", e.ADDS(R8, R9, IMM(255)));
|
|
DIS("ADC r0, r1, r2", e.ADC(R0, R1, R2));
|
|
DIS("ADC r3, r4, #0", e.ADC(R3, R4, IMM(0)));
|
|
DIS("ADCS r0, r1, r2, asr #31", e.ADCS(R0, R1, Operand2(R2, ST_ASR, 31)));
|
|
DIS("ADCS r0, r1, #3", e.ADCS(R0, R1, IMM(3)));
|
|
DIS("SBC r0, r1, r2", e.SBC(R0, R1, R2));
|
|
DIS("SBC r6, r7, #0xc000000f", e.SBC(R6, R7, Operand2(0x3F, 1)));
|
|
DIS("SBCS r0, r1, #10", e.SBCS(R0, R1, IMM(10)));
|
|
DIS("SBCS r0, r1, r2, lsr r3", e.SBCS(R0, R1, Operand2(R2, ST_LSR, R3)));
|
|
DIS("RSC r0, r1, r2", e.RSC(R0, R1, R2));
|
|
DIS("RSC r0, r1, #100", e.RSC(R0, R1, IMM(100)));
|
|
DIS("RSCS r0, r1, r2, lsl #1", e.RSCS(R0, R1, Operand2(R2, ST_LSL, 1)));
|
|
DIS("RSCS r11, r12, #0", e.RSCS(R11, R12, IMM(0)));
|
|
DIS("TST r0, #1", e.TST(R0, IMM(1)));
|
|
DIS("TST r1, r2, lsl #16", e.TST(R1, Operand2(R2, ST_LSL, 16)));
|
|
DIS("TEQ r0, r1", e.TEQ(R0, R1));
|
|
DIS("TEQ r3, #128", e.TEQ(R3, IMM(0x80)));
|
|
DIS("CMP r0, #0", e.CMP(R0, IMM(0)));
|
|
DIS("CMP r1, r2", e.CMP(R1, R2));
|
|
DIS("CMN r0, #1", e.CMN(R0, IMM(1)));
|
|
DIS("CMN r7, r8, asr r9", e.CMN(R7, Operand2(R8, ST_ASR, R9)));
|
|
DIS("ORR r0, r1, #16", e.ORR(R0, R1, IMM(0x10)));
|
|
DIS("ORR r0, r1, r2, ror r3", e.ORR(R0, R1, Operand2(R2, ST_ROR, R3)));
|
|
DIS("ORRS r0, r1, r2", e.ORRS(R0, R1, R2));
|
|
DIS("ORRS r0, r0, #0x10000", e.ORRS(R0, R0, Operand2(0x01, 8)));
|
|
DIS("MOV r0, r1", e.MOV(R0, R1));
|
|
DIS("MOV r0, #42", e.MOV(R0, IMM(42)));
|
|
DIS("MOV pc, lr", e.MOV(R_PC, R_LR));
|
|
DIS("LSL r2, r3, #5", e.MOV(R2, Operand2(R3, ST_LSL, 5)));
|
|
DIS("LSR r2, r3, r4", e.MOV(R2, Operand2(R3, ST_LSR, R4)));
|
|
DIS("RRX r2, r3", e.MOV(R2, Operand2(R3, ST_RRX, 0)));
|
|
DIS("MOVS r0, r1", e.MOVS(R0, R1));
|
|
DIS("MOVS r5, #0", e.MOVS(R5, IMM(0)));
|
|
DIS("BIC r0, r1, #15", e.BIC(R0, R1, IMM(0xF)));
|
|
DIS("BIC r0, r1, #0xff00", e.BIC(R0, R1, Operand2(0xFF, 12)));
|
|
DIS("BICS r0, r1, r2", e.BICS(R0, R1, R2));
|
|
DIS("BICS r0, r1, r2, asr #2", e.BICS(R0, R1, Operand2(R2, ST_ASR, 2)));
|
|
DIS("MVN r0, #0", e.MVN(R0, IMM(0)));
|
|
DIS("MVN r0, r1", e.MVN(R0, R1));
|
|
DIS("MVNS r0, r1, lsl #2", e.MVNS(R0, Operand2(R1, ST_LSL, 2)));
|
|
DIS("MVNS r3, #192", e.MVNS(R3, IMM(0xC0)));
|
|
DIS("MOVW r0, #0x1234", e.MOVW(R0, IMM(0x1234)));
|
|
DIS("MOVW r12, #0xffff", e.MOVW(R12, IMM(0xFFFF)));
|
|
DIS("MOVT r0, #0x5678", e.MOVT(R0, IMM(0x5678)));
|
|
DIS("MOVT r1, #0x89ab", e.MOVT(R1, IMM(0x89AB0000), true));
|
|
DIS("ADDLT r0, r1, #1", e.SetCC(CC_LT); e.ADD(R0, R1, IMM(1)); e.SetCC());
|
|
DIS("MOVSHI r1, r2", e.SetCC(CC_HI); e.MOVS(R1, R2); e.SetCC());
|
|
|
|
// Shifts
|
|
DIS("LSL r0, r1, #3", e.LSL(R0, R1, IMM(3)));
|
|
DIS("LSL r0, r1, r2", e.LSL(R0, R1, R2));
|
|
DIS("LSLS r0, r1, #31", e.LSLS(R0, R1, IMM(31)));
|
|
DIS("LSLS r4, r5, r6", e.LSLS(R4, R5, R6));
|
|
DIS("LSR r0, r1, #1", e.LSR(R0, R1, IMM(1)));
|
|
DIS("LSR r0, r1, r2", e.LSR(R0, R1, R2));
|
|
DIS("LSRS r0, r1, #16", e.LSRS(R0, R1, IMM(16)));
|
|
DIS("LSRS r0, r1, r12", e.LSRS(R0, R1, R12));
|
|
DIS("ASR r0, r1, #31", e.ASR(R0, R1, IMM(31)));
|
|
DIS("ASR r0, r1, r2", e.ASR(R0, R1, R2));
|
|
DIS("ASRS r0, r1, #8", e.ASRS(R0, R1, IMM(8)));
|
|
DIS("ASRS r7, r8, r9", e.ASRS(R7, R8, R9));
|
|
|
|
// Multiplies and divides
|
|
DIS("MUL r0, r2, r1", e.MUL(R0, R1, R2));
|
|
DIS("MUL r12, r11, r10", e.MUL(R12, R10, R11));
|
|
DIS("MULS r0, r2, r1", e.MULS(R0, R1, R2));
|
|
DIS("MULS r3, r5, r4", e.MULS(R3, R4, R5));
|
|
DIS("UMULL r0, r1, r2, r3", e.UMULL(R0, R1, R2, R3));
|
|
DIS("UMULL r4, r5, r6, r7", e.UMULL(R4, R5, R6, R7));
|
|
DIS("SMULL r0, r1, r2, r3", e.SMULL(R0, R1, R2, R3));
|
|
DIS("SMULL r8, r9, r10, r11", e.SMULL(R8, R9, R10, R11));
|
|
DIS("UMLAL r0, r1, r2, r3", e.UMLAL(R0, R1, R2, R3));
|
|
DIS("UMLAL r4, r12, r6, r7", e.UMLAL(R4, R12, R6, R7));
|
|
DIS("SMLAL r0, r1, r2, r3", e.SMLAL(R0, R1, R2, R3));
|
|
DIS("SMLAL r2, r3, r0, r1", e.SMLAL(R2, R3, R0, R1));
|
|
DIS("UDIV r0, r1, r2", e.UDIV(R0, R1, R2));
|
|
DIS("UDIV r3, r4, r5", e.UDIV(R3, R4, R5));
|
|
DIS("SDIV r0, r1, r2", e.SDIV(R0, R1, R2));
|
|
DIS("SDIV r6, r7, r8", e.SDIV(R6, R7, R8));
|
|
|
|
// Bitfields, extension and the like
|
|
DIS("SXTB r0, r1", e.SXTB(R0, R1));
|
|
DIS("SXTB r5, r12", e.SXTB(R5, R12));
|
|
DIS("SXTH r0, r1", e.SXTH(R0, R1));
|
|
DIS("SXTH r2, r3, ror #16", e.SXTH(R2, R3, 2));
|
|
DIS("SXTAH r0, r1, r2", e.SXTAH(R0, R1, R2));
|
|
DIS("SXTAH r0, r1, r2, ror #8", e.SXTAH(R0, R1, R2, 1));
|
|
DIS("BFI r0, r1, #4, #8", e.BFI(R0, R1, 4, 8));
|
|
DIS("BFI r2, r3, #0, #32", e.BFI(R2, R3, 0, 32));
|
|
DIS("BFC r0, #4, #8", e.BFC(R0, 4, 8));
|
|
DIS("BFC r5, #16, #16", e.BFC(R5, 16, 16));
|
|
DIS("UBFX r0, r1, #4, #8", e.UBFX(R0, R1, 4, 8));
|
|
DIS("UBFX r2, r3, #0, #1", e.UBFX(R2, R3, 0, 1));
|
|
DIS("SBFX r0, r1, #4, #8", e.SBFX(R0, R1, 4, 8));
|
|
DIS("SBFX r2, r3, #31, #1", e.SBFX(R2, R3, 31, 1));
|
|
DIS("CLZ r0, r1", e.CLZ(R0, R1));
|
|
DIS("CLZ r12, r11", e.CLZ(R12, R11));
|
|
DIS("RBIT r0, r1", e.RBIT(R0, R1));
|
|
DIS("RBIT r7, r8", e.RBIT(R7, R8));
|
|
DIS("REV r0, r1", e.REV(R0, R1));
|
|
DIS("REV r9, r10", e.REV(R9, R10));
|
|
DIS("REV16 r0, r1", e.REV16(R0, R1));
|
|
DIS("REV16 r3, r4", e.REV16(R3, R4));
|
|
|
|
// Loads and stores
|
|
DIS("LDR r3, [r7]", e.LDR(R3, R7));
|
|
DIS("LDR r0, [r1, #4]", e.LDR(R0, R1, IMM(4)));
|
|
DIS("LDR r0, [r1, #-8]", e.LDR(R0, R1, Operand2((u32)-8)));
|
|
DIS("LDR r0, [r1, r2]", e.LDR(R0, R1, R2));
|
|
DIS("LDR r0, [r1, -r2]", e.LDR(R0, R1, R2, false));
|
|
DIS("LDR r0, [r1, r2, lsl #2]", e.LDR(R0, R1, Operand2(R2, ST_LSL, 2)));
|
|
DIS("LDRB r0, [r1, #1]", e.LDRB(R0, R1, IMM(1)));
|
|
DIS("LDRB r0, [r1, r2]", e.LDRB(R0, R1, R2));
|
|
DIS("LDRH r0, [r1, #2]", e.LDRH(R0, R1, IMM(2)));
|
|
DIS("LDRH r0, [r1, -r2]", e.LDRH(R0, R1, R2, false));
|
|
DIS("LDRSB r0, [r1, #255]", e.LDRSB(R0, R1, IMM(0xFF)));
|
|
DIS("LDRSB r0, [r1, r2]", e.LDRSB(R0, R1, R2));
|
|
DIS("LDRSH r0, [r1, #-2]", e.LDRSH(R0, R1, Operand2((u32)-2)));
|
|
DIS("LDRSH r0, [r1, r2]", e.LDRSH(R0, R1, R2));
|
|
DIS("STR r0, [r1, #4095]", e.STR(R0, R1, IMM(4095)));
|
|
DIS("STR r0, [sp, -r2, asr #1]", e.STR(R0, R_SP, Operand2(R2, ST_ASR, 1), false));
|
|
DIS("STRB r0, [r1]", e.STRB(R0, R1));
|
|
DIS("STRB r0, [r1, r2]", e.STRB(R0, R1, R2));
|
|
DIS("STRH r0, [r1, #16]", e.STRH(R0, R1, IMM(0x10)));
|
|
DIS("STRH r0, [r1, r2]", e.STRH(R0, R1, R2));
|
|
DIS("PLD [r0]", e.PLD(R0, 0));
|
|
DIS("PLDW [r1, #-64]", e.PLD(R1, -64, true));
|
|
DIS("LDREX r0, [r1]", e.LDREX(R0, R1));
|
|
DIS("LDREX r4, [r5]", e.LDREX(R4, R5));
|
|
DIS("STREX r0, r2, [r1]", e.STREX(R0, R1, R2));
|
|
DIS("STREX r3, r5, [r4]", e.STREX(R3, R4, R5));
|
|
|
|
// Load and store multiple
|
|
DIS("PUSH {r4, lr}", e.PUSH(2, R4, R_LR));
|
|
DIS("STMDB sp!, {r4}", e.PUSH(1, R4));
|
|
DIS("POP {r4, r5, pc}", e.POP(3, R4, R5, R_PC));
|
|
DIS("LDMIA sp!, {r0}", e.POP(1, R0));
|
|
DIS("PUSH {r0, r1}", e.STMFD(R_SP, true, 2, R0, R1));
|
|
DIS("STMDB r2, {r0, r1}", e.STMFD(R2, false, 2, R0, R1));
|
|
DIS("POP {r0, r1}", e.LDMFD(R_SP, true, 2, R0, R1));
|
|
DIS("LDMIA r3, {r12}", e.LDMFD(R3, false, 1, R12));
|
|
DIS("STMIA r0!, {r1, r2}", e.STMIA(R0, true, 2, R1, R2));
|
|
DIS("STMIA r0, {r1, r2, r3}", e.STMIA(R0, false, 3, R1, R2, R3));
|
|
DIS("LDMIA r0!, {r1, r2}", e.LDMIA(R0, true, 2, R1, R2));
|
|
DIS("LDMIA r0, {r4, r11}", e.LDMIA(R0, false, 2, R4, R11));
|
|
DIS("STMDB r0!, {r1, r2}", e.STM(R0, false, true, true, 2, R1, R2));
|
|
DIS("STMIB r0, {r1, r2}", e.STM(R0, true, true, false, 2, R1, R2));
|
|
DIS("LDMDA r0, {r1, r2}", e.LDM(R0, false, false, false, 2, R1, R2));
|
|
DIS("LDMIB r0!, {r1, r2}", e.LDM(R0, true, true, true, 2, R1, R2));
|
|
DIS("STMIA r0!, {r4, r5, r6, r7}", e.STMBitmask(R0, true, false, true, 0x00F0));
|
|
DIS("PUSH {r4, r5, r6, r7, r8, r9, r10, r11, lr}", e.STMBitmask(R_SP, false, true, true, 0x4FF0));
|
|
DIS("LDMIA r0, {r1, r2, r3}", e.LDMBitmask(R0, true, false, false, 0x000E));
|
|
DIS("POP {r4, r5, r6, r7, r8, r9, r10, r11, pc}", e.LDMBitmask(R_SP, true, false, true, 0x8FF0));
|
|
|
|
// Helpers that pick an encoding
|
|
DIS("MOVW r0, #0x5678; MOVT r0, #0x1234", e.MOVI2R(R0, 0x12345678));
|
|
DIS("MVN r0, #255", e.MOVI2R(R0, 0xFFFFFF00));
|
|
DIS("MOVW r1, #0x1234", e.MOVI2R(R1, 0x1234));
|
|
DIS("MOVW r2, #0x0; MOVT r2, #0xabcd", e.MOVI2R(R2, 0xABCD0000, false));
|
|
DIS("MOVW r3, #0x4000; MOVT r3, #0x880", e.MOVP2R(R3, (void *)(uintptr_t)0x08804000));
|
|
DIS("ADD r0, r1, #0x100", e.ADDI2R(R0, R1, 0x100, R12));
|
|
DIS("MOVW r12, #0x2345; MOVT r12, #0x1; ADD r0, r1, r12", e.ADDI2R(R0, R1, 0x12345, R12));
|
|
DIS("ADD r0, r1, #0x1200; ADD r0, r0, #52", e.TryADDI2R(R0, R1, 0x1234));
|
|
DIS("SUB r0, r1, #4", e.SUBI2R(R0, R1, 4, R12));
|
|
DIS("SUB r0, r1, #0x1200; SUB r0, r0, #52", e.SUBI2R(R0, R1, 0x1234, R12));
|
|
DIS("AND r0, r1, #0xff00", e.ANDI2R(R0, R1, 0xFF00, R12));
|
|
DIS("BIC r0, r1, #0xf000", e.ANDI2R(R0, R1, 0xFFFF0FFF, R12));
|
|
DIS("BIC r0, r1, #0xfe0000; BIC r0, r0, #0xff000000", e.ANDI2R(R0, R1, 0x0001FFFF, R12));
|
|
DIS("BIC r0, r1, #135; BIC r0, r0, #0xa900; BIC r0, r0, #0xcb0000; BIC r0, r0, #0xed000000", e.ANDI2R(R0, R1, 0x12345678, R12));
|
|
DIS("ORR r0, r1, #0x80000000", e.ORI2R(R0, R1, 0x80000000, R12));
|
|
DIS("ORR r0, r1, #240; ORR r0, r0, #0xf00000", e.ORI2R(R0, R1, 0x00F000F0, R12));
|
|
DIS("ORR r0, r1, #0x278; ORR r0, r0, #0x5400; ORR r0, r0, #0x2340000; ORR r0, r0, #0x10000008", e.ORI2R(R0, R1, 0x12345678, R12));
|
|
DIS("EOR r0, r1, #0x3fc", e.EORI2R(R0, R1, 0x3FC, R12));
|
|
DIS("MOVW r12, #0x1234; EOR r0, r1, r12", e.EORI2R(R0, R1, 0x1234, R12));
|
|
DIS("CMP r0, #16", e.CMPI2R(R0, 0x10, R12));
|
|
DIS("CMN r0, #16", e.CMPI2R(R0, (u32)-0x10, R12));
|
|
DIS("MOVW r12, #0x1234; CMP r0, r12", e.CMPI2R(R0, 0x1234, R12));
|
|
DIS("TST r0, #0x100", e.TSTI2R(R0, 0x100, R12));
|
|
DIS("MOVW r12, #0x101; TST r0, r12", e.TSTI2R(R0, 0x101, R12));
|
|
DIS("MOV r0, #255; ORR r0, r0, #0xff0000", e.TrySetValue_TwoOp(R0, 0x00FF00FF));
|
|
DIS("MOV r0, #1; ORR r0, r0, #0x80000000", e.TrySetValue_TwoOp(R0, 0x80000001));
|
|
DIS("NOP; NOP", e.NopAlignCode16());
|
|
DIS("BKPT #0; BKPT #0", e.ReserveCodeSpace(8));
|
|
}
|
|
|
|
static void TestFloatInstructions(DisasmChecker &c, ARMXEmitter &e) {
|
|
// VFP loads and stores
|
|
DIS("VLDR s3, [r8, #48]", e.VLDR(S3, R8, 48));
|
|
DIS("VLDR d17, [r0, #-1020]", e.VLDR(D17, R0, -1020));
|
|
DIS("VSTR s5, [r12, #-36]", e.VSTR(S5, R12, -36));
|
|
DIS("VSTR d0, [sp]", e.VSTR(D0, R_SP, 0));
|
|
DIS("VLDMIA r0, {s0-s3}", e.VLDMIA(R0, false, S0, 4));
|
|
DIS("VLDMIA r1!, {d8-d15}", e.VLDMIA(R1, true, D8, 8));
|
|
DIS("VSTMIA r0!, {s4}", e.VSTMIA(R0, true, S4, 1));
|
|
DIS("VSTMIA r2, {d16-d31}", e.VSTMIA(R2, false, D16, 16));
|
|
DIS("VLDMDB r0!, {s8-s9}", e.VLDMDB(R0, true, S8, 2));
|
|
DIS("VLDMDB r3!, {d2-d4}", e.VLDMDB(R3, true, D2, 3));
|
|
DIS("VSTMDB r0!, {d0-d1}", e.VSTMDB(R0, true, D0, 2));
|
|
DIS("VSTMDB r4!, {s30-s31}", e.VSTMDB(R4, true, S30, 2));
|
|
DIS("VPUSH {d8-d15}", e.VPUSH(D8, 8));
|
|
DIS("VPUSH {s16}", e.VPUSH(S16, 1));
|
|
DIS("VPOP {d8-d15}", e.VPOP(D8, 8));
|
|
DIS("VPOP {s0-s2}", e.VPOP(S0, 3));
|
|
|
|
// VFP arithmetic, single and double
|
|
DIS("VADD.f32 s1, s2, s3", e.VADD(S1, S2, S3));
|
|
DIS("VADD.f64 d1, d2, d3", e.VADD(D1, D2, D3));
|
|
DIS("VSUB.f32 s1, s2, s3", e.VSUB(S1, S2, S3));
|
|
DIS("VSUB.f64 d20, d21, d31", e.VSUB(D20, D21, D31));
|
|
DIS("VMUL.f32 s7, s8, s9", e.VMUL(S7, S8, S9));
|
|
DIS("VMUL.f64 d0, d16, d1", e.VMUL(D0, D16, D1));
|
|
DIS("VNMUL.f32 s7, s8, s9", e.VNMUL(S7, S8, S9));
|
|
DIS("VNMUL.f64 d7, d8, d9", e.VNMUL(D7, D8, D9));
|
|
DIS("VMLA.f32 s7, s8, s9", e.VMLA(S7, S8, S9));
|
|
DIS("VMLA.f64 d5, d6, d7", e.VMLA(D5, D6, D7));
|
|
DIS("VMLS.f32 s0, s1, s2", e.VMLS(S0, S1, S2));
|
|
DIS("VMLS.f64 d1, d2, d3", e.VMLS(D1, D2, D3));
|
|
DIS("VNMLA.f32 s7, s8, s9", e.VNMLA(S7, S8, S9));
|
|
DIS("VNMLA.f64 d1, d2, d3", e.VNMLA(D1, D2, D3));
|
|
DIS("VNMLS.f32 s7, s8, s9", e.VNMLS(S7, S8, S9));
|
|
DIS("VNMLS.f64 d30, d31, d29", e.VNMLS(D30, D31, D29));
|
|
DIS("VDIV.f32 s1, s2, s3", e.VDIV(S1, S2, S3));
|
|
DIS("VDIV.f64 d1, d2, d3", e.VDIV(D1, D2, D3));
|
|
DIS("VSQRT.f32 s1, s2", e.VSQRT(S1, S2));
|
|
DIS("VSQRT.f64 d10, d11", e.VSQRT(D10, D11));
|
|
DIS("VABS.f32 s1, s2", e.VABS(S1, S2));
|
|
DIS("VABS.f64 d3, d4", e.VABS(D3, D4));
|
|
DIS("VNEG.f32 s1, s2", e.VNEG(S1, S2));
|
|
DIS("VNEG.f64 d18, d19", e.VNEG(D18, D19));
|
|
DIS("VCMP.f32 s1, s2", e.VCMP(S1, S2));
|
|
DIS("VCMP.f64 d1, d2", e.VCMP(D1, D2));
|
|
DIS("VCMP.f32 s5, #0.0", e.VCMP(S5));
|
|
DIS("VCMP.f64 d6, #0.0", e.VCMP(D6));
|
|
DIS("VCMPE.f32 s1, s2", e.VCMPE(S1, S2));
|
|
DIS("VCMPE.f64 d3, d4", e.VCMPE(D3, D4));
|
|
DIS("VCMPE.f32 s7, #0.0", e.VCMPE(S7));
|
|
DIS("VCMPE.f64 d8, #0.0", e.VCMPE(D8));
|
|
DIS("VADDNE.f32 s0, s1, s2", e.SetCC(CC_NEQ); e.VADD(S0, S1, S2); e.SetCC());
|
|
|
|
// VFP moves
|
|
DIS("VMOV.f32 s1, s2", e.VMOV(S1, S2));
|
|
DIS("VMOV.f32 s25, s21", e.VMOV(S25, S21));
|
|
DIS("VMOV.f64 d1, d2", e.VMOV(D1, D2));
|
|
DIS("VMOV.f64 d26, d30", e.VMOV(D26, D30));
|
|
DIS("VMOV s9, r3", e.VMOV(S9, R3));
|
|
DIS("VMOV s31, r0", e.VMOV(S31, R0));
|
|
DIS("VMOV r9, s3", e.VMOV(R9, S3));
|
|
DIS("VMOV r0, s30", e.VMOV(R0, S30));
|
|
DIS("VMOV d0, r1, r2", e.VMOV(D0, R1, R2));
|
|
DIS("VMOV d17, r3, r4", e.VMOV(D17, R3, R4));
|
|
DIS("VMOV r1, r2, d0", e.VMOV(R1, R2, D0));
|
|
DIS("VMOV r5, r6, d31", e.VMOV(R5, R6, D31));
|
|
DIS("VMOV.32 d1[0], r2", e.VMOV(D1, R2, false));
|
|
DIS("VMOV.32 d20[1], r3", e.VMOV(D20, R3, true));
|
|
DIS("VMOV.f32 s0, #1.0", e.VMOV(S0, IMM(0x70)));
|
|
DIS("VMOV.f64 d1, #-0.5", e.VMOV(D1, IMM(0xE0)));
|
|
DIS("VMOV.f32 s0, #1.0", e.MOVI2F(S0, 1.0f, R12));
|
|
DIS("MOVW r12, #0xcccd; MOVT r12, #0x3dcc; VMOV s1, r12", e.MOVI2F(S1, 0.1f, R12));
|
|
DIS("VMOV.f32 s2, #-2.0", e.MOVI2F(S2, 2.0f, R12, true));
|
|
DIS("MOV r0, #0x3f800000", e.MOVI2FR(R0, 1.0f));
|
|
DIS("MOV r1, #0xbf000000", e.MOVI2FR(R1, -0.5f));
|
|
DIS("MVN r12, #0x80000000; VMOV s3, r12", e.MOVIU2F(S3, 0x7FFFFFFF, R12));
|
|
DIS("VMRS r1, fpscr", e.VMRS(R1));
|
|
DIS("VMRS r12, fpscr", e.VMRS(R12));
|
|
DIS("VMSR fpscr, r7", e.VMSR(R7));
|
|
DIS("VMSR fpscr, r0", e.VMSR(R0));
|
|
DIS("VMRS APSR_nzcv, fpscr", e.VMRS_APSR());
|
|
DIS("VMRSEQ APSR_nzcv, fpscr", e.SetCC(CC_EQ); e.VMRS_APSR(); e.SetCC());
|
|
|
|
// VFP conversions
|
|
DIS("VCVTR.s32.f32 s0, s1", e.VCVT(S0, S1, TO_INT | IS_SIGNED));
|
|
DIS("VCVT.s32.f32 s0, s1", e.VCVT(S0, S1, TO_INT | IS_SIGNED | ROUND_TO_ZERO));
|
|
DIS("VCVTR.u32.f32 s2, s3", e.VCVT(S2, S3, TO_INT));
|
|
DIS("VCVT.u32.f32 s2, s3", e.VCVT(S2, S3, TO_INT | ROUND_TO_ZERO));
|
|
DIS("VCVT.f32.s32 s4, s5", e.VCVT(S4, S5, TO_FLOAT | IS_SIGNED));
|
|
DIS("VCVT.f32.u32 s4, s5", e.VCVT(S4, S5, TO_FLOAT));
|
|
DIS("VCVT.f64.f32 d0, s1", e.VCVT(D0, S1, TO_FLOAT));
|
|
DIS("VCVT.f32.f64 s0, d1", e.VCVT(S0, D1, TO_FLOAT));
|
|
DIS("VCVT.s32.f64 s0, d1", e.VCVT(S0, D1, TO_INT | IS_SIGNED | ROUND_TO_ZERO));
|
|
DIS("VCVT.f64.s32 d0, s1", e.VCVT(D0, S1, TO_INT | IS_SIGNED));
|
|
DIS("VCVT.f64.u32 d5, s7", e.VCVT(D5, S7, TO_INT));
|
|
DIS("VCVT.u32.f64 s6, d20", e.VCVT(S6, D20, TO_INT | ROUND_TO_ZERO));
|
|
}
|
|
|
|
static void TestNeonInstructions(DisasmChecker &c, ARMXEmitter &e) {
|
|
// Three registers of the same length
|
|
DIS("VADD.i8 d3, d4, d19", e.VADD(I_8, D3, D4, D19));
|
|
DIS("VADD.i32 q3, q4, q15", e.VADD(I_32, Q3, Q4, Q15));
|
|
DIS("VADD.f32 d3, d4, d19", e.VADD(F_32, D3, D4, D19));
|
|
DIS("VADD.f32 q11, q11, q10", e.VADD(F_32, Q11, Q11, Q10));
|
|
DIS("VADD.i8 d3, d4, d5", e.VADD(I_I8, D3, D4, D5));
|
|
DIS("VADD.i64 q1, q2, q3", e.VADD(I_I64, Q1, Q2, Q3));
|
|
DIS("VSUB.i16 q5, q6, q15", e.VSUB(I_16, Q5, Q6, Q15));
|
|
DIS("VSUB.i64 d0, d1, d2", e.VSUB(I_64, D0, D1, D2));
|
|
DIS("VSUB.f32 q1, q2, q3", e.VSUB(F_32, Q1, Q2, Q3));
|
|
DIS("VSUB.f32 d1, d2, d3", e.VSUB(F_32, D1, D2, D3));
|
|
DIS("VSUB.i32 q1, q2, q9", e.VSUB(I_I32, Q1, Q2, Q9));
|
|
DIS("VSUB.i8 q4, q5, q6", e.VSUB(I_I8, Q4, Q5, Q6));
|
|
DIS("VMUL.f32 q1, q2, q3", e.VMUL(F_32, Q1, Q2, Q3));
|
|
DIS("VMUL.f32 q13, q15, q14", e.VMUL(F_32, Q13, Q15, Q14));
|
|
DIS("VMUL.i16 d0, d1, d2", e.VMUL(I_16, D0, D1, D2));
|
|
DIS("VMUL.p8 q0, q1, q2", e.VMUL(I_8 | I_POLYNOMIAL, Q0, Q1, Q2));
|
|
DIS("VMLA.f32 q1, q2, q3", e.VMLA(F_32, Q1, Q2, Q3));
|
|
DIS("VMLA.i32 d1, d2, d3", e.VMLA(I_32, D1, D2, D3));
|
|
DIS("VMLS.f32 q1, q2, q3", e.VMLS(F_32, Q1, Q2, Q3));
|
|
DIS("VMLS.i16 q1, q2, q3", e.VMLS(I_16, Q1, Q2, Q3));
|
|
DIS("VFMA.f32 q1, q2, q3", e.VFMA(F_32, Q1, Q2, Q3));
|
|
DIS("VFMA.f32 d1, d2, d3", e.VFMA(F_32, D1, D2, D3));
|
|
DIS("VFMS.f32 q1, q2, q3", e.VFMS(F_32, Q1, Q2, Q3));
|
|
DIS("VFMS.f32 d16, d17, d18", e.VFMS(F_32, D16, D17, D18));
|
|
DIS("VABA.s8 d0, d1, d2", e.VABA(I_8 | I_SIGNED, D0, D1, D2));
|
|
DIS("VABA.u32 q0, q1, q2", e.VABA(I_32 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VABD.s16 d0, d1, d2", e.VABD(I_16 | I_SIGNED, D0, D1, D2));
|
|
DIS("VABD.u8 q0, q1, q2", e.VABD(I_8 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VABD.f32 d0, d1, d2", e.VABD(F_32, D0, D1, D2));
|
|
DIS("VABD.f32 q0, q1, q2", e.VABD(F_32, Q0, Q1, Q2));
|
|
DIS("VABD.f32 q0, q1, q2", e.VABD(I_I32, Q0, Q1, Q2));
|
|
DIS("VABD.f32 d0, d1, d2", e.VABD(I_I32, D0, D1, D2));
|
|
DIS("VACGE.f32 d0, d1, d2", e.VACGE(D0, D1, D2));
|
|
DIS("VACGE.f32 q0, q1, q2", e.VACGE(Q0, Q1, Q2));
|
|
DIS("VACGT.f32 d0, d1, d2", e.VACGT(D0, D1, D2));
|
|
DIS("VACGT.f32 q0, q1, q2", e.VACGT(Q0, Q1, Q2));
|
|
DIS("VACGE.f32 d0, d2, d1", e.VACLE(D0, D1, D2));
|
|
DIS("VACGE.f32 q0, q2, q1", e.VACLE(Q0, Q1, Q2));
|
|
DIS("VACGT.f32 d0, d2, d1", e.VACLT(D0, D1, D2));
|
|
DIS("VACGT.f32 q0, q2, q1", e.VACLT(Q0, Q1, Q2));
|
|
DIS("VCEQ.i8 d0, d1, d2", e.VCEQ(I_8, D0, D1, D2));
|
|
DIS("VCEQ.f32 q0, q1, q2", e.VCEQ(F_32, Q0, Q1, Q2));
|
|
DIS("VCGE.s16 d0, d1, d2", e.VCGE(I_16 | I_SIGNED, D0, D1, D2));
|
|
DIS("VCGE.u32 q0, q1, q2", e.VCGE(I_32 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VCGE.f32 q0, q1, q2", e.VCGE(F_32, Q0, Q1, Q2));
|
|
DIS("VCGT.u8 d0, d1, d2", e.VCGT(I_8 | I_UNSIGNED, D0, D1, D2));
|
|
DIS("VCGT.f32 q0, q1, q2", e.VCGT(F_32, Q0, Q1, Q2));
|
|
DIS("VCGE.s32 d0, d2, d1", e.VCLE(I_32 | I_SIGNED, D0, D1, D2));
|
|
DIS("VCGE.f32 q0, q2, q1", e.VCLE(F_32, Q0, Q1, Q2));
|
|
DIS("VCGT.u32 q8, q4, q8", e.VCLT(I_32 | I_UNSIGNED, Q8, Q8, Q4));
|
|
DIS("VCGT.f32 d0, d2, d1", e.VCLT(F_32, D0, D1, D2));
|
|
DIS("VTST.8 d0, d1, d2", e.VTST(I_8, D0, D1, D2));
|
|
DIS("VTST.32 q0, q1, q2", e.VTST(I_32, Q0, Q1, Q2));
|
|
DIS("VHADD.s8 d0, d1, d2", e.VHADD(I_8 | I_SIGNED, D0, D1, D2));
|
|
DIS("VHADD.u16 q0, q1, q2", e.VHADD(I_16 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VHSUB.s32 d0, d1, d2", e.VHSUB(I_32 | I_SIGNED, D0, D1, D2));
|
|
DIS("VHSUB.u8 q0, q1, q2", e.VHSUB(I_8 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VRHADD.s8 d0, d1, d2", e.VRHADD(I_8 | I_SIGNED, D0, D1, D2));
|
|
DIS("VRHADD.u16 q0, q1, q2", e.VRHADD(I_16 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VQADD.s8 d0, d1, d2", e.VQADD(I_8 | I_SIGNED, D0, D1, D2));
|
|
DIS("VQADD.u64 q0, q1, q2", e.VQADD(I_64 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VQSUB.s16 d0, d1, d2", e.VQSUB(I_16 | I_SIGNED, D0, D1, D2));
|
|
DIS("VQSUB.u32 q0, q1, q2", e.VQSUB(I_32 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VMAX.s8 d0, d1, d2", e.VMAX(I_8 | I_SIGNED, D0, D1, D2));
|
|
DIS("VMAX.u32 q0, q1, q2", e.VMAX(I_32 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VMAX.f32 q3, q4, q9", e.VMAX(F_32, Q3, Q4, Q9));
|
|
DIS("VMAX.f32 d3, d4, d5", e.VMAX(F_32, D3, D4, D5));
|
|
DIS("VMIN.s16 d0, d1, d2", e.VMIN(I_16 | I_SIGNED, D0, D1, D2));
|
|
DIS("VMIN.u8 q0, q1, q2", e.VMIN(I_8 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VMIN.f32 d3, d4, d19", e.VMIN(F_32, D3, D4, D19));
|
|
DIS("VMIN.f32 q3, q4, q5", e.VMIN(F_32, Q3, Q4, Q5));
|
|
DIS("VPADD.f32 d0, d0, d0", e.VPADD(F_32, D0, D0, D0));
|
|
DIS("VPADD.i16 d1, d2, d3", e.VPADD(I_16, D1, D2, D3));
|
|
DIS("VPMAX.f32 d0, d1, d2", e.VPMAX(F_32, D0, D1, D2));
|
|
DIS("VPMAX.u8 d0, d1, d2", e.VPMAX(I_8 | I_UNSIGNED, D0, D1, D2));
|
|
DIS("VPMIN.f32 d0, d1, d2", e.VPMIN(F_32, D0, D1, D2));
|
|
DIS("VPMIN.s32 d0, d1, d2", e.VPMIN(I_32 | I_SIGNED, D0, D1, D2));
|
|
DIS("VQDMULH.s16 d0, d1, d2", e.VQDMULH(I_16, D0, D1, D2));
|
|
DIS("VQDMULH.s32 q0, q1, q2", e.VQDMULH(I_32, Q0, Q1, Q2));
|
|
DIS("VQRDMULH.s16 d0, d1, d2", e.VQRDMULH(I_16, D0, D1, D2));
|
|
DIS("VQRDMULH.s32 q0, q1, q2", e.VQRDMULH(I_32, Q0, Q1, Q2));
|
|
DIS("VRECPS.f32 d0, d1, d2", e.VRECPS(D0, D1, D2));
|
|
DIS("VRECPS.f32 q0, q1, q2", e.VRECPS(Q0, Q1, Q2));
|
|
DIS("VRSQRTS.f32 d0, d1, d2", e.VRSQRTS(D0, D1, D2));
|
|
DIS("VRSQRTS.f32 q0, q1, q2", e.VRSQRTS(Q0, Q1, Q2));
|
|
DIS("VSHL.s8 d0, d1, d2", e.VSHL(I_8 | I_SIGNED, D0, D1, D2));
|
|
DIS("VSHL.u32 q0, q1, q2", e.VSHL(I_32 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VRSHL.s16 d0, d2, d1", e.VRSHL(I_16 | I_SIGNED, D0, D1, D2));
|
|
DIS("VRSHL.u64 q0, q2, q1", e.VRSHL(I_64 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VQSHL.s8 d0, d2, d1", e.VQSHL(I_8 | I_SIGNED, D0, D1, D2));
|
|
DIS("VQSHL.u32 q0, q2, q1", e.VQSHL(I_32 | I_UNSIGNED, Q0, Q1, Q2));
|
|
DIS("VQRSHL.s16 d0, d2, d1", e.VQRSHL(I_16 | I_SIGNED, D0, D1, D2));
|
|
DIS("VQRSHL.u8 q0, q2, q1", e.VQRSHL(I_8 | I_UNSIGNED, Q0, Q1, Q2));
|
|
|
|
// Bitwise
|
|
DIS("VAND q1, q2, q3", e.VAND(Q1, Q2, Q3));
|
|
DIS("VAND d1, d2, d3", e.VAND(D1, D2, D3));
|
|
DIS("VBIC q1, q2, q3", e.VBIC(Q1, Q2, Q3));
|
|
DIS("VBIC d1, d2, d3", e.VBIC(D1, D2, D3));
|
|
DIS("VEOR q0, q1, q2", e.VEOR(Q0, Q1, Q2));
|
|
DIS("VEOR d0, d0, d0", e.VEOR(D0, D0, D0));
|
|
DIS("VORR q1, q2, q3", e.VORR(Q1, Q2, Q3));
|
|
DIS("VORR d1, d2, d3", e.VORR(D1, D2, D3));
|
|
DIS("VORN q1, q2, q3", e.VORN(Q1, Q2, Q3));
|
|
DIS("VORN d1, d2, d3", e.VORN(D1, D2, D3));
|
|
DIS("VBIF q1, q2, q3", e.VBIF(Q1, Q2, Q3));
|
|
DIS("VBIF d1, d2, d3", e.VBIF(D1, D2, D3));
|
|
DIS("VBIT q1, q2, q3", e.VBIT(Q1, Q2, Q3));
|
|
DIS("VBIT d1, d2, d3", e.VBIT(D1, D2, D3));
|
|
DIS("VBSL q1, q2, q3", e.VBSL(Q1, Q2, Q3));
|
|
DIS("VBSL d1, d2, d3", e.VBSL(D1, D2, D3));
|
|
DIS("VMOV q14, q2", e.VMOV(Q14, Q2));
|
|
DIS("VMOV q1, q2", e.VMOV_neon(Q1, Q2));
|
|
|
|
// Three registers of different lengths
|
|
DIS("VADDL.s8 q0, d1, d2", e.VADDL(I_8 | I_SIGNED, Q0, D1, D2));
|
|
DIS("VADDL.u32 q8, d20, d21", e.VADDL(I_32 | I_UNSIGNED, Q8, D20, D21));
|
|
DIS("VADDW.s16 q0, q1, d4", e.VADDW(I_16 | I_SIGNED, Q0, Q1, D4));
|
|
DIS("VADDW.u8 q0, q1, d4", e.VADDW(I_8 | I_UNSIGNED, Q0, Q1, D4));
|
|
DIS("VSUBL.s8 q0, d1, d2", e.VSUBL(I_8 | I_SIGNED, Q0, D1, D2));
|
|
DIS("VSUBL.u16 q0, d1, d2", e.VSUBL(I_16 | I_UNSIGNED, Q0, D1, D2));
|
|
DIS("VSUBW.s32 q0, q1, d4", e.VSUBW(I_32 | I_SIGNED, Q0, Q1, D4));
|
|
DIS("VSUBW.u8 q0, q1, d4", e.VSUBW(I_8 | I_UNSIGNED, Q0, Q1, D4));
|
|
DIS("VADDHN.i16 d0, q1, q2", e.VADDHN(I_16, D0, Q1, Q2));
|
|
DIS("VADDHN.i64 d0, q1, q2", e.VADDHN(I_64, D0, Q1, Q2));
|
|
DIS("VRADDHN.i16 d0, q1, q2", e.VRADDHN(I_16, D0, Q1, Q2));
|
|
DIS("VRADDHN.i32 d0, q1, q2", e.VRADDHN(I_32, D0, Q1, Q2));
|
|
DIS("VSUBHN.i32 d0, q1, q2", e.VSUBHN(I_32, D0, Q1, Q2));
|
|
DIS("VSUBHN.i64 d0, q1, q2", e.VSUBHN(I_64, D0, Q1, Q2));
|
|
DIS("VRSUBHN.i16 d0, q1, q2", e.VRSUBHN(I_16, D0, Q1, Q2));
|
|
DIS("VRSUBHN.i64 d0, q1, q2", e.VRSUBHN(I_64, D0, Q1, Q2));
|
|
DIS("VABAL.s8 q0, d2, d3", e.VABAL(I_8 | I_SIGNED, Q0, D2, D3));
|
|
DIS("VABAL.u16 q0, d2, d3", e.VABAL(I_16 | I_UNSIGNED, Q0, D2, D3));
|
|
DIS("VABDL.s32 q0, d2, d3", e.VABDL(I_32 | I_SIGNED, Q0, D2, D3));
|
|
DIS("VABDL.u8 q0, d2, d3", e.VABDL(I_8 | I_UNSIGNED, Q0, D2, D3));
|
|
DIS("VMLAL.s8 q0, d2, d3", e.VMLAL(I_8 | I_SIGNED, Q0, D2, D3));
|
|
DIS("VMLAL.u32 q0, d2, d3", e.VMLAL(I_32 | I_UNSIGNED, Q0, D2, D3));
|
|
DIS("VMLSL.s16 q0, d2, d3", e.VMLSL(I_16 | I_SIGNED, Q0, D2, D3));
|
|
DIS("VMLSL.u8 q0, d2, d3", e.VMLSL(I_8 | I_UNSIGNED, Q0, D2, D3));
|
|
DIS("VMULL.s8 q0, d2, d3", e.VMULL(I_8 | I_SIGNED, Q0, D2, D3));
|
|
DIS("VMULL.u16 q0, d2, d3", e.VMULL(I_16 | I_UNSIGNED, Q0, D2, D3));
|
|
DIS("VMULL.p8 q0, d2, d3", e.VMULL(I_8 | I_POLYNOMIAL, Q0, D2, D3));
|
|
DIS("VQDMLAL.s16 q0, d2, d3", e.VQDMLAL(I_16, Q0, D2, D3));
|
|
DIS("VQDMLAL.s32 q0, d2, d3", e.VQDMLAL(I_32, Q0, D2, D3));
|
|
DIS("VQDMLSL.s16 q0, d2, d3", e.VQDMLSL(I_16, Q0, D2, D3));
|
|
DIS("VQDMLSL.s32 q0, d2, d3", e.VQDMLSL(I_32, Q0, D2, D3));
|
|
DIS("VQDMULL.s16 q0, d2, d3", e.VQDMULL(I_16, Q0, D2, D3));
|
|
DIS("VQDMULL.s32 q0, d2, d3", e.VQDMULL(I_32, Q0, D2, D3));
|
|
|
|
// Two registers and a scalar
|
|
DIS("VMUL.f32 q12, q8, d0[0]", e.VMUL_scalar(F_32, Q12, Q8, DScalar(D0, 0)));
|
|
DIS("VMUL.f32 q1, q2, d7[1]", e.VMUL_scalar(F_32, Q1, Q2, DScalar(D7, 1)));
|
|
DIS("VMUL.f32 d1, d2, d14[0]", e.VMUL_scalar(F_32, D1, D2, QScalar(Q7, 0)));
|
|
DIS("VMUL.f32 d1, d2, d15[1]", e.VMUL_scalar(F_32, D1, D2, QScalar(Q7, 3)));
|
|
DIS("VMLA.f32 q8, q13, d8[1]", e.VMLA_scalar(F_32, Q8, Q13, DScalar(D8, 1)));
|
|
DIS("VMLA.f32 q1, q2, d7[0]", e.VMLA_scalar(F_32, Q1, Q2, DScalar(D7, 0)));
|
|
DIS("VMLA.f32 d1, d2, d7[0]", e.VMLA_scalar(F_32, D1, D2, XScalar(Q3, 2)));
|
|
DIS("VMLA.f32 d1, d2, d3[1]", e.VMLA_scalar(F_32, D1, D2, XScalar(D3, 1)));
|
|
|
|
// Two registers, miscellaneous
|
|
DIS("VABS.f32 q1, q2", e.VABS(F_32, Q1, Q2));
|
|
DIS("VABS.s8 d1, d2", e.VABS(I_8, D1, D2));
|
|
DIS("VNEG.f32 q1, q2", e.VNEG(F_32, Q1, Q2));
|
|
DIS("VNEG.s32 d1, d2", e.VNEG(I_32, D1, D2));
|
|
DIS("VMVN q1, q13", e.VMVN(Q1, Q13));
|
|
DIS("VMVN d1, d2", e.VMVN(D1, D2));
|
|
DIS("VCEQ.i16 d0, d1, #0", e.VCEQ(I_16, D0, D1));
|
|
DIS("VCEQ.f32 q0, q1, #0", e.VCEQ(F_32, Q0, Q1));
|
|
DIS("VCGE.s8 d0, d1, #0", e.VCGE(I_8, D0, D1));
|
|
DIS("VCGE.f32 q0, q1, #0", e.VCGE(F_32, Q0, Q1));
|
|
DIS("VCGT.s32 q0, q1, #0", e.VCGT(I_32, Q0, Q1));
|
|
DIS("VCGT.f32 d0, d1, #0", e.VCGT(F_32, D0, D1));
|
|
DIS("VCLE.s16 d0, d1, #0", e.VCLE(I_16, D0, D1));
|
|
DIS("VCLE.f32 q0, q1, #0", e.VCLE(F_32, Q0, Q1));
|
|
DIS("VCLT.s8 q0, q1, #0", e.VCLT(I_8, Q0, Q1));
|
|
DIS("VCLT.f32 d0, d1, #0", e.VCLT(F_32, D0, D1));
|
|
DIS("VCLS.s8 d0, d1", e.VCLS(I_8, D0, D1));
|
|
DIS("VCLS.s32 q0, q1", e.VCLS(I_32, Q0, Q1));
|
|
DIS("VCLZ.i16 d0, d1", e.VCLZ(I_16, D0, D1));
|
|
DIS("VCLZ.i32 q0, q1", e.VCLZ(I_32, Q0, Q1));
|
|
DIS("VCNT.8 d0, d1", e.VCNT(I_8, D0, D1));
|
|
DIS("VCNT.8 q0, q1", e.VCNT(I_8, Q0, Q1));
|
|
DIS("VPADAL.s8 d0, d1", e.VPADAL(I_8 | I_SIGNED, D0, D1));
|
|
DIS("VPADAL.u32 q0, q1", e.VPADAL(I_32 | I_UNSIGNED, Q0, Q1));
|
|
DIS("VPADDL.s16 d0, d1", e.VPADDL(I_16 | I_SIGNED, D0, D1));
|
|
DIS("VPADDL.u8 q0, q1", e.VPADDL(I_8 | I_UNSIGNED, Q0, Q1));
|
|
DIS("VQABS.s8 d0, d1", e.VQABS(I_8, D0, D1));
|
|
DIS("VQABS.s32 q0, q1", e.VQABS(I_32, Q0, Q1));
|
|
DIS("VQNEG.s16 d0, d1", e.VQNEG(I_16, D0, D1));
|
|
DIS("VQNEG.s8 q0, q1", e.VQNEG(I_8, Q0, Q1));
|
|
DIS("VRECPE.f32 q0, q1", e.VRECPE(F_32, Q0, Q1));
|
|
DIS("VRECPE.u32 d0, d1", e.VRECPE(I_32, D0, D1));
|
|
DIS("VRSQRTE.f32 q0, q1", e.VRSQRTE(F_32, Q0, Q1));
|
|
DIS("VRSQRTE.u32 d0, d1", e.VRSQRTE(I_32, D0, D1));
|
|
DIS("VSWP q0, q1", e.VSWP(Q0, Q1));
|
|
DIS("VSWP d0, d1", e.VSWP(D0, D1));
|
|
DIS("VTRN.8 d0, d1", e.VTRN(I_8, D0, D1));
|
|
DIS("VTRN.32 q0, q1", e.VTRN(I_32, Q0, Q1));
|
|
DIS("VUZP.16 d0, d1", e.VUZP(I_16, D0, D1));
|
|
DIS("VUZP.8 q0, q1", e.VUZP(I_8, Q0, Q1));
|
|
DIS("VZIP.8 d0, d1", e.VZIP(I_8, D0, D1));
|
|
DIS("VZIP.16 q0, q1", e.VZIP(I_16, Q0, Q1));
|
|
DIS("VREV64.8 d0, d1", e.VREV64(I_8, D0, D1));
|
|
DIS("VREV64.32 q0, q1", e.VREV64(I_32, Q0, Q1));
|
|
DIS("VREV32.16 d0, d1", e.VREV32(I_16, D0, D1));
|
|
DIS("VREV32.8 q0, q1", e.VREV32(I_8, Q0, Q1));
|
|
DIS("VREV16.8 d0, d1", e.VREV16(I_8, D0, D1));
|
|
DIS("VREV16.8 q2, q3", e.VREV16(I_8, Q2, Q3));
|
|
DIS("VMOVN.i32 d1, q2", e.VMOVN(I_32, D1, Q2));
|
|
DIS("VMOVN.i16 d0, q15", e.VMOVN(I_16, D0, Q15));
|
|
DIS("VQMOVN.s32 d1, q2", e.VQMOVN(I_32 | I_SIGNED, D1, Q2));
|
|
DIS("VQMOVN.u64 d1, q2", e.VQMOVN(I_64 | I_UNSIGNED, D1, Q2));
|
|
DIS("VQMOVUN.s16 d1, q2", e.VQMOVUN(I_16, D1, Q2));
|
|
DIS("VQMOVUN.s32 d1, q2", e.VQMOVUN(I_32, D1, Q2));
|
|
DIS("VCVT.f32.u32 q0, q1", e.VCVT(F_32 | I_UNSIGNED, Q0, Q1));
|
|
DIS("VCVT.f32.s32 d0, d1", e.VCVT(F_32 | I_SIGNED, D0, D1));
|
|
DIS("VCVT.u32.f32 q2, q2", e.VCVT(I_32 | I_UNSIGNED, Q2, Q2));
|
|
DIS("VCVT.s32.f32 d2, d3", e.VCVT(I_32 | I_SIGNED, D2, D3));
|
|
DIS("VCVT.f32.f16 q0, d2", e.VCVTF32F16(Q0, D2));
|
|
DIS("VCVT.f32.f16 q8, d15", e.VCVTF32F16(Q8, D15));
|
|
DIS("VCVT.f16.f32 d0, q1", e.VCVTF16F32(D0, Q1));
|
|
DIS("VCVT.f16.f32 d15, q8", e.VCVTF16F32(D15, Q8));
|
|
|
|
// VEXT, VDUP and moves to and from core registers
|
|
DIS("VEXT.8 d0, d1, d2, #3", e.VEXT(D0, D1, D2, 3));
|
|
DIS("VEXT.8 q0, q1, q2, #15", e.VEXT(Q0, Q1, Q2, 15));
|
|
DIS("VDUP.32 q14, d30[1]", e.VDUP(F_32, Q14, D30, 1));
|
|
DIS("VDUP.32 d14, d30[1]", e.VDUP(F_32, D14, D30, 1));
|
|
DIS("VDUP.8 d0, d1[7]", e.VDUP(I_8, D0, D1, 7));
|
|
DIS("VDUP.16 q0, d1[3]", e.VDUP(I_16, Q0, D1, 3));
|
|
DIS("VDUP.32 q0, r0", e.VDUP(I_32, Q0, R0));
|
|
DIS("VDUP.32 q5, r3", e.VDUP(I_32, Q5, R3));
|
|
DIS("VDUP.16 q2, r7", e.VDUP(I_16, Q2, R7));
|
|
DIS("VDUP.32 d0, r0", e.VDUP(I_32, D0, R0));
|
|
DIS("VDUP.16 d3, r5", e.VDUP(I_16, D3, R5));
|
|
DIS("VDUP.8 q1, r2", e.VDUP(I_8, Q1, R2));
|
|
DIS("VMOV.32 d5[1], r4", e.VMOV_neon(F_32, D5, R4, 1));
|
|
DIS("VMOV.8 d0[6], r1", e.VMOV_neon(I_8, D0, R1, 6));
|
|
DIS("VMOV.16 d20[3], r1", e.VMOV_neon(I_16, D20, R1, 3));
|
|
DIS("VMOV.32 r2, d4[0]", e.VMOV_neon(I_32, R2, D4, 0));
|
|
DIS("VMOV.u8 r2, d4[5]", e.VMOV_neon(I_8 | I_UNSIGNED, R2, D4, 5));
|
|
DIS("VMOV.s16 r2, d17[2]", e.VMOV_neon(I_16 | I_SIGNED, R2, D17, 2));
|
|
|
|
// Immediates
|
|
DIS("VMOV.i32 d0, #0xf3", e.VMOV_imm(I_32, D0, VIMM___x___x, 0xF3));
|
|
DIS("VMOV.i32 q1, #0x12000000", e.VMOV_imm(I_32, Q1, VIMMx___x___, 0x12));
|
|
DIS("VMOV.i16 d0, #0x80", e.VMOV_imm(I_16, D0, VIMM_x_x_x_x, 0x80));
|
|
DIS("VMOV.i16 q0, #0x7f00", e.VMOV_imm(I_16, Q0, VIMMx_x_x_x_, 0x7F));
|
|
DIS("VMOV.i8 q0, #0xf3", e.VMOV_imm(I_8, Q0, VIMMxxxxxxxx, 0xF3));
|
|
DIS("VMOV.i64 d1, #0xff000000000000ff", e.VMOV_imm(I_64, D1, VIMMbits2bytes, 0x81));
|
|
DIS("VMOV.f32 q0, #1.0", e.VMOV_immf(Q0, 1.0f));
|
|
DIS("VMOV.f32 d0, #-1.0", e.VMOV_immf(D0, -1.0f));
|
|
DIS("VMOV.f32 q2, #1.5", e.VMOV_immf(Q2, 1.5f));
|
|
DIS("VEOR q3, q3, q3", e.VMOV_immf(Q3, 0.0f));
|
|
DIS("VORR.i32 d0, #0xf300", e.VORR_imm(I_32, D0, VIMM__x___x_, 0xF3));
|
|
DIS("VORR.i16 q0, #0x1", e.VORR_imm(I_16, Q0, VIMM_x_x_x_x, 0x01));
|
|
DIS("VBIC.i32 q0, #0xf30000", e.VBIC_imm(I_32, Q0, VIMM_x___x__, 0xF3));
|
|
DIS("VBIC.i16 d0, #0xff00", e.VBIC_imm(I_16, D0, VIMMx_x_x_x_, 0xFF));
|
|
DIS("VMVN.i32 d0, #0xf3", e.VMVN_imm(I_32, D0, VIMM___x___x, 0xF3));
|
|
DIS("VMVN.i16 q0, #0x2", e.VMVN_imm(I_16, Q0, VIMM_x_x_x_x, 0x02));
|
|
DIS("VMOV.i32 q0, #0xab", e.VMOV_neon(I_32, Q0, (u32)0x000000AB));
|
|
DIS("VMOV.i32 d0, #0xab00", e.VMOV_neon(I_32, D0, (u32)0x0000AB00));
|
|
DIS("VMOV.i32 d0, #0xab0000", e.VMOV_neon(I_32, D0, (u32)0x00AB0000));
|
|
DIS("VMOV.i32 d0, #0xab000000", e.VMOV_neon(I_32, D0, (u32)0xAB000000));
|
|
DIS("VMOV.i16 d0, #0xab", e.VMOV_neon(I_16, D0, (u32)0x00AB));
|
|
DIS("VMOV.i16 q0, #0xab00", e.VMOV_neon(I_16, Q0, (u32)0xAB00));
|
|
DIS("VMOV.i32 d0, #0xabff", e.VMOV_neon(I_32, D0, (u32)0x0000ABFF));
|
|
DIS("VMOV.i32 d0, #0xabffff", e.VMOV_neon(I_32, D0, (u32)0x00ABFFFF));
|
|
DIS("VMOV.i8 q0, #0x5a", e.VMOV_neon(I_8, Q0, (u32)0x5A));
|
|
DIS("VMOV.f32 q0, #1.0", e.VMOV_neon(I_32, Q0, (u32)0x3F800000));
|
|
DIS("VMOV.i16 q0, #0xff00", e.VMOV_neon(I_32, Q0, (u32)0xFF00FF00));
|
|
DIS("VMOV.i32 q1, #0x40000000", e.VMOV_neon(F_32, Q1, 2.0f));
|
|
DIS("VMOV.f32 q0, #1.0", e.MOVI2F_neon(Q0, 1.0f, R12));
|
|
DIS("MOVW r12, #0xcccd; MOVT r12, #0x3dcc; VDUP.32 d0, r12", e.MOVI2F_neon(D0, 0.1f, R12));
|
|
|
|
// Shifts by immediate
|
|
DIS("VSHL.i8 d1, d2, #7", e.VSHL(I_8, D1, D2, 7));
|
|
DIS("VSHL.i64 q1, q2, #33", e.VSHL(I_64, Q1, Q2, 33));
|
|
DIS("VSHLL.i16 q0, d0, #16", e.VSHLL(I_16, Q0, D0, 16));
|
|
DIS("VSHLL.i8 q0, d0, #8", e.VSHLL(I_8, Q0, D0, 8));
|
|
DIS("VSHLL.s8 q0, d0, #4", e.VSHLL(I_8, Q0, D0, 4));
|
|
DIS("VSHLL.s32 q1, d2, #17", e.VSHLL(I_32, Q1, D2, 17));
|
|
DIS("VSHLL.u16 q1, d2, #3", e.VSHLL(I_16 | I_UNSIGNED, Q1, D2, 3));
|
|
DIS("VSHR.u32 q1, q2, #19", e.VSHR(I_32 | I_UNSIGNED, Q1, Q2, 19));
|
|
DIS("VSHR.s64 q1, q2, #36", e.VSHR(I_64, Q1, Q2, 36));
|
|
DIS("VSHR.s8 d1, d2, #8", e.VSHR(I_8 | I_SIGNED, D1, D2, 8));
|
|
DIS("VSHRN.i32 d0, q0, #16", e.VSHRN(I_32, D0, Q0, 16));
|
|
DIS("VSHRN.i64 d1, q2, #24", e.VSHRN(I_64, D1, Q2, 24));
|
|
DIS("VSHRN.i32 d1, q2, #8", e.VSHRN(I_32, D1, Q2, 8));
|
|
DIS("VSHRN.i16 d1, q2, #1", e.VSHRN(I_16, D1, Q2, 1));
|
|
DIS("VMOVL.u16 q0, d0", e.VMOVL(I_16 | I_UNSIGNED, Q0, D0));
|
|
DIS("VMOVL.s32 q0, d0", e.VMOVL(I_32 | I_SIGNED, Q0, D0));
|
|
DIS("VMOVL.u8 q8, d31", e.VMOVL(I_8 | I_UNSIGNED, Q8, D31));
|
|
|
|
// Element and structure loads and stores
|
|
DIS("VLD1.32 {d19-d20}, [r3]", e.VLD1(I_32, D19, R3, 2, ALIGN_NONE, R_PC));
|
|
DIS("VLD1.32 {d0-d3}, [r0:128]!", e.VLD1(F_32, D0, R0, 4, ALIGN_128, REG_UPDATE));
|
|
DIS("VLD1.8 {d16-d18}, [r1:64], r2", e.VLD1(I_8, D16, R1, 3, ALIGN_64, R2));
|
|
DIS("VLD1.64 {d2}, [r4]", e.VLD1(I_64, D2, R4, 1));
|
|
DIS("VST1.32 {d23}, [r9]", e.VST1(I_32, D23, R9, 1, ALIGN_NONE, R_PC));
|
|
DIS("VST1.16 {d0-d1}, [sp:128]!", e.VST1(I_16, D0, R_SP, 2, ALIGN_128, REG_UPDATE));
|
|
DIS("VST1.32 {d8-d11}, [r0:256]", e.VST1(F_32, D8, R0, 4, ALIGN_256));
|
|
DIS("VLD1.32 {d8[0]}, [r3]", e.VLD1_lane(F_32, D8, R3, 0, false));
|
|
DIS("VLD1.8 {d8[2]}, [r3]", e.VLD1_lane(I_8, D8, R3, 2, false));
|
|
DIS("VLD1.16 {d0[3]}, [r1:16]!", e.VLD1_lane(I_16, D0, R1, 3, true, REG_UPDATE));
|
|
DIS("VLD1.32 {d3[1]}, [r1:32], r2", e.VLD1_lane(I_32, Q1, R1, 3, true, R2));
|
|
DIS("VST1.32 {d8[1]}, [r3]", e.VST1_lane(I_32, D8, R3, 1, false));
|
|
DIS("VST1.8 {d5[2]}, [r3]", e.VST1_lane(I_8, Q2, R3, 10, false));
|
|
DIS("VLD1.32 {d0[], d1[]}, [r0:32]", e.VLD1_all_lanes(F_32, Q0, R0, true));
|
|
DIS("VLD1.16 {d2[]}, [r1]!", e.VLD1_all_lanes(I_16, D2, R1, false, REG_UPDATE));
|
|
DIS("VLD1.8 {d2[]}, [r1], r3", e.VLD1_all_lanes(I_8, D2, R1, false, R3));
|
|
}
|
|
|
|
bool TestArmDisasm() {
|
|
static u32 code[4096];
|
|
const u8 *base = (const u8 *)code;
|
|
ARMXEmitter emitter((u8 *)code);
|
|
DisasmChecker checker{ emitter, base };
|
|
|
|
// These assert on CPU features, which we don't care about when only encoding.
|
|
bool vfpv4 = cpu_info.bVFPv4;
|
|
bool idiva = cpu_info.bIDIVa;
|
|
cpu_info.bVFPv4 = true;
|
|
cpu_info.bIDIVa = true;
|
|
|
|
TestIntegerInstructions(checker, emitter, base);
|
|
emitter.SetCodePointer((u8 *)base + 0x2000, (u8 *)base + 0x2000);
|
|
TestFloatInstructions(checker, emitter);
|
|
TestNeonInstructions(checker, emitter);
|
|
|
|
cpu_info.bVFPv4 = vfpv4;
|
|
cpu_info.bIDIVa = idiva;
|
|
|
|
printf("%d of %d ARM disassembly checks failed\n", checker.failures, checker.checks);
|
|
return checker.failures == 0;
|
|
}
|