mirror of https://github.com/bsnes-emu/bsnes.git
Update to v103r28 release.
byuu says: Changelog: - processor/arm7tdmi: implemented 10 of 19 ARM instructions - processor/arm7tdmi: implemented 1 of 22 THUMB instructions Today's WIP was 6 hours of work, and yesterday's was 5 hours. Half of today was just trying to come up with the design to use a lambda-based dispatcher to map both instructions and disassembly, similar to the 68K core. The problem is that the ARM core has 28 unique bits, which is just far too many bits to have a full lookup table like the 16-bit 68K core. The thing I wanted more than anything else was to perform the opcode bitfield decoding once, and have it decoded for both instructions and the disassembler. It took three hours to come up with a design that worked for the ARM half ... relying on #defines being able to pull in other #defines that were declared and changed later after the first one. But, I'm happy with it. The decoding is in the table building, as it is with the 68K core. The decoding does happen at run-time on each instruction invocation, but it has to be done. As to the THUMB core, I can create a 64K-entry lambda table to cover all possible encodings, and ... even though it's a cache killer, I've decided to go for it, given the outstanding performance it obtained in the M68K core, as well as considering that THUMB mode is far more common in GBA games. As to both cores ... I'm a little torn between two extremes: On the one hand, I can condense the number of ARM/THUMB instructions further to eliminate more redundant code. On the other, I can split them apart to reduce the number of conditional tests needed to execute each instruction. It's really the disassembler that makes me not want to split them up further ... as I have to split the disassembler functions up equally to the instruction functions. But it may be worth it if it's a speed improvement.
This commit is contained in:
parent
0b6f1df987
commit
a72ff8b7fa
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "103.27";
|
||||
static const string Version = "103.28";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -81,7 +81,7 @@ auto ARM::disassembleInstructionARM(uint32 pc) -> string {
|
|||
uint4 rm = instruction;
|
||||
|
||||
output.append("swp", conditions[condition], byte ? "b " : " ");
|
||||
output.append(registers[rd], ",", registers[rm], "[", registers[rn], "]");
|
||||
output.append(registers[rd], ",", registers[rm], ",[", registers[rn], "]");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
auto ARM7TDMI::ADD(uint32 source, uint32 modify, bool carry, bool updateFlags) -> uint32 {
|
||||
auto ARM7TDMI::ADD(uint32 source, uint32 modify, bool carry) -> uint32 {
|
||||
uint32 result = source + modify + carry;
|
||||
if(updateFlags) {
|
||||
if(cpsr().t || opcode.bit(20)) {
|
||||
uint32 overflow = ~(source ^ modify) & (source ^ result);
|
||||
cpsr().v = 1 << 31 & (overflow);
|
||||
cpsr().c = 1 << 31 & (overflow ^ source ^ modify ^ result);
|
||||
|
@ -18,8 +18,8 @@ auto ARM7TDMI::ASR(uint32 source, uint8 shift) -> uint32 {
|
|||
return source;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::BIT(uint32 result, bool updateFlags) -> uint32 {
|
||||
if(updateFlags) {
|
||||
auto ARM7TDMI::BIT(uint32 result) -> uint32 {
|
||||
if(cpsr().t || opcode.bit(20)) {
|
||||
cpsr().c = carry;
|
||||
cpsr().z = result == 0;
|
||||
cpsr().n = result.bit(31);
|
||||
|
@ -43,13 +43,13 @@ auto ARM7TDMI::LSR(uint32 source, uint8 shift) -> uint32 {
|
|||
return source;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::MUL(uint32 product, uint32 multiplicand, uint32 multiplier, bool updateFlags) -> uint32 {
|
||||
auto ARM7TDMI::MUL(uint32 product, uint32 multiplicand, uint32 multiplier) -> uint32 {
|
||||
idle();
|
||||
if(multiplier >> 8 && multiplier >> 8 != 0xffffff) idle();
|
||||
if(multiplier >> 16 && multiplier >> 16 != 0xffff) idle();
|
||||
if(multiplier >> 24 && multiplier >> 24 != 0xff) idle();
|
||||
product += multiplicand * multiplier;
|
||||
if(updateFlags) {
|
||||
if(cpsr().t || opcode.bit(20)) {
|
||||
cpsr().z = product == 0;
|
||||
cpsr().n = product.bit(31);
|
||||
}
|
||||
|
@ -69,8 +69,8 @@ auto ARM7TDMI::RRX(uint32 source) -> uint32 {
|
|||
return cpsr().c << 31 | source >> 1;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::SUB(uint32 source, uint32 modify, bool carry, bool updateFlags) -> uint32 {
|
||||
return ADD(source, ~modify, carry, updateFlags);
|
||||
auto ARM7TDMI::SUB(uint32 source, uint32 modify, bool carry) -> uint32 {
|
||||
return ADD(source, ~modify, carry);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::TST(uint4 mode) -> bool {
|
||||
|
|
|
@ -10,6 +10,12 @@ namespace Processor {
|
|||
#include "instructions-arm.cpp"
|
||||
#include "instructions-thumb.cpp"
|
||||
#include "serialization.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
ARM7TDMI::ARM7TDMI() {
|
||||
armInitialize();
|
||||
thumbInitialize();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::power() -> void {
|
||||
processor = {};
|
||||
|
@ -20,4 +26,21 @@ auto ARM7TDMI::power() -> void {
|
|||
irq = 0;
|
||||
}
|
||||
|
||||
struct CPU : ARM7TDMI {
|
||||
auto step(uint) -> void {}
|
||||
auto sleep() -> void {}
|
||||
auto get(uint, uint32) -> uint32 {}
|
||||
auto set(uint, uint32, uint32) -> void {}
|
||||
|
||||
CPU() {
|
||||
/*
|
||||
uint32 opcode = 0x00337e92;
|
||||
uint12 id = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4;
|
||||
print("!!", hex(id), "\n");
|
||||
armInstruction[id](opcode);
|
||||
print(armDisassemble[id](opcode), "\n");
|
||||
*/
|
||||
}
|
||||
} cpu;
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ struct ARM7TDMI {
|
|||
virtual auto set(uint mode, uint32 address, uint32 word) -> void = 0;
|
||||
|
||||
//arm7tdmi.cpp
|
||||
ARM7TDMI();
|
||||
auto power() -> void;
|
||||
|
||||
//registers.cpp
|
||||
|
@ -44,31 +45,51 @@ struct ARM7TDMI {
|
|||
auto store(uint mode, uint32 address, uint32 word) -> void;
|
||||
|
||||
//algorithms.cpp
|
||||
auto ADD(uint32, uint32, bool, bool = true) -> uint32;
|
||||
auto ADD(uint32, uint32, bool) -> uint32;
|
||||
auto ASR(uint32, uint8) -> uint32;
|
||||
auto BIT(uint32, bool = true) -> uint32;
|
||||
auto BIT(uint32) -> uint32;
|
||||
auto LSL(uint32, uint8) -> uint32;
|
||||
auto LSR(uint32, uint8) -> uint32;
|
||||
auto MUL(uint32, uint32, uint32, bool = true) -> uint32;
|
||||
auto MUL(uint32, uint32, uint32) -> uint32;
|
||||
auto ROR(uint32, uint8) -> uint32;
|
||||
auto RRX(uint32) -> uint32;
|
||||
auto SUB(uint32, uint32, bool, bool = true) -> uint32;
|
||||
auto SUB(uint32, uint32, bool) -> uint32;
|
||||
auto TST(uint4) -> bool;
|
||||
|
||||
//instruction.cpp
|
||||
auto fetch() -> void;
|
||||
auto instruction() -> void;
|
||||
auto interrupt(uint mode, uint32 address) -> void;
|
||||
auto armInitialize() -> void;
|
||||
auto thumbInitialize() -> void;
|
||||
|
||||
//instructions-arm.cpp
|
||||
auto armALU(uint4 mode, uint4 target, uint4 source, uint32 data, bool save) -> void;
|
||||
auto armALU(uint4 mode, uint4 target, uint4 source, uint32 data) -> void;
|
||||
auto armMoveToStatus(uint4 field, uint1 source, uint32 data) -> void;
|
||||
|
||||
auto armInstructionBranchExchangeRegister(uint4) -> void;
|
||||
auto armInstructionLoadImmediate(uint8, uint1, uint4, uint4, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionLoadRegister(uint4, uint1, uint4, uint4, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMemorySwap(uint4, uint4, uint4, uint1) -> void;
|
||||
auto armInstructionMoveHalfImmediate(uint8, uint4, uint4, uint1, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMoveHalfRegister(uint4, uint4, uint4, uint1, uint1, uint1, uint1) -> void;
|
||||
auto armInstructionMoveToRegisterFromStatus(uint4, uint1) -> void;
|
||||
auto armInstructionMoveToStatusFromImmediate(uint8, uint4, uint4, uint1) -> void;
|
||||
auto armInstructionMoveToStatusFromRegister(uint4, uint4, uint1) -> void;
|
||||
auto armInstructionMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> void;
|
||||
auto armInstructionMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> void;
|
||||
|
||||
//instructions-thumb.cpp
|
||||
auto thumbALU(uint4 mode, uint4 target, uint4 source) -> void;
|
||||
|
||||
auto thumbInstructionAdjustRegister(uint3, uint3, uint3, uint1) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint32 pc) -> string;
|
||||
|
||||
struct GPR {
|
||||
inline operator uint32_t() const {
|
||||
return data;
|
||||
|
@ -86,10 +107,15 @@ struct ARM7TDMI {
|
|||
|
||||
struct PSR {
|
||||
enum : uint {
|
||||
USR26 = 0x00, //26-bit user
|
||||
FIQ26 = 0x01, //26-bit fast interrupt
|
||||
IRQ26 = 0x02, //26-bit interrupt
|
||||
SVC26 = 0x03, //26-bit service
|
||||
|
||||
USR = 0x10, //user
|
||||
FIQ = 0x11, //fast interrupt request
|
||||
IRQ = 0x12, //interrupt request
|
||||
SVC = 0x13, //supervisor (software interrupt)
|
||||
FIQ = 0x11, //fast interrupt
|
||||
IRQ = 0x12, //interrupt
|
||||
SVC = 0x13, //service
|
||||
ABT = 0x17, //abort
|
||||
UND = 0x1b, //undefined
|
||||
SYS = 0x1f, //system
|
||||
|
@ -173,8 +199,30 @@ struct ARM7TDMI {
|
|||
Instruction execute;
|
||||
} pipeline;
|
||||
|
||||
uint32 opcode;
|
||||
boolean carry;
|
||||
boolean irq;
|
||||
|
||||
function<void (uint32 opcode)> armInstruction[4096];
|
||||
function<void ()> thumbInstruction[65536];
|
||||
|
||||
function<string (uint32 opcode)> armDisassemble[4096];
|
||||
function<string ()> thumbDisassemble[65536];
|
||||
|
||||
//disassembler.cpp
|
||||
auto armDisassembleBranchExchangeRegister(uint4) -> string;
|
||||
auto armDisassembleLoadImmediate(uint8, uint1, uint4, uint4, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleLoadRegister(uint4, uint1, uint4, uint4, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMemorySwap(uint4, uint4, uint4, uint1) -> string;
|
||||
auto armDisassembleMoveHalfImmediate(uint8, uint4, uint4, uint1, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMoveHalfRegister(uint4, uint4, uint4, uint1, uint1, uint1, uint1) -> string;
|
||||
auto armDisassembleMoveToRegisterFromStatus(uint4, uint1) -> string;
|
||||
auto armDisassembleMoveToStatusFromImmediate(uint8, uint4, uint4, uint1) -> string;
|
||||
auto armDisassembleMoveToStatusFromRegister(uint4, uint4, uint1) -> string;
|
||||
auto armDisassembleMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> string;
|
||||
auto armDisassembleMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> string;
|
||||
|
||||
auto thumbDisassembleAdjustRegister(uint3, uint3, uint3, uint1) -> string;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
static uint32 _pc;
|
||||
static string _c;
|
||||
static string _r[16] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc"
|
||||
};
|
||||
#define _s save ? "s" : ""
|
||||
|
||||
auto ARM7TDMI::disassemble(uint32 pc) -> string {
|
||||
return "";
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ARM7TDMI::armDisassembleBranchExchangeRegister
|
||||
(uint4 m) -> string {
|
||||
return {"bx", _c, " ", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadImmediate
|
||||
(uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(read((half ? Half : Byte) | Nonsequential,
|
||||
_pc + 8 + (up ? +immediate : -immediate)), half ? 4L : 2L)};
|
||||
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleLoadRegister
|
||||
(uint4 m, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
return {"ldr", _c, half ? "sh" : "sb", " ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMemorySwap
|
||||
(uint4 m, uint4 d, uint4 n, uint1 byte) -> string {
|
||||
return {"swp", _c, byte ? "b" : "", " ", _r[d], ",", _r[m], ",[", _r[n], "]"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveHalfImmediate
|
||||
(uint8 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
string data;
|
||||
if(n == 15) data = {" =0x", hex(read(Half | Nonsequential, _pc + (up ? +immediate : -immediate)), 4L)};
|
||||
|
||||
return {mode ? "ldr" : "str", _c, "h ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 2L)} : string{},
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : "", data};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveHalfRegister
|
||||
(uint4 m, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> string {
|
||||
return {mode ? "ldr" : "str", _c, "h ",
|
||||
_r[d], ",[", _r[n],
|
||||
pre == 0 ? "]" : "",
|
||||
",", up ? "+" : "-", _r[m],
|
||||
pre == 1 ? "]" : "",
|
||||
pre == 0 || writeback ? "!" : ""};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToRegisterFromStatus
|
||||
(uint4 d, uint1 mode) -> string {
|
||||
return {"mrs", _c, " ", _r[d], ",", mode ? "spsr" : "cpsr"};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToStatusFromImmediate
|
||||
(uint8 immediate, uint4 rotate, uint4 field, uint1 mode) -> string {
|
||||
uint32 data = immediate >> (rotate << 1) | immediate << 32 - (rotate << 1);
|
||||
return {"msr", _c, " ", mode ? "spsr:" : "cpsr:",
|
||||
field.bit(0) ? "c" : "",
|
||||
field.bit(1) ? "x" : "",
|
||||
field.bit(2) ? "s" : "",
|
||||
field.bit(3) ? "f" : "",
|
||||
",#0x", hex(data, 8L)};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMoveToStatusFromRegister
|
||||
(uint4 m, uint4 field, uint1 mode) -> string {
|
||||
return {"msr", _c, " ", mode ? "spsr:" : "cpsr:",
|
||||
field.bit(0) ? "c" : "",
|
||||
field.bit(1) ? "x" : "",
|
||||
field.bit(2) ? "s" : "",
|
||||
field.bit(3) ? "f" : "",
|
||||
",", _r[m]};
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMultiply
|
||||
(uint4 m, uint4 s, uint4 n, uint4 d, uint1 save, uint1 accumulate) -> string {
|
||||
if(accumulate) {
|
||||
return {"mla", _c, _s, " ", _r[d], ",", _r[m], ",", _r[s], ",", _r[n]};
|
||||
} else {
|
||||
return {"mul", _c, _s, " ", _r[d], ",", _r[m], ",", _r[s]};
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armDisassembleMultiplyLong
|
||||
(uint4 m, uint4 s, uint4 l, uint4 h, uint1 save, uint1 accumulate, uint1 sign) -> string {
|
||||
return {sign ? "s" : "u", accumulate ? "mlal" : "mull", _c, _s, " ",
|
||||
_r[l], ",", _r[h], ",", _r[m], ",", _r[s]};
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ARM7TDMI::thumbDisassembleAdjustRegister
|
||||
(uint3 d, uint3 n, uint3 m, uint1 mode) -> string {
|
||||
return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",", _r[m]};
|
||||
}
|
|
@ -35,9 +35,12 @@ auto ARM7TDMI::instruction() -> void {
|
|||
return;
|
||||
}
|
||||
|
||||
opcode = pipeline.execute.instruction;
|
||||
if(!cpsr().t) {
|
||||
if(!TST(pipeline.execute.instruction.bits(28,31))) return;
|
||||
if(!TST(opcode.bits(28,31))) return;
|
||||
armInstruction[(opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4](opcode);
|
||||
} else {
|
||||
thumbInstruction[opcode & 0xffff]();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,3 +54,188 @@ auto ARM7TDMI::interrupt(uint mode, uint32 address) -> void {
|
|||
r(14) = pipeline.decode.address;
|
||||
r(15) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInitialize() -> void {
|
||||
#define bind(id, name, ...) { \
|
||||
uint index = (id & 0x0ff00000) >> 16 | (id & 0x000000f0) >> 4; \
|
||||
assert(!armInstruction[index]); \
|
||||
armInstruction[index] = [&](uint32 opcode) { return armInstruction##name(arguments); }; \
|
||||
armDisassemble[index] = [&](uint32 opcode) { return armDisassemble##name(arguments); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
std::integral_constant<uint32_t, bit::test(s)>::value
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3) /* m */
|
||||
{
|
||||
auto opcode = pattern(".... 0001 0010 ---- ---- ---- 0001 ????");
|
||||
bind(opcode, BranchExchangeRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3) << 0 | opcode.bits( 8,11) << 4, /* immediate */ \
|
||||
opcode.bit ( 5), /* half */ \
|
||||
opcode.bits(12,15), /* d */ \
|
||||
opcode.bits(16,19), /* n */ \
|
||||
opcode.bit (21), /* writeback */ \
|
||||
opcode.bit (23), /* up */ \
|
||||
opcode.bit (24) /* pre */
|
||||
for(uint1 half : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?1 ???? ???? ???? 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3), /* m */ \
|
||||
opcode.bit ( 5), /* half */ \
|
||||
opcode.bits(12,15), /* d */ \
|
||||
opcode.bits(16,19), /* n */ \
|
||||
opcode.bit (21), /* writeback */ \
|
||||
opcode.bit (23), /* up */ \
|
||||
opcode.bit (24) /* pre */
|
||||
for(uint1 half : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?1 ???? ???? ---- 11?1 ????") | half << 5 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, LoadRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3), /* m */ \
|
||||
opcode.bits(12,15), /* d */ \
|
||||
opcode.bits(16,19), /* n */ \
|
||||
opcode.bit (22) /* byte */
|
||||
for(uint1 byte : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ???? ???? ---- 1001 ????") | byte << 22;
|
||||
bind(opcode, MemorySwap);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3) << 0 | opcode.bits( 8,11) << 4, /* immediate */ \
|
||||
opcode.bits(12,15), /* d */ \
|
||||
opcode.bits(16,19), /* n */ \
|
||||
opcode.bit (20), /* mode */ \
|
||||
opcode.bit (21), /* writeback */ \
|
||||
opcode.bit (23), /* up */ \
|
||||
opcode.bit (24) /* pre */
|
||||
for(uint1 mode : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?1?? ???? ???? ???? 1011 ????") | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveHalfImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3), /* m */ \
|
||||
opcode.bits(12,15), /* d */ \
|
||||
opcode.bits(16,19), /* n */ \
|
||||
opcode.bit (20), /* mode */ \
|
||||
opcode.bit (21), /* writeback */ \
|
||||
opcode.bit (23), /* up */ \
|
||||
opcode.bit (24) /* pre */
|
||||
for(uint1 mode : range(2))
|
||||
for(uint1 writeback : range(2))
|
||||
for(uint1 up : range(2))
|
||||
for(uint1 pre : range(2)) {
|
||||
auto opcode = pattern(".... 000? ?0?? ???? ???? ---- 1011 ????") | mode << 20 | writeback << 21 | up << 23 | pre << 24;
|
||||
bind(opcode, MoveHalfRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3), /* d */ \
|
||||
opcode.bit (22) /* mode */
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?00 ---- ---- ---- 0000 ????") | mode << 22;
|
||||
bind(opcode, MoveToRegisterFromStatus);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 7), /* immediate */ \
|
||||
opcode.bits( 8,11), /* rotate */ \
|
||||
opcode.bits(16,19), /* field */ \
|
||||
opcode.bit (22) /* mode */
|
||||
for(uint4 immediateHi : range(16))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0011 0?10 ???? ---- ???? ???? ????") | immediateHi << 4 | mode << 22;
|
||||
bind(opcode, MoveToStatusFromImmediate);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3), /* m */ \
|
||||
opcode.bits(16,19), /* field */ \
|
||||
opcode.bit (22) /* mode */
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern(".... 0001 0?10 ???? ---- ---- 0000 ????") | mode << 22;
|
||||
bind(opcode, MoveToStatusFromRegister);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3), /* m */ \
|
||||
opcode.bits( 8,11), /* s */ \
|
||||
opcode.bits(12,15), /* n */ \
|
||||
opcode.bits(16,19), /* d */ \
|
||||
opcode.bit (20), /* save */ \
|
||||
opcode.bit (21) /* accumulate */
|
||||
for(uint1 save : range(2))
|
||||
for(uint1 accumulate : range(2)) {
|
||||
auto opcode = pattern(".... 0000 00?? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21;
|
||||
bind(opcode, Multiply);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#define arguments \
|
||||
opcode.bits( 0, 3), /* m */ \
|
||||
opcode.bits( 8,11), /* s */ \
|
||||
opcode.bits(12,15), /* l */ \
|
||||
opcode.bits(16,19), /* h */ \
|
||||
opcode.bit (20), /* save */ \
|
||||
opcode.bit (21), /* accumulate */ \
|
||||
opcode.bit (22) /* sign */
|
||||
for(uint1 save : range(2))
|
||||
for(uint1 accumulate : range(2))
|
||||
for(uint1 sign : range(2)) {
|
||||
auto opcode = pattern(".... 0000 1??? ???? ???? ???? 1001 ????") | save << 20 | accumulate << 21 | sign << 22;
|
||||
bind(opcode, MultiplyLong);
|
||||
}
|
||||
#undef arguments
|
||||
|
||||
#undef bind
|
||||
#undef pattern
|
||||
}
|
||||
|
||||
auto ARM7TDMI::thumbInitialize() -> void {
|
||||
#define bind(id, name, ...) { \
|
||||
assert(!thumbInstruction[id]); \
|
||||
thumbInstruction[id] = [=] { return thumbInstruction##name(__VA_ARGS__); }; \
|
||||
thumbDisassemble[id] = [=] { return thumbDisassemble##name(__VA_ARGS__); }; \
|
||||
}
|
||||
|
||||
#define pattern(s) \
|
||||
std::integral_constant<uint16_t, bit::test(s)>::value
|
||||
|
||||
for(uint3 d : range(8))
|
||||
for(uint3 n : range(8))
|
||||
for(uint3 m : range(8))
|
||||
for(uint1 mode : range(2)) {
|
||||
auto opcode = pattern("0001 10?? ???? ????") | d << 0 | n << 3 | m << 6 | mode << 9;
|
||||
bind(opcode, AdjustRegister, d, n, m, mode);
|
||||
}
|
||||
|
||||
#undef bind
|
||||
#undef pattern
|
||||
}
|
||||
|
|
|
@ -1,24 +1,174 @@
|
|||
auto ARM7TDMI::armALU(uint4 mode, uint4 target, uint4 source, uint32 data, bool save) -> void {
|
||||
auto ARM7TDMI::armALU(uint4 mode, uint4 target, uint4 source, uint32 data) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(target) = BIT(r(source) & data, save); break; //AND
|
||||
case 1: r(target) = BIT(r(source) ^ data, save); break; //EOR
|
||||
case 2: r(target) = SUB(r(source), data, 1, save); break; //SUB
|
||||
case 3: r(target) = SUB(data, r(source), 1, save); break; //RSB
|
||||
case 4: r(target) = ADD(r(source), data, 0, save); break; //ADD
|
||||
case 5: r(target) = ADD(r(source), data, cpsr().c, save); break; //ADC
|
||||
case 6: r(target) = SUB(r(source), data, cpsr().c, save); break; //SBC
|
||||
case 7: r(target) = SUB(data, r(source), cpsr().c, save); break; //RSC
|
||||
case 8: BIT(r(source) & data, save); break; //TST
|
||||
case 9: BIT(r(source) ^ data, save); break; //TEQ
|
||||
case 10: SUB(r(source), data, 1, save); break; //CMP
|
||||
case 11: ADD(r(source), data, 0, save); break; //CMN
|
||||
case 12: r(target) = BIT(r(source) | data, save); break; //ORR
|
||||
case 13: r(target) = BIT(data, save); break; //MOV
|
||||
case 14: r(target) = BIT(r(source) & ~data, save); break; //BIC
|
||||
case 15: r(target) = BIT(~data, save); break; //MVN
|
||||
case 0: r(target) = BIT(r(source) & data); break; //AND
|
||||
case 1: r(target) = BIT(r(source) ^ data); break; //EOR
|
||||
case 2: r(target) = SUB(r(source), data, 1); break; //SUB
|
||||
case 3: r(target) = SUB(data, r(source), 1); break; //RSB
|
||||
case 4: r(target) = ADD(r(source), data, 0); break; //ADD
|
||||
case 5: r(target) = ADD(r(source), data, cpsr().c); break; //ADC
|
||||
case 6: r(target) = SUB(r(source), data, cpsr().c); break; //SBC
|
||||
case 7: r(target) = SUB(data, r(source), cpsr().c); break; //RSC
|
||||
case 8: BIT(r(source) & data); break; //TST
|
||||
case 9: BIT(r(source) ^ data); break; //TEQ
|
||||
case 10: SUB(r(source), data, 1); break; //CMP
|
||||
case 11: ADD(r(source), data, 0); break; //CMN
|
||||
case 12: r(target) = BIT(r(source) | data); break; //ORR
|
||||
case 13: r(target) = BIT(data); break; //MOV
|
||||
case 14: r(target) = BIT(r(source) & ~data); break; //BIC
|
||||
case 15: r(target) = BIT(~data); break; //MVN
|
||||
}
|
||||
|
||||
if(exception() && target == 15 && save) {
|
||||
if(exception() && target == 15 && opcode.bit(20)) {
|
||||
cpsr() = spsr();
|
||||
}
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void {
|
||||
if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return;
|
||||
PSR& psr = mode ? spsr() : cpsr();
|
||||
|
||||
if(field.bit(0)) {
|
||||
if(mode || privileged()) {
|
||||
psr.m = 0x10 | data.bits(0,4);
|
||||
psr.t = data.bit (5);
|
||||
psr.f = data.bit (6);
|
||||
psr.i = data.bit (7);
|
||||
}
|
||||
}
|
||||
|
||||
if(field.bit(3)) {
|
||||
psr.v = data.bit(28);
|
||||
psr.c = data.bit(29);
|
||||
psr.z = data.bit(30);
|
||||
psr.n = data.bit(31);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ARM7TDMI::armInstructionBranchExchangeRegister
|
||||
(uint4 m) -> void {
|
||||
uint32 address = r(m);
|
||||
cpsr().t = address.bit(0);
|
||||
r(15) = address;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadImmediate
|
||||
(uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionLoadRegister
|
||||
(uint4 m, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rm = r(m);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMemorySwap
|
||||
(uint4 m, uint4 d, uint4 n, uint1 byte) -> void {
|
||||
uint32 word = load((byte ? Byte : Word) | Nonsequential, r(n));
|
||||
store((byte ? Byte : Word) | Nonsequential, r(n), r(m));
|
||||
r(d) = word;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfImmediate
|
||||
(uint8 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveHalfRegister
|
||||
(uint4 m, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 up, uint1 pre) -> void {
|
||||
uint32 rn = r(n);
|
||||
uint32 rm = r(m);
|
||||
uint32 rd = r(d);
|
||||
|
||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||
if(mode == 1) rd = load(Half | Nonsequential, rn);
|
||||
if(mode == 0) store(Half | Nonsequential, rn, rd);
|
||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||
|
||||
if(pre == 0 || writeback) r(n) = rn;
|
||||
if(mode == 1) r(d) = rd;
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToRegisterFromStatus
|
||||
(uint4 d, uint1 mode) -> void {
|
||||
if(mode && (cpsr().m == PSR::USR || cpsr().m == PSR::SYS)) return;
|
||||
r(d) = mode ? spsr() : cpsr();
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToStatusFromImmediate
|
||||
(uint8 immediate, uint4 rotate, uint4 field, uint1 mode) -> void {
|
||||
uint32 data = immediate;
|
||||
if(rotate) data = ROR(data, rotate << 1);
|
||||
armMoveToStatus(field, mode, data);
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMoveToStatusFromRegister
|
||||
(uint4 m, uint4 field, uint1 mode) -> void {
|
||||
armMoveToStatus(field, mode, r(m));
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiply
|
||||
(uint4 m, uint4 s, uint4 n, uint4 d, uint1 save, uint1 accumulate) -> void {
|
||||
if(accumulate) idle();
|
||||
r(d) = MUL(accumulate ? r(n) : 0, r(m), r(s));
|
||||
}
|
||||
|
||||
auto ARM7TDMI::armInstructionMultiplyLong
|
||||
(uint4 m, uint4 s, uint4 l, uint4 h, uint1 save, uint1 accumulate, uint1 sign) -> void {
|
||||
uint64 rm = r(m);
|
||||
uint64 rs = r(s);
|
||||
|
||||
idle();
|
||||
idle();
|
||||
if(accumulate) idle();
|
||||
|
||||
if(sign) {
|
||||
if(rs >> 8 && rs >> 8 != 0xffffff) idle();
|
||||
if(rs >> 16 && rs >> 16 != 0xffff) idle();
|
||||
if(rs >> 24 && rs >> 24 != 0xff) idle();
|
||||
rm = (int32)rm;
|
||||
rs = (int32)rs;
|
||||
} else {
|
||||
if(rs >> 8) idle();
|
||||
if(rs >> 16) idle();
|
||||
if(rs >> 24) idle();
|
||||
}
|
||||
|
||||
uint64 rd = rm * rs;
|
||||
if(accumulate) rd += (uint64)r(h) << 32 | (uint64)r(l) << 0;
|
||||
|
||||
r(h) = rd >> 32;
|
||||
r(l) = rd >> 0;
|
||||
|
||||
if(save) {
|
||||
cpsr().z = rd == 0;
|
||||
cpsr().n = rd.bit(63);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,3 +18,13 @@ auto ARM7TDMI::thumbALU(uint4 mode, uint4 target, uint4 source) -> void {
|
|||
case 15: r(target) = BIT(~r(source)); break; //MVN
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto ARM7TDMI::thumbInstructionAdjustRegister
|
||||
(uint3 d, uint3 n, uint3 m, uint1 mode) -> void {
|
||||
switch(mode) {
|
||||
case 0: r(d) = ADD(r(n), r(m), 0); break;
|
||||
case 1: r(d) = SUB(r(n), r(m), 1); break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue