diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index c13bff9e..4ca3fe5e 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -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/"; diff --git a/higan/processor/arm/disassembler.cpp b/higan/processor/arm/disassembler.cpp index 4792de2f..d164a7d6 100644 --- a/higan/processor/arm/disassembler.cpp +++ b/higan/processor/arm/disassembler.cpp @@ -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; } diff --git a/higan/processor/arm7tdmi/algorithms.cpp b/higan/processor/arm7tdmi/algorithms.cpp index c97bbbec..15c0db41 100644 --- a/higan/processor/arm7tdmi/algorithms.cpp +++ b/higan/processor/arm7tdmi/algorithms.cpp @@ -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 { diff --git a/higan/processor/arm7tdmi/arm7tdmi.cpp b/higan/processor/arm7tdmi/arm7tdmi.cpp index e4532f49..4e0020f8 100644 --- a/higan/processor/arm7tdmi/arm7tdmi.cpp +++ b/higan/processor/arm7tdmi/arm7tdmi.cpp @@ -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; + } diff --git a/higan/processor/arm7tdmi/arm7tdmi.hpp b/higan/processor/arm7tdmi/arm7tdmi.hpp index e92aa535..d0a37b0b 100644 --- a/higan/processor/arm7tdmi/arm7tdmi.hpp +++ b/higan/processor/arm7tdmi/arm7tdmi.hpp @@ -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 armInstruction[4096]; + function thumbInstruction[65536]; + + function armDisassemble[4096]; + function 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; }; } diff --git a/higan/processor/arm7tdmi/disassembler.cpp b/higan/processor/arm7tdmi/disassembler.cpp new file mode 100644 index 00000000..01f7dbaf --- /dev/null +++ b/higan/processor/arm7tdmi/disassembler.cpp @@ -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]}; +} diff --git a/higan/processor/arm7tdmi/instruction.cpp b/higan/processor/arm7tdmi/instruction.cpp index fabbb47e..456d06c5 100644 --- a/higan/processor/arm7tdmi/instruction.cpp +++ b/higan/processor/arm7tdmi/instruction.cpp @@ -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::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::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 +} diff --git a/higan/processor/arm7tdmi/instructions-arm.cpp b/higan/processor/arm7tdmi/instructions-arm.cpp index 38813a4f..d7ddedb0 100644 --- a/higan/processor/arm7tdmi/instructions-arm.cpp +++ b/higan/processor/arm7tdmi/instructions-arm.cpp @@ -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); + } +} diff --git a/higan/processor/arm7tdmi/instructions-thumb.cpp b/higan/processor/arm7tdmi/instructions-thumb.cpp index cad99109..6d224066 100644 --- a/higan/processor/arm7tdmi/instructions-thumb.cpp +++ b/higan/processor/arm7tdmi/instructions-thumb.cpp @@ -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; + } +}