//--------------------------------------------------------------------------- // NEOPOP : Emulator as in Dreamland // // Copyright (c) 2001-2002 by neopop_uk //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. See also the license.txt file for // additional informations. //--------------------------------------------------------------------------- /* //--------------------------------------------------------------------------- //========================================================================= TLCS900h_disassemble.c //========================================================================= //--------------------------------------------------------------------------- History of changes: =================== 20 JUL 2002 - neopop_uk ======================================= - Cleaned and tidied up for the source release 25 JUL 2002 - neopop_uk ======================================= - Added missing registers to disassmbly table (unused, I hope!) //--------------------------------------------------------------------------- */ //========================================================================= #include "../neopop.h" #include "TLCS900h_disassemble.h" #include "TLCS900h_registers.h" #include "TLCS900h_interpret.h" #include "../mem.h" namespace TLCS900H { void TLCS900h_disassemble_extra(void); void TLCS900h_disassemble_src(int size); void TLCS900h_disassemble_dst(void); void TLCS900h_disassemble_reg(int size); //========================================================================= char str_R[8]; //Big R char str_r[8]; //Little R //Control register names const char* crName[3][0x40] = { { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0, "DMAM0", 0, 0,0, "DMAM1", 0, 0,0, "DMAM2", 0, 0,0, "DMAM3", 0, }, { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, "DMAC0", 0, "DMAC1", 0, "DMAC2", 0, "DMAC3", 0, 0,0, //30 0,0, 0,0, "NSP",0, //3C }, { "DMAS0", //00 "DMAS1", "DMAS2", "DMAS3", "DMAD0", //10 "DMAD1", "DMAD2", "DMAD3", 0, //20 0, 0, 0, 0, //30 0, 0, "XNSP", //3C } }; //Register names const char* gprName[8][3] = { {"W", "WA", "XWA"}, {"A", "BC", "XBC"}, {"B", "DE", "XDE"}, {"C", "HL", "XHL"}, {"D", "IX", "XIX"}, {"E", "IY", "XIY"}, {"H", "IZ", "XIZ"}, {"L", "SP", "XSP"} }; //Condition Code names const char* ccName[] = { "F","LT","LE","ULE", "OV","MI","Z","C", "T","GE","GT","UGT", "NOV","PL","NZ","NC" }; const char* regCodeName[3][256] = { { "RA0","RW0","QA0","QW0","RC0","RB0","QC0","QB0", //BANK 0 "RE0","RD0","QE0","QD0","RL0","RH0","QL0","QH0", "RA1","RW1","QA1","QW1","RC1","RB1","QC1","QB1", //BANK 1 "RE1","RD1","QE1","QD1","RL1","RH1","QL1","QH1", "RA2","RW2","QA2","QW2","RC2","RB2","QC2","QB2", //BANK 2 "RE2","RD2","QE2","QD2","RL2","RH2","QL2","QH2", "RA3","RW3","QA3","QW3","RC3","RB3","QC3","QB3", //BANK 3 "RE3","RD3","QE3","QD3","RL3","RH3","QL3","QH3", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, "A'","W'","QA'","QW'","C'","B'","QC'","QB'", //Previous Bank "E'","D'","QE'","QD'","L'","H'","QL'","QH'", "A","W","QA","QW","C","B","QC","QB", //Current Bank "E","D","QE","QD","L","H","QL","QH", "IXL","IXH","QIXL","QIXH","IYL","IYH","QIYL","QIYH", "IZL","IZH","QIZL","QIZH","SPL","SPH","QSPL","QSPX" }, { "RWA0","QWA0","RBC0","QBC0", //BANK 0 "RDE0","QDE0","RHL0","QHL0", "RWA1","QWA1","RBC1","QBC1", //BANK 1 "RDE1","QDE1","RHL1","QHL1", "RWA2","QWA2","RBC2","QBC2", //BANK 2 "RDE2","QDE2","RHL2","QHL2", "RWA3","QWA3","RBC3","QBC3", //BANK 3 "RDE3","QDE3","RHL3","QHL3", 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, "WA'","QWA'","BC'","QBC'","DE'","QDE'","HL'","QHL'",//Previous Bank "WA","QWA","BC","QBC","DE","QDE","HL","QHL", //Current Bank "IX","QIX","IY","QIY","IZ","QIZ","SP","QSP" }, { "XWA0","XBC0","XDE0","XHL0", //BANK 0 "XWA1","XBC1","XDE1","XHL1", //BANK 1 "XWA2","XBC2","XDE2","XHL2", //BANK 2 "XWA3","XBC3","XDE3","XHL3", //BANK 3 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0, "XWA'","XBC'","XDE'","XHL'", //Previous Bank "XWA","XBC","XDE","XHL", //Current Bank "XIX","XIY","XIZ","XSP" } }; //========================================================================= void get_rr_Name(void) { sprintf(str_r, "???"); if (size == 0 && first == 0xC7) { sprintf(str_r, "%s", extra); return; } switch(first & 7) { case 0: if (size == 1) sprintf(str_r, "XWA"); break; case 1: if (size == 0) sprintf(str_r, "WA"); if (size == 1) sprintf(str_r, "XBC"); break; case 2: if (size == 1) sprintf(str_r, "XDE"); break; case 3: if (size == 0) sprintf(str_r, "BC"); if (size == 1) sprintf(str_r, "XHL"); break; case 4: if (size == 1) sprintf(str_r, "XIX"); break; case 5: if (size == 0) sprintf(str_r, "DE"); if (size == 1) sprintf(str_r, "XIY"); break; case 6: if (size == 1) sprintf(str_r, "XIZ"); break; case 7: if (size == 0) sprintf(str_r, "HL"); if (size == 1) sprintf(str_r, "XSP"); break; } } void get_RR_Name(void) { sprintf(str_R, "???"); switch(second & 7) { case 0: if (size == 1) sprintf(str_R, "XWA"); break; case 1: if (size == 0) sprintf(str_R, "WA"); if (size == 1) sprintf(str_R, "XBC"); break; case 2: if (size == 1) sprintf(str_R, "XDE"); break; case 3: if (size == 0) sprintf(str_R, "BC"); if (size == 1) sprintf(str_R, "XHL"); break; case 4: if (size == 1) sprintf(str_R, "XIX"); break; case 5: if (size == 0) sprintf(str_R, "DE"); if (size == 1) sprintf(str_R, "XIY"); break; case 6: if (size == 1) sprintf(str_R, "XIZ"); break; case 7: if (size == 0) sprintf(str_R, "HL"); if (size == 1) sprintf(str_R, "XSP"); break; } } //============================================================================= char instr[128]; //Print the disassembled instruction to this string uint8 bytes[16]; //Stores the bytes used uint8 bcnt; //Byte Counter for above //============================================================================= uint8 get8_dis(void) { uint8 a = bytes[bcnt++] = loadB(pc++); return a; } uint16 get16_dis(void) { uint16 a = *(uint16*)(uint8*)(bytes + bcnt) = loadW(pc); pc += 2; bcnt += 2; return a; } uint32 get24_dis(void) { uint8 b; uint16 a; a = *(uint16*)(uint8*)(bytes + bcnt) = loadW(pc); pc += 2; bcnt += 2; b = bytes[bcnt++] = loadB(pc++); return ((uint32)b << 16) | (uint32)a; } uint32 get32_dis(void) { uint32 a = *(uint32*)(uint8*)(bytes + bcnt) = loadL(pc); pc += 4; bcnt += 4; return a; } //========================================================================= static void src_B() { TLCS900h_disassemble_src(0); } static void src_W() { TLCS900h_disassemble_src(1); } static void src_L() { TLCS900h_disassemble_src(2); } static void dst() { TLCS900h_disassemble_dst(); } static void reg_B() { TLCS900h_disassemble_reg(0);} static void reg_W() { TLCS900h_disassemble_reg(1);} static void reg_L() { TLCS900h_disassemble_reg(2);} //========================================================================= //Single Byte Opcode static void NOP() { sprintf(instr, "NOP"); } static void NORMAL() { sprintf(instr, "NORMAL"); } static void PUSHSR() { sprintf(instr, "PUSH SR"); } static void POPSR() { sprintf(instr, "POP SR"); } static void MAX() { sprintf(instr, "MAX"); } static void HALT() { sprintf(instr, "HALT"); } static void EI() { uint8 value = get8_dis(); if (value == 7) sprintf(instr, "DI"); else sprintf(instr, "EI %d", value); } static void RETI() { sprintf(instr, "RETI"); } static void LD8_8() { uint8 dst = get8_dis(), src = get8_dis(); sprintf(instr, "LD (0x%02X),0x%02X", dst, src); } static void PUSH8() { sprintf(instr, "PUSH 0x%02X", get8_dis()); } static void LD8_16() { uint8 dst = get8_dis(); uint16 src = get16_dis(); sprintf(instr, "LD.w (0x%02X),0x%04X", dst, src); } static void PUSH16() { sprintf(instr, "PUSH 0x%04X", get16_dis()); } static void INCF() { sprintf(instr, "INCF"); } static void DECF() { sprintf(instr, "DECF"); } static void RET() { sprintf(instr, "RET"); } static void RETD() { sprintf(instr, "RETD %d", get16_dis()); } static void RCF() { sprintf(instr, "RCF"); } static void SCF() { sprintf(instr, "SCF"); } static void CCF() { sprintf(instr, "CCF"); } static void ZCF() { sprintf(instr, "ZCF"); } static void PUSHA() { sprintf(instr, "PUSH A"); } static void POPA() { sprintf(instr, "POP A"); } static void EX() { sprintf(instr, "EX F,F'"); } static void LDF() { sprintf(instr, "LDF 0x%02X", get8_dis()); } static void PUSHF() { sprintf(instr, "PUSH F"); } static void POPF() { sprintf(instr, "POP F"); } static void JP16() { sprintf(instr, "JP 0x%04X", get16_dis()); } static void JP24() { sprintf(instr, "JP 0x%06X", get24_dis()); } static void CALL16() { sprintf(instr, "CALL 0x%04X", get16_dis()); } static void CALL24() { sprintf(instr, "CALL 0x%06X", get24_dis()); } static void CALR() { sprintf(instr, "CALR 0x%06X", (int16)get16_dis() + pc); } static void LDB() { sprintf(instr, "LD %s,0x%02X", gprName[first & 7][0], get8_dis()); } static void PUSHW() { sprintf(instr, "PUSH %s", gprName[first & 7][1]); } static void LDW() { sprintf(instr, "LD %s,0x%04X", gprName[first & 7][1], get16_dis()); } static void PUSHL() { sprintf(instr, "PUSH %s", gprName[first & 7][2]); } static void LDL() { sprintf(instr, "LD %s,0x%08X", gprName[first & 7][2], get32_dis()); } static void POPW() { sprintf(instr, "POP %s", gprName[first & 7][1]); } static void POPL() { sprintf(instr, "POP %s", gprName[first & 7][2]); } static void JR() { sprintf(instr, "JR %s,0x%06X", ccName[first & 0xF], (int8)get8_dis() + pc); } static void JRL() { sprintf(instr, "JRL %s,0x%06X", ccName[first & 0xF], (int16)get16_dis() + pc); } static void LDX() { uint8 dst, src; get8_dis(); //00 dst = get8_dis(); //#8 get8_dis(); //00 src = get8_dis(); //# get8_dis(); //00 sprintf(instr, "LDX (0x%02X),0x%02X", dst, src); } static void SWI() { sprintf(instr, "SWI %d", first & 7); } //========================================================================= static void dBIOSHLE() { sprintf(instr, "BIOS-HLE"); } //========================================================================= //Primary Instruction decode static void (*decode[256])() = { /*0*/ NOP, NORMAL, PUSHSR, POPSR, MAX, HALT, EI, RETI, LD8_8, PUSH8, LD8_16, PUSH16, INCF, DECF, RET, RETD, /*1*/ RCF, SCF, CCF, ZCF, PUSHA, POPA, EX, LDF, PUSHF, POPF, JP16, JP24, CALL16, CALL24, CALR, dBIOSHLE, /*2*/ LDB, LDB, LDB, LDB, LDB, LDB, LDB, LDB, PUSHW, PUSHW, PUSHW, PUSHW, PUSHW, PUSHW, PUSHW, PUSHW, /*3*/ LDW, LDW, LDW, LDW, LDW, LDW, LDW, LDW, PUSHL, PUSHL, PUSHL, PUSHL, PUSHL, PUSHL, PUSHL, PUSHL, /*4*/ LDL, LDL, LDL, LDL, LDL, LDL, LDL, LDL, POPW, POPW, POPW, POPW, POPW, POPW, POPW, POPW, /*5*/ 0, 0, 0, 0, 0, 0, 0, 0, POPL, POPL, POPL, POPL, POPL, POPL, POPL, POPL, /*6*/ JR, JR, JR, JR, JR, JR, JR, JR, JR, JR, JR, JR, JR, JR, JR, JR, /*7*/ JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, JRL, /*8*/ src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, src_B, /*9*/ src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, src_W, /*A*/ src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, src_L, /*B*/ dst, dst, dst, dst, dst, dst, dst, dst, dst, dst, dst, dst, dst, dst, dst, dst, /*C*/ src_B, src_B, src_B, src_B, src_B, src_B, 0, reg_B, reg_B, reg_B, reg_B, reg_B, reg_B, reg_B, reg_B, reg_B, /*D*/ src_W, src_W, src_W, src_W, src_W, src_W, 0, reg_W, reg_W, reg_W, reg_W, reg_W, reg_W, reg_W, reg_W, reg_W, /*E*/ src_L, src_L, src_L, src_L, src_L, src_L, 0, reg_L, reg_L, reg_L, reg_L, reg_L, reg_L, reg_L, reg_L, reg_L, /*F*/ dst, dst, dst, dst, dst, dst, 0, LDX, SWI, SWI, SWI, SWI, SWI, SWI, SWI, SWI }; //============================================================================= char* TLCS900h_disassemble(void) { char str[80]; unsigned int i; memset(str, 0, 80); //Reset bcnt = 0; brCode = FALSE; sprintf(instr, "unknown"); sprintf(extra, "unknown"); //Fix big addresses pc &= 0xFFFFFF; //Add the program counter sprintf(str, "%06X: ", pc); first = get8_dis(); //Get the first opcode //Disassemble if (decode[first]) { //Decode any extra data TLCS900h_disassemble_extra(); (*decode[first])(); } //Add the instruction strcat(str, instr); //Add the bytes used for (i = strlen(str); i < 32; i++) str[i] = ' '; str[32] = '\"'; for (i = 0; i < bcnt; i++) { char tmp[80]; sprintf(tmp, "%02X ", bytes[i]); strcat(str, tmp); } str[strlen(str) - 1] = '\"'; return strdup(str); } }; //=============================================================================