robmcmullen-apple2/src/dis65c02.cpp

178 lines
5.8 KiB
C++

//
// 65C02 disassembler
//
// by James Hammons
// (c) 2005-2018 Underground Software
//
#include "dis65c02.h"
#include <stdio.h>
#include <string.h>
#include "log.h"
// Private global variables
static uint8_t op_mat[256] = {
14, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 2, 3, 3, 2, 14, 10, 14, 0, 8, 9, 9, 13,
8, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 3, 3, 3, 2, 14, 10, 14, 0, 9, 9, 9, 13,
14, 6, 0, 0, 0, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 0, 3, 3, 2, 14, 10, 14, 0, 0, 9, 9, 13,
14, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 11, 8, 8, 13,
13, 7, 5, 0, 3, 3, 3, 2, 14, 10, 14, 0, 12, 9, 9, 13,
13, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 3, 3, 4, 2, 14, 10, 14, 0, 8, 9, 9, 13,
1, 6, 1, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 3, 3, 4, 2, 14, 10, 14, 0, 9, 9, 10, 13,
1, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 0, 3, 3, 2, 14, 10, 14, 0, 0, 9, 9, 13,
1, 6, 0, 0, 2, 2, 2, 2, 14, 1, 14, 0, 8, 8, 8, 13,
13, 7, 5, 0, 0, 3, 3, 2, 14, 10, 14, 0, 0, 9, 9, 13
};
static uint8_t mnemonics[256][5] = {
"BRK ","ORA ","??? ","??? ","TSB ","ORA ","ASL ","RMB0",
"PHP ","ORA ","ASL ","??? ","TSB ","ORA ","ASL ","BBR0",
"BPL ","ORA ","ORA ","??? ","TRB ","ORA ","ASL ","RMB1",
"CLC ","ORA ","INC ","??? ","TRB ","ORA ","ASL ","BBR1",
"JSR ","AND ","??? ","??? ","BIT ","AND ","ROL ","RMB2",
"PLP ","AND ","ROL ","??? ","BIT ","AND ","ROL ","BBR2",
"BMI ","AND ","AND ","??? ","BIT ","AND ","ROL ","RMB3",
"SEC ","AND ","DEC ","??? ","BIT ","AND ","ROL ","BBR3",
"RTI ","EOR ","??? ","??? ","??? ","EOR ","LSR ","RMB4",
"PHA ","EOR ","LSR ","??? ","JMP ","EOR ","LSR ","BBR4",
"BVC ","EOR ","EOR ","??? ","??? ","EOR ","LSR ","RMB5",
"CLI ","EOR ","PHY ","??? ","??? ","EOR ","LSR ","BBR5",
"RTS ","ADC ","??? ","??? ","STZ ","ADC ","ROR ","RMB6",
"PLA ","ADC ","ROR ","??? ","JMP ","ADC ","ROR ","BBR6",
"BVS ","ADC ","ADC ","??? ","STZ ","ADC ","ROR ","RMB7",
"SEI ","ADC ","PLY ","??? ","JMP ","ADC ","ROR ","BBR7",
"BRA ","STA ","??? ","??? ","STY ","STA ","STX ","SMB0",
"DEY ","BIT ","TXA ","??? ","STY ","STA ","STX ","BBS0",
"BCC ","STA ","STA ","??? ","STY ","STA ","STX ","SMB1",
"TYA ","STA ","TXS ","??? ","STZ ","STA ","STZ ","BBS1",
"LDY ","LDA ","LDX ","??? ","LDY ","LDA ","LDX ","SMB2",
"TAY ","LDA ","TAX ","??? ","LDY ","LDA ","LDX ","BBS2",
"BCS ","LDA ","LDA ","??? ","LDY ","LDA ","LDX ","SMB3",
"CLV ","LDA ","TSX ","??? ","LDY ","LDA ","LDX ","BBS3",
"CPY ","CMP ","??? ","??? ","CPY ","CMP ","DEC ","SMB4",
"INY ","CMP ","DEX ","??? ","CPY ","CMP ","DEC ","BBS4",
"BNE ","CMP ","CMP ","??? ","??? ","CMP ","DEC ","SMB5",
"CLD ","CMP ","PHX ","??? ","??? ","CMP ","DEC ","BBS5",
"CPX ","SBC ","??? ","??? ","CPX ","SBC ","INC ","SMB6",
"INX ","SBC ","NOP ","??? ","CPX ","SBC ","INC ","BBS6",
"BEQ ","SBC ","SBC ","??? ","??? ","SBC ","INC ","SMB7",
"SED ","SBC ","PLX ","??? ","??? ","SBC ","INC ","BBS7"
};
//
// Display bytes in mem in hex
//
static void DisplayBytes(V65C02REGS * regs, char * outbuf, uint16_t src, uint32_t dst)
{
char buf[32];
sprintf(outbuf, "%04X: ", src);
uint8_t cnt = 0;
// That should fix the $FFFF bug...
if (src > dst)
dst += 0x10000;
for(uint32_t i=src; i<dst; i++)
{
sprintf(buf, "%02X ", regs->RdMem(i));
strcat(outbuf, buf);
cnt++;
}
// Pad the leftover spaces...
for(int i=cnt; i<3; i++)
{
sprintf(buf, " ");
strcat(outbuf, buf);
}
}
//
// Decode a 65C02 instruction
//
int Decode65C02(V65C02REGS * regs, char * outbuf, uint16_t pc)
{
char buf[32], buf2[32];
uint16_t addr = pc;
uint16_t w;
uint8_t opcode = regs->RdMem(addr++); // Get the opcode
switch (op_mat[opcode]) // Decode the addressing mode...
{
case 0: // Illegal
sprintf(buf, "???");
break;
case 1: // Immediate
sprintf(buf, "%s #$%02X", mnemonics[opcode], regs->RdMem(addr++));
break;
case 2: // Zero page
sprintf(buf, "%s $%02X", mnemonics[opcode], regs->RdMem(addr++));
break;
case 3: // Zero page, X
sprintf(buf, "%s $%02X,X", mnemonics[opcode], regs->RdMem(addr++));
break;
case 4: // Zero page, Y
sprintf(buf, "%s $%02X,Y", mnemonics[opcode], regs->RdMem(addr++));
break;
case 5: // Zero page indirect
sprintf(buf, "%s ($%02X)", mnemonics[opcode], regs->RdMem(addr++));
break;
case 6: // Zero page, X indirect
sprintf(buf, "%s ($%02X,X)", mnemonics[opcode], regs->RdMem(addr++));
break;
case 7: // Zero page, Y indirect
sprintf(buf, "%s ($%02X),Y", mnemonics[opcode], regs->RdMem(addr++));
break;
case 8: // Absolute
w = regs->RdMem(addr++);
w |= regs->RdMem(addr++) << 8;
sprintf(buf, "%s $%04X", mnemonics[opcode], w);
break;
case 9: // Absolute, X
w = regs->RdMem(addr++);
w |= regs->RdMem(addr++) << 8;
sprintf(buf, "%s $%04X,X", mnemonics[opcode], w);
break;
case 10: // Absolute, Y
w = regs->RdMem(addr++);
w |= regs->RdMem(addr++) << 8;
sprintf(buf, "%s $%04X,Y", mnemonics[opcode], w);
break;
case 11: // Indirect
w = regs->RdMem(addr++);
w |= regs->RdMem(addr++) << 8;
sprintf(buf, "%s ($%04X)", mnemonics[opcode], w);
break;
case 12: // Indirect, X
w = regs->RdMem(addr++);
w |= regs->RdMem(addr++) << 8;
sprintf(buf, "%s ($%04X,X)", mnemonics[opcode], w);
break;
case 13: // Relative
sprintf(buf, "%s $%04X", mnemonics[opcode], addr + (int16_t)((int8_t)regs->RdMem(addr)) + 1);
addr++;
break;
case 14: // Inherent
sprintf(buf, "%s ", mnemonics[opcode]);
break;
}
DisplayBytes(regs, buf2, pc, addr); // Show bytes
sprintf(outbuf, "%s %-14s", buf2, buf); // Display opcode & addressing, etc.
return addr - pc;
}