642 lines
13 KiB
C++
642 lines
13 KiB
C++
//---------------------------------------------------------------------------
|
|
// 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);
|
|
}
|
|
};
|
|
//=============================================================================
|