dynarmic_tests: Remove skyeye interpreter
This is quite a messy interpreter and would require a large amount of work to bring it up to speed to begin implementing newer portions of the AArch32 instruction set into Dynarmic. Given we already have fuzzing with Unicorn set up for AArch64/AArch32, we can get rid of this and unify our testing infrastructure. This will also make building the tests much faster, given a whole interpreter doesn't need to be built anymore as part of the project.
This commit is contained in:
parent
d29582a0e1
commit
4f2b60c8e7
23 changed files with 2 additions and 14534 deletions
|
@ -1,470 +0,0 @@
|
|||
// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "A32/skyeye_interpreter/dyncom/arm_dyncom_dec.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armsupp.h"
|
||||
|
||||
const InstructionSetEncodingItem arm_instruction[] = {
|
||||
{ "vmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }},
|
||||
{ "vmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }},
|
||||
{ "vnmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }},
|
||||
{ "vnmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }},
|
||||
{ "vnmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }},
|
||||
{ "vmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }},
|
||||
{ "vadd", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }},
|
||||
{ "vsub", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }},
|
||||
{ "vdiv", 5, ARMVFP2, { 23, 27, 0x1D, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }},
|
||||
{ "vmov(i)", 4, ARMVFP3, { 23, 27, 0x1D, 20, 21, 0x3, 9, 11, 0x5, 4, 7, 0 }},
|
||||
{ "vmov(r)", 5, ARMVFP3, { 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 }},
|
||||
{ "vabs", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }},
|
||||
{ "vneg", 5, ARMVFP2, { 23, 27, 0x1D, 17, 21, 0x18, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 }},
|
||||
{ "vsqrt", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x31, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }},
|
||||
{ "vcmp", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x34, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }},
|
||||
{ "vcmp2", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x35, 9, 11, 0x5, 0, 6, 0x40 }},
|
||||
{ "vcvt(bds)", 5, ARMVFP2, { 23, 27, 0x1D, 16, 21, 0x37, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 }},
|
||||
{ "vcvt(bff)", 6, ARMVFP3, { 23, 27, 0x1D, 19, 21, 0x7, 17, 17, 0x1, 9, 11, 5, 6, 6, 1 }},
|
||||
{ "vcvt(bfi)", 5, ARMVFP2, { 23, 27, 0x1D, 19, 21, 0x7, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }},
|
||||
{ "vmovbrs", 3, ARMVFP2, { 21, 27, 0x70, 8, 11, 0xA, 0, 6, 0x10 }},
|
||||
{ "vmsr", 2, ARMVFP2, { 20, 27, 0xEE, 0, 11, 0xA10 }},
|
||||
{ "vmovbrc", 4, ARMVFP2, { 23, 27, 0x1C, 20, 20, 0x0, 8, 11, 0xB, 0, 4, 0x10 }},
|
||||
{ "vmrs", 2, ARMVFP2, { 20, 27, 0xEF, 0, 11, 0xA10 }},
|
||||
{ "vmovbcr", 4, ARMVFP2, { 24, 27, 0xE, 20, 20, 1, 8, 11, 0xB, 0, 4, 0x10 }},
|
||||
{ "vmovbrrss", 3, ARMVFP2, { 21, 27, 0x62, 8, 11, 0xA, 4, 4, 1 }},
|
||||
{ "vmovbrrd", 3, ARMVFP2, { 21, 27, 0x62, 6, 11, 0x2C, 4, 4, 1 }},
|
||||
{ "vstr", 3, ARMVFP2, { 24, 27, 0xD, 20, 21, 0, 9, 11, 5 }},
|
||||
{ "vpush", 3, ARMVFP2, { 23, 27, 0x1A, 16, 21, 0x2D, 9, 11, 5 }},
|
||||
{ "vstm", 3, ARMVFP2, { 25, 27, 0x6, 20, 20, 0, 9, 11, 5 }},
|
||||
{ "vpop", 3, ARMVFP2, { 23, 27, 0x19, 16, 21, 0x3D, 9, 11, 5 }},
|
||||
{ "vldr", 3, ARMVFP2, { 24, 27, 0xD, 20, 21, 1, 9, 11, 5 }},
|
||||
{ "vldm", 3, ARMVFP2, { 25, 27, 0x6, 20, 20, 1, 9, 11, 5 }},
|
||||
|
||||
{ "srs", 4, 6, { 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005 }},
|
||||
{ "rfe", 4, 6, { 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a }},
|
||||
{ "bkpt", 2, 3, { 20, 27, 0x00000012, 4, 7, 0x00000007 }},
|
||||
{ "blx", 1, 3, { 25, 31, 0x0000007d }},
|
||||
{ "cps", 3, 6, { 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000 }},
|
||||
{ "pld", 4, 4, { 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f }},
|
||||
{ "setend", 2, 6, { 16, 31, 0x0000f101, 4, 7, 0x00000000 }},
|
||||
{ "clrex", 1, 6, { 0, 31, 0xf57ff01f }},
|
||||
{ "rev16", 2, 6, { 16, 27, 0x000006bf, 4, 11, 0x000000fb }},
|
||||
{ "usad8", 3, 6, { 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001 }},
|
||||
{ "sxtb", 2, 6, { 16, 27, 0x000006af, 4, 7, 0x00000007 }},
|
||||
{ "uxtb", 2, 6, { 16, 27, 0x000006ef, 4, 7, 0x00000007 }},
|
||||
{ "sxth", 2, 6, { 16, 27, 0x000006bf, 4, 7, 0x00000007 }},
|
||||
{ "sxtb16", 2, 6, { 16, 27, 0x0000068f, 4, 7, 0x00000007 }},
|
||||
{ "uxth", 2, 6, { 16, 27, 0x000006ff, 4, 7, 0x00000007 }},
|
||||
{ "uxtb16", 2, 6, { 16, 27, 0x000006cf, 4, 7, 0x00000007 }},
|
||||
{ "cpy", 2, 6, { 20, 27, 0x0000001a, 4, 11, 0x00000000 }},
|
||||
{ "uxtab", 2, 6, { 20, 27, 0x0000006e, 4, 9, 0x00000007 }},
|
||||
{ "ssub8", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x0000000f }},
|
||||
{ "shsub8", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x0000000f }},
|
||||
{ "ssubaddx", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000005 }},
|
||||
{ "strex", 2, 6, { 20, 27, 0x00000018, 4, 7, 0x00000009 }},
|
||||
{ "strexb", 2, 7, { 20, 27, 0x0000001c, 4, 7, 0x00000009 }},
|
||||
{ "swp", 2, 0, { 20, 27, 0x00000010, 4, 7, 0x00000009 }},
|
||||
{ "swpb", 2, 0, { 20, 27, 0x00000014, 4, 7, 0x00000009 }},
|
||||
{ "ssub16", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000007 }},
|
||||
{ "ssat16", 2, 6, { 20, 27, 0x0000006a, 4, 7, 0x00000003 }},
|
||||
{ "shsubaddx", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000005 }},
|
||||
{ "qsubaddx", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000005 }},
|
||||
{ "shaddsubx", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000003 }},
|
||||
{ "shadd8", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000009 }},
|
||||
{ "shadd16", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000001 }},
|
||||
{ "sel", 2, 6, { 20, 27, 0x00000068, 4, 7, 0x0000000b }},
|
||||
{ "saddsubx", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000003 }},
|
||||
{ "sadd8", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000009 }},
|
||||
{ "sadd16", 2, 6, { 20, 27, 0x00000061, 4, 7, 0x00000001 }},
|
||||
{ "shsub16", 2, 6, { 20, 27, 0x00000063, 4, 7, 0x00000007 }},
|
||||
{ "umaal", 2, 6, { 20, 27, 0x00000004, 4, 7, 0x00000009 }},
|
||||
{ "uxtab16", 2, 6, { 20, 27, 0x0000006c, 4, 7, 0x00000007 }},
|
||||
{ "usubaddx", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000005 }},
|
||||
{ "usub8", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x0000000f }},
|
||||
{ "usub16", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000007 }},
|
||||
{ "usat16", 2, 6, { 20, 27, 0x0000006e, 4, 7, 0x00000003 }},
|
||||
{ "usada8", 2, 6, { 20, 27, 0x00000078, 4, 7, 0x00000001 }},
|
||||
{ "uqsubaddx", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000005 }},
|
||||
{ "uqsub8", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x0000000f }},
|
||||
{ "uqsub16", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000007 }},
|
||||
{ "uqaddsubx", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000003 }},
|
||||
{ "uqadd8", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000009 }},
|
||||
{ "uqadd16", 2, 6, { 20, 27, 0x00000066, 4, 7, 0x00000001 }},
|
||||
{ "sxtab", 2, 6, { 20, 27, 0x0000006a, 4, 7, 0x00000007 }},
|
||||
{ "uhsubaddx", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000005 }},
|
||||
{ "uhsub8", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x0000000f }},
|
||||
{ "uhsub16", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000007 }},
|
||||
{ "uhaddsubx", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000003 }},
|
||||
{ "uhadd8", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000009 }},
|
||||
{ "uhadd16", 2, 6, { 20, 27, 0x00000067, 4, 7, 0x00000001 }},
|
||||
{ "uaddsubx", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000003 }},
|
||||
{ "uadd8", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000009 }},
|
||||
{ "uadd16", 2, 6, { 20, 27, 0x00000065, 4, 7, 0x00000001 }},
|
||||
{ "sxtah", 2, 6, { 20, 27, 0x0000006b, 4, 7, 0x00000007 }},
|
||||
{ "sxtab16", 2, 6, { 20, 27, 0x00000068, 4, 7, 0x00000007 }},
|
||||
{ "qadd8", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000009 }},
|
||||
{ "bxj", 2, 5, { 20, 27, 0x00000012, 4, 7, 0x00000002 }},
|
||||
{ "clz", 2, 3, { 20, 27, 0x00000016, 4, 7, 0x00000001 }},
|
||||
{ "uxtah", 2, 6, { 20, 27, 0x0000006f, 4, 7, 0x00000007 }},
|
||||
{ "bx", 2, 2, { 20, 27, 0x00000012, 4, 7, 0x00000001 }},
|
||||
{ "rev", 2, 6, { 20, 27, 0x0000006b, 4, 7, 0x00000003 }},
|
||||
{ "blx", 2, 3, { 20, 27, 0x00000012, 4, 7, 0x00000003 }},
|
||||
{ "revsh", 2, 6, { 20, 27, 0x0000006f, 4, 7, 0x0000000b }},
|
||||
{ "qadd", 2, 4, { 20, 27, 0x00000010, 4, 7, 0x00000005 }},
|
||||
{ "qadd16", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000001 }},
|
||||
{ "qaddsubx", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000003 }},
|
||||
{ "ldrex", 2, 0, { 20, 27, 0x00000019, 4, 7, 0x00000009 }},
|
||||
{ "qdadd", 2, 4, { 20, 27, 0x00000014, 4, 7, 0x00000005 }},
|
||||
{ "qdsub", 2, 4, { 20, 27, 0x00000016, 4, 7, 0x00000005 }},
|
||||
{ "qsub", 2, 4, { 20, 27, 0x00000012, 4, 7, 0x00000005 }},
|
||||
{ "ldrexb", 2, 7, { 20, 27, 0x0000001d, 4, 7, 0x00000009 }},
|
||||
{ "qsub8", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x0000000f }},
|
||||
{ "qsub16", 2, 6, { 20, 27, 0x00000062, 4, 7, 0x00000007 }},
|
||||
{ "smuad", 4, 6, { 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 }},
|
||||
{ "smmul", 4, 6, { 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 }},
|
||||
{ "smusd", 4, 6, { 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001 }},
|
||||
{ "smlsd", 3, 6, { 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001 }},
|
||||
{ "smlsld", 3, 6, { 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001 }},
|
||||
{ "smmla", 3, 6, { 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001 }},
|
||||
{ "smmls", 3, 6, { 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001 }},
|
||||
{ "smlald", 3, 6, { 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001 }},
|
||||
{ "smlad", 3, 6, { 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001 }},
|
||||
{ "smlaw", 3, 4, { 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000 }},
|
||||
{ "smulw", 3, 4, { 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002 }},
|
||||
{ "pkhtb", 2, 6, { 20, 27, 0x00000068, 4, 6, 0x00000005 }},
|
||||
{ "pkhbt", 2, 6, { 20, 27, 0x00000068, 4, 6, 0x00000001 }},
|
||||
{ "smul", 3, 4, { 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000 }},
|
||||
{ "smlalxy", 3, 4, { 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000 }},
|
||||
{ "smla", 3, 4, { 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000 }},
|
||||
{ "mcrr", 1, 6, { 20, 27, 0x000000c4 }},
|
||||
{ "mrrc", 1, 6, { 20, 27, 0x000000c5 }},
|
||||
{ "cmp", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000015 }},
|
||||
{ "tst", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000011 }},
|
||||
{ "teq", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000013 }},
|
||||
{ "cmn", 2, 0, { 26, 27, 0x00000000, 20, 24, 0x00000017 }},
|
||||
{ "smull", 2, 0, { 21, 27, 0x00000006, 4, 7, 0x00000009 }},
|
||||
{ "umull", 2, 0, { 21, 27, 0x00000004, 4, 7, 0x00000009 }},
|
||||
{ "umlal", 2, 0, { 21, 27, 0x00000005, 4, 7, 0x00000009 }},
|
||||
{ "smlal", 2, 0, { 21, 27, 0x00000007, 4, 7, 0x00000009 }},
|
||||
{ "mul", 2, 0, { 21, 27, 0x00000000, 4, 7, 0x00000009 }},
|
||||
{ "mla", 2, 0, { 21, 27, 0x00000001, 4, 7, 0x00000009 }},
|
||||
{ "ssat", 2, 6, { 21, 27, 0x00000035, 4, 5, 0x00000001 }},
|
||||
{ "usat", 2, 6, { 21, 27, 0x00000037, 4, 5, 0x00000001 }},
|
||||
{ "mrs", 4, 0, { 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000 }},
|
||||
{ "msr", 3, 0, { 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000 }},
|
||||
{ "and", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000000 }},
|
||||
{ "bic", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000e }},
|
||||
{ "ldm", 3, 0, { 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000 }},
|
||||
{ "eor", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000001 }},
|
||||
{ "add", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000004 }},
|
||||
{ "rsb", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000003 }},
|
||||
{ "rsc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000007 }},
|
||||
{ "sbc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000006 }},
|
||||
{ "adc", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000005 }},
|
||||
{ "sub", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x00000002 }},
|
||||
{ "orr", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000c }},
|
||||
{ "mvn", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000f }},
|
||||
{ "mov", 2, 0, { 26, 27, 0x00000000, 21, 24, 0x0000000d }},
|
||||
{ "stm", 2, 0, { 25, 27, 0x00000004, 20, 22, 0x00000004 }},
|
||||
{ "ldm", 4, 0, { 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001 }},
|
||||
{ "ldrsh", 3, 2, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f }},
|
||||
{ "stm", 3, 0, { 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000 }},
|
||||
{ "ldm", 3, 0, { 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001 }},
|
||||
{ "ldrsb", 3, 2, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d }},
|
||||
{ "strd", 3, 4, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f }},
|
||||
{ "ldrh", 3, 0, { 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b }},
|
||||
{ "strh", 3, 0, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b }},
|
||||
{ "ldrd", 3, 4, { 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d }},
|
||||
{ "strt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002 }},
|
||||
{ "strbt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006 }},
|
||||
{ "ldrbt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007 }},
|
||||
{ "ldrt", 3, 0, { 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003 }},
|
||||
{ "mrc", 3, 6, { 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001 }},
|
||||
{ "mcr", 3, 0, { 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001 }},
|
||||
{ "msr", 3, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000001 }},
|
||||
{ "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 19, 0x00000004 }},
|
||||
{ "msr", 5, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 19, 19, 0x00000001, 16, 17, 0x00000000 }},
|
||||
{ "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 16, 17, 0x00000001 }},
|
||||
{ "msr", 4, 0, { 23, 27, 0x00000006, 20, 21, 0x00000002, 22, 22, 0x00000000, 17, 17, 0x00000001 }},
|
||||
{ "ldrb", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001 }},
|
||||
{ "strb", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000 }},
|
||||
{ "ldr", 4, 0, { 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 }},
|
||||
{ "ldrcond", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 }},
|
||||
{ "str", 3, 0, { 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000 }},
|
||||
{ "cdp", 2, 0, { 24, 27, 0x0000000e, 4, 4, 0x00000000 }},
|
||||
{ "stc", 2, 0, { 25, 27, 0x00000006, 20, 20, 0x00000000 }},
|
||||
{ "ldc", 2, 0, { 25, 27, 0x00000006, 20, 20, 0x00000001 }},
|
||||
{ "ldrexd", 2, ARMV6K, { 20, 27, 0x0000001B, 4, 7, 0x00000009 }},
|
||||
{ "strexd", 2, ARMV6K, { 20, 27, 0x0000001A, 4, 7, 0x00000009 }},
|
||||
{ "ldrexh", 2, ARMV6K, { 20, 27, 0x0000001F, 4, 7, 0x00000009 }},
|
||||
{ "strexh", 2, ARMV6K, { 20, 27, 0x0000001E, 4, 7, 0x00000009 }},
|
||||
{ "nop", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000000 }},
|
||||
{ "yield", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000001 }},
|
||||
{ "wfe", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000002 }},
|
||||
{ "wfi", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000003 }},
|
||||
{ "sev", 5, ARMV6K, { 23, 27, 0x00000006, 22, 22, 0x00000000, 20, 21, 0x00000002, 16, 19, 0x00000000, 0, 7, 0x00000004 }},
|
||||
{ "swi", 1, 0, { 24, 27, 0x0000000f }},
|
||||
{ "bbl", 1, 0, { 25, 27, 0x00000005 }},
|
||||
};
|
||||
|
||||
const InstructionSetEncodingItem arm_exclusion_code[] = {
|
||||
{ "vmla", 0, ARMVFP2, { 0 }},
|
||||
{ "vmls", 0, ARMVFP2, { 0 }},
|
||||
{ "vnmla", 0, ARMVFP2, { 0 }},
|
||||
{ "vnmls", 0, ARMVFP2, { 0 }},
|
||||
{ "vnmul", 0, ARMVFP2, { 0 }},
|
||||
{ "vmul", 0, ARMVFP2, { 0 }},
|
||||
{ "vadd", 0, ARMVFP2, { 0 }},
|
||||
{ "vsub", 0, ARMVFP2, { 0 }},
|
||||
{ "vdiv", 0, ARMVFP2, { 0 }},
|
||||
{ "vmov(i)", 0, ARMVFP3, { 0 }},
|
||||
{ "vmov(r)", 0, ARMVFP3, { 0 }},
|
||||
{ "vabs", 0, ARMVFP2, { 0 }},
|
||||
{ "vneg", 0, ARMVFP2, { 0 }},
|
||||
{ "vsqrt", 0, ARMVFP2, { 0 }},
|
||||
{ "vcmp", 0, ARMVFP2, { 0 }},
|
||||
{ "vcmp2", 0, ARMVFP2, { 0 }},
|
||||
{ "vcvt(bff)", 0, ARMVFP3, { 4, 4, 1 }},
|
||||
{ "vcvt(bds)", 0, ARMVFP2, { 0 }},
|
||||
{ "vcvt(bfi)", 0, ARMVFP2, { 0 }},
|
||||
{ "vmovbrs", 0, ARMVFP2, { 0 }},
|
||||
{ "vmsr", 0, ARMVFP2, { 0 }},
|
||||
{ "vmovbrc", 0, ARMVFP2, { 0 }},
|
||||
{ "vmrs", 0, ARMVFP2, { 0 }},
|
||||
{ "vmovbcr", 0, ARMVFP2, { 0 }},
|
||||
{ "vmovbrrss", 0, ARMVFP2, { 0 }},
|
||||
{ "vmovbrrd", 0, ARMVFP2, { 0 }},
|
||||
{ "vstr", 0, ARMVFP2, { 0 }},
|
||||
{ "vpush", 0, ARMVFP2, { 0 }},
|
||||
{ "vstm", 0, ARMVFP2, { 0 }},
|
||||
{ "vpop", 0, ARMVFP2, { 0 }},
|
||||
{ "vldr", 0, ARMVFP2, { 0 }},
|
||||
{ "vldm", 0, ARMVFP2, { 0 }},
|
||||
|
||||
{ "srs", 0, 6, { 0 }},
|
||||
{ "rfe", 0, 6, { 0 }},
|
||||
{ "bkpt", 0, 3, { 0 }},
|
||||
{ "blx", 0, 3, { 0 }},
|
||||
{ "cps", 0, 6, { 0 }},
|
||||
{ "pld", 0, 4, { 0 }},
|
||||
{ "setend", 0, 6, { 0 }},
|
||||
{ "clrex", 0, 6, { 0 }},
|
||||
{ "rev16", 0, 6, { 0 }},
|
||||
{ "usad8", 0, 6, { 0 }},
|
||||
{ "sxtb", 0, 6, { 0 }},
|
||||
{ "uxtb", 0, 6, { 0 }},
|
||||
{ "sxth", 0, 6, { 0 }},
|
||||
{ "sxtb16", 0, 6, { 0 }},
|
||||
{ "uxth", 0, 6, { 0 }},
|
||||
{ "uxtb16", 0, 6, { 0 }},
|
||||
{ "cpy", 0, 6, { 0 }},
|
||||
{ "uxtab", 0, 6, { 0 }},
|
||||
{ "ssub8", 0, 6, { 0 }},
|
||||
{ "shsub8", 0, 6, { 0 }},
|
||||
{ "ssubaddx", 0, 6, { 0 }},
|
||||
{ "strex", 0, 6, { 0 }},
|
||||
{ "strexb", 0, 7, { 0 }},
|
||||
{ "swp", 0, 0, { 0 }},
|
||||
{ "swpb", 0, 0, { 0 }},
|
||||
{ "ssub16", 0, 6, { 0 }},
|
||||
{ "ssat16", 0, 6, { 0 }},
|
||||
{ "shsubaddx", 0, 6, { 0 }},
|
||||
{ "qsubaddx", 0, 6, { 0 }},
|
||||
{ "shaddsubx", 0, 6, { 0 }},
|
||||
{ "shadd8", 0, 6, { 0 }},
|
||||
{ "shadd16", 0, 6, { 0 }},
|
||||
{ "sel", 0, 6, { 0 }},
|
||||
{ "saddsubx", 0, 6, { 0 }},
|
||||
{ "sadd8", 0, 6, { 0 }},
|
||||
{ "sadd16", 0, 6, { 0 }},
|
||||
{ "shsub16", 0, 6, { 0 }},
|
||||
{ "umaal", 0, 6, { 0 }},
|
||||
{ "uxtab16", 0, 6, { 0 }},
|
||||
{ "usubaddx", 0, 6, { 0 }},
|
||||
{ "usub8", 0, 6, { 0 }},
|
||||
{ "usub16", 0, 6, { 0 }},
|
||||
{ "usat16", 0, 6, { 0 }},
|
||||
{ "usada8", 0, 6, { 0 }},
|
||||
{ "uqsubaddx", 0, 6, { 0 }},
|
||||
{ "uqsub8", 0, 6, { 0 }},
|
||||
{ "uqsub16", 0, 6, { 0 }},
|
||||
{ "uqaddsubx", 0, 6, { 0 }},
|
||||
{ "uqadd8", 0, 6, { 0 }},
|
||||
{ "uqadd16", 0, 6, { 0 }},
|
||||
{ "sxtab", 0, 6, { 0 }},
|
||||
{ "uhsubaddx", 0, 6, { 0 }},
|
||||
{ "uhsub8", 0, 6, { 0 }},
|
||||
{ "uhsub16", 0, 6, { 0 }},
|
||||
{ "uhaddsubx", 0, 6, { 0 }},
|
||||
{ "uhadd8", 0, 6, { 0 }},
|
||||
{ "uhadd16", 0, 6, { 0 }},
|
||||
{ "uaddsubx", 0, 6, { 0 }},
|
||||
{ "uadd8", 0, 6, { 0 }},
|
||||
{ "uadd16", 0, 6, { 0 }},
|
||||
{ "sxtah", 0, 6, { 0 }},
|
||||
{ "sxtab16", 0, 6, { 0 }},
|
||||
{ "qadd8", 0, 6, { 0 }},
|
||||
{ "bxj", 0, 5, { 0 }},
|
||||
{ "clz", 0, 3, { 0 }},
|
||||
{ "uxtah", 0, 6, { 0 }},
|
||||
{ "bx", 0, 2, { 0 }},
|
||||
{ "rev", 0, 6, { 0 }},
|
||||
{ "blx", 0, 3, { 0 }},
|
||||
{ "revsh", 0, 6, { 0 }},
|
||||
{ "qadd", 0, 4, { 0 }},
|
||||
{ "qadd16", 0, 6, { 0 }},
|
||||
{ "qaddsubx", 0, 6, { 0 }},
|
||||
{ "ldrex", 0, 0, { 0 }},
|
||||
{ "qdadd", 0, 4, { 0 }},
|
||||
{ "qdsub", 0, 4, { 0 }},
|
||||
{ "qsub", 0, 4, { 0 }},
|
||||
{ "ldrexb", 0, 7, { 0 }},
|
||||
{ "qsub8", 0, 6, { 0 }},
|
||||
{ "qsub16", 0, 6, { 0 }},
|
||||
{ "smuad", 0, 6, { 0 }},
|
||||
{ "smmul", 0, 6, { 0 }},
|
||||
{ "smusd", 0, 6, { 0 }},
|
||||
{ "smlsd", 0, 6, { 0 }},
|
||||
{ "smlsld", 0, 6, { 0 }},
|
||||
{ "smmla", 0, 6, { 0 }},
|
||||
{ "smmls", 0, 6, { 0 }},
|
||||
{ "smlald", 0, 6, { 0 }},
|
||||
{ "smlad", 0, 6, { 0 }},
|
||||
{ "smlaw", 0, 4, { 0 }},
|
||||
{ "smulw", 0, 4, { 0 }},
|
||||
{ "pkhtb", 0, 6, { 0 }},
|
||||
{ "pkhbt", 0, 6, { 0 }},
|
||||
{ "smul", 0, 4, { 0 }},
|
||||
{ "smlal", 0, 4, { 0 }},
|
||||
{ "smla", 0, 4, { 0 }},
|
||||
{ "mcrr", 0, 6, { 0 }},
|
||||
{ "mrrc", 0, 6, { 0 }},
|
||||
{ "cmp", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "tst", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "teq", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "cmn", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "smull", 0, 0, { 0 }},
|
||||
{ "umull", 0, 0, { 0 }},
|
||||
{ "umlal", 0, 0, { 0 }},
|
||||
{ "smlal", 0, 0, { 0 }},
|
||||
{ "mul", 0, 0, { 0 }},
|
||||
{ "mla", 0, 0, { 0 }},
|
||||
{ "ssat", 0, 6, { 0 }},
|
||||
{ "usat", 0, 6, { 0 }},
|
||||
{ "mrs", 0, 0, { 0 }},
|
||||
{ "msr", 0, 0, { 0 }},
|
||||
{ "and", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "bic", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "ldm", 0, 0, { 0 }},
|
||||
{ "eor", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "add", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "rsb", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "rsc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "sbc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "adc", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "sub", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "orr", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "mvn", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "mov", 3, 0, { 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 }},
|
||||
{ "stm", 0, 0, { 0 }},
|
||||
{ "ldm", 0, 0, { 0 }},
|
||||
{ "ldrsh", 0, 2, { 0 }},
|
||||
{ "stm", 0, 0, { 0 }},
|
||||
{ "ldm", 0, 0, { 0 }},
|
||||
{ "ldrsb", 0, 2, { 0 }},
|
||||
{ "strd", 0, 4, { 0 }},
|
||||
{ "ldrh", 0, 0, { 0 }},
|
||||
{ "strh", 0, 0, { 0 }},
|
||||
{ "ldrd", 0, 4, { 0 }},
|
||||
{ "strt", 0, 0, { 0 }},
|
||||
{ "strbt", 0, 0, { 0 }},
|
||||
{ "ldrbt", 0, 0, { 0 }},
|
||||
{ "ldrt", 0, 0, { 0 }},
|
||||
{ "mrc", 0, 6, { 0 }},
|
||||
{ "mcr", 0, 0, { 0 }},
|
||||
{ "msr", 0, 0, { 0 }},
|
||||
{ "msr", 0, 0, { 0 }},
|
||||
{ "msr", 0, 0, { 0 }},
|
||||
{ "msr", 0, 0, { 0 }},
|
||||
{ "msr", 0, 0, { 0 }},
|
||||
{ "ldrb", 0, 0, { 0 }},
|
||||
{ "strb", 0, 0, { 0 }},
|
||||
{ "ldr", 0, 0, { 0 }},
|
||||
{ "ldrcond", 1, 0, { 28, 31, 0x0000000e }},
|
||||
{ "str", 0, 0, { 0 }},
|
||||
{ "cdp", 0, 0, { 0 }},
|
||||
{ "stc", 0, 0, { 0 }},
|
||||
{ "ldc", 0, 0, { 0 }},
|
||||
{ "ldrexd", 0, ARMV6K, { 0 }},
|
||||
{ "strexd", 0, ARMV6K, { 0 }},
|
||||
{ "ldrexh", 0, ARMV6K, { 0 }},
|
||||
{ "strexh", 0, ARMV6K, { 0 }},
|
||||
{ "nop", 0, ARMV6K, { 0 }},
|
||||
{ "yield", 0, ARMV6K, { 0 }},
|
||||
{ "wfe", 0, ARMV6K, { 0 }},
|
||||
{ "wfi", 0, ARMV6K, { 0 }},
|
||||
{ "sev", 0, ARMV6K, { 0 }},
|
||||
{ "swi", 0, 0, { 0 }},
|
||||
{ "bbl", 0, 0, { 0 }},
|
||||
|
||||
{ "bl_1_thumb", 0, INVALID, { 0 }}, // Should be table[-4]
|
||||
{ "bl_2_thumb", 0, INVALID, { 0 }}, // Should be located at the end of the table[-3]
|
||||
{ "blx_1_thumb", 0, INVALID, { 0 }}, // Should be located at table[-2]
|
||||
{ "invalid", 0, INVALID, { 0 }}
|
||||
};
|
||||
|
||||
ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) {
|
||||
int n = 0;
|
||||
int base = 0;
|
||||
int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem);
|
||||
ARMDecodeStatus ret = ARMDecodeStatus::FAILURE;
|
||||
|
||||
for (int i = 0; i < instr_slots; i++) {
|
||||
n = arm_instruction[i].attribute_value;
|
||||
base = 0;
|
||||
|
||||
// 3DS has no VFP3 support
|
||||
if (arm_instruction[i].version == ARMVFP3)
|
||||
continue;
|
||||
|
||||
while (n) {
|
||||
if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
|
||||
// clrex
|
||||
if (instr != arm_instruction[i].content[base + 2]) {
|
||||
break;
|
||||
}
|
||||
} else if (BITS(instr, arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) {
|
||||
break;
|
||||
}
|
||||
base += 3;
|
||||
n--;
|
||||
}
|
||||
|
||||
// All conditions are satisfied.
|
||||
if (n == 0)
|
||||
ret = ARMDecodeStatus::SUCCESS;
|
||||
|
||||
if (ret == ARMDecodeStatus::SUCCESS) {
|
||||
n = arm_exclusion_code[i].attribute_value;
|
||||
if (n != 0) {
|
||||
base = 0;
|
||||
while (n) {
|
||||
if (BITS(instr, arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) {
|
||||
break;
|
||||
}
|
||||
base += 3;
|
||||
n--;
|
||||
}
|
||||
|
||||
// All conditions are satisfied.
|
||||
if (n == 0)
|
||||
ret = ARMDecodeStatus::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == ARMDecodeStatus::SUCCESS) {
|
||||
*idx = i;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2012 Michael Kang, 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
enum class ARMDecodeStatus {
|
||||
SUCCESS,
|
||||
FAILURE
|
||||
};
|
||||
|
||||
ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx);
|
||||
|
||||
struct InstructionSetEncodingItem {
|
||||
const char *name;
|
||||
int attribute_value;
|
||||
int version;
|
||||
u32 content[21];
|
||||
};
|
||||
|
||||
// ARM versions
|
||||
enum {
|
||||
INVALID = 0,
|
||||
ARMALL,
|
||||
ARMV4,
|
||||
ARMV4T,
|
||||
ARMV5T,
|
||||
ARMV5TE,
|
||||
ARMV5TEJ,
|
||||
ARMV6,
|
||||
ARM1176JZF_S,
|
||||
ARMVFP2,
|
||||
ARMVFP3,
|
||||
ARMV6K,
|
||||
};
|
||||
|
||||
extern const InstructionSetEncodingItem arm_instruction[];
|
File diff suppressed because it is too large
Load diff
|
@ -1,10 +0,0 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
struct ARMul_State;
|
||||
|
||||
unsigned InterpreterMainLoop(ARMul_State* state);
|
||||
void InterpreterClearCache();
|
|
@ -1,48 +0,0 @@
|
|||
/* Copyright (C)
|
||||
* 2011 - Michael.Kang blackfin.kang@gmail.com
|
||||
* 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; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armstate.h"
|
||||
|
||||
/**
|
||||
* Checks if the PC is being read, and if so, word-aligns it.
|
||||
* Used with address calculations.
|
||||
*
|
||||
* @param cpu The ARM CPU state instance.
|
||||
* @param Rn The register being read.
|
||||
*
|
||||
* @return If the PC is being read, then the word-aligned PC value is returned.
|
||||
* If the PC is not being read, then the value stored in the register is returned.
|
||||
*/
|
||||
inline u32 CHECK_READ_REG15_WA(const ARMul_State* cpu, int Rn) {
|
||||
return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn];
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the PC. Used for data processing operations that use the PC.
|
||||
*
|
||||
* @param cpu The ARM CPU state instance.
|
||||
* @param Rn The register being read.
|
||||
*
|
||||
* @return If the PC is being read, then the incremented PC value is returned.
|
||||
* If the PC is not being read, then the values stored in the register is returned.
|
||||
*/
|
||||
inline u32 CHECK_READ_REG15(const ARMul_State* cpu, int Rn) {
|
||||
return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn];
|
||||
}
|
|
@ -1,402 +0,0 @@
|
|||
// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
|
||||
// ARM instruction, and using the existing ARM simulator.
|
||||
|
||||
#include "A32/skyeye_interpreter/dyncom/arm_dyncom_thumb.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armsupp.h"
|
||||
|
||||
// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
|
||||
// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
|
||||
// allows easier simulation of the special dual BL instruction.
|
||||
|
||||
ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
|
||||
ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED;
|
||||
u32 tinstr = GetThumbInstruction(instr, addr);
|
||||
|
||||
*ainstr = 0xDEADC0DE; // Debugging to catch non updates
|
||||
|
||||
switch ((tinstr & 0xF800) >> 11) {
|
||||
case 0: // LSL
|
||||
case 1: // LSR
|
||||
case 2: // ASR
|
||||
*ainstr = 0xE1B00000 // base opcode
|
||||
| ((tinstr & 0x1800) >> (11 - 5)) // shift type
|
||||
|((tinstr & 0x07C0) << (7 - 6)) // imm5
|
||||
|((tinstr & 0x0038) >> 3) // Rs
|
||||
|((tinstr & 0x0007) << 12); // Rd
|
||||
break;
|
||||
|
||||
case 3: // ADD/SUB
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE0900000, // ADDS Rd,Rs,Rn
|
||||
0xE0500000, // SUBS Rd,Rs,Rn
|
||||
0xE2900000, // ADDS Rd,Rs,#imm3
|
||||
0xE2500000 // SUBS Rd,Rs,#imm3
|
||||
};
|
||||
// It is quicker indexing into a table, than performing switch or conditionals:
|
||||
*ainstr = subset[(tinstr & 0x0600) >> 9] // base opcode
|
||||
|((tinstr & 0x01C0) >> 6) // Rn or imm3
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rs
|
||||
|((tinstr & 0x0007) << (12 - 0)); // Rd
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // MOV
|
||||
case 5: // CMP
|
||||
case 6: // ADD
|
||||
case 7: // SUB
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE3B00000, // MOVS Rd,#imm8
|
||||
0xE3500000, // CMP Rd,#imm8
|
||||
0xE2900000, // ADDS Rd,Rd,#imm8
|
||||
0xE2500000, // SUBS Rd,Rd,#imm8
|
||||
};
|
||||
|
||||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base opcode
|
||||
|((tinstr & 0x00FF) >> 0) // imm8
|
||||
|((tinstr & 0x0700) << (16 - 8)) // Rn
|
||||
|((tinstr & 0x0700) << (12 - 8)); // Rd
|
||||
}
|
||||
break;
|
||||
|
||||
case 8: // Arithmetic and high register transfers
|
||||
|
||||
// TODO: Since the subsets for both Format 4 and Format 5 instructions are made up of
|
||||
// different ARM encodings, we could save the following conditional, and just have one
|
||||
// large subset
|
||||
|
||||
if ((tinstr & (1 << 10)) == 0) {
|
||||
enum otype {
|
||||
t_norm,
|
||||
t_shift,
|
||||
t_neg,
|
||||
t_mul
|
||||
};
|
||||
|
||||
static const struct {
|
||||
u32 opcode;
|
||||
otype type;
|
||||
} subset[16] = {
|
||||
{ 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs
|
||||
{ 0xE0300000, t_norm }, // EORS Rd,Rd,Rs
|
||||
{ 0xE1B00010, t_shift }, // MOVS Rd,Rd,LSL Rs
|
||||
{ 0xE1B00030, t_shift }, // MOVS Rd,Rd,LSR Rs
|
||||
{ 0xE1B00050, t_shift }, // MOVS Rd,Rd,ASR Rs
|
||||
{ 0xE0B00000, t_norm }, // ADCS Rd,Rd,Rs
|
||||
{ 0xE0D00000, t_norm }, // SBCS Rd,Rd,Rs
|
||||
{ 0xE1B00070, t_shift }, // MOVS Rd,Rd,ROR Rs
|
||||
{ 0xE1100000, t_norm }, // TST Rd,Rs
|
||||
{ 0xE2700000, t_neg }, // RSBS Rd,Rs,#0
|
||||
{ 0xE1500000, t_norm }, // CMP Rd,Rs
|
||||
{ 0xE1700000, t_norm }, // CMN Rd,Rs
|
||||
{ 0xE1900000, t_norm }, // ORRS Rd,Rd,Rs
|
||||
{ 0xE0100090, t_mul }, // MULS Rd,Rd,Rs
|
||||
{ 0xE1D00000, t_norm }, // BICS Rd,Rd,Rs
|
||||
{ 0xE1F00000, t_norm } // MVNS Rd,Rs
|
||||
};
|
||||
|
||||
*ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; // base
|
||||
|
||||
switch (subset[(tinstr & 0x03C0) >> 6].type) {
|
||||
case t_norm:
|
||||
*ainstr |= ((tinstr & 0x0007) << 16) // Rn
|
||||
|((tinstr & 0x0007) << 12) // Rd
|
||||
|((tinstr & 0x0038) >> 3); // Rs
|
||||
break;
|
||||
case t_shift:
|
||||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
||||
|((tinstr & 0x0007) >> 0) // Rm
|
||||
|((tinstr & 0x0038) << (8 - 3)); // Rs
|
||||
break;
|
||||
case t_neg:
|
||||
*ainstr |= ((tinstr & 0x0007) << 12) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)); // Rn
|
||||
break;
|
||||
case t_mul:
|
||||
*ainstr |= ((tinstr & 0x0007) << 16) // Rd
|
||||
|((tinstr & 0x0007) << 8) // Rs
|
||||
|((tinstr & 0x0038) >> 3); // Rm
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
u32 Rd = ((tinstr & 0x0007) >> 0);
|
||||
u32 Rs = ((tinstr & 0x0078) >> 3);
|
||||
|
||||
if (tinstr & (1 << 7))
|
||||
Rd += 8;
|
||||
|
||||
switch ((tinstr & 0x03C0) >> 6) {
|
||||
case 0x0: // ADD Rd,Rd,Rs
|
||||
case 0x1: // ADD Rd,Rd,Hs
|
||||
case 0x2: // ADD Hd,Hd,Rs
|
||||
case 0x3: // ADD Hd,Hd,Hs
|
||||
*ainstr = 0xE0800000 // base
|
||||
| (Rd << 16) // Rn
|
||||
|(Rd << 12) // Rd
|
||||
|(Rs << 0); // Rm
|
||||
break;
|
||||
case 0x4: // CMP Rd,Rs
|
||||
case 0x5: // CMP Rd,Hs
|
||||
case 0x6: // CMP Hd,Rs
|
||||
case 0x7: // CMP Hd,Hs
|
||||
*ainstr = 0xE1500000 // base
|
||||
| (Rd << 16) // Rn
|
||||
|(Rs << 0); // Rm
|
||||
break;
|
||||
case 0x8: // MOV Rd,Rs
|
||||
case 0x9: // MOV Rd,Hs
|
||||
case 0xA: // MOV Hd,Rs
|
||||
case 0xB: // MOV Hd,Hs
|
||||
*ainstr = 0xE1A00000 // base
|
||||
|(Rd << 12) // Rd
|
||||
|(Rs << 0); // Rm
|
||||
break;
|
||||
case 0xC: // BX Rs
|
||||
case 0xD: // BX Hs
|
||||
*ainstr = 0xE12FFF10 // base
|
||||
| ((tinstr & 0x0078) >> 3); // Rd
|
||||
break;
|
||||
case 0xE: // BLX
|
||||
case 0xF: // BLX
|
||||
*ainstr = 0xE1200030 // base
|
||||
| (Rs << 0); // Rm
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: // LDR Rd,[PC,#imm8]
|
||||
*ainstr = 0xE59F0000 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|((tinstr & 0x00FF) << (2 - 0)); // off8
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case 11:
|
||||
{
|
||||
static const u32 subset[8] = {
|
||||
0xE7800000, // STR Rd,[Rb,Ro]
|
||||
0xE18000B0, // STRH Rd,[Rb,Ro]
|
||||
0xE7C00000, // STRB Rd,[Rb,Ro]
|
||||
0xE19000D0, // LDRSB Rd,[Rb,Ro]
|
||||
0xE7900000, // LDR Rd,[Rb,Ro]
|
||||
0xE19000B0, // LDRH Rd,[Rb,Ro]
|
||||
0xE7D00000, // LDRB Rd,[Rb,Ro]
|
||||
0xE19000F0 // LDRSH Rd,[Rb,Ro]
|
||||
};
|
||||
|
||||
*ainstr = subset[(tinstr & 0xE00) >> 9] // base
|
||||
|((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
|((tinstr & 0x01C0) >> 6); // Ro
|
||||
}
|
||||
break;
|
||||
|
||||
case 12: // STR Rd,[Rb,#imm5]
|
||||
case 13: // LDR Rd,[Rb,#imm5]
|
||||
case 14: // STRB Rd,[Rb,#imm5]
|
||||
case 15: // LDRB Rd,[Rb,#imm5]
|
||||
{
|
||||
static const u32 subset[4] = {
|
||||
0xE5800000, // STR Rd,[Rb,#imm5]
|
||||
0xE5900000, // LDR Rd,[Rb,#imm5]
|
||||
0xE5C00000, // STRB Rd,[Rb,#imm5]
|
||||
0xE5D00000 // LDRB Rd,[Rb,#imm5]
|
||||
};
|
||||
// The offset range defends on whether we are transferring a byte or word value:
|
||||
*ainstr = subset[(tinstr & 0x1800) >> 11] // base
|
||||
|((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
|((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); // off5
|
||||
}
|
||||
break;
|
||||
|
||||
case 16: // STRH Rd,[Rb,#imm5]
|
||||
case 17: // LDRH Rd,[Rb,#imm5]
|
||||
*ainstr = ((tinstr & (1 << 11)) // base
|
||||
? 0xE1D000B0 // LDRH
|
||||
: 0xE1C000B0) // STRH
|
||||
|((tinstr & 0x0007) << (12 - 0)) // Rd
|
||||
|((tinstr & 0x0038) << (16 - 3)) // Rb
|
||||
|((tinstr & 0x01C0) >> (6 - 1)) // off5, low nibble
|
||||
|((tinstr & 0x0600) >> (9 - 8)); // off5, high nibble
|
||||
break;
|
||||
|
||||
case 18: // STR Rd,[SP,#imm8]
|
||||
case 19: // LDR Rd,[SP,#imm8]
|
||||
*ainstr = ((tinstr & (1 << 11)) // base
|
||||
? 0xE59D0000 // LDR
|
||||
: 0xE58D0000) // STR
|
||||
|((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|((tinstr & 0x00FF) << 2); // off8
|
||||
break;
|
||||
|
||||
case 20: // ADD Rd,PC,#imm8
|
||||
case 21: // ADD Rd,SP,#imm8
|
||||
|
||||
if ((tinstr & (1 << 11)) == 0) {
|
||||
|
||||
// NOTE: The PC value used here should by word aligned. We encode shift-left-by-2 in the
|
||||
// rotate immediate field, so no shift of off8 is needed.
|
||||
|
||||
*ainstr = 0xE28F0F00 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|(tinstr & 0x00FF); // off8
|
||||
} else {
|
||||
// We encode shift-left-by-2 in the rotate immediate field, so no shift of off8 is needed.
|
||||
*ainstr = 0xE28D0F00 // base
|
||||
| ((tinstr & 0x0700) << (12 - 8)) // Rd
|
||||
|(tinstr & 0x00FF); // off8
|
||||
}
|
||||
break;
|
||||
|
||||
case 22:
|
||||
case 23:
|
||||
if ((tinstr & 0x0F00) == 0x0000) {
|
||||
// NOTE: The instruction contains a shift left of 2 equivalent (implemented as ROR #30):
|
||||
*ainstr = ((tinstr & (1 << 7)) // base
|
||||
? 0xE24DDF00 // SUB
|
||||
: 0xE28DDF00) // ADD
|
||||
|(tinstr & 0x007F); // off7
|
||||
} else if ((tinstr & 0x0F00) == 0x0e00) {
|
||||
// BKPT
|
||||
*ainstr = 0xEF000000 // base
|
||||
| BITS(tinstr, 0, 3) // imm4 field;
|
||||
| (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
|
||||
} else if ((tinstr & 0x0F00) == 0x0200) {
|
||||
static const u32 subset[4] = {
|
||||
0xE6BF0070, // SXTH
|
||||
0xE6AF0070, // SXTB
|
||||
0xE6FF0070, // UXTH
|
||||
0xE6EF0070, // UXTB
|
||||
};
|
||||
|
||||
*ainstr = subset[BITS(tinstr, 6, 7)] // base
|
||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||
| BITS(tinstr, 3, 5); // Rm
|
||||
} else if ((tinstr & 0x0F00) == 0x600) {
|
||||
if (BIT(tinstr, 5) == 0) {
|
||||
// SETEND
|
||||
*ainstr = 0xF1010000 // base
|
||||
| (BIT(tinstr, 3) << 9); // endian specifier
|
||||
} else {
|
||||
// CPS
|
||||
*ainstr = 0xF1080000 // base
|
||||
| (BIT(tinstr, 0) << 6) // fiq bit
|
||||
| (BIT(tinstr, 1) << 7) // irq bit
|
||||
| (BIT(tinstr, 2) << 8) // abort bit
|
||||
| (BIT(tinstr, 4) << 18); // enable bit
|
||||
}
|
||||
} else if ((tinstr & 0x0F00) == 0x0a00) {
|
||||
static const u32 subset[4] = {
|
||||
0xE6BF0F30, // REV
|
||||
0xE6BF0FB0, // REV16
|
||||
0, // undefined
|
||||
0xE6FF0FB0, // REVSH
|
||||
};
|
||||
|
||||
size_t subset_index = BITS(tinstr, 6, 7);
|
||||
|
||||
if (subset_index == 2) {
|
||||
valid = ThumbDecodeStatus::UNDEFINED;
|
||||
} else {
|
||||
*ainstr = subset[subset_index] // base
|
||||
| (BITS(tinstr, 0, 2) << 12) // Rd
|
||||
| BITS(tinstr, 3, 5); // Rm
|
||||
}
|
||||
} else {
|
||||
static const u32 subset[4] = {
|
||||
0xE92D0000, // STMDB sp!,{rlist}
|
||||
0xE92D4000, // STMDB sp!,{rlist,lr}
|
||||
0xE8BD0000, // LDMIA sp!,{rlist}
|
||||
0xE8BD8000 // LDMIA sp!,{rlist,pc}
|
||||
};
|
||||
*ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] // base
|
||||
|(tinstr & 0x00FF); // mask8
|
||||
}
|
||||
break;
|
||||
|
||||
case 24: // STMIA
|
||||
case 25: // LDMIA
|
||||
if (tinstr & (1 << 11))
|
||||
{
|
||||
unsigned int base = 0xE8900000;
|
||||
unsigned int rn = BITS(tinstr, 8, 10);
|
||||
|
||||
// Writeback
|
||||
if ((tinstr & (1 << rn)) == 0)
|
||||
base |= (1 << 21);
|
||||
|
||||
*ainstr = base // base (LDMIA)
|
||||
| (rn << 16) // Rn
|
||||
| (tinstr & 0x00FF); // Register list
|
||||
}
|
||||
else
|
||||
{
|
||||
*ainstr = 0xE8A00000 // base (STMIA)
|
||||
| (BITS(tinstr, 8, 10) << 16) // Rn
|
||||
| (tinstr & 0x00FF); // Register list
|
||||
}
|
||||
break;
|
||||
|
||||
case 26: // Bcc
|
||||
case 27: // Bcc/SWI
|
||||
if ((tinstr & 0x0F00) == 0x0F00) {
|
||||
// Format 17 : SWI
|
||||
*ainstr = 0xEF000000;
|
||||
// Breakpoint must be handled specially.
|
||||
if ((tinstr & 0x00FF) == 0x18)
|
||||
*ainstr |= ((tinstr & 0x00FF) << 16);
|
||||
// New breakpoint value. See gdb/arm-tdep.c
|
||||
else if ((tinstr & 0x00FF) == 0xFE)
|
||||
*ainstr |= 0x180000; // base |= BKPT mask
|
||||
else
|
||||
*ainstr |= (tinstr & 0x00FF);
|
||||
} else if ((tinstr & 0x0F00) != 0x0E00)
|
||||
valid = ThumbDecodeStatus::BRANCH;
|
||||
else // UNDEFINED : cc=1110(AL) uses different format
|
||||
valid = ThumbDecodeStatus::UNDEFINED;
|
||||
|
||||
break;
|
||||
|
||||
case 28: // B
|
||||
valid = ThumbDecodeStatus::BRANCH;
|
||||
break;
|
||||
|
||||
case 29:
|
||||
if (tinstr & 0x1)
|
||||
valid = ThumbDecodeStatus::UNDEFINED;
|
||||
else
|
||||
valid = ThumbDecodeStatus::BRANCH;
|
||||
break;
|
||||
|
||||
case 30: // BL instruction 1
|
||||
|
||||
// There is no single ARM instruction equivalent for this Thumb instruction. To keep the
|
||||
// simulation simple (from the user perspective) we check if the following instruction is
|
||||
// the second half of this BL, and if it is we simulate it immediately
|
||||
|
||||
valid = ThumbDecodeStatus::BRANCH;
|
||||
break;
|
||||
|
||||
case 31: // BL instruction 2
|
||||
|
||||
// There is no single ARM instruction equivalent for this instruction. Also, it should only
|
||||
// ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the
|
||||
// simulation of it on its own, with undefined results if r14 is not suitably initialised.
|
||||
|
||||
valid = ThumbDecodeStatus::BRANCH;
|
||||
break;
|
||||
}
|
||||
|
||||
*inst_size = 2;
|
||||
|
||||
return valid;
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/* Copyright (C)
|
||||
* 2011 - Michael.Kang blackfin.kang@gmail.com
|
||||
* 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; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file arm_dyncom_thumb.h
|
||||
* @brief The thumb dyncom
|
||||
* @author Michael.Kang blackfin.kang@gmail.com
|
||||
* @version 78.77
|
||||
* @date 2011-11-07
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
enum class ThumbDecodeStatus {
|
||||
UNDEFINED, // Undefined Thumb instruction
|
||||
DECODED, // Instruction decoded to ARM equivalent
|
||||
BRANCH, // Thumb branch (already processed)
|
||||
UNINITIALIZED,
|
||||
};
|
||||
|
||||
// Translates a Thumb mode instruction into its ARM equivalent.
|
||||
ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size);
|
||||
|
||||
inline u32 GetThumbInstruction(u32 instr, u32 address) {
|
||||
// Normally you would need to handle instruction endianness,
|
||||
// however, it is fixed to little-endian on the MPCore, so
|
||||
// there's no need to check for this beforehand.
|
||||
if ((address & 0x3) != 0)
|
||||
return instr >> 16;
|
||||
|
||||
return instr & 0xFFFF;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,499 +0,0 @@
|
|||
struct ARMul_State;
|
||||
typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
|
||||
|
||||
enum class TransExtData {
|
||||
COND = (1 << 0),
|
||||
NON_BRANCH = (1 << 1),
|
||||
DIRECT_BRANCH = (1 << 2),
|
||||
INDIRECT_BRANCH = (1 << 3),
|
||||
CALL = (1 << 4),
|
||||
RET = (1 << 5),
|
||||
END_OF_PAGE = (1 << 6),
|
||||
THUMB = (1 << 7),
|
||||
SINGLE_STEP = (1 << 8)
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4200)
|
||||
#endif
|
||||
struct arm_inst {
|
||||
unsigned int idx;
|
||||
unsigned int cond;
|
||||
TransExtData br;
|
||||
#ifdef __GNUC__
|
||||
__extension__
|
||||
#endif
|
||||
char component[0];
|
||||
};
|
||||
|
||||
struct generic_arm_inst {
|
||||
u32 Ra;
|
||||
u32 Rm;
|
||||
u32 Rn;
|
||||
u32 Rd;
|
||||
u8 op1;
|
||||
u8 op2;
|
||||
};
|
||||
|
||||
struct adc_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct add_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct orr_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct and_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct eor_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct bbl_inst {
|
||||
unsigned int L;
|
||||
int signed_immed_24;
|
||||
unsigned int next_addr;
|
||||
unsigned int jmp_addr;
|
||||
};
|
||||
|
||||
struct bx_inst {
|
||||
unsigned int Rm;
|
||||
};
|
||||
|
||||
struct blx_inst {
|
||||
union {
|
||||
s32 signed_immed_24;
|
||||
u32 Rm;
|
||||
} val;
|
||||
unsigned int inst;
|
||||
};
|
||||
|
||||
struct clz_inst {
|
||||
unsigned int Rm;
|
||||
unsigned int Rd;
|
||||
};
|
||||
|
||||
struct cps_inst {
|
||||
unsigned int imod0;
|
||||
unsigned int imod1;
|
||||
unsigned int mmod;
|
||||
unsigned int A, I, F;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
struct clrex_inst {
|
||||
};
|
||||
|
||||
struct cpy_inst {
|
||||
unsigned int Rm;
|
||||
unsigned int Rd;
|
||||
};
|
||||
|
||||
struct bic_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct sub_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct tst_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct cmn_inst {
|
||||
unsigned int I;
|
||||
unsigned int Rn;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct teq_inst {
|
||||
unsigned int I;
|
||||
unsigned int Rn;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct stm_inst {
|
||||
unsigned int inst;
|
||||
};
|
||||
|
||||
struct bkpt_inst {
|
||||
u32 imm;
|
||||
};
|
||||
|
||||
struct stc_inst {
|
||||
};
|
||||
|
||||
struct ldc_inst {
|
||||
};
|
||||
|
||||
struct swi_inst {
|
||||
unsigned int num;
|
||||
};
|
||||
|
||||
struct cmp_inst {
|
||||
unsigned int I;
|
||||
unsigned int Rn;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct mov_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct mvn_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct rev_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rm;
|
||||
unsigned int op1;
|
||||
unsigned int op2;
|
||||
};
|
||||
|
||||
struct rsb_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct rsc_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct sbc_inst {
|
||||
unsigned int I;
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int shifter_operand;
|
||||
shtop_fp_t shtop_func;
|
||||
};
|
||||
|
||||
struct mul_inst {
|
||||
unsigned int S;
|
||||
unsigned int Rd;
|
||||
unsigned int Rs;
|
||||
unsigned int Rm;
|
||||
};
|
||||
|
||||
struct smul_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rs;
|
||||
unsigned int Rm;
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
};
|
||||
|
||||
struct umull_inst {
|
||||
unsigned int S;
|
||||
unsigned int RdHi;
|
||||
unsigned int RdLo;
|
||||
unsigned int Rs;
|
||||
unsigned int Rm;
|
||||
};
|
||||
|
||||
struct smlad_inst {
|
||||
unsigned int m;
|
||||
unsigned int Rm;
|
||||
unsigned int Rd;
|
||||
unsigned int Ra;
|
||||
unsigned int Rn;
|
||||
unsigned int op1;
|
||||
unsigned int op2;
|
||||
};
|
||||
|
||||
struct smla_inst {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int Rm;
|
||||
unsigned int Rd;
|
||||
unsigned int Rs;
|
||||
unsigned int Rn;
|
||||
};
|
||||
|
||||
struct smlalxy_inst {
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int RdLo;
|
||||
unsigned int RdHi;
|
||||
unsigned int Rm;
|
||||
unsigned int Rn;
|
||||
};
|
||||
|
||||
struct ssat_inst {
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int imm5;
|
||||
unsigned int sat_imm;
|
||||
unsigned int shift_type;
|
||||
};
|
||||
|
||||
struct umaal_inst {
|
||||
unsigned int Rn;
|
||||
unsigned int Rm;
|
||||
unsigned int RdHi;
|
||||
unsigned int RdLo;
|
||||
};
|
||||
|
||||
struct umlal_inst {
|
||||
unsigned int S;
|
||||
unsigned int Rm;
|
||||
unsigned int Rs;
|
||||
unsigned int RdHi;
|
||||
unsigned int RdLo;
|
||||
};
|
||||
|
||||
struct smlal_inst {
|
||||
unsigned int S;
|
||||
unsigned int Rm;
|
||||
unsigned int Rs;
|
||||
unsigned int RdHi;
|
||||
unsigned int RdLo;
|
||||
};
|
||||
|
||||
struct smlald_inst {
|
||||
unsigned int RdLo;
|
||||
unsigned int RdHi;
|
||||
unsigned int Rm;
|
||||
unsigned int Rn;
|
||||
unsigned int swap;
|
||||
unsigned int op1;
|
||||
unsigned int op2;
|
||||
};
|
||||
|
||||
struct mla_inst {
|
||||
unsigned int S;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int Rs;
|
||||
unsigned int Rm;
|
||||
};
|
||||
|
||||
struct mrc_inst {
|
||||
unsigned int opcode_1;
|
||||
unsigned int opcode_2;
|
||||
unsigned int cp_num;
|
||||
unsigned int crn;
|
||||
unsigned int crm;
|
||||
unsigned int Rd;
|
||||
unsigned int inst;
|
||||
};
|
||||
|
||||
struct mcr_inst {
|
||||
unsigned int opcode_1;
|
||||
unsigned int opcode_2;
|
||||
unsigned int cp_num;
|
||||
unsigned int crn;
|
||||
unsigned int crm;
|
||||
unsigned int Rd;
|
||||
unsigned int inst;
|
||||
};
|
||||
|
||||
struct mcrr_inst {
|
||||
unsigned int opcode_1;
|
||||
unsigned int cp_num;
|
||||
unsigned int crm;
|
||||
unsigned int rt;
|
||||
unsigned int rt2;
|
||||
};
|
||||
|
||||
struct mrs_inst {
|
||||
unsigned int R;
|
||||
unsigned int Rd;
|
||||
};
|
||||
|
||||
struct msr_inst {
|
||||
unsigned int field_mask;
|
||||
unsigned int R;
|
||||
unsigned int inst;
|
||||
};
|
||||
|
||||
struct pld_inst {
|
||||
};
|
||||
|
||||
struct sxtb_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rm;
|
||||
unsigned int rotate;
|
||||
};
|
||||
|
||||
struct sxtab_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rn;
|
||||
unsigned int Rm;
|
||||
unsigned rotate;
|
||||
};
|
||||
|
||||
struct sxtah_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rn;
|
||||
unsigned int Rm;
|
||||
unsigned int rotate;
|
||||
};
|
||||
|
||||
struct sxth_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rm;
|
||||
unsigned int rotate;
|
||||
};
|
||||
|
||||
struct uxtab_inst {
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int rotate;
|
||||
unsigned int Rm;
|
||||
};
|
||||
|
||||
struct uxtah_inst {
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int rotate;
|
||||
unsigned int Rm;
|
||||
};
|
||||
|
||||
struct uxth_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rm;
|
||||
unsigned int rotate;
|
||||
};
|
||||
|
||||
struct cdp_inst {
|
||||
unsigned int opcode_1;
|
||||
unsigned int CRn;
|
||||
unsigned int CRd;
|
||||
unsigned int cp_num;
|
||||
unsigned int opcode_2;
|
||||
unsigned int CRm;
|
||||
unsigned int inst;
|
||||
};
|
||||
|
||||
struct uxtb_inst {
|
||||
unsigned int Rd;
|
||||
unsigned int Rm;
|
||||
unsigned int rotate;
|
||||
};
|
||||
|
||||
struct swp_inst {
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned int Rm;
|
||||
};
|
||||
|
||||
struct setend_inst {
|
||||
unsigned int set_bigend;
|
||||
};
|
||||
|
||||
struct b_2_thumb {
|
||||
unsigned int imm;
|
||||
};
|
||||
struct b_cond_thumb {
|
||||
unsigned int imm;
|
||||
unsigned int cond;
|
||||
};
|
||||
|
||||
struct bl_1_thumb {
|
||||
unsigned int imm;
|
||||
};
|
||||
struct bl_2_thumb {
|
||||
unsigned int imm;
|
||||
};
|
||||
struct blx_1_thumb {
|
||||
unsigned int imm;
|
||||
unsigned int instr;
|
||||
};
|
||||
|
||||
struct pkh_inst {
|
||||
unsigned int Rm;
|
||||
unsigned int Rn;
|
||||
unsigned int Rd;
|
||||
unsigned char imm;
|
||||
};
|
||||
|
||||
// Floating point VFPv3 structures
|
||||
#define VFP_INTERPRETER_STRUCT
|
||||
#include "A32/skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp"
|
||||
#undef VFP_INTERPRETER_STRUCT
|
||||
|
||||
typedef void (*get_addr_fp_t)(ARMul_State *cpu, unsigned int inst, unsigned int &virt_addr);
|
||||
|
||||
struct ldst_inst {
|
||||
unsigned int inst;
|
||||
get_addr_fp_t get_addr;
|
||||
};
|
||||
|
||||
typedef arm_inst* ARM_INST_PTR;
|
||||
typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int);
|
||||
|
||||
extern const transop_fp_t arm_instruction_trans[];
|
||||
extern const size_t arm_instruction_trans_len;
|
||||
|
||||
#define TRANS_CACHE_SIZE (64 * 1024 * 2000)
|
||||
extern char trans_cache_buf[TRANS_CACHE_SIZE];
|
||||
extern size_t trans_cache_buf_top;
|
|
@ -1,187 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
enum {
|
||||
R0 = 0,
|
||||
R1,
|
||||
R2,
|
||||
R3,
|
||||
R4,
|
||||
R5,
|
||||
R6,
|
||||
R7,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
LR,
|
||||
R15, //PC,
|
||||
CPSR_REG,
|
||||
SPSR_REG,
|
||||
|
||||
PHYS_PC,
|
||||
R13_USR,
|
||||
R14_USR,
|
||||
R13_SVC,
|
||||
R14_SVC,
|
||||
R13_ABORT,
|
||||
R14_ABORT,
|
||||
R13_UNDEF,
|
||||
R14_UNDEF,
|
||||
R13_IRQ,
|
||||
R14_IRQ,
|
||||
R8_FIRQ,
|
||||
R9_FIRQ,
|
||||
R10_FIRQ,
|
||||
R11_FIRQ,
|
||||
R12_FIRQ,
|
||||
R13_FIRQ,
|
||||
R14_FIRQ,
|
||||
SPSR_INVALID1,
|
||||
SPSR_INVALID2,
|
||||
SPSR_SVC,
|
||||
SPSR_ABORT,
|
||||
SPSR_UNDEF,
|
||||
SPSR_IRQ,
|
||||
SPSR_FIRQ,
|
||||
MODE_REG, /* That is the cpsr[4 : 0], just for calculation easily */
|
||||
BANK_REG,
|
||||
EXCLUSIVE_TAG,
|
||||
EXCLUSIVE_STATE,
|
||||
EXCLUSIVE_RESULT,
|
||||
|
||||
MAX_REG_NUM,
|
||||
};
|
||||
|
||||
// VFP system registers
|
||||
enum VFPSystemRegister {
|
||||
VFP_FPSID,
|
||||
VFP_FPSCR,
|
||||
VFP_FPEXC,
|
||||
VFP_FPINST,
|
||||
VFP_FPINST2,
|
||||
VFP_MVFR0,
|
||||
VFP_MVFR1,
|
||||
|
||||
// Not an actual register.
|
||||
// All VFP system registers should be defined above this.
|
||||
VFP_SYSTEM_REGISTER_COUNT
|
||||
};
|
||||
|
||||
enum CP15Register {
|
||||
// c0 - Information registers
|
||||
CP15_MAIN_ID,
|
||||
CP15_CACHE_TYPE,
|
||||
CP15_TCM_STATUS,
|
||||
CP15_TLB_TYPE,
|
||||
CP15_CPU_ID,
|
||||
CP15_PROCESSOR_FEATURE_0,
|
||||
CP15_PROCESSOR_FEATURE_1,
|
||||
CP15_DEBUG_FEATURE_0,
|
||||
CP15_AUXILIARY_FEATURE_0,
|
||||
CP15_MEMORY_MODEL_FEATURE_0,
|
||||
CP15_MEMORY_MODEL_FEATURE_1,
|
||||
CP15_MEMORY_MODEL_FEATURE_2,
|
||||
CP15_MEMORY_MODEL_FEATURE_3,
|
||||
CP15_ISA_FEATURE_0,
|
||||
CP15_ISA_FEATURE_1,
|
||||
CP15_ISA_FEATURE_2,
|
||||
CP15_ISA_FEATURE_3,
|
||||
CP15_ISA_FEATURE_4,
|
||||
|
||||
// c1 - Control registers
|
||||
CP15_CONTROL,
|
||||
CP15_AUXILIARY_CONTROL,
|
||||
CP15_COPROCESSOR_ACCESS_CONTROL,
|
||||
|
||||
// c2 - Translation table registers
|
||||
CP15_TRANSLATION_BASE_TABLE_0,
|
||||
CP15_TRANSLATION_BASE_TABLE_1,
|
||||
CP15_TRANSLATION_BASE_CONTROL,
|
||||
CP15_DOMAIN_ACCESS_CONTROL,
|
||||
CP15_RESERVED,
|
||||
|
||||
// c5 - Fault status registers
|
||||
CP15_FAULT_STATUS,
|
||||
CP15_INSTR_FAULT_STATUS,
|
||||
CP15_COMBINED_DATA_FSR = CP15_FAULT_STATUS,
|
||||
CP15_INST_FSR,
|
||||
|
||||
// c6 - Fault Address registers
|
||||
CP15_FAULT_ADDRESS,
|
||||
CP15_COMBINED_DATA_FAR = CP15_FAULT_ADDRESS,
|
||||
CP15_WFAR,
|
||||
CP15_IFAR,
|
||||
|
||||
// c7 - Cache operation registers
|
||||
CP15_WAIT_FOR_INTERRUPT,
|
||||
CP15_PHYS_ADDRESS,
|
||||
CP15_INVALIDATE_INSTR_CACHE,
|
||||
CP15_INVALIDATE_INSTR_CACHE_USING_MVA,
|
||||
CP15_INVALIDATE_INSTR_CACHE_USING_INDEX,
|
||||
CP15_FLUSH_PREFETCH_BUFFER,
|
||||
CP15_FLUSH_BRANCH_TARGET_CACHE,
|
||||
CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY,
|
||||
CP15_INVALIDATE_DATA_CACHE,
|
||||
CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA,
|
||||
CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX,
|
||||
CP15_INVALIDATE_DATA_AND_INSTR_CACHE,
|
||||
CP15_CLEAN_DATA_CACHE,
|
||||
CP15_CLEAN_DATA_CACHE_LINE_USING_MVA,
|
||||
CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX,
|
||||
CP15_DATA_SYNC_BARRIER,
|
||||
CP15_DATA_MEMORY_BARRIER,
|
||||
CP15_CLEAN_AND_INVALIDATE_DATA_CACHE,
|
||||
CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA,
|
||||
CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX,
|
||||
|
||||
// c8 - TLB operations
|
||||
CP15_INVALIDATE_ITLB,
|
||||
CP15_INVALIDATE_ITLB_SINGLE_ENTRY,
|
||||
CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH,
|
||||
CP15_INVALIDATE_ITLB_ENTRY_ON_MVA,
|
||||
CP15_INVALIDATE_DTLB,
|
||||
CP15_INVALIDATE_DTLB_SINGLE_ENTRY,
|
||||
CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH,
|
||||
CP15_INVALIDATE_DTLB_ENTRY_ON_MVA,
|
||||
CP15_INVALIDATE_UTLB,
|
||||
CP15_INVALIDATE_UTLB_SINGLE_ENTRY,
|
||||
CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH,
|
||||
CP15_INVALIDATE_UTLB_ENTRY_ON_MVA,
|
||||
|
||||
// c9 - Data cache lockdown register
|
||||
CP15_DATA_CACHE_LOCKDOWN,
|
||||
|
||||
// c10 - TLB/Memory map registers
|
||||
CP15_TLB_LOCKDOWN,
|
||||
CP15_PRIMARY_REGION_REMAP,
|
||||
CP15_NORMAL_REGION_REMAP,
|
||||
|
||||
// c13 - Thread related registers
|
||||
CP15_PID,
|
||||
CP15_CONTEXT_ID,
|
||||
CP15_THREAD_UPRW, // Thread ID register - User/Privileged Read/Write
|
||||
CP15_THREAD_URO, // Thread ID register - User Read Only (Privileged R/W)
|
||||
CP15_THREAD_PRW, // Thread ID register - Privileged R/W only.
|
||||
|
||||
// c15 - Performance and TLB lockdown registers
|
||||
CP15_PERFORMANCE_MONITOR_CONTROL,
|
||||
CP15_CYCLE_COUNTER,
|
||||
CP15_COUNT_0,
|
||||
CP15_COUNT_1,
|
||||
CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY,
|
||||
CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY,
|
||||
CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS,
|
||||
CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS,
|
||||
CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE,
|
||||
CP15_TLB_DEBUG_CONTROL,
|
||||
|
||||
// Skyeye defined
|
||||
CP15_TLB_FAULT_ADDR,
|
||||
CP15_TLB_FAULT_STATUS,
|
||||
|
||||
// Not an actual register.
|
||||
// All registers should be defined above this.
|
||||
CP15_REGISTER_COUNT,
|
||||
};
|
|
@ -1,693 +0,0 @@
|
|||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4244)
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armstate.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/vfp/vfp.h"
|
||||
|
||||
ARMul_State::ARMul_State(PrivilegeMode initial_mode)
|
||||
{
|
||||
Reset();
|
||||
ChangePrivilegeMode(initial_mode);
|
||||
}
|
||||
|
||||
void ARMul_State::ChangePrivilegeMode(u32 new_mode)
|
||||
{
|
||||
if (Mode == new_mode)
|
||||
return;
|
||||
|
||||
if (new_mode != USERBANK) {
|
||||
switch (Mode) {
|
||||
case SYSTEM32MODE: // Shares registers with user mode
|
||||
case USER32MODE:
|
||||
Reg_usr[0] = Reg[13];
|
||||
Reg_usr[1] = Reg[14];
|
||||
break;
|
||||
case IRQ32MODE:
|
||||
Reg_irq[0] = Reg[13];
|
||||
Reg_irq[1] = Reg[14];
|
||||
Spsr[IRQBANK] = Spsr_copy;
|
||||
break;
|
||||
case SVC32MODE:
|
||||
Reg_svc[0] = Reg[13];
|
||||
Reg_svc[1] = Reg[14];
|
||||
Spsr[SVCBANK] = Spsr_copy;
|
||||
break;
|
||||
case ABORT32MODE:
|
||||
Reg_abort[0] = Reg[13];
|
||||
Reg_abort[1] = Reg[14];
|
||||
Spsr[ABORTBANK] = Spsr_copy;
|
||||
break;
|
||||
case UNDEF32MODE:
|
||||
Reg_undef[0] = Reg[13];
|
||||
Reg_undef[1] = Reg[14];
|
||||
Spsr[UNDEFBANK] = Spsr_copy;
|
||||
break;
|
||||
case FIQ32MODE:
|
||||
std::copy(Reg.begin() + 8, Reg.end() - 1, Reg_firq.begin());
|
||||
Spsr[FIQBANK] = Spsr_copy;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (new_mode) {
|
||||
case USER32MODE:
|
||||
Reg[13] = Reg_usr[0];
|
||||
Reg[14] = Reg_usr[1];
|
||||
Bank = USERBANK;
|
||||
break;
|
||||
case IRQ32MODE:
|
||||
Reg[13] = Reg_irq[0];
|
||||
Reg[14] = Reg_irq[1];
|
||||
Spsr_copy = Spsr[IRQBANK];
|
||||
Bank = IRQBANK;
|
||||
break;
|
||||
case SVC32MODE:
|
||||
Reg[13] = Reg_svc[0];
|
||||
Reg[14] = Reg_svc[1];
|
||||
Spsr_copy = Spsr[SVCBANK];
|
||||
Bank = SVCBANK;
|
||||
break;
|
||||
case ABORT32MODE:
|
||||
Reg[13] = Reg_abort[0];
|
||||
Reg[14] = Reg_abort[1];
|
||||
Spsr_copy = Spsr[ABORTBANK];
|
||||
Bank = ABORTBANK;
|
||||
break;
|
||||
case UNDEF32MODE:
|
||||
Reg[13] = Reg_undef[0];
|
||||
Reg[14] = Reg_undef[1];
|
||||
Spsr_copy = Spsr[UNDEFBANK];
|
||||
Bank = UNDEFBANK;
|
||||
break;
|
||||
case FIQ32MODE:
|
||||
std::copy(Reg_firq.begin(), Reg_firq.end(), Reg.begin() + 8);
|
||||
Spsr_copy = Spsr[FIQBANK];
|
||||
Bank = FIQBANK;
|
||||
break;
|
||||
case SYSTEM32MODE: // Shares registers with user mode.
|
||||
Reg[13] = Reg_usr[0];
|
||||
Reg[14] = Reg_usr[1];
|
||||
Bank = SYSTEMBANK;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the mode bits in the APSR
|
||||
Cpsr = (Cpsr & ~Mode) | new_mode;
|
||||
Mode = new_mode;
|
||||
}
|
||||
}
|
||||
|
||||
// Performs a reset
|
||||
void ARMul_State::Reset()
|
||||
{
|
||||
VFPInit(this);
|
||||
|
||||
// Set stack pointer to the top of the stack
|
||||
Reg[13] = 0x10000000;
|
||||
Reg[15] = 0;
|
||||
|
||||
Cpsr = INTBITS | SVC32MODE;
|
||||
Mode = SVC32MODE;
|
||||
Bank = SVCBANK;
|
||||
|
||||
ResetMPCoreCP15Registers();
|
||||
|
||||
NresetSig = HIGH;
|
||||
NfiqSig = HIGH;
|
||||
NirqSig = HIGH;
|
||||
NtransSig = (Mode & 3) ? HIGH : LOW;
|
||||
abortSig = LOW;
|
||||
|
||||
NumInstrs = 0;
|
||||
Emulate = RUN;
|
||||
}
|
||||
|
||||
// Resets certain MPCore CP15 values to their ARM-defined reset values.
|
||||
void ARMul_State::ResetMPCoreCP15Registers()
|
||||
{
|
||||
// c0
|
||||
CP15[CP15_MAIN_ID] = 0x410FB024;
|
||||
CP15[CP15_TLB_TYPE] = 0x00000800;
|
||||
CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111;
|
||||
CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001;
|
||||
CP15[CP15_DEBUG_FEATURE_0] = 0x00000002;
|
||||
CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103;
|
||||
CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302;
|
||||
CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000;
|
||||
CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000;
|
||||
CP15[CP15_ISA_FEATURE_0] = 0x00100011;
|
||||
CP15[CP15_ISA_FEATURE_1] = 0x12002111;
|
||||
CP15[CP15_ISA_FEATURE_2] = 0x11221011;
|
||||
CP15[CP15_ISA_FEATURE_3] = 0x01102131;
|
||||
CP15[CP15_ISA_FEATURE_4] = 0x00000141;
|
||||
|
||||
// c1
|
||||
CP15[CP15_CONTROL] = 0x00054078;
|
||||
CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F;
|
||||
CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000;
|
||||
|
||||
// c2
|
||||
CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000;
|
||||
CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000;
|
||||
CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000;
|
||||
|
||||
// c3
|
||||
CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000;
|
||||
|
||||
// c7
|
||||
CP15[CP15_PHYS_ADDRESS] = 0x00000000;
|
||||
|
||||
// c9
|
||||
CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0;
|
||||
|
||||
// c10
|
||||
CP15[CP15_TLB_LOCKDOWN] = 0x00000000;
|
||||
CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4;
|
||||
CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0;
|
||||
|
||||
// c13
|
||||
CP15[CP15_PID] = 0x00000000;
|
||||
CP15[CP15_CONTEXT_ID] = 0x00000000;
|
||||
CP15[CP15_THREAD_UPRW] = 0x00000000;
|
||||
CP15[CP15_THREAD_URO] = 0x00000000;
|
||||
CP15[CP15_THREAD_PRW] = 0x00000000;
|
||||
|
||||
// c15
|
||||
CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000;
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000;
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000;
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000;
|
||||
CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
|
||||
}
|
||||
|
||||
//static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type)
|
||||
//{
|
||||
// if (GDBStub::g_server_enabled && GDBStub::CheckBreakpoint(address, type)) {
|
||||
// LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address);
|
||||
// GDBStub::Break(true);
|
||||
// }
|
||||
//}
|
||||
|
||||
u8 ARMul_State::ReadMemory8(u32 address) const
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
return user_callbacks->MemoryRead8(address);
|
||||
}
|
||||
|
||||
u16 ARMul_State::ReadMemory16(u32 address) const
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
u16 data = user_callbacks->MemoryRead16(address);
|
||||
|
||||
if (InBigEndianMode())
|
||||
data = Dynarmic::Common::Swap16(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
u32 ARMul_State::ReadMemory32(u32 address) const
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
u32 data = user_callbacks->MemoryRead32(address);
|
||||
|
||||
if (InBigEndianMode())
|
||||
data = Dynarmic::Common::Swap32(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
u64 ARMul_State::ReadMemory64(u32 address) const
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||
|
||||
u64 data = user_callbacks->MemoryRead64(address);
|
||||
|
||||
if (InBigEndianMode())
|
||||
data = Dynarmic::Common::Swap64(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory8(u32 address, u8 data)
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
user_callbacks->MemoryWrite8(address, data);
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory16(u32 address, u16 data)
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
if (InBigEndianMode())
|
||||
data = Dynarmic::Common::Swap16(data);
|
||||
|
||||
user_callbacks->MemoryWrite16(address, data);
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory32(u32 address, u32 data)
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
if (InBigEndianMode())
|
||||
data = Dynarmic::Common::Swap32(data);
|
||||
|
||||
user_callbacks->MemoryWrite32(address, data);
|
||||
}
|
||||
|
||||
void ARMul_State::WriteMemory64(u32 address, u64 data)
|
||||
{
|
||||
// CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||
|
||||
if (InBigEndianMode())
|
||||
data = Dynarmic::Common::Swap64(data);
|
||||
|
||||
user_callbacks->MemoryWrite64(address, data);
|
||||
}
|
||||
|
||||
|
||||
// Reads from the CP15 registers. Used with implementation of the MRC instruction.
|
||||
// Note that since the 3DS does not have the hypervisor extensions, these registers
|
||||
// are not implemented.
|
||||
u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const
|
||||
{
|
||||
// Unprivileged registers
|
||||
if (crn == 13 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 2)
|
||||
return CP15[CP15_THREAD_UPRW];
|
||||
|
||||
if (opcode_2 == 3)
|
||||
return CP15[CP15_THREAD_URO];
|
||||
}
|
||||
|
||||
if (InAPrivilegedMode())
|
||||
{
|
||||
if (crn == 0 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_MAIN_ID];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_CACHE_TYPE];
|
||||
|
||||
if (opcode_2 == 3)
|
||||
return CP15[CP15_TLB_TYPE];
|
||||
|
||||
if (opcode_2 == 5)
|
||||
return CP15[CP15_CPU_ID];
|
||||
}
|
||||
else if (crm == 1)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PROCESSOR_FEATURE_0];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_PROCESSOR_FEATURE_1];
|
||||
|
||||
if (opcode_2 == 2)
|
||||
return CP15[CP15_DEBUG_FEATURE_0];
|
||||
|
||||
if (opcode_2 == 4)
|
||||
return CP15[CP15_MEMORY_MODEL_FEATURE_0];
|
||||
|
||||
if (opcode_2 == 5)
|
||||
return CP15[CP15_MEMORY_MODEL_FEATURE_1];
|
||||
|
||||
if (opcode_2 == 6)
|
||||
return CP15[CP15_MEMORY_MODEL_FEATURE_2];
|
||||
|
||||
if (opcode_2 == 7)
|
||||
return CP15[CP15_MEMORY_MODEL_FEATURE_3];
|
||||
}
|
||||
else if (crm == 2)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_ISA_FEATURE_0];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_ISA_FEATURE_1];
|
||||
|
||||
if (opcode_2 == 2)
|
||||
return CP15[CP15_ISA_FEATURE_2];
|
||||
|
||||
if (opcode_2 == 3)
|
||||
return CP15[CP15_ISA_FEATURE_3];
|
||||
|
||||
if (opcode_2 == 4)
|
||||
return CP15[CP15_ISA_FEATURE_4];
|
||||
}
|
||||
}
|
||||
|
||||
if (crn == 1 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_CONTROL];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_AUXILIARY_CONTROL];
|
||||
|
||||
if (opcode_2 == 2)
|
||||
return CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
|
||||
}
|
||||
|
||||
if (crn == 2 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_TRANSLATION_BASE_TABLE_0];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_TRANSLATION_BASE_TABLE_1];
|
||||
|
||||
if (opcode_2 == 2)
|
||||
return CP15[CP15_TRANSLATION_BASE_CONTROL];
|
||||
}
|
||||
|
||||
if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
return CP15[CP15_DOMAIN_ACCESS_CONTROL];
|
||||
|
||||
if (crn == 5 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_FAULT_STATUS];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_INSTR_FAULT_STATUS];
|
||||
}
|
||||
|
||||
if (crn == 6 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_FAULT_ADDRESS];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_WFAR];
|
||||
}
|
||||
|
||||
if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
|
||||
return CP15[CP15_PHYS_ADDRESS];
|
||||
|
||||
if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
return CP15[CP15_DATA_CACHE_LOCKDOWN];
|
||||
|
||||
if (crn == 10 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 0 && opcode_2 == 0)
|
||||
return CP15[CP15_TLB_LOCKDOWN];
|
||||
|
||||
if (crm == 2)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PRIMARY_REGION_REMAP];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_NORMAL_REGION_REMAP];
|
||||
}
|
||||
}
|
||||
|
||||
if (crn == 13 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PID];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_CONTEXT_ID];
|
||||
|
||||
if (opcode_2 == 4)
|
||||
return CP15[CP15_THREAD_PRW];
|
||||
}
|
||||
|
||||
if (crn == 15)
|
||||
{
|
||||
if (opcode_1 == 0 && crm == 12)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
return CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
|
||||
|
||||
if (opcode_2 == 1)
|
||||
return CP15[CP15_CYCLE_COUNTER];
|
||||
|
||||
if (opcode_2 == 2)
|
||||
return CP15[CP15_COUNT_0];
|
||||
|
||||
if (opcode_2 == 3)
|
||||
return CP15[CP15_COUNT_1];
|
||||
}
|
||||
|
||||
if (opcode_1 == 5 && opcode_2 == 2)
|
||||
{
|
||||
if (crm == 5)
|
||||
return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
|
||||
|
||||
if (crm == 6)
|
||||
return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS];
|
||||
|
||||
if (crm == 7)
|
||||
return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE];
|
||||
}
|
||||
|
||||
if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
|
||||
return CP15[CP15_TLB_DEBUG_CONTROL];
|
||||
}
|
||||
}
|
||||
|
||||
// LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
|
||||
ASSERT_MSG(false, "MRC CRn={}, CRm={}, OP1={} OP2={} is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write to the CP15 registers. Used with implementation of the MCR instruction.
|
||||
// Note that since the 3DS does not have the hypervisor extensions, these registers
|
||||
// are not implemented.
|
||||
void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
|
||||
{
|
||||
if (InAPrivilegedMode())
|
||||
{
|
||||
if (crn == 1 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_CONTROL] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_AUXILIARY_CONTROL] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
|
||||
}
|
||||
else if (crn == 2 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
|
||||
}
|
||||
else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
{
|
||||
CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
|
||||
}
|
||||
else if (crn == 5 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_FAULT_STATUS] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INSTR_FAULT_STATUS] = value;
|
||||
}
|
||||
else if (crn == 6 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_FAULT_ADDRESS] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_WFAR] = value;
|
||||
}
|
||||
else if (crn == 7 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 0 && opcode_2 == 4)
|
||||
{
|
||||
CP15[CP15_WAIT_FOR_INTERRUPT] = value;
|
||||
}
|
||||
else if (crm == 4 && opcode_2 == 0)
|
||||
{
|
||||
// NOTE: Not entirely accurate. This should do permission checks.
|
||||
//CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
|
||||
}
|
||||
else if (crm == 5)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value;
|
||||
else if (opcode_2 == 6)
|
||||
CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
|
||||
else if (opcode_2 == 7)
|
||||
CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
|
||||
}
|
||||
else if (crm == 6)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_DATA_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
|
||||
}
|
||||
else if (crm == 7 && opcode_2 == 0)
|
||||
{
|
||||
CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
|
||||
}
|
||||
else if (crm == 10)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_CLEAN_DATA_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
|
||||
}
|
||||
else if (crm == 14)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
|
||||
}
|
||||
}
|
||||
else if (crn == 8 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 5)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_ITLB] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
|
||||
}
|
||||
else if (crm == 6)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_DTLB] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
|
||||
}
|
||||
else if (crm == 7)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_INVALIDATE_UTLB] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
|
||||
}
|
||||
}
|
||||
else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
|
||||
{
|
||||
CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
|
||||
}
|
||||
else if (crn == 10 && opcode_1 == 0)
|
||||
{
|
||||
if (crm == 0 && opcode_2 == 0)
|
||||
{
|
||||
CP15[CP15_TLB_LOCKDOWN] = value;
|
||||
}
|
||||
else if (crm == 2)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_PRIMARY_REGION_REMAP] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_NORMAL_REGION_REMAP] = value;
|
||||
}
|
||||
}
|
||||
else if (crn == 13 && opcode_1 == 0 && crm == 0)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_PID] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_CONTEXT_ID] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_THREAD_URO] = value;
|
||||
else if (opcode_2 == 4)
|
||||
CP15[CP15_THREAD_PRW] = value;
|
||||
}
|
||||
else if (crn == 15)
|
||||
{
|
||||
if (opcode_1 == 0 && crm == 12)
|
||||
{
|
||||
if (opcode_2 == 0)
|
||||
CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
|
||||
else if (opcode_2 == 1)
|
||||
CP15[CP15_CYCLE_COUNTER] = value;
|
||||
else if (opcode_2 == 2)
|
||||
CP15[CP15_COUNT_0] = value;
|
||||
else if (opcode_2 == 3)
|
||||
CP15[CP15_COUNT_1] = value;
|
||||
}
|
||||
else if (opcode_1 == 5)
|
||||
{
|
||||
if (crm == 4)
|
||||
{
|
||||
if (opcode_2 == 2)
|
||||
CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
|
||||
else if (opcode_2 == 4)
|
||||
CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
|
||||
}
|
||||
else if (crm == 5 && opcode_2 == 2)
|
||||
{
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
|
||||
}
|
||||
else if (crm == 6 && opcode_2 == 2)
|
||||
{
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
|
||||
}
|
||||
else if (crm == 7 && opcode_2 == 2)
|
||||
{
|
||||
CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
|
||||
}
|
||||
}
|
||||
else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
|
||||
{
|
||||
CP15[CP15_TLB_DEBUG_CONTROL] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unprivileged registers
|
||||
if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4)
|
||||
{
|
||||
CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
|
||||
}
|
||||
else if (crn == 7 && opcode_1 == 0 && crm == 10)
|
||||
{
|
||||
if (opcode_2 == 4)
|
||||
CP15[CP15_DATA_SYNC_BARRIER] = value;
|
||||
else if (opcode_2 == 5)
|
||||
CP15[CP15_DATA_MEMORY_BARRIER] = value;
|
||||
}
|
||||
else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
|
||||
{
|
||||
CP15[CP15_THREAD_UPRW] = value;
|
||||
}
|
||||
}
|
|
@ -1,256 +0,0 @@
|
|||
/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
|
||||
Copyright (C) 1994 Advanced RISC Machines Ltd.
|
||||
|
||||
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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <dynarmic/A32/config.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/arm_regformat.h"
|
||||
|
||||
// Signal levels
|
||||
enum {
|
||||
LOW = 0,
|
||||
HIGH = 1,
|
||||
LOWHIGH = 1,
|
||||
HIGHLOW = 2
|
||||
};
|
||||
|
||||
// Cache types
|
||||
enum {
|
||||
NONCACHE = 0,
|
||||
DATACACHE = 1,
|
||||
INSTCACHE = 2,
|
||||
};
|
||||
|
||||
// ARM privilege modes
|
||||
enum PrivilegeMode {
|
||||
USER32MODE = 16,
|
||||
FIQ32MODE = 17,
|
||||
IRQ32MODE = 18,
|
||||
SVC32MODE = 19,
|
||||
ABORT32MODE = 23,
|
||||
UNDEF32MODE = 27,
|
||||
SYSTEM32MODE = 31
|
||||
};
|
||||
|
||||
// ARM privilege mode register banks
|
||||
enum {
|
||||
USERBANK = 0,
|
||||
FIQBANK = 1,
|
||||
IRQBANK = 2,
|
||||
SVCBANK = 3,
|
||||
ABORTBANK = 4,
|
||||
UNDEFBANK = 5,
|
||||
DUMMYBANK = 6,
|
||||
SYSTEMBANK = 7
|
||||
};
|
||||
|
||||
// Hardware vector addresses
|
||||
enum {
|
||||
ARMResetV = 0,
|
||||
ARMUndefinedInstrV = 4,
|
||||
ARMSWIV = 8,
|
||||
ARMPrefetchAbortV = 12,
|
||||
ARMDataAbortV = 16,
|
||||
ARMAddrExceptnV = 20,
|
||||
ARMIRQV = 24,
|
||||
ARMFIQV = 28,
|
||||
ARMErrorV = 32, // This is an offset, not an address!
|
||||
|
||||
ARMul_ResetV = ARMResetV,
|
||||
ARMul_UndefinedInstrV = ARMUndefinedInstrV,
|
||||
ARMul_SWIV = ARMSWIV,
|
||||
ARMul_PrefetchAbortV = ARMPrefetchAbortV,
|
||||
ARMul_DataAbortV = ARMDataAbortV,
|
||||
ARMul_AddrExceptnV = ARMAddrExceptnV,
|
||||
ARMul_IRQV = ARMIRQV,
|
||||
ARMul_FIQV = ARMFIQV
|
||||
};
|
||||
|
||||
// Coprocessor status values
|
||||
enum {
|
||||
ARMul_FIRST = 0,
|
||||
ARMul_TRANSFER = 1,
|
||||
ARMul_BUSY = 2,
|
||||
ARMul_DATA = 3,
|
||||
ARMul_INTERRUPT = 4,
|
||||
ARMul_DONE = 0,
|
||||
ARMul_CANT = 1,
|
||||
ARMul_INC = 3
|
||||
};
|
||||
|
||||
// Instruction condition codes
|
||||
enum ConditionCode {
|
||||
EQ = 0,
|
||||
NE = 1,
|
||||
CS = 2,
|
||||
CC = 3,
|
||||
MI = 4,
|
||||
PL = 5,
|
||||
VS = 6,
|
||||
VC = 7,
|
||||
HI = 8,
|
||||
LS = 9,
|
||||
GE = 10,
|
||||
LT = 11,
|
||||
GT = 12,
|
||||
LE = 13,
|
||||
AL = 14,
|
||||
NV = 15,
|
||||
};
|
||||
|
||||
// Flags for use with the APSR.
|
||||
enum : u32 {
|
||||
NBIT = (1U << 31U),
|
||||
ZBIT = (1 << 30),
|
||||
CBIT = (1 << 29),
|
||||
VBIT = (1 << 28),
|
||||
QBIT = (1 << 27),
|
||||
JBIT = (1 << 24),
|
||||
EBIT = (1 << 9),
|
||||
ABIT = (1 << 8),
|
||||
IBIT = (1 << 7),
|
||||
FBIT = (1 << 6),
|
||||
TBIT = (1 << 5),
|
||||
|
||||
// Masks for groups of bits in the APSR.
|
||||
MODEBITS = 0x1F,
|
||||
INTBITS = 0x1C0,
|
||||
};
|
||||
|
||||
// Values for Emulate.
|
||||
enum {
|
||||
STOP = 0, // Stop
|
||||
CHANGEMODE = 1, // Change mode
|
||||
ONCE = 2, // Execute just one iteration
|
||||
RUN = 3 // Continuous execution
|
||||
};
|
||||
|
||||
|
||||
struct ARMul_State final
|
||||
{
|
||||
public:
|
||||
explicit ARMul_State(PrivilegeMode initial_mode);
|
||||
|
||||
void ChangePrivilegeMode(u32 new_mode);
|
||||
void Reset();
|
||||
|
||||
// Reads/writes data in big/little endian format based on the
|
||||
// state of the E (endian) bit in the APSR.
|
||||
u8 ReadMemory8(u32 address) const;
|
||||
u16 ReadMemory16(u32 address) const;
|
||||
u32 ReadMemory32(u32 address) const;
|
||||
u64 ReadMemory64(u32 address) const;
|
||||
void WriteMemory8(u32 address, u8 data);
|
||||
void WriteMemory16(u32 address, u16 data);
|
||||
void WriteMemory32(u32 address, u32 data);
|
||||
void WriteMemory64(u32 address, u64 data);
|
||||
|
||||
u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const;
|
||||
void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
|
||||
|
||||
// Exclusive memory access functions
|
||||
bool IsExclusiveMemoryAccess(u32 address) const {
|
||||
return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK);
|
||||
}
|
||||
void SetExclusiveMemoryAddress(u32 address) {
|
||||
exclusive_tag = address & RESERVATION_GRANULE_MASK;
|
||||
exclusive_state = true;
|
||||
}
|
||||
void UnsetExclusiveMemoryAddress() {
|
||||
exclusive_tag = 0xFFFFFFFF;
|
||||
exclusive_state = false;
|
||||
}
|
||||
|
||||
// Whether or not the given CPU is in big endian mode (E bit is set)
|
||||
bool InBigEndianMode() const {
|
||||
return (Cpsr & (1 << 9)) != 0;
|
||||
}
|
||||
// Whether or not the given CPU is in a mode other than user mode.
|
||||
bool InAPrivilegedMode() const {
|
||||
return (Mode != USER32MODE);
|
||||
}
|
||||
// Note that for the 3DS, a Thumb instruction will only ever be
|
||||
// two bytes in size. Thus we don't need to worry about ThumbEE
|
||||
// or Thumb-2 where instructions can be 4 bytes in length.
|
||||
u32 GetInstructionSize() const {
|
||||
return TFlag ? 2 : 4;
|
||||
}
|
||||
|
||||
std::array<u32, 16> Reg{}; // The current register file
|
||||
std::array<u32, 2> Reg_usr{};
|
||||
std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC
|
||||
std::array<u32, 2> Reg_abort{}; // R13_ABORT R14_ABORT
|
||||
std::array<u32, 2> Reg_undef{}; // R13 UNDEF R14 UNDEF
|
||||
std::array<u32, 2> Reg_irq{}; // R13_IRQ R14_IRQ
|
||||
std::array<u32, 7> Reg_firq{}; // R8---R14 FIRQ
|
||||
std::array<u32, 7> Spsr{}; // The exception psr's
|
||||
std::array<u32, CP15_REGISTER_COUNT> CP15{};
|
||||
|
||||
// FPSID, FPSCR, and FPEXC
|
||||
std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP{};
|
||||
|
||||
// VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
|
||||
// VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
|
||||
// and only 32 singleword registers are accessible (S0-S31).
|
||||
std::array<u32, 64> ExtReg{};
|
||||
|
||||
u32 Emulate; // To start and stop emulation
|
||||
u32 Cpsr; // The current PSR
|
||||
u32 Spsr_copy;
|
||||
u32 phys_pc;
|
||||
|
||||
u32 Mode; // The current mode
|
||||
u32 Bank; // The current register bank
|
||||
|
||||
u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
|
||||
unsigned int shifter_carry_out;
|
||||
|
||||
u32 TFlag; // Thumb state
|
||||
|
||||
unsigned long long NumInstrs; // The number of instructions executed
|
||||
unsigned NumInstrsToExecute;
|
||||
|
||||
unsigned NresetSig; // Reset the processor
|
||||
unsigned NfiqSig;
|
||||
unsigned NirqSig;
|
||||
|
||||
unsigned abortSig;
|
||||
unsigned NtransSig;
|
||||
unsigned bigendSig;
|
||||
unsigned syscallSig;
|
||||
|
||||
// TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
|
||||
// process for our purposes), not per ARMul_State (which tracks CPU core state).
|
||||
std::unordered_map<u32, int> instruction_cache;
|
||||
|
||||
void ResetMPCoreCP15Registers();
|
||||
|
||||
// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
|
||||
// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
|
||||
// support LDR/STREXD.
|
||||
static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
|
||||
|
||||
u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
|
||||
bool exclusive_state;
|
||||
|
||||
Dynarmic::A32::UserCallbacks* user_callbacks;
|
||||
};
|
|
@ -1,207 +0,0 @@
|
|||
/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
|
||||
Copyright (C) 1994 Advanced RISC Machines Ltd.
|
||||
|
||||
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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
//#include "common/logging/log.h"
|
||||
|
||||
#include "A32/skyeye_interpreter/skyeye_common/arm_regformat.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armstate.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armsupp.h"
|
||||
|
||||
// Unsigned sum of absolute difference
|
||||
u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
|
||||
{
|
||||
if (left > right)
|
||||
return left - right;
|
||||
|
||||
return right - left;
|
||||
}
|
||||
|
||||
// Add with carry, indicates if a carry-out or signed overflow occurred.
|
||||
u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred)
|
||||
{
|
||||
u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in;
|
||||
s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in;
|
||||
u64 result = (unsigned_sum & 0xFFFFFFFF);
|
||||
|
||||
if (carry_out_occurred)
|
||||
*carry_out_occurred = (result != unsigned_sum);
|
||||
|
||||
if (overflow_occurred)
|
||||
*overflow_occurred = ((s64)(s32)result != signed_sum);
|
||||
|
||||
return (u32)result;
|
||||
}
|
||||
|
||||
// Compute whether an addition of A and B, giving RESULT, overflowed.
|
||||
bool AddOverflow(u32 a, u32 b, u32 result)
|
||||
{
|
||||
return ((NEG(a) && NEG(b) && POS(result)) ||
|
||||
(POS(a) && POS(b) && NEG(result)));
|
||||
}
|
||||
|
||||
// Compute whether a subtraction of A and B, giving RESULT, overflowed.
|
||||
bool SubOverflow(u32 a, u32 b, u32 result)
|
||||
{
|
||||
return ((NEG(a) && POS(b) && POS(result)) ||
|
||||
(POS(a) && NEG(b) && NEG(result)));
|
||||
}
|
||||
|
||||
// Returns true if the Q flag should be set as a result of overflow.
|
||||
bool ARMul_AddOverflowQ(u32 a, u32 b)
|
||||
{
|
||||
u32 result = a + b;
|
||||
if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 8-bit signed saturated addition
|
||||
u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
|
||||
{
|
||||
u8 result = left + right;
|
||||
|
||||
if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
|
||||
if (left & 0x80)
|
||||
result = 0x80;
|
||||
else
|
||||
result = 0x7F;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 8-bit signed saturated subtraction
|
||||
u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
|
||||
{
|
||||
u8 result = left - right;
|
||||
|
||||
if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
|
||||
if (left & 0x80)
|
||||
result = 0x80;
|
||||
else
|
||||
result = 0x7F;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 16-bit signed saturated addition
|
||||
u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
|
||||
{
|
||||
u16 result = left + right;
|
||||
|
||||
if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
|
||||
if (left & 0x8000)
|
||||
result = 0x8000;
|
||||
else
|
||||
result = 0x7FFF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 16-bit signed saturated subtraction
|
||||
u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
|
||||
{
|
||||
u16 result = left - right;
|
||||
|
||||
if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
|
||||
if (left & 0x8000)
|
||||
result = 0x8000;
|
||||
else
|
||||
result = 0x7FFF;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 8-bit unsigned saturated addition
|
||||
u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
|
||||
{
|
||||
u8 result = left + right;
|
||||
|
||||
if (result < left)
|
||||
result = 0xFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 16-bit unsigned saturated addition
|
||||
u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
|
||||
{
|
||||
u16 result = left + right;
|
||||
|
||||
if (result < left)
|
||||
result = 0xFFFF;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 8-bit unsigned saturated subtraction
|
||||
u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
|
||||
{
|
||||
if (left <= right)
|
||||
return 0;
|
||||
|
||||
return left - right;
|
||||
}
|
||||
|
||||
// 16-bit unsigned saturated subtraction
|
||||
u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
|
||||
{
|
||||
if (left <= right)
|
||||
return 0;
|
||||
|
||||
return left - right;
|
||||
}
|
||||
|
||||
// Signed saturation.
|
||||
u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
|
||||
{
|
||||
const u32 max = (1 << shift) - 1;
|
||||
const s32 top = (value >> shift);
|
||||
|
||||
if (top > 0) {
|
||||
*saturation_occurred = true;
|
||||
return max;
|
||||
}
|
||||
else if (top < -1) {
|
||||
*saturation_occurred = true;
|
||||
return ~max;
|
||||
}
|
||||
|
||||
*saturation_occurred = false;
|
||||
return (u32)value;
|
||||
}
|
||||
|
||||
// Unsigned saturation
|
||||
u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
|
||||
{
|
||||
const u32 max = (1 << shift) - 1;
|
||||
|
||||
if (value < 0) {
|
||||
*saturation_occurred = true;
|
||||
return 0;
|
||||
} else if ((u32)value > max) {
|
||||
*saturation_occurred = true;
|
||||
return max;
|
||||
}
|
||||
|
||||
*saturation_occurred = false;
|
||||
return (u32)value;
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
|
||||
#define BIT(s, n) ((s >> (n)) & 1)
|
||||
|
||||
#define POS(i) ( (~(i)) >> 31 )
|
||||
#define NEG(i) ( (i) >> 31 )
|
||||
|
||||
bool AddOverflow(u32, u32, u32);
|
||||
bool SubOverflow(u32, u32, u32);
|
||||
|
||||
u32 AddWithCarry(u32, u32, u32, bool*, bool*);
|
||||
bool ARMul_AddOverflowQ(u32, u32);
|
||||
|
||||
u8 ARMul_SignedSaturatedAdd8(u8, u8);
|
||||
u8 ARMul_SignedSaturatedSub8(u8, u8);
|
||||
u16 ARMul_SignedSaturatedAdd16(u16, u16);
|
||||
u16 ARMul_SignedSaturatedSub16(u16, u16);
|
||||
|
||||
u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
|
||||
u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
|
||||
u8 ARMul_UnsignedSaturatedSub8(u8, u8);
|
||||
u16 ARMul_UnsignedSaturatedSub16(u16, u16);
|
||||
u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
|
||||
u32 ARMul_SignedSatQ(s32, u8, bool*);
|
||||
u32 ARMul_UnsignedSatQ(s32, u8, bool*);
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* arch/arm/include/asm/vfp.h
|
||||
*
|
||||
* VFP register definitions.
|
||||
* First, the standard VFP set.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// ARM11 MPCore FPSID Information
|
||||
// Note that these are used as values and not as flags.
|
||||
enum : u32 {
|
||||
VFP_FPSID_IMPLMEN = 0x41, // Implementation code. Should be the same as cp15 0 c0 0
|
||||
VFP_FPSID_SW = 0, // Software emulation bit value
|
||||
VFP_FPSID_SUBARCH = 0x1, // Subarchitecture version number
|
||||
VFP_FPSID_PARTNUM = 0x20, // Part number
|
||||
VFP_FPSID_VARIANT = 0xB, // Variant number
|
||||
VFP_FPSID_REVISION = 0x4 // Revision number
|
||||
};
|
||||
|
||||
// FPEXC bits
|
||||
enum : u32 {
|
||||
FPEXC_EX = (1U << 31U),
|
||||
FPEXC_EN = (1 << 30),
|
||||
FPEXC_DEX = (1 << 29),
|
||||
FPEXC_FP2V = (1 << 28),
|
||||
FPEXC_VV = (1 << 27),
|
||||
FPEXC_TFV = (1 << 26),
|
||||
FPEXC_LENGTH_BIT = (8),
|
||||
FPEXC_LENGTH_MASK = (7 << FPEXC_LENGTH_BIT),
|
||||
FPEXC_IDF = (1 << 7),
|
||||
FPEXC_IXF = (1 << 4),
|
||||
FPEXC_UFF = (1 << 3),
|
||||
FPEXC_OFF = (1 << 2),
|
||||
FPEXC_DZF = (1 << 1),
|
||||
FPEXC_IOF = (1 << 0),
|
||||
FPEXC_TRAP_MASK = (FPEXC_IDF|FPEXC_IXF|FPEXC_UFF|FPEXC_OFF|FPEXC_DZF|FPEXC_IOF)
|
||||
};
|
||||
|
||||
// FPSCR Flags
|
||||
enum : u32 {
|
||||
FPSCR_NFLAG = (1U << 31U), // Negative condition flag
|
||||
FPSCR_ZFLAG = (1 << 30), // Zero condition flag
|
||||
FPSCR_CFLAG = (1 << 29), // Carry condition flag
|
||||
FPSCR_VFLAG = (1 << 28), // Overflow condition flag
|
||||
|
||||
FPSCR_QC = (1 << 27), // Cumulative saturation bit
|
||||
FPSCR_AHP = (1 << 26), // Alternative half-precision control bit
|
||||
FPSCR_DEFAULT_NAN = (1 << 25), // Default NaN mode control bit
|
||||
FPSCR_FLUSH_TO_ZERO = (1 << 24), // Flush-to-zero mode control bit
|
||||
FPSCR_RMODE_MASK = (3 << 22), // Rounding Mode bit mask
|
||||
FPSCR_STRIDE_MASK = (3 << 20), // Vector stride bit mask
|
||||
FPSCR_LENGTH_MASK = (7 << 16), // Vector length bit mask
|
||||
|
||||
FPSCR_IDE = (1 << 15), // Input Denormal exception trap enable.
|
||||
FPSCR_IXE = (1 << 12), // Inexact exception trap enable
|
||||
FPSCR_UFE = (1 << 11), // Undeflow exception trap enable
|
||||
FPSCR_OFE = (1 << 10), // Overflow exception trap enable
|
||||
FPSCR_DZE = (1 << 9), // Division by Zero exception trap enable
|
||||
FPSCR_IOE = (1 << 8), // Invalid Operation exception trap enable
|
||||
|
||||
FPSCR_IDC = (1 << 7), // Input Denormal cumulative exception bit
|
||||
FPSCR_IXC = (1 << 4), // Inexact cumulative exception bit
|
||||
FPSCR_UFC = (1 << 3), // Undeflow cumulative exception bit
|
||||
FPSCR_OFC = (1 << 2), // Overflow cumulative exception bit
|
||||
FPSCR_DZC = (1 << 1), // Division by Zero cumulative exception bit
|
||||
FPSCR_IOC = (1 << 0), // Invalid Operation cumulative exception bit
|
||||
};
|
||||
|
||||
// FPSCR bit offsets
|
||||
enum : u32 {
|
||||
FPSCR_RMODE_BIT = 22,
|
||||
FPSCR_STRIDE_BIT = 20,
|
||||
FPSCR_LENGTH_BIT = 16,
|
||||
};
|
||||
|
||||
// FPSCR rounding modes
|
||||
enum : u32 {
|
||||
FPSCR_ROUND_NEAREST = (0 << 22),
|
||||
FPSCR_ROUND_PLUSINF = (1 << 22),
|
||||
FPSCR_ROUND_MINUSINF = (2 << 22),
|
||||
FPSCR_ROUND_TOZERO = (3 << 22)
|
||||
};
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
armvfp.c - ARM VFPv3 emulation unit
|
||||
Copyright (C) 2003 Skyeye Develop Group
|
||||
for help please send mail to <skyeye-developer@lists.gro.clinux.org>
|
||||
|
||||
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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/* Note: this file handles interface with arm core and vfp registers */
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armstate.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/vfp/asm_vfp.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/vfp/vfp.h"
|
||||
|
||||
#define LOG_INFO(...) do{}while(0)
|
||||
#define LOG_TRACE(...) do{}while(0)
|
||||
|
||||
void VFPInit(ARMul_State* state)
|
||||
{
|
||||
state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
|
||||
VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
|
||||
state->VFP[VFP_FPEXC] = 0;
|
||||
state->VFP[VFP_FPSCR] = 0;
|
||||
|
||||
// ARM11 MPCore instruction register reset values.
|
||||
state->VFP[VFP_FPINST] = 0xEE000A00;
|
||||
state->VFP[VFP_FPINST2] = 0;
|
||||
|
||||
// ARM11 MPCore feature register values.
|
||||
state->VFP[VFP_MVFR0] = 0x11111111;
|
||||
state->VFP[VFP_MVFR1] = 0;
|
||||
}
|
||||
|
||||
void VMOVBRS(ARMul_State* state, u32 to_arm, [[maybe_unused]] u32 t, u32 n, u32* value)
|
||||
{
|
||||
if (to_arm)
|
||||
{
|
||||
*value = state->ExtReg[n];
|
||||
}
|
||||
else
|
||||
{
|
||||
state->ExtReg[n] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
void VMOVBRRD(ARMul_State* state, u32 to_arm, [[maybe_unused]] u32 t, [[maybe_unused]] u32 t2,
|
||||
u32 n, u32* value1, u32* value2)
|
||||
{
|
||||
if (to_arm)
|
||||
{
|
||||
*value2 = state->ExtReg[n*2+1];
|
||||
*value1 = state->ExtReg[n*2];
|
||||
}
|
||||
else
|
||||
{
|
||||
state->ExtReg[n*2+1] = *value2;
|
||||
state->ExtReg[n*2] = *value1;
|
||||
}
|
||||
}
|
||||
void VMOVBRRSS(ARMul_State* state, u32 to_arm, [[maybe_unused]] u32 t, [[maybe_unused]] u32 t2,
|
||||
u32 n, u32* value1, u32* value2)
|
||||
{
|
||||
if (to_arm)
|
||||
{
|
||||
*value1 = state->ExtReg[n+0];
|
||||
*value2 = state->ExtReg[n+1];
|
||||
}
|
||||
else
|
||||
{
|
||||
state->ExtReg[n+0] = *value1;
|
||||
state->ExtReg[n+1] = *value2;
|
||||
}
|
||||
}
|
||||
|
||||
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm)
|
||||
{
|
||||
if (single)
|
||||
{
|
||||
state->ExtReg[d] = imm;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check endian please */
|
||||
state->ExtReg[d*2+1] = imm;
|
||||
state->ExtReg[d*2] = 0;
|
||||
}
|
||||
}
|
||||
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m)
|
||||
{
|
||||
if (single)
|
||||
{
|
||||
state->ExtReg[d] = state->ExtReg[m];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check endian please */
|
||||
state->ExtReg[d*2+1] = state->ExtReg[m*2+1];
|
||||
state->ExtReg[d*2] = state->ExtReg[m*2];
|
||||
}
|
||||
}
|
||||
|
||||
/* Miscellaneous functions */
|
||||
s32 vfp_get_float(ARMul_State* state, unsigned int reg)
|
||||
{
|
||||
LOG_TRACE(Core_ARM11, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]);
|
||||
return state->ExtReg[reg];
|
||||
}
|
||||
|
||||
void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg)
|
||||
{
|
||||
LOG_TRACE(Core_ARM11, "VFP put float: s%d <= [%08x]", reg, val);
|
||||
state->ExtReg[reg] = val;
|
||||
}
|
||||
|
||||
u64 vfp_get_double(ARMul_State* state, unsigned int reg)
|
||||
{
|
||||
u64 result = ((u64) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
|
||||
LOG_TRACE(Core_ARM11, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg)
|
||||
{
|
||||
LOG_TRACE(Core_ARM11, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2, (u32)(val >> 32), (u32)(val & 0xffffffff));
|
||||
state->ExtReg[reg*2] = (u32) (val & 0xffffffff);
|
||||
state->ExtReg[reg*2+1] = (u32) (val>>32);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process bitmask of exception conditions. (from vfpmodule.c)
|
||||
*/
|
||||
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
|
||||
{
|
||||
LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x", exceptions);
|
||||
|
||||
if (exceptions == VFP_EXCEPTION_ERROR) {
|
||||
ASSERT_MSG(false, "unhandled bounce {:08x}", inst);
|
||||
}
|
||||
|
||||
/*
|
||||
* If any of the status flags are set, update the FPSCR.
|
||||
* Comparison instructions always return at least one of
|
||||
* these flags set.
|
||||
*/
|
||||
if (exceptions & (FPSCR_NFLAG|FPSCR_ZFLAG|FPSCR_CFLAG|FPSCR_VFLAG))
|
||||
fpscr &= ~(FPSCR_NFLAG|FPSCR_ZFLAG|FPSCR_CFLAG|FPSCR_VFLAG);
|
||||
|
||||
fpscr |= exceptions;
|
||||
|
||||
state->VFP[VFP_FPSCR] = fpscr;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
vfp/vfp.h - ARM VFPv3 emulation unit - vfp interface
|
||||
Copyright (C) 2003 Skyeye Develop Group
|
||||
for help please send mail to <skyeye-developer@lists.gro.clinux.org>
|
||||
|
||||
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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "A32/skyeye_interpreter/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
|
||||
|
||||
#define LOG_INFO(...) do{}while(0)
|
||||
#define LOG_TRACE(...) do{}while(0)
|
||||
|
||||
#define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested", __FUNCTION__);
|
||||
#define CHECK_VFP_ENABLED
|
||||
#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
|
||||
|
||||
void VFPInit(ARMul_State* state);
|
||||
|
||||
s32 vfp_get_float(ARMul_State* state, u32 reg);
|
||||
void vfp_put_float(ARMul_State* state, s32 val, u32 reg);
|
||||
u64 vfp_get_double(ARMul_State* state, u32 reg);
|
||||
void vfp_put_double(ARMul_State* state, u64 val, u32 reg);
|
||||
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr);
|
||||
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
|
||||
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
|
||||
|
||||
void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value);
|
||||
void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
|
||||
void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
|
||||
void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm);
|
||||
void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm);
|
|
@ -1,448 +0,0 @@
|
|||
/*
|
||||
vfp/vfp.h - ARM VFPv3 emulation unit - SoftFloat lib helper
|
||||
Copyright (C) 2003 Skyeye Develop Group
|
||||
for help please send mail to <skyeye-developer@lists.gro.clinux.org>
|
||||
|
||||
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; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following code is derivative from Linux Android kernel vfp
|
||||
* floating point support.
|
||||
*
|
||||
* Copyright (C) 2004 ARM Limited.
|
||||
* Written by Deep Blue Solutions Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include "common/common_types.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armstate.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/vfp/asm_vfp.h"
|
||||
|
||||
#define LOG_INFO(...) do{}while(0)
|
||||
#define LOG_TRACE(...) do{}while(0)
|
||||
|
||||
#define do_div(n, base) {n/=base;}
|
||||
|
||||
enum : u32 {
|
||||
FOP_MASK = 0x00b00040,
|
||||
FOP_FMAC = 0x00000000,
|
||||
FOP_FNMAC = 0x00000040,
|
||||
FOP_FMSC = 0x00100000,
|
||||
FOP_FNMSC = 0x00100040,
|
||||
FOP_FMUL = 0x00200000,
|
||||
FOP_FNMUL = 0x00200040,
|
||||
FOP_FADD = 0x00300000,
|
||||
FOP_FSUB = 0x00300040,
|
||||
FOP_FDIV = 0x00800000,
|
||||
FOP_EXT = 0x00b00040
|
||||
};
|
||||
|
||||
#define FOP_TO_IDX(inst) ((inst & 0x00b00000) >> 20 | (inst & (1 << 6)) >> 4)
|
||||
|
||||
enum : u32 {
|
||||
FEXT_MASK = 0x000f0080,
|
||||
FEXT_FCPY = 0x00000000,
|
||||
FEXT_FABS = 0x00000080,
|
||||
FEXT_FNEG = 0x00010000,
|
||||
FEXT_FSQRT = 0x00010080,
|
||||
FEXT_FCMP = 0x00040000,
|
||||
FEXT_FCMPE = 0x00040080,
|
||||
FEXT_FCMPZ = 0x00050000,
|
||||
FEXT_FCMPEZ = 0x00050080,
|
||||
FEXT_FCVT = 0x00070080,
|
||||
FEXT_FUITO = 0x00080000,
|
||||
FEXT_FSITO = 0x00080080,
|
||||
FEXT_FTOUI = 0x000c0000,
|
||||
FEXT_FTOUIZ = 0x000c0080,
|
||||
FEXT_FTOSI = 0x000d0000,
|
||||
FEXT_FTOSIZ = 0x000d0080
|
||||
};
|
||||
|
||||
#define FEXT_TO_IDX(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
|
||||
|
||||
#define vfp_get_sd(inst) ((inst & 0x0000f000) >> 11 | (inst & (1 << 22)) >> 22)
|
||||
#define vfp_get_dd(inst) ((inst & 0x0000f000) >> 12 | (inst & (1 << 22)) >> 18)
|
||||
#define vfp_get_sm(inst) ((inst & 0x0000000f) << 1 | (inst & (1 << 5)) >> 5)
|
||||
#define vfp_get_dm(inst) ((inst & 0x0000000f) | (inst & (1 << 5)) >> 1)
|
||||
#define vfp_get_sn(inst) ((inst & 0x000f0000) >> 15 | (inst & (1 << 7)) >> 7)
|
||||
#define vfp_get_dn(inst) ((inst & 0x000f0000) >> 16 | (inst & (1 << 7)) >> 3)
|
||||
|
||||
#define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00)
|
||||
|
||||
inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift)
|
||||
{
|
||||
if (shift) {
|
||||
if (shift < 32)
|
||||
val = val >> shift | ((val << (32 - shift)) != 0);
|
||||
else
|
||||
val = val != 0;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift)
|
||||
{
|
||||
if (shift) {
|
||||
if (shift < 64)
|
||||
val = val >> shift | ((val << (64 - shift)) != 0);
|
||||
else
|
||||
val = val != 0;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
inline u32 vfp_hi64to32jamming(u64 val)
|
||||
{
|
||||
u32 v;
|
||||
u32 highval = val >> 32;
|
||||
u32 lowval = val & 0xffffffff;
|
||||
|
||||
if (lowval >= 1)
|
||||
v = highval | 1;
|
||||
else
|
||||
v = highval;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml)
|
||||
{
|
||||
*resl = nl + ml;
|
||||
*resh = nh + mh;
|
||||
if (*resl < nl)
|
||||
*resh += 1;
|
||||
}
|
||||
|
||||
inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml)
|
||||
{
|
||||
*resl = nl - ml;
|
||||
*resh = nh - mh;
|
||||
if (*resl > nl)
|
||||
*resh -= 1;
|
||||
}
|
||||
|
||||
inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m)
|
||||
{
|
||||
u32 nh, nl, mh, ml;
|
||||
u64 rh, rma, rmb, rl;
|
||||
|
||||
nl = static_cast<u32>(n);
|
||||
ml = static_cast<u32>(m);
|
||||
rl = (u64)nl * ml;
|
||||
|
||||
nh = n >> 32;
|
||||
rma = (u64)nh * ml;
|
||||
|
||||
mh = m >> 32;
|
||||
rmb = (u64)nl * mh;
|
||||
rma += rmb;
|
||||
|
||||
rh = (u64)nh * mh;
|
||||
rh += ((u64)(rma < rmb) << 32) + (rma >> 32);
|
||||
|
||||
rma <<= 32;
|
||||
rl += rma;
|
||||
rh += (rl < rma);
|
||||
|
||||
*resl = rl;
|
||||
*resh = rh;
|
||||
}
|
||||
|
||||
inline void shift64left(u64* resh, u64* resl, u64 n)
|
||||
{
|
||||
*resh = n >> 63;
|
||||
*resl = n << 1;
|
||||
}
|
||||
|
||||
inline u64 vfp_hi64multiply64(u64 n, u64 m)
|
||||
{
|
||||
u64 rh, rl;
|
||||
mul64to128(&rh, &rl, n, m);
|
||||
return rh | (rl != 0);
|
||||
}
|
||||
|
||||
inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
|
||||
{
|
||||
u64 mh, ml, remh, reml, termh, terml, z;
|
||||
|
||||
if (nh >= m)
|
||||
return ~0ULL;
|
||||
mh = m >> 32;
|
||||
if (mh << 32 <= nh) {
|
||||
z = 0xffffffff00000000ULL;
|
||||
} else {
|
||||
z = nh;
|
||||
do_div(z, mh);
|
||||
z <<= 32;
|
||||
}
|
||||
mul64to128(&termh, &terml, m, z);
|
||||
sub128(&remh, &reml, nh, nl, termh, terml);
|
||||
ml = m << 32;
|
||||
while ((s64)remh < 0) {
|
||||
z -= 0x100000000ULL;
|
||||
add128(&remh, &reml, remh, reml, mh, ml);
|
||||
}
|
||||
remh = (remh << 32) | (reml >> 32);
|
||||
if (mh << 32 <= remh) {
|
||||
z |= 0xffffffff;
|
||||
} else {
|
||||
do_div(remh, mh);
|
||||
z |= remh;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
// Operations on unpacked elements
|
||||
#define vfp_sign_negate(sign) (sign ^ 0x8000)
|
||||
|
||||
// Single-precision
|
||||
struct vfp_single {
|
||||
s16 exponent;
|
||||
u16 sign;
|
||||
u32 significand;
|
||||
};
|
||||
|
||||
// VFP_SINGLE_MANTISSA_BITS - number of bits in the mantissa
|
||||
// VFP_SINGLE_EXPONENT_BITS - number of bits in the exponent
|
||||
// VFP_SINGLE_LOW_BITS - number of low bits in the unpacked significand
|
||||
// which are not propagated to the float upon packing.
|
||||
#define VFP_SINGLE_MANTISSA_BITS (23)
|
||||
#define VFP_SINGLE_EXPONENT_BITS (8)
|
||||
#define VFP_SINGLE_LOW_BITS (32 - VFP_SINGLE_MANTISSA_BITS - 2)
|
||||
#define VFP_SINGLE_LOW_BITS_MASK ((1 << VFP_SINGLE_LOW_BITS) - 1)
|
||||
|
||||
// The bit in an unpacked float which indicates that it is a quiet NaN
|
||||
#define VFP_SINGLE_SIGNIFICAND_QNAN (1 << (VFP_SINGLE_MANTISSA_BITS - 1 + VFP_SINGLE_LOW_BITS))
|
||||
|
||||
// Operations on packed single-precision numbers
|
||||
#define vfp_single_packed_sign(v) ((v) & 0x80000000)
|
||||
#define vfp_single_packed_negate(v) ((v) ^ 0x80000000)
|
||||
#define vfp_single_packed_abs(v) ((v) & ~0x80000000)
|
||||
#define vfp_single_packed_exponent(v) (((v) >> VFP_SINGLE_MANTISSA_BITS) & ((1 << VFP_SINGLE_EXPONENT_BITS) - 1))
|
||||
#define vfp_single_packed_mantissa(v) ((v) & ((1 << VFP_SINGLE_MANTISSA_BITS) - 1))
|
||||
|
||||
enum : u32 {
|
||||
VFP_NUMBER = (1 << 0),
|
||||
VFP_ZERO = (1 << 1),
|
||||
VFP_DENORMAL = (1 << 2),
|
||||
VFP_INFINITY = (1 << 3),
|
||||
VFP_NAN = (1 << 4),
|
||||
VFP_NAN_SIGNAL = (1 << 5),
|
||||
|
||||
VFP_QNAN = (VFP_NAN),
|
||||
VFP_SNAN = (VFP_NAN|VFP_NAN_SIGNAL)
|
||||
};
|
||||
|
||||
inline int vfp_single_type(const vfp_single* s)
|
||||
{
|
||||
int type = VFP_NUMBER;
|
||||
if (s->exponent == 255) {
|
||||
if (s->significand == 0)
|
||||
type = VFP_INFINITY;
|
||||
else if (s->significand & VFP_SINGLE_SIGNIFICAND_QNAN)
|
||||
type = VFP_QNAN;
|
||||
else
|
||||
type = VFP_SNAN;
|
||||
} else if (s->exponent == 0) {
|
||||
if (s->significand == 0)
|
||||
type |= VFP_ZERO;
|
||||
else
|
||||
type |= VFP_DENORMAL;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// Unpack a single-precision float. Note that this returns the magnitude
|
||||
// of the single-precision float mantissa with the 1. if necessary,
|
||||
// aligned to bit 30.
|
||||
inline u32 vfp_single_unpack(vfp_single* s, s32 val, u32 fpscr)
|
||||
{
|
||||
u32 exceptions = 0;
|
||||
s->sign = vfp_single_packed_sign(val) >> 16;
|
||||
s->exponent = vfp_single_packed_exponent(val);
|
||||
|
||||
u32 significand = ((u32)val << (32 - VFP_SINGLE_MANTISSA_BITS)) >> 2;
|
||||
if (s->exponent && s->exponent != 255)
|
||||
significand |= 0x40000000;
|
||||
s->significand = significand;
|
||||
|
||||
// If flush-to-zero mode is enabled, turn the denormal into zero.
|
||||
// On a VFPv2 architecture, the sign of the zero is always positive.
|
||||
if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_single_type(s) & VFP_DENORMAL) != 0) {
|
||||
s->sign = 0;
|
||||
s->exponent = 0;
|
||||
s->significand = 0;
|
||||
exceptions |= FPSCR_IDC;
|
||||
}
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
// Re-pack a single-precision float. This assumes that the float is
|
||||
// already normalised such that the MSB is bit 30, _not_ bit 31.
|
||||
inline s32 vfp_single_pack(const vfp_single* s)
|
||||
{
|
||||
u32 val = (s->sign << 16) +
|
||||
(s->exponent << VFP_SINGLE_MANTISSA_BITS) +
|
||||
(s->significand >> VFP_SINGLE_LOW_BITS);
|
||||
return (s32)val;
|
||||
}
|
||||
|
||||
|
||||
u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, const char* func);
|
||||
|
||||
// Double-precision
|
||||
struct vfp_double {
|
||||
s16 exponent;
|
||||
u16 sign;
|
||||
u64 significand;
|
||||
};
|
||||
|
||||
#define VFP_DOUBLE_MANTISSA_BITS (52)
|
||||
#define VFP_DOUBLE_EXPONENT_BITS (11)
|
||||
#define VFP_DOUBLE_LOW_BITS (64 - VFP_DOUBLE_MANTISSA_BITS - 2)
|
||||
#define VFP_DOUBLE_LOW_BITS_MASK ((1 << VFP_DOUBLE_LOW_BITS) - 1)
|
||||
|
||||
// The bit in an unpacked double which indicates that it is a quiet NaN
|
||||
#define VFP_DOUBLE_SIGNIFICAND_QNAN (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1 + VFP_DOUBLE_LOW_BITS))
|
||||
|
||||
// Operations on packed single-precision numbers
|
||||
#define vfp_double_packed_sign(v) ((v) & (1ULL << 63))
|
||||
#define vfp_double_packed_negate(v) ((v) ^ (1ULL << 63))
|
||||
#define vfp_double_packed_abs(v) ((v) & ~(1ULL << 63))
|
||||
#define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1))
|
||||
#define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1))
|
||||
|
||||
inline int vfp_double_type(const vfp_double* s)
|
||||
{
|
||||
int type = VFP_NUMBER;
|
||||
if (s->exponent == 2047) {
|
||||
if (s->significand == 0)
|
||||
type = VFP_INFINITY;
|
||||
else if (s->significand & VFP_DOUBLE_SIGNIFICAND_QNAN)
|
||||
type = VFP_QNAN;
|
||||
else
|
||||
type = VFP_SNAN;
|
||||
} else if (s->exponent == 0) {
|
||||
if (s->significand == 0)
|
||||
type |= VFP_ZERO;
|
||||
else
|
||||
type |= VFP_DENORMAL;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// Unpack a double-precision float. Note that this returns the magnitude
|
||||
// of the double-precision float mantissa with the 1. if necessary,
|
||||
// aligned to bit 62.
|
||||
inline u32 vfp_double_unpack(vfp_double* s, s64 val, u32 fpscr)
|
||||
{
|
||||
u32 exceptions = 0;
|
||||
s->sign = vfp_double_packed_sign(val) >> 48;
|
||||
s->exponent = vfp_double_packed_exponent(val);
|
||||
|
||||
u64 significand = ((u64)val << (64 - VFP_DOUBLE_MANTISSA_BITS)) >> 2;
|
||||
if (s->exponent && s->exponent != 2047)
|
||||
significand |= (1ULL << 62);
|
||||
s->significand = significand;
|
||||
|
||||
// If flush-to-zero mode is enabled, turn the denormal into zero.
|
||||
// On a VFPv2 architecture, the sign of the zero is always positive.
|
||||
if ((fpscr & FPSCR_FLUSH_TO_ZERO) != 0 && (vfp_double_type(s) & VFP_DENORMAL) != 0) {
|
||||
s->sign = 0;
|
||||
s->exponent = 0;
|
||||
s->significand = 0;
|
||||
exceptions |= FPSCR_IDC;
|
||||
}
|
||||
return exceptions;
|
||||
}
|
||||
|
||||
// Re-pack a double-precision float. This assumes that the float is
|
||||
// already normalised such that the MSB is bit 30, _not_ bit 31.
|
||||
inline s64 vfp_double_pack(const vfp_double* s)
|
||||
{
|
||||
u64 val = ((u64)s->sign << 48) +
|
||||
((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) +
|
||||
(s->significand >> VFP_DOUBLE_LOW_BITS);
|
||||
return (s64)val;
|
||||
}
|
||||
|
||||
u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
|
||||
|
||||
// A special flag to tell the normalisation code not to normalise.
|
||||
#define VFP_NAN_FLAG 0x100
|
||||
|
||||
// A bit pattern used to indicate the initial (unset) value of the
|
||||
// exception mask, in case nothing handles an instruction. This
|
||||
// doesn't include the NAN flag, which get masked out before
|
||||
// we check for an error.
|
||||
#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG)
|
||||
|
||||
// A flag to tell vfp instruction type.
|
||||
// OP_SCALAR - This operation always operates in scalar mode
|
||||
// OP_SD - The instruction exceptionally writes to a single precision result.
|
||||
// OP_DD - The instruction exceptionally writes to a double precision result.
|
||||
// OP_SM - The instruction exceptionally reads from a single precision operand.
|
||||
enum : u32 {
|
||||
OP_SCALAR = (1 << 0),
|
||||
OP_SD = (1 << 1),
|
||||
OP_DD = (1 << 1),
|
||||
OP_SM = (1 << 2)
|
||||
};
|
||||
|
||||
struct op {
|
||||
u32 (* const fn)(ARMul_State* state, int dd, int dn, int dm, u32 fpscr);
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
inline u32 fls(u32 x)
|
||||
{
|
||||
int r = 32;
|
||||
|
||||
if (!x)
|
||||
return 0;
|
||||
if (!(x & 0xffff0000u)) {
|
||||
x <<= 16;
|
||||
r -= 16;
|
||||
}
|
||||
if (!(x & 0xff000000u)) {
|
||||
x <<= 8;
|
||||
r -= 8;
|
||||
}
|
||||
if (!(x & 0xf0000000u)) {
|
||||
x <<= 4;
|
||||
r -= 4;
|
||||
}
|
||||
if (!(x & 0xc0000000u)) {
|
||||
x <<= 2;
|
||||
r -= 2;
|
||||
}
|
||||
if (!(x & 0x80000000u)) {
|
||||
x <<= 1;
|
||||
r -= 1;
|
||||
}
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr);
|
||||
u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double *vdm, u32 fpscr);
|
||||
u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, const char* func);
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -9,8 +9,6 @@
|
|||
#include <dynarmic/A32/a32.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "A32/skyeye_interpreter/dyncom/arm_dyncom_interpreter.h"
|
||||
#include "A32/skyeye_interpreter/skyeye_common/armstate.h"
|
||||
#include "testenv.h"
|
||||
|
||||
static Dynarmic::A32::UserConfig GetUserConfig(ThumbTestEnv* testenv) {
|
||||
|
|
|
@ -1,27 +1,4 @@
|
|||
add_executable(dynarmic_tests
|
||||
A32/fuzz_arm.cpp
|
||||
A32/fuzz_thumb.cpp
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_dec.cpp
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_dec.h
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_interpreter.cpp
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_interpreter.h
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_run.h
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_thumb.cpp
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_thumb.h
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_trans.cpp
|
||||
A32/skyeye_interpreter/dyncom/arm_dyncom_trans.h
|
||||
A32/skyeye_interpreter/skyeye_common/arm_regformat.h
|
||||
A32/skyeye_interpreter/skyeye_common/armstate.cpp
|
||||
A32/skyeye_interpreter/skyeye_common/armstate.h
|
||||
A32/skyeye_interpreter/skyeye_common/armsupp.cpp
|
||||
A32/skyeye_interpreter/skyeye_common/armsupp.h
|
||||
A32/skyeye_interpreter/skyeye_common/vfp/asm_vfp.h
|
||||
A32/skyeye_interpreter/skyeye_common/vfp/vfp.cpp
|
||||
A32/skyeye_interpreter/skyeye_common/vfp/vfp.h
|
||||
A32/skyeye_interpreter/skyeye_common/vfp/vfp_helper.h
|
||||
A32/skyeye_interpreter/skyeye_common/vfp/vfpdouble.cpp
|
||||
A32/skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp
|
||||
A32/skyeye_interpreter/skyeye_common/vfp/vfpsingle.cpp
|
||||
A32/test_arm_disassembler.cpp
|
||||
A32/test_thumb_instructions.cpp
|
||||
A32/testenv.h
|
||||
|
@ -39,6 +16,8 @@ add_executable(dynarmic_tests
|
|||
|
||||
if (DYNARMIC_TESTS_USE_UNICORN)
|
||||
target_sources(dynarmic_tests PRIVATE
|
||||
A32/fuzz_arm.cpp
|
||||
A32/fuzz_thumb.cpp
|
||||
A64/fuzz_with_unicorn.cpp
|
||||
A64/verify_unicorn.cpp
|
||||
fuzz_util.cpp
|
||||
|
|
Loading…
Reference in a new issue