From 559eeccc8948b17cd4f430554834a81229d0b16c Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 8 Aug 2017 21:51:41 +1000 Subject: [PATCH] Update to v103r29 release. byuu says: Changelog: - processor/arm7tdmi: implementation all nine remaining ARM instructions - processor/arm7tdmi: implemented five more THUMB instructions (sixteen remain) --- higan/emulator/emulator.hpp | 2 +- higan/processor/arm/disassembler.cpp | 4 +- higan/processor/arm/instructions-arm.cpp | 1 - higan/processor/arm7tdmi/arm7tdmi.hpp | 29 ++- higan/processor/arm7tdmi/disassembler.cpp | 171 ++++++++++++++- higan/processor/arm7tdmi/instruction.cpp | 195 ++++++++++++++++++ higan/processor/arm7tdmi/instructions-arm.cpp | 131 ++++++++++++ .../processor/arm7tdmi/instructions-thumb.cpp | 73 +++++-- higan/processor/arm7tdmi/registers.cpp | 22 -- 9 files changed, 578 insertions(+), 50 deletions(-) diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 4ca3fe5e..63b56cac 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.28"; + static const string Version = "103.29"; 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 d164a7d6..d30e486f 100644 --- a/higan/processor/arm/disassembler.cpp +++ b/higan/processor/arm/disassembler.cpp @@ -301,7 +301,7 @@ auto ARM::disassembleInstructionARM(uint32 pc) -> string { output.append(opcodes[opcode], conditions[condition]); if(isMove(opcode)) output.append(save ? "s " : " ", registers[rd], ","); - if(isComp(opcode)) output.append(registers[rn], ","); + if(isComp(opcode)) output.append(" ", registers[rn], ","); if(isMath(opcode)) output.append(save ? "s " : " ", registers[rd], ",", registers[rn], ","); output.append(registers[rm]); if(mode == 0) output.append(" lsl "); @@ -357,7 +357,7 @@ auto ARM::disassembleInstructionARM(uint32 pc) -> string { if(pre == 1) output.append("]"); if(pre == 0 || writeback == 1) output.append("!"); - if(rn == 15) output.append(" =0x", hex(read((byte ? Byte : Word) | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), 8L)); + if(rn == 15) output.append(" =0x", hex(read((byte ? Byte : Word) | Nonsequential, pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L)); return output; } diff --git a/higan/processor/arm/instructions-arm.cpp b/higan/processor/arm/instructions-arm.cpp index df17e33f..8652cc70 100644 --- a/higan/processor/arm/instructions-arm.cpp +++ b/higan/processor/arm/instructions-arm.cpp @@ -496,7 +496,6 @@ auto ARM::arm_op_move_register_offset() { uint32 rd = r(d); uint32 rs = immediate; uint32 rm = r(m); - bool c = cpsr().c; if(mode == 0) rm = lsl(rm, rs); if(mode == 1) rm = lsr(rm, rs ? rs : (uint32)32); diff --git a/higan/processor/arm7tdmi/arm7tdmi.hpp b/higan/processor/arm7tdmi/arm7tdmi.hpp index d0a37b0b..7a8ad035 100644 --- a/higan/processor/arm7tdmi/arm7tdmi.hpp +++ b/higan/processor/arm7tdmi/arm7tdmi.hpp @@ -31,7 +31,6 @@ struct ARM7TDMI { struct GPR; struct PSR; inline auto r(uint4) -> GPR&; - inline auto u(uint4) -> GPR&; inline auto cpsr() -> PSR&; inline auto spsr() -> PSR&; inline auto privileged() const -> bool; @@ -67,22 +66,33 @@ struct ARM7TDMI { auto armALU(uint4 mode, uint4 target, uint4 source, uint32 data) -> void; auto armMoveToStatus(uint4 field, uint1 source, uint32 data) -> void; + auto armInstructionBranch(int24, uint1) -> void; auto armInstructionBranchExchangeRegister(uint4) -> void; + auto armInstructionDataImmediate(uint8, uint4, uint4, uint4, uint1, uint4) -> void; + auto armInstructionDataImmediateShift(uint4, uint2, uint5, uint4, uint4, uint1, uint4) -> void; + auto armInstructionDataRegisterShift(uint4, uint2, uint4, uint4, uint4, uint1, 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 armInstructionMoveImmediateOffset(uint12, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> void; + auto armInstructionMoveMultiple(uint16, uint4, uint1, uint1, uint1, uint1, uint1) -> void; + auto armInstructionMoveRegisterOffset(uint4, uint2, uint5, uint4, uint4, uint1, 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; + auto armInstructionSoftwareInterrupt(uint24 immediate) -> void; //instructions-thumb.cpp - auto thumbALU(uint4 mode, uint4 target, uint4 source) -> void; - + auto thumbInstructionALU(uint3, uint3, uint4) -> void; + auto thumbInstructionAdjustImmediate(uint3, uint3, uint3, uint1) -> void; auto thumbInstructionAdjustRegister(uint3, uint3, uint3, uint1) -> void; + auto thumbInstructionBranchExchange(uint4) -> void; + auto thumbInstructionImmediate(uint8, uint3, uint2) -> void; + auto thumbInstructionShiftImmediate(uint3, uint3, uint5, uint2) -> void; //serialization.cpp auto serialize(serializer&) -> void; @@ -210,19 +220,32 @@ struct ARM7TDMI { function thumbDisassemble[65536]; //disassembler.cpp + auto armDisassembleBranch(int24, uint1) -> string; auto armDisassembleBranchExchangeRegister(uint4) -> string; + auto armDisassembleDataImmediate(uint8, uint4, uint4, uint4, uint1, uint4) -> string; + auto armDisassembleDataImmediateShift(uint4, uint2, uint5, uint4, uint4, uint1, uint4) -> string; + auto armDisassembleDataRegisterShift(uint4, uint2, uint4, uint4, uint4, uint1, 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 armDisassembleMoveImmediateOffset(uint12, uint4, uint4, uint1, uint1, uint1, uint1, uint1) -> string; + auto armDisassembleMoveMultiple(uint16, uint4, uint1, uint1, uint1, uint1, uint1) -> string; + auto armDisassembleMoveRegisterOffset(uint4, uint2, uint5, uint4, uint4, uint1, 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 armDisassembleSoftwareInterrupt(uint24) -> string; + auto thumbDisassembleALU(uint3, uint3, uint4) -> string; + auto thumbDisassembleAdjustImmediate(uint3, uint3, uint3, uint1) -> string; auto thumbDisassembleAdjustRegister(uint3, uint3, uint3, uint1) -> string; + auto thumbDisassembleBranchExchange(uint4) -> string; + auto thumbDisassembleImmediate(uint8, uint3, uint2) -> string; + auto thumbDisassembleShiftImmediate(uint3, uint3, uint5, uint2) -> string; }; } diff --git a/higan/processor/arm7tdmi/disassembler.cpp b/higan/processor/arm7tdmi/disassembler.cpp index 01f7dbaf..fd1d459d 100644 --- a/higan/processor/arm7tdmi/disassembler.cpp +++ b/higan/processor/arm7tdmi/disassembler.cpp @@ -1,22 +1,81 @@ static uint32 _pc; static string _c; -static string _r[16] = { +static const string _r[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }; #define _s save ? "s" : "" +#define isMove(mode) (mode == 13 || mode == 15) +#define isComp(mode) (mode >= 8 && mode <= 11) +#define isMath(mode) (mode <= 7 || mode == 12 || mode == 14) + auto ARM7TDMI::disassemble(uint32 pc) -> string { return ""; } // +auto ARM7TDMI::armDisassembleBranch +(int24 displacement, uint1 link) -> string { + return {"b", link ? "l" : "", _c, " 0x", hex(_pc + 8 + displacement * 4, 8L)}; +} + auto ARM7TDMI::armDisassembleBranchExchangeRegister (uint4 m) -> string { return {"bx", _c, " ", _r[m]}; } +auto ARM7TDMI::armDisassembleDataImmediate +(uint8 immediate, uint4 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", + }; + uint32 data = immediate >> (shift << 1) | immediate << 32 - (shift << 1); + return {opcode[mode], _c, + isMove(mode) ? string{_s, " ", _r[d]} : string{}, + isComp(mode) ? string{" ", _r[n]} : string{}, + isMath(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{}, + ",#0x", hex(data, 8L)}; +} + +auto ARM7TDMI::armDisassembleDataImmediateShift +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", + }; + return {opcode[mode], _c, + isMove(mode) ? string{_s, " ", _r[d]} : string{}, + isComp(mode) ? string{" ", _r[n]} : string{}, + isMath(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{}, + ",", _r[m], + type == 0 && shift ? string{" lsl #", shift} : string{}, + type == 1 ? string{" lsr #", shift ? (uint)shift : 32} : string{}, + type == 2 ? string{" asr #", shift ? (uint)shift : 32} : string{}, + type == 3 && shift ? string{" ror #", shift} : string{}, + type == 3 && !shift ? " rrx" : ""}; +} + +auto ARM7TDMI::armDisassembleDataRegisterShift +(uint4 m, uint2 type, uint4 s, uint4 d, uint4 n, uint1 save, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "sub", "rsb", "add", "adc", "sbc", "rsc", + "tst", "teq", "cmp", "cmn", "orr", "mov", "bic", "mvn", + }; + return {opcode[mode], _c, + isMove(mode) ? string{_s, " ", _r[d]} : string{}, + isComp(mode) ? string{" ", _r[n]} : string{}, + isMath(mode) ? string{_s, " ", _r[d], ",", _r[n]} : string{}, + ",", _r[m], " ", + type == 0 ? "lsl" : "", + type == 1 ? "lsr" : "", + type == 2 ? "asr" : "", + type == 3 ? "ror" : "", + " ", _r[s]}; +} + auto ARM7TDMI::armDisassembleLoadImmediate (uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> string { string data; @@ -69,6 +128,48 @@ auto ARM7TDMI::armDisassembleMoveHalfRegister pre == 0 || writeback ? "!" : ""}; } +auto ARM7TDMI::armDisassembleMoveImmediateOffset +(uint12 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> string { + string data; + if(n == 15) data = {" =0x", hex(read((byte ? Byte : Word) | Nonsequential, + _pc + 8 + (up ? +immediate : -immediate)), byte ? 2L : 4L)}; + return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + immediate ? string{",", up ? "+" : "-", "0x", hex(immediate, 3L)} : string{}, + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : "", data}; +} + +auto ARM7TDMI::armDisassembleMoveMultiple +(uint16 list, uint4 n, uint1 mode, uint1 writeback, uint1 type, uint1 up, uint1 pre) -> string { + string registers; + for(auto index : range(16)) { + if(list.bit(index)) registers.append(_r[index], ","); + } + registers.trimRight(",", 1L); + return {mode ? "ldm" : "stm", + up == 0 && pre == 0 ? "da" : "", + up == 0 && pre == 1 ? "db" : "", + up == 1 && pre == 0 ? "ia" : "", + up == 1 && pre == 1 ? "ib" : "", + " ", _r[n], writeback ? "!" : "", + ",{", registers, "}", type ? "^" : ""}; +} + +auto ARM7TDMI::armDisassembleMoveRegisterOffset +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> string { + return {mode ? "ldr" : "str", _c, byte ? "b" : "", " ", _r[d], ",[", _r[n], + pre == 0 ? "]" : "", + ",", up ? "+" : "-", _r[m], + type == 0 && shift ? string{" lsl #", shift} : string{}, + type == 1 ? string{" lsr #", shift ? (uint)shift : 32} : string{}, + type == 2 ? string{" asr #", shift ? (uint)shift : 32} : string{}, + type == 3 && shift ? string{" ror #", shift} : string{}, + type == 3 && !shift ? " rrx" : "", + pre == 1 ? "]" : "", + pre == 0 || writeback ? "!" : ""}; +} + auto ARM7TDMI::armDisassembleMoveToRegisterFromStatus (uint4 d, uint1 mode) -> string { return {"mrs", _c, " ", _r[d], ",", mode ? "spsr" : "cpsr"}; @@ -110,9 +211,77 @@ auto ARM7TDMI::armDisassembleMultiplyLong _r[l], ",", _r[h], ",", _r[m], ",", _r[s]}; } +auto ARM7TDMI::armDisassembleSoftwareInterrupt +(uint24 immediate) -> string { + return {"swi #0x", hex(immediate, 6L)}; +} + // +auto ARM7TDMI::thumbDisassembleALU +(uint3 d, uint3 m, uint4 mode) -> string { + static const string opcode[] = { + "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", + "tst", "neg", "cmp", "cmn", "orr", "mul", "bic", "mvn", + }; + return {opcode[mode], " ", _r[d], ",", _r[m]}; +} + +auto ARM7TDMI::thumbDisassembleAdjustImmediate +(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> string { + return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",#", immediate}; +} + auto ARM7TDMI::thumbDisassembleAdjustRegister (uint3 d, uint3 n, uint3 m, uint1 mode) -> string { return {!mode ? "add" : "sub", " ", _r[d], ",", _r[n], ",", _r[m]}; } + +auto ARM7TDMI::thumbDisassembleBranchExchange +(uint4 m) -> string { + return {"bx ", _r[m]}; +} + +auto ARM7TDMI::thumbDisassembleImmediate +(uint8 immediate, uint3 d, uint2 mode) -> string { + static const string opcode[] = {"mov", "cmp", "add", "sub"}; + return {opcode[mode], " ", _r[d], ",#0x", hex(immediate, 2L)}; +} + +auto ARM7TDMI::thumbDisassembleShiftImmediate +(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> string { + static const string opcode[] = {"lsl", "lsr", "asr"}; + return {opcode[mode], " ", _r[d], ",", _r[m], ",#", immediate}; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/higan/processor/arm7tdmi/instruction.cpp b/higan/processor/arm7tdmi/instruction.cpp index 456d06c5..9faf1520 100644 --- a/higan/processor/arm7tdmi/instruction.cpp +++ b/higan/processor/arm7tdmi/instruction.cpp @@ -66,6 +66,18 @@ auto ARM7TDMI::armInitialize() -> void { #define pattern(s) \ std::integral_constant::value + #define arguments \ + opcode.bits( 0,23), /* displacement */ \ + opcode.bit (24) /* link */ + for(uint4 displacementLo : range(16)) + for(uint4 displacementHi : range(16)) + for(uint1 link : range(2)) { + auto opcode = pattern(".... 101? ???? ???? ???? ???? ???? ????") + | displacementLo << 4 | displacementHi << 20 | link << 24; + bind(opcode, Branch); + } + #undef arguments + #define arguments \ opcode.bits( 0, 3) /* m */ { @@ -74,6 +86,57 @@ auto ARM7TDMI::armInitialize() -> void { } #undef arguments + #define arguments \ + opcode.bits( 0, 7), /* immediate */ \ + opcode.bits( 8,11), /* shift */ \ + opcode.bits(12,15), /* d */ \ + opcode.bits(16,19), /* n */ \ + opcode.bit (20), /* save */ \ + opcode.bits(21,24) /* mode */ + for(uint4 shiftHi : range(16)) + for(uint1 save : range(2)) + for(uint4 mode : range(16)) { + if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN + auto opcode = pattern(".... 001? ???? ???? ???? ???? ???? ????") | shiftHi << 4 | save << 20 | mode << 21; + bind(opcode, DataImmediate); + } + #undef arguments + + #define arguments \ + opcode.bits( 0, 3), /* m */ \ + opcode.bits( 5, 6), /* type */ \ + opcode.bits( 7,11), /* shift */ \ + opcode.bits(12,15), /* d */ \ + opcode.bits(16,19), /* n */ \ + opcode.bit (20), /* save */ \ + opcode.bits(21,24) /* mode */ + for(uint2 type : range(4)) + for(uint1 shiftLo : range(2)) + for(uint1 save : range(2)) + for(uint4 mode : range(16)) { + if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN + auto opcode = pattern(".... 000? ???? ???? ???? ???? ???0 ????") | type << 5 | shiftLo << 7 | save << 20 | mode << 21; + bind(opcode, DataImmediateShift); + } + #undef arguments + + #define arguments \ + opcode.bits( 0, 3), /* m */ \ + opcode.bits( 5, 6), /* type */ \ + opcode.bits( 8,11), /* s */ \ + opcode.bits(12,15), /* d */ \ + opcode.bits(16,19), /* n */ \ + opcode.bit (20), /* save */ \ + opcode.bits(21,24) /* mode */ + for(uint2 type : range(4)) + for(uint1 save : range(2)) + for(uint4 mode : range(16)) { + if(mode >= 8 && mode <= 11 && !save) continue; //TST, TEQ, CMP, CMN + auto opcode = pattern(".... 000? ???? ???? ???? ???? 0??1 ????") | type << 5 | save << 20 | mode << 21; + bind(opcode, DataRegisterShift); + } + #undef arguments + #define arguments \ opcode.bits( 0, 3) << 0 | opcode.bits( 8,11) << 4, /* immediate */ \ opcode.bit ( 5), /* half */ \ @@ -153,6 +216,71 @@ auto ARM7TDMI::armInitialize() -> void { } #undef arguments + #define arguments \ + opcode.bits( 0,11), /* immediate */ \ + opcode.bits(12,15), /* d */ \ + opcode.bits(16,19), /* n */ \ + opcode.bit (20), /* mode */ \ + opcode.bit (21), /* writeback */ \ + opcode.bit (22), /* byte */ \ + opcode.bit (23), /* up */ \ + opcode.bit (24) /* pre */ + for(uint4 immediatePart : range(16)) + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 byte : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 010? ???? ???? ???? ???? ???? ????") + | immediatePart << 4 | mode << 20 | writeback << 21 | byte << 22 | up << 23 | pre << 24; + bind(opcode, MoveImmediateOffset); + } + #undef arguments + + #define arguments \ + opcode.bits( 0,15), /* list */ \ + opcode.bits(16,19), /* n */ \ + opcode.bit (20), /* mode */ \ + opcode.bit (21), /* writeback */ \ + opcode.bit (22), /* type */ \ + opcode.bit (23), /* up */ \ + opcode.bit (24) /* pre */ + for(uint4 listPart : range(16)) + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 type : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 100? ???? ???? ???? ???? ???? ????") + | listPart << 4 | mode << 20 | writeback << 21 | type << 22 | up << 23 | pre << 24; + bind(opcode, MoveMultiple); + } + #undef arguments + + #define arguments \ + opcode.bits( 0, 3), /* m */ \ + opcode.bits( 5, 6), /* type */ \ + opcode.bits( 7,11), /* shift */ \ + opcode.bits(12,15), /* d */ \ + opcode.bits(16,19), /* n */ \ + opcode.bit (20), /* mode */ \ + opcode.bit (21), /* writeback */ \ + opcode.bit (22), /* byte */ \ + opcode.bit (23), /* up */ \ + opcode.bit (24) /* pre */ + for(uint2 type : range(4)) + for(uint1 shiftLo : range(2)) + for(uint1 mode : range(2)) + for(uint1 writeback : range(2)) + for(uint1 byte : range(2)) + for(uint1 up : range(2)) + for(uint1 pre : range(2)) { + auto opcode = pattern(".... 011? ???? ???? ???? ???? ???0 ????") + | type << 5 | shiftLo << 7 | mode << 20 | writeback << 21 | byte << 22 | up << 23 | pre << 24; + bind(opcode, MoveRegisterOffset); + } + #undef arguments + #define arguments \ opcode.bits( 0, 3), /* d */ \ opcode.bit (22) /* mode */ @@ -214,6 +342,15 @@ auto ARM7TDMI::armInitialize() -> void { } #undef arguments + #define arguments \ + opcode.bits( 0,23) /* immediate */ + for(uint4 immediateLo : range(16)) + for(uint4 immediateHi : range(16)) { + auto opcode = pattern(".... 1111 ???? ???? ???? ???? ???? ????") | immediateLo << 4 | immediateHi << 20; + bind(opcode, SoftwareInterrupt); + } + #undef arguments + #undef bind #undef pattern } @@ -228,6 +365,21 @@ auto ARM7TDMI::thumbInitialize() -> void { #define pattern(s) \ std::integral_constant::value + for(uint3 d : range(8)) + for(uint3 m : range(8)) + for(uint4 mode : range(16)) { + auto opcode = pattern("0100 00?? ???? ????") | d << 0 | m << 3 | mode << 6; + bind(opcode, ALU, d, m, mode); + } + + for(uint3 d : range(8)) + for(uint3 n : range(8)) + for(uint3 immediate : range(8)) + for(uint1 mode : range(2)) { + auto opcode = pattern("0001 11?? ???? ????") | d << 0 | n << 3 | immediate << 6 | mode << 9; + bind(opcode, AdjustImmediate, d, n, immediate, mode); + } + for(uint3 d : range(8)) for(uint3 n : range(8)) for(uint3 m : range(8)) @@ -236,6 +388,49 @@ auto ARM7TDMI::thumbInitialize() -> void { bind(opcode, AdjustRegister, d, n, m, mode); } + for(uint3 _ : range(8)) + for(uint4 m : range(16)) { + auto opcode = pattern("0100 0111 0??? ?---") | _ << 0 | m << 3; + bind(opcode, BranchExchange, m); + } + + for(uint8 immediate : range(256)) + for(uint3 d : range(8)) + for(uint2 mode : range(4)) { + auto opcode = pattern("001? ???? ???? ????") | immediate << 0 | d << 8 | mode << 11; + bind(opcode, Immediate, immediate, d, mode); + } + + for(uint3 d : range(8)) + for(uint3 m : range(8)) + for(uint5 immediate : range(32)) + for(uint2 mode : range(4)) { + if(mode == 3) continue; + auto opcode = pattern("000? ???? ???? ????") | d << 0 | m << 3 | immediate << 6 | mode << 11; + bind(opcode, ShiftImmediate, d, m, immediate, mode); + } + #undef bind #undef pattern } + + + + + + + + + + + + + + + + + + + + + diff --git a/higan/processor/arm7tdmi/instructions-arm.cpp b/higan/processor/arm7tdmi/instructions-arm.cpp index d7ddedb0..be11900f 100644 --- a/higan/processor/arm7tdmi/instructions-arm.cpp +++ b/higan/processor/arm7tdmi/instructions-arm.cpp @@ -46,6 +46,12 @@ auto ARM7TDMI::armMoveToStatus(uint4 field, uint1 mode, uint32 data) -> void { // +auto ARM7TDMI::armInstructionBranch +(int24 displacement, uint1 link) -> void { + if(link) r(14) = r(15) - 4; + r(15) = r(15) + displacement * 4; +} + auto ARM7TDMI::armInstructionBranchExchangeRegister (uint4 m) -> void { uint32 address = r(m); @@ -53,6 +59,45 @@ auto ARM7TDMI::armInstructionBranchExchangeRegister r(15) = address; } +auto ARM7TDMI::armInstructionDataImmediate +(uint8 immediate, uint4 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> void { + uint32 data = immediate; + carry = cpsr().c; + if(shift) data = ROR(data, shift << 1); + armALU(mode, d, n, data); +} + +auto ARM7TDMI::armInstructionDataImmediateShift +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 save, uint4 mode) -> void { + uint32 rm = r(m); + carry = cpsr().c; + + switch(type) { + case 0: rm = LSL(rm, shift); break; + case 1: rm = LSR(rm, shift ? (uint)shift : 32); break; + case 2: rm = ASR(rm, shift ? (uint)shift : 32); break; + case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break; + } + + armALU(mode, d, n, rm); +} + +auto ARM7TDMI::armInstructionDataRegisterShift +(uint4 m, uint2 type, uint4 s, uint4 d, uint4 n, uint1 save, uint4 mode) -> void { + uint8 rs = r(s) + (s == 15 ? 4 : 0); + uint32 rm = r(m) + (m == 15 ? 4 : 0); + carry = cpsr().c; + + switch(type) { + case 0: rm = LSL(rm, rs < 33 ? rs : (uint8)33); break; + case 1: rm = LSR(rm, rs < 33 ? rs : (uint8)33); break; + case 2: rm = ASR(rm, rs < 32 ? rs : (uint8)32); break; + case 3: if(rs) rm = ROR(rm, rs & 31 ? rs & 31 : 32); break; + } + + armALU(mode, d, n, rm); +} + auto ARM7TDMI::armInstructionLoadImmediate (uint8 immediate, uint1 half, uint4 d, uint4 n, uint1 writeback, uint1 up, uint1 pre) -> void { uint32 rn = r(n); @@ -116,6 +161,87 @@ auto ARM7TDMI::armInstructionMoveHalfRegister if(mode == 1) r(d) = rd; } +auto ARM7TDMI::armInstructionMoveImmediateOffset +(uint12 immediate, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, 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((byte ? Byte : Word) | Nonsequential, rn); + if(mode == 0) store((byte ? Byte : Word) | 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::armInstructionMoveMultiple +(uint16 list, uint4 n, uint1 mode, uint1 writeback, uint1 type, uint1 up, uint1 pre) -> void { + uint32 rn = r(n); + if(pre == 0 && up == 1) rn = rn + 0; //IA + if(pre == 1 && up == 1) rn = rn + 4; //IB + if(pre == 1 && up == 0) rn = rn - bit::count(list) * 4 + 0; //DB + if(pre == 0 && up == 0) rn = rn - bit::count(list) * 4 + 4; //DA + + if(writeback && mode == 1) { + if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA,IB + if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA,DB + } + + auto cpsrMode = cpsr().m; + bool usr = false; + if(type && mode == 1 && !list.bit(15)) usr = true; + if(type && mode == 0) usr = true; + if(usr) cpsr().m = PSR::USR; + + uint sequential = Nonsequential; + for(uint m : range(16)) { + if(!list.bit(m)) continue; + if(mode == 1) r(m) = read(Word | sequential, rn); + if(mode == 0) write(Word | sequential, rn, r(m)); + rn += 4; + sequential = Sequential; + } + + if(usr) cpsr().m = cpsrMode; + + if(mode) { + idle(); + if(type && list.bit(15) && cpsr().m != PSR::USR && cpsr().m != PSR::SYS) { + cpsr() = spsr(); + } + } else { + pipeline.nonsequential = true; + } + + if(writeback && mode == 0) { + if(up == 1) r(n) = r(n) + bit::count(list) * 4; //IA,IB + if(up == 0) r(n) = r(n) - bit::count(list) * 4; //DA,DB + } +} + +auto ARM7TDMI::armInstructionMoveRegisterOffset +(uint4 m, uint2 type, uint5 shift, uint4 d, uint4 n, uint1 mode, uint1 writeback, uint1 byte, uint1 up, uint1 pre) -> void { + uint32 rm = r(m); + uint32 rd = r(d); + uint32 rn = r(n); + + switch(type) { + case 0: rm = LSL(rm, shift); break; + case 1: rm = LSR(rm, shift ? (uint)shift : 32); break; + case 2: rm = ASR(rm, shift ? (uint)shift : 32); break; + case 3: rm = shift ? ROR(rm, shift) : RRX(rm); break; + } + + if(pre == 1) rn = up ? rn + rm : rn - rm; + if(mode == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn); + if(mode == 0) store((byte ? Byte : Word) | 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; @@ -172,3 +298,8 @@ auto ARM7TDMI::armInstructionMultiplyLong cpsr().n = rd.bit(63); } } + +auto ARM7TDMI::armInstructionSoftwareInterrupt +(uint24 immediate) -> void { + interrupt(PSR::SVC, 0x08); +} diff --git a/higan/processor/arm7tdmi/instructions-thumb.cpp b/higan/processor/arm7tdmi/instructions-thumb.cpp index 6d224066..60316917 100644 --- a/higan/processor/arm7tdmi/instructions-thumb.cpp +++ b/higan/processor/arm7tdmi/instructions-thumb.cpp @@ -1,30 +1,63 @@ -auto ARM7TDMI::thumbALU(uint4 mode, uint4 target, uint4 source) -> void { +auto ARM7TDMI::thumbInstructionALU +(uint3 d, uint3 m, uint4 mode) -> void { switch(mode) { - case 0: r(target) = BIT(r(target) & r(source)); break; //AND - case 1: r(target) = BIT(r(target) ^ r(source)); break; //EOR - case 2: r(target) = BIT(LSL(r(target), r(source))); break; //LSL - case 3: r(target) = BIT(LSR(r(target), r(source))); break; //LSR - case 4: r(target) = BIT(ASR(r(target), r(source))); break; //ASR - case 5: r(target) = ADD(r(target), r(source), cpsr().c); break; //ADC - case 6: r(target) = SUB(r(target), r(source), cpsr().c); break; //SBC - case 7: r(target) = BIT(ROR(r(target), r(source))); break; //ROR - case 8: BIT(r(target) & r(source)); break; //TST - case 9: r(target) = SUB(0, r(source), 1); break; //NEG - case 10: SUB(r(target), r(source), 1); break; //CMP - case 11: ADD(r(target), r(source), 0); break; //CMN - case 12: r(target) = BIT(r(target) | r(source)); break; //ORR - case 13: r(target) = MUL(0, r(source), r(target)); break; //MUL - case 14: r(target) = BIT(r(target) & ~r(source)); break; //BIC - case 15: r(target) = BIT(~r(source)); break; //MVN + case 0: r(d) = BIT(r(d) & r(m)); break; //AND + case 1: r(d) = BIT(r(d) ^ r(m)); break; //EOR + case 2: r(d) = BIT(LSL(r(d), r(m))); break; //LSL + case 3: r(d) = BIT(LSR(r(d), r(m))); break; //LSR + case 4: r(d) = BIT(ASR(r(d), r(m))); break; //ASR + case 5: r(d) = ADD(r(d), r(m), cpsr().c); break; //ADC + case 6: r(d) = SUB(r(d), r(m), cpsr().c); break; //SBC + case 7: r(d) = BIT(ROR(r(d), r(m))); break; //ROR + case 8: BIT(r(d) & r(m)); break; //TST + case 9: r(d) = SUB(0, r(m), 1); break; //NEG + case 10: SUB(r(d), r(m), 1); break; //CMP + case 11: ADD(r(d), r(m), 0); break; //CMN + case 12: r(d) = BIT(r(d) | r(m)); break; //ORR + case 13: r(d) = MUL(0, r(m), r(d)); break; //MUL + case 14: r(d) = BIT(r(d) & ~r(m)); break; //BIC + case 15: r(d) = BIT(~r(m)); break; //MVN } } -// +auto ARM7TDMI::thumbInstructionAdjustImmediate +(uint3 d, uint3 n, uint3 immediate, uint1 mode) -> void { + switch(mode) { + case 0: r(d) = ADD(r(n), immediate, 0); break; //ADD + case 1: r(d) = SUB(r(n), immediate, 1); break; //SUB + } +} 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; + case 0: r(d) = ADD(r(n), r(m), 0); break; //ADD + case 1: r(d) = SUB(r(n), r(m), 1); break; //SUB + } +} + +auto ARM7TDMI::thumbInstructionBranchExchange +(uint4 m) -> void { + uint32 address = r(m); + cpsr().t = address.bit(0); + r(15) = address; +} + +auto ARM7TDMI::thumbInstructionImmediate +(uint8 immediate, uint3 d, uint2 mode) -> void { + switch(mode) { + case 0: r(d) = BIT(immediate); break; //MOV + case 1: SUB(r(d), immediate, 1); break; //CMP + case 2: r(d) = ADD(r(d), immediate, 0); break; //ADD + case 3: r(d) = SUB(r(d), immediate, 1); break; //SUB + } +} + +auto ARM7TDMI::thumbInstructionShiftImmediate +(uint3 d, uint3 m, uint5 immediate, uint2 mode) -> void { + switch(mode) { + case 0: r(d) = BIT(LSL(r(m), immediate)); break; //LSL + case 1: r(d) = BIT(LSR(r(m), immediate ? (uint)immediate : 32)); break; //LSR + case 2: r(d) = BIT(ASR(r(m), immediate ? (uint)immediate : 32)); break; //ASR } } diff --git a/higan/processor/arm7tdmi/registers.cpp b/higan/processor/arm7tdmi/registers.cpp index 24af3793..848f0883 100644 --- a/higan/processor/arm7tdmi/registers.cpp +++ b/higan/processor/arm7tdmi/registers.cpp @@ -34,28 +34,6 @@ auto ARM7TDMI::r(uint4 index) -> GPR& { unreachable; } -auto ARM7TDMI::u(uint4 index) -> GPR& { - switch(index) { - case 0: return processor.r0; - case 1: return processor.r1; - case 2: return processor.r2; - case 3: return processor.r3; - case 4: return processor.r4; - case 5: return processor.r5; - case 6: return processor.r6; - case 7: return processor.r7; - case 8: return processor.r8; - case 9: return processor.r9; - case 10: return processor.r10; - case 11: return processor.r11; - case 12: return processor.r12; - case 13: return processor.r13; - case 14: return processor.r14; - case 15: return processor.r15; - } - unreachable; -} - auto ARM7TDMI::cpsr() -> PSR& { return processor.cpsr; }