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:
Tim Allen 2017-08-07 22:20:35 +10:00
parent 0b6f1df987
commit a72ff8b7fa
9 changed files with 574 additions and 37 deletions

View File

@ -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/";

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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;
};
}

View File

@ -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]};
}

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -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;
}
}