Path: blob/master/libmeteor/source/disassembler/instruction.cpp
2 views
// Meteor - A Nintendo Gameboy Advance emulator1// Copyright (C) 2009-2011 Philippe Daouadi2//3// This program is free software: you can redistribute it and/or modify4// it under the terms of the GNU General Public License as published by5// the Free Software Foundation, either version 3 of the License, or6// (at your option) any later version.7//8// This program is distributed in the hope that it will be useful,9// but WITHOUT ANY WARRANTY; without even the implied warranty of10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11// GNU General Public License for more details.12//13// You should have received a copy of the GNU General Public License14// along with this program. If not, see <http://www.gnu.org/licenses/>.1516#include "ameteor/disassembler/instruction.hpp"1718#include "ameteor/disassembler/argregister.hpp"19#include "ameteor/disassembler/argrelative.hpp"20#include "ameteor/disassembler/argimmediate.hpp"21#include "ameteor/disassembler/arguimmediate.hpp"22#include "ameteor/disassembler/argshift.hpp"23#include "ameteor/disassembler/argpsr.hpp"24#include "ameteor/disassembler/argmulregisters.hpp"2526#include "../globals.hpp" // for ROR2728namespace AMeteor29{30namespace Disassembler31{32void Instruction::Clear ()33{34m_operator.clear();35m_args.Clear();36}3738#define Rn ((code >> 16) & 0xF)39#define Rd ((code >> 12) & 0xF)40#define Rs ((code >> 8) & 0xF)41#define Rm (code & 0xF)4243void Instruction::ParseArm (uint32_t offset, uint32_t code)44{45Clear();4647if ((code & 0x0FFFFFD0) == 0x12FFF10)48{49if (code & (0x1 << 5))50m_operator = "BLX";51else52m_operator = "BX";53m_args.AddArgument(ArgRegister(Rm));54ParseArmCondition(code);55}56else if (((code >> 25) & 0x7) == 0x5)57{58if (((code >> 28) & 0xF) == 0xF)59{60m_operator = "BLX";61m_args.AddArgument(ArgImmediate(offset + 8 +62(((code & (0x1 << 23)) ? 0xFF000000 | (code & 0x00FFFFFF)63: (code & 0x00FFFFFF)) << 2)64+ ((code & (0x1 << 24)) ? 2 : 0)));65}66else67{68if (code & (0x1 << 24))69m_operator = "BL";70else71m_operator = "B";72m_args.AddArgument(ArgImmediate(offset + 8 +73(((code & (0x1 << 23)) ? 0xFF000000 | (code & 0x00FFFFFF)74: (code & 0x00FFFFFF)) << 2)));75ParseArmCondition(code);76}77}78else if (((code >> 25) & 0x7) == 0x1)79{80ParseArmDataProc(code);81}82else if (((code >> 26) & 0x3) == 0x1)83{84if ((code & 0xF0100000) != 0xF0100000) // not PLD85m_args.AddArgument(ArgRegister(Rd));86if (code & (0x1 << 25)) // register offset87{88switch ((code >> 5) & 0x3)89{90case 0: // Logical Shift Left91m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),92ArgImmediate((code >> 7) & 0x1F), SHIFT_LSL, false),93code & (0x1 << 24), code & (0x1 << 23),94code & (0x1 << 21)));95break;96case 1: // Logical Shift Right97if (code & (0x1F << 7))98m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),99ArgImmediate((code >> 7) & 0x1F), SHIFT_LSR, false),100code & (0x1 << 24), code & (0x1 << 23),101code & (0x1 << 21)));102else103m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),104ArgImmediate(32), SHIFT_LSR, false),105code & (0x1 << 24), code & (0x1 << 23),106code & (0x1 << 21)));107break;108case 2: // Arithmetic Shift Right109if (code & (0x1F << 7))110m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),111ArgImmediate((code >> 7) & 0x1F), SHIFT_ASR, false),112code & (0x1 << 24), code & (0x1 << 23),113code & (0x1 << 21)));114else115m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),116ArgImmediate(32), SHIFT_ASR, false),117code & (0x1 << 24), code & (0x1 << 23),118code & (0x1 << 21)));119break;120case 3: // ROtate Right121if (code & (0x1F << 7))122m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),123ArgImmediate((code >> 7) & 0x1F), SHIFT_ROR, false),124code & (0x1 << 24), code & (0x1 << 23),125code & (0x1 << 21)));126else127m_args.AddArgument(ArgRelative(Rn, ArgShift(ArgRegister(Rm),128ArgImmediate(1), SHIFT_RRX, false),129code & (0x1 << 24), code & (0x1 << 23),130code & (0x1 << 21)));131break;132}133}134else // immediate offset135{136m_args.AddArgument(ArgRelative(Rn, ArgImmediate(code & 0xFFF),137code & (0x1 << 24), code & (0x1 << 23),138code & (0x1 << 21)));139}140141if ((code & 0xF0100000) == 0xF0100000)142m_operator = "PLD";143else144{145if (code & (0x1 << 20))146m_operator = "LDR";147else148m_operator = "STR";149if (code & (0x1 << 22))150m_operator += "B";151152ParseArmCondition(code);153}154}155else if (((code >> 25) & 0x7) == 0x4)156{157if (code & (0x1 << 20))158m_operator = "LDM";159else160m_operator = "STM";161162if (code & (0x1 << 23))163m_operator += 'I';164else165m_operator += 'D';166167if (code & (0x1 << 24))168m_operator += 'B';169else170m_operator += 'A';171172m_args.AddArgument(ArgRegister(Rn, code & (0x1 << 21)));173174ArgMulRegisters argRegs(code & (0x1 << 22));175for (register uint8_t n = 0; n < 16; ++n)176if (code & (0x1 << n))177argRegs.AddRegister(n);178m_args.AddArgument(argRegs);179180ParseArmCondition(code);181}182else if (((code >> 25) & 0x7) == 0x0)183{184if ((code & 0x0FC000F0) == 0x00000090 ||185(code & 0x0F8000F0) == 0x00800090 ||186(code & 0x0F900090) == 0x01000080)187{188// NOTE : In this instruction Rn and Rd are inverted189static const char* Instructions[] = {"MUL", "MLA", "Reserved",190"Reserved", "UMULL", "UMLAL", "SMULL", "SMLAL", "SMLAxy",191"", // This is for SMLAWy and SMULWy192"SMLALxy", "SMULxy", "Reserved", "Reserved", "Reserved",193"Reserved"};194195uint8_t opcode = (code >> 21) & 0xF;196if (opcode == 0x9)197m_operator = (code & (0x1 << 5)) ? "SMULWy" : "SMLAWy";198else199m_operator = Instructions[opcode];200if (!(opcode & (0x1 << 4)) && (code & (0x1 << 20)))201m_operator += 'S';202203ParseArmCondition(code);204205if ((opcode & 0xC) == 0x4 || opcode == 0xA)206m_args.AddArgument(ArgRegister(Rd));207m_args.AddArgument(ArgRegister(Rn));208m_args.AddArgument(ArgRegister(Rm));209m_args.AddArgument(ArgRegister(Rs));210if ((opcode & 0xE) == 0x8 || opcode == 0x1)211m_args.AddArgument(ArgRegister(Rd));212}213else if ((code & (0x1 << 7)) && (code & (0x1 << 4)))214{215if (((code >> 23) & 0x3) == 0x2 && ((code >> 20) & 0x3) == 0x0216&& ((code >> 4) & 0xFF) == 0x09)217{218if (code & (0x1 << 22)) // SWPB219m_operator = "SWPB";220else // SWP221m_operator = "SWP";222223ParseArmCondition(code);224225m_args.AddArgument(ArgRegister(Rd));226m_args.AddArgument(ArgRegister(Rm));227m_args.AddArgument(ArgRegister(Rn, false, false, true));228}229else230{231static const char* Instructions[] = {"Reserved", "STRH", "LDRD",232"STRD", "Reserved", "LDRH", "LDRSB", "LDRSH"};233234m_operator = Instructions[((code >> 18) & 0x4)235| ((code >> 5) & 0x3)];236237ParseArmCondition(code);238239m_args.AddArgument(ArgRegister(Rd));240241if (code & (0x1 << 22)) // immediate242{243m_args.AddArgument(ArgRelative(ArgRegister(Rn),244ArgImmediate(((code >> 4) & 0xF0) | (code & 0xF)),245code & (0x1 << 24), code & (0x1 << 23),246code & (0x1 << 21)));247}248else249{250m_args.AddArgument(ArgRelative(ArgRegister(Rn),251ArgRegister(code & 0xF),252code & (0x1 << 24), code & (0x1 << 23),253code & (0x1 << 21)));254}255}256}257else if (((code >> 23) & 0x3) == 0x2)258{259if (!((code >> 20) & 0x1))260{261if (code & (0x1 << 21))262{263m_operator = "MSR";264265m_args.AddArgument(ArgPsr(code & (0x1 << 22),266(code >> 16) & 0xF));267268if (code & (0x1 << 25)) // immediate269{270m_args.AddArgument(ArgUImmediate(271ROR(code & 0xFF, (code >> 8) & 0xF)));272}273else274{275m_args.AddArgument(ArgRegister(Rm));276}277}278else279{280m_operator = "MRS";281282m_args.AddArgument(ArgRegister(Rd));283m_args.AddArgument(ArgPsr(code & (0x1 << 22)));284}285286ParseArmCondition(code);287}288else289{290ParseArmDataProc(code);291}292}293else294{295ParseArmDataProc(code);296}297}298else299{300m_operator = "Unknown";301}302}303304void Instruction::ParseArmDataProc (uint32_t code)305{306static const char* ops[] = {"AND", "EOR", "SUB", "RSB", "ADD", "ADC",307"SBC", "RSC", "TST", "TEQ", "CMP", "CMN", "ORR", "MOV", "BIC", "MVN"};308309uint8_t opcode = (code >> 21) & 0xF;310311if (opcode < 0x8 || opcode > 0xB)312m_args.AddArgument(ArgRegister(Rd));313if (opcode != 0xD && opcode != 0xF)314m_args.AddArgument(ArgRegister(Rn));315316if (code & (0x1 << 25)) // Immediate operand 2317{318/*if (code & (0xF << 8))319m_args.AddArgument(ArgShift(ArgImmediate(code & 0xFF),320ArgImmediate(((code >> 8) & 0xF) << 1), SHIFT_ROR, false));321else322m_args.AddArgument(ArgImmediate(code & 0xFF));*/323m_args.AddArgument(ArgUImmediate(324ROR(code & 0xFF, (code >> 7) & 0x1E)));325}326else327{328switch ((code >> 5) & 0x3)329{330case 0: // Logical Shift Left331if (code & (0x1 << 4)) // Shift by register332{333m_args.AddArgument(ArgShift(ArgRegister(Rm),334ArgRegister(Rs), SHIFT_LSL, false));335}336else // Shift by immediate337{338if (code & (0x1F << 7))339m_args.AddArgument(ArgShift(ArgRegister(Rm),340ArgImmediate((code >> 7) & 0x1F), SHIFT_LSL, false));341else342m_args.AddArgument(ArgRegister(Rm));343}344break;345case 1: // Logical Shift Right346if (code & (0x1 << 4)) // Shift by register347{348m_args.AddArgument(ArgShift(ArgRegister(Rm),349ArgRegister(Rs), SHIFT_LSR, false));350}351else // Shift by immediate352{353if (code & (0x1F << 7))354m_args.AddArgument(ArgShift(ArgRegister(Rm),355ArgImmediate((code >> 7) & 0x1F), SHIFT_LSR, false));356else357m_args.AddArgument(ArgShift(ArgRegister(Rm),358ArgImmediate(32), SHIFT_LSR, false));359}360break;361case 2: // Arithmetic Shift Right362if (code & (0x1 << 4)) // Shift by register363{364m_args.AddArgument(ArgShift(ArgRegister(Rm),365ArgRegister(Rs), SHIFT_ASR, false));366}367else // Shift by immediate368{369if (code & (0x1F << 7))370m_args.AddArgument(ArgShift(ArgRegister(Rm),371ArgImmediate((code >> 7) & 0x1F), SHIFT_ASR, false));372else373m_args.AddArgument(ArgShift(ArgRegister(Rm),374ArgImmediate(32), SHIFT_ASR, false));375}376break;377case 3: // ROtate Right378if (code & (0x1 << 4)) // Shift by register379{380m_args.AddArgument(ArgShift(ArgRegister(Rm),381ArgRegister(Rs), SHIFT_ROR, false));382}383else // Shift by immediate384{385if (code & (0x1F << 7))386m_args.AddArgument(ArgShift(ArgRegister(Rm),387ArgImmediate((code >> 7) & 0x1F), SHIFT_ROR, false));388else389m_args.AddArgument(ArgShift(ArgRegister(Rm),390ArgImmediate(1), SHIFT_RRX, false));391}392break;393}394}395396m_operator = ops[opcode];397398if (code & (0x1 << 20) && (opcode < 0x8 || opcode > 0xB))399{400m_operator += "S";401}402ParseArmCondition(code);403}404405void Instruction::ParseArmCondition (uint32_t code)406{407static const char* Conditions[] = {"EQ", "NE", "CS", "CC", "MI", "PL",408"VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"};409410m_operator += Conditions[code >> 28];411}412413#undef Rn414#undef Rd415#undef Rs416#undef Rm417418#define Rb ((code >> 8) & 0x7)419#define Ro ((code >> 6) & 0x7)420#define Rs ((code >> 3) & 0x7)421#define Rd ((code ) & 0x7)422#define Imm (code & 0xFF)423#define Off ((code >> 6) & 0x1F)424425#define HiRs ((code >> 3) & 0xF)426#define HiRd (((code & (0x1 << 7)) >> 4) | Rd)427428void Instruction::ParseThumb (uint32_t offset, uint16_t code)429{430Clear ();431432if ((code >> 12) == 0xB && ((code >> 9) & 0x3) == 0x2) // 1011x10433{434if (code & (0x1 << 11))435m_operator = "POP";436else437m_operator = "PUSH";438439ArgMulRegisters argRegs(false);440for (register uint8_t n = 0; n < 8; ++n)441if (Imm & (0x1 << n))442argRegs.AddRegister(n);443444if (code & (0x1 << 8))445{446if (code & (0x1 << 11))447argRegs.AddLastRegister(SPREG_PC);448else449argRegs.AddLastRegister(SPREG_LR);450}451m_args.AddArgument(argRegs);452}453else if ((code >> 11) == 0x9) // 01001454{455m_operator = "LDR";456457m_args.AddArgument(ArgRegister(Rb));458m_args.AddArgument(ArgRelative(15, ArgImmediate(Imm << 2),459true, true, false));460}461else if ((code >> 12) == 0x8) // 1000462{463if (code & (0x1 << 11))464m_operator = "LDRH";465else466m_operator = "STRH";467468m_args.AddArgument(ArgRegister(Rd));469m_args.AddArgument(ArgRelative(Rs, ArgImmediate(Off << 1),470true, true, false));471}472else if ((code >> 10) == 0x10) // 010000473{474static const char* Instructions[] = {"AND", "EOR", "LSL", "LSR", "ASR",475"ADC", "SBC", "ROR", "TST", "NEG", "CMP", "CMN", "ORR", "MUL", "BIC",476"MVN"};477478m_operator = Instructions[(code >> 6) & 0xF];479480m_args.AddArgument(ArgRegister(Rd));481m_args.AddArgument(ArgRegister(Rs));482}483else if ((code >> 10) == 0x11) // 010001484{485switch ((code >> 8) & 0x3)486{487case 0x0: // ADD488m_operator = "ADD";489m_args.AddArgument(ArgRegister(HiRd));490m_args.AddArgument(ArgRegister(HiRs));491break;492case 0x1: // CMP493m_operator = "CMP";494m_args.AddArgument(ArgRegister(HiRd));495m_args.AddArgument(ArgRegister(HiRs));496break;497case 0x2:498if (HiRd != 8 || HiRs != 8) // MOV499{500m_operator = "MOV";501m_args.AddArgument(ArgRegister(HiRd));502m_args.AddArgument(ArgRegister(HiRs));503}504else505m_operator = "NOP";506break;507case 0x3:508if (code & (0x1 << 7)) // BLX509{510m_operator = "BLX";511m_args.AddArgument(ArgRegister(HiRs));512}513else // BX514{515m_operator = "BX";516m_args.AddArgument(ArgRegister(HiRs));517}518break;519}520}521else if ((code >> 13) == 0x1) // 001522{523static const char* Instructions[] = {"MOV", "CMP", "ADD", "SUB"};524525m_operator = Instructions[(code >> 11) & 0x3];526527m_args.AddArgument(ArgRegister(Rb));528m_args.AddArgument(ArgImmediate(Imm));529}530else if ((code >> 13) == 0x3) // 011531{532static const char* Instructions[] = {"STR", "LDR", "STRB", "LDRB"};533534m_operator = Instructions[(code >> 11) & 0x3];535536m_args.AddArgument(ArgRegister(Rd));537if (code & (0x1 << 12))538m_args.AddArgument(ArgRelative(Rs, ArgImmediate(Off), true,539true, false));540else541m_args.AddArgument(ArgRelative(Rs, ArgImmediate(Off << 2), true,542true, false));543}544else if ((code >> 12) == 0xC) // 1100545{546if (code & (0x1 << 11))547m_operator = "LDMIA";548else549m_operator = "STMIA";550551m_args.AddArgument(ArgRegister(Rb, true));552553ArgMulRegisters argRegs(false);554for (register uint8_t n = 0; n < 8; ++n)555if (Imm & (0x1 << n))556argRegs.AddRegister(n);557m_args.AddArgument(argRegs);558}559else if ((code >> 13) == 0x0) // 000560{561if ((code >> 11) == 0x3) // 00011562{563if ((code >> 9) & 0x1)564m_operator = "SUB";565else566m_operator = "ADD";567568m_args.AddArgument(ArgRegister(Rd));569m_args.AddArgument(ArgRegister(Rs));570571if ((code >> 10) & 0x1) // imm572m_args.AddArgument(ArgImmediate(Ro));573else // reg574m_args.AddArgument(ArgRegister(Ro));575}576else // 000577{578static const char* Instructions[] = {"LSL", "LSR", "ASR", "Reserved"};579580m_operator = Instructions[(code >> 11) & 0x3];581582m_args.AddArgument(ArgRegister(Rd));583m_args.AddArgument(ArgRegister(Rs));584m_args.AddArgument(ArgImmediate(Off));585}586}587else if ((code >> 11) == 0x1E) // 11110588{589m_operator = "BL.W1";590591m_args.AddArgument(ArgImmediate(offset + 4 + ((code & 0x7FF) << 12)));592}593else if ((code >> 13) == 0x7 && (code & (0x1 << 11))) // 111x1594{595m_operator = "BL.W2";596597m_args.AddArgument(ArgImmediate((code & 0x7FF) << 1));598}599else if ((code >> 11) == 0x1C) // 11100600{601m_operator = "B";602603if (code & (0x1 << 10))604m_args.AddArgument(ArgUImmediate(offset + 4 +605((int32_t)(((code & 0x3FF) << 1) | 0xFFFFF800))));606else607m_args.AddArgument(ArgUImmediate(offset + 4 + ((code & 0x3FF) << 1)));608}609else if ((code >> 12) == 0xD) // 1101610{611if (((code >> 8) & 0xF) == 0xF) // 11011111612{613m_operator = "SWI";614615m_args.AddArgument(ArgImmediate(code & 0xFF));616}617else // 1101618{619static const char* Conditions[] = {"EQ", "NE", "CS", "CC", "MI", "PL",620"VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "__", "**"};621622m_operator = "B";623m_operator += Conditions[(code >> 8) & 0xF];624625m_args.AddArgument(ArgUImmediate(offset + 4 +626(((int32_t)(int8_t)Imm) << 1)));627}628}629else if ((code >> 8) == 0xB0) // 10110000630{631m_operator = "ADD";632633m_args.AddArgument(ArgRegister(13, false, true));634if (code & (0x1 << 7)) // substract635m_args.AddArgument(ArgImmediate(-((code & 0x7F) << 2)));636else // add637m_args.AddArgument(ArgImmediate((code & 0x7F) << 2));638}639else if ((code >> 12) == 0x5) // 0101640{641if (code & (0x1 << 11))642m_operator = "LDR";643else644m_operator = "STR";645646if (code & (0x1 << 10))647m_operator += 'B';648649m_args.AddArgument(ArgRegister(Rd));650m_args.AddArgument(ArgRelative(Rs, ArgRegister(Ro), true, true, false));651}652else if ((code >> 12) == 0x9) // 1001653{654if (code & (0x1 << 11))655m_operator = "LDR";656else657m_operator = "STR";658659m_args.AddArgument(ArgRegister(Rb));660m_args.AddArgument(ArgRelative(ArgRegister(13, false, true),661ArgImmediate(Imm << 2), true, true, false));662}663else if ((code >> 12) == 0xA) // 1010664{665m_operator = "ADD";666667m_args.AddArgument(ArgRegister(Rb));668if (code & (0x1 << 11)) // with SP669m_args.AddArgument(ArgRegister(13, false, true));670else // with PC671m_args.AddArgument(ArgRegister(15, false, true));672m_args.AddArgument(ArgImmediate(Imm << 2));673}674else675{676m_operator = "Unknown";677}678}679680#undef Rb681#undef Ro682#undef Rs683#undef Rd684#undef Imm685#undef Off686687#undef HiRs688#undef HiRd689}690}691692693