BizHawk/waterbox/ngp/TLCS-900h/TLCS900h_disassemble.cpp

642 lines
13 KiB
C++
Raw Normal View History

//---------------------------------------------------------------------------
// 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);
}
};
//=============================================================================