Its been too long since a checkin, but here's some of the improvements: - Support for diffing with other emulators - Better disassmbed output - New CPU instructions implemented - Lots of CPU fixes
433 lines
6.7 KiB
C
433 lines
6.7 KiB
C
/*TODO: This is hacky and has some bugs but whatever*/
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "gb_disas.h"
|
|
|
|
static const char *opcodes[256] = {
|
|
//0
|
|
"NOP",
|
|
"LD BC,d16",
|
|
"LD (BC),A",
|
|
"INC BC",
|
|
"INC B",
|
|
"DEC B",
|
|
"LD B,d8",
|
|
"RLCA",
|
|
"LD (a16),SP",
|
|
"ADD HL,BC",
|
|
"LD A,(BC)",
|
|
"DEC BC",
|
|
"INC C",
|
|
"DEC C",
|
|
"LD C,d8",
|
|
"RRCA",
|
|
//1
|
|
"STOP",
|
|
"LD DE,d16",
|
|
"LD (DE),A",
|
|
"INC DE",
|
|
"INC D",
|
|
"DEC D",
|
|
"LD D,d8",
|
|
"RLA",
|
|
"JR r8",
|
|
"ADD HL,DE",
|
|
"LD A,(DE)",
|
|
"DEC DE",
|
|
"INC E",
|
|
"DEC E",
|
|
"LD E,d8",
|
|
"RRA",
|
|
//2
|
|
"JR NZ,r8",
|
|
"LD HL,d16",
|
|
"LD (HL+),A",
|
|
"INC HL",
|
|
"INC H",
|
|
"DEC H",
|
|
"LD H,d8",
|
|
"DAA",
|
|
"JR Z,r8",
|
|
"ADD HL,HL",
|
|
"LD A,(HL+)",
|
|
"DEC HL",
|
|
"INC L",
|
|
"DEC L",
|
|
"LD L,d8",
|
|
"CPL",
|
|
//3
|
|
"JR NC,r8",
|
|
"LD SP,d16",
|
|
"LD (HL-),A",
|
|
"INC SP",
|
|
"INC (HL)",
|
|
"DEC (HL)",
|
|
"LD (HL),d8",
|
|
"SCF",
|
|
"JR C,r8",
|
|
"ADD HL,SP",
|
|
"LD A,(HL-)",
|
|
"DEC SP",
|
|
"INC A",
|
|
"DEC A",
|
|
"LD A,d8",
|
|
"CCF",
|
|
//4
|
|
"LD B,B",
|
|
"LD B,C",
|
|
"LD B,D",
|
|
"LD B,E",
|
|
"LD B,H",
|
|
"LD B,L",
|
|
"LD B,(HL)",
|
|
"LD B,A",
|
|
"LD C,B",
|
|
"LD C,C",
|
|
"LD C,D",
|
|
"LD C,E",
|
|
"LD C,H",
|
|
"LD C,L",
|
|
"LD C,(HL)",
|
|
"LD C,A",
|
|
//5
|
|
"LD D,B",
|
|
"LD D,C",
|
|
"LD D,D",
|
|
"LD D,E",
|
|
"LD D,H",
|
|
"LD D,L",
|
|
"LD D,(HL)",
|
|
"LD D,A",
|
|
"LD E,B",
|
|
"LD E,C",
|
|
"LD E,D",
|
|
"LD E,E",
|
|
"LD E,H",
|
|
"LD E,L",
|
|
"LD E,(HL)",
|
|
"LD E,A",
|
|
//6
|
|
"LD H,B",
|
|
"LD H,C",
|
|
"LD H,D",
|
|
"LD H,E",
|
|
"LD H,H",
|
|
"LD H,L",
|
|
"LD H,(HL)",
|
|
"LD H,A",
|
|
"LD L,B",
|
|
"LD L,C",
|
|
"LD L,D",
|
|
"LD L,E",
|
|
"LD L,H",
|
|
"LD L,L",
|
|
"LD L,(HL)",
|
|
"LD L,A",
|
|
//7
|
|
"LD (HL),B",
|
|
"LD (HL),C",
|
|
"LD (HL),D",
|
|
"LD (HL),E",
|
|
"LD (HL),H",
|
|
"LD (HL),L",
|
|
"HALT",
|
|
"LD (HL),A",
|
|
"LD A,B",
|
|
"LD A,C",
|
|
"LD A,D",
|
|
"LD A,E",
|
|
"LD A,H",
|
|
"LD A,L",
|
|
"LD A,(HL)",
|
|
"LD A,A",
|
|
//8
|
|
"ADD A,B",
|
|
"ADD A,C",
|
|
"ADD A,D",
|
|
"ADD A,E",
|
|
"ADD A,H",
|
|
"ADD A,L",
|
|
"ADD A,(HL)",
|
|
"ADD A,A",
|
|
"ADC A,B",
|
|
"ADC A,C",
|
|
"ADC A,D",
|
|
"ADC A,E",
|
|
"ADC A,H",
|
|
"ADC A,L",
|
|
"ADC A,(HL)",
|
|
"ADC A,A",
|
|
//9
|
|
"SUB B",
|
|
"SUB C",
|
|
"SUB D",
|
|
"SUB E",
|
|
"SUB H",
|
|
"SUB L",
|
|
"SUB (HL)",
|
|
"SUB A",
|
|
"SBC A,B",
|
|
"SBC A,C",
|
|
"SBC A,D",
|
|
"SBC A,E",
|
|
"SBC A,H",
|
|
"SBC A,L",
|
|
"SBC A,(HL)",
|
|
"SBC A,A",
|
|
//10
|
|
"AND B",
|
|
"AND C",
|
|
"AND D",
|
|
"AND E",
|
|
"AND H",
|
|
"AND L",
|
|
"AND (HL)",
|
|
"AND A",
|
|
"XOR B",
|
|
"XOR C",
|
|
"XOR D",
|
|
"XOR E",
|
|
"XOR H",
|
|
"XOR L",
|
|
"XOR (HL)",
|
|
"XOR A",
|
|
//11
|
|
"OR B",
|
|
"OR C",
|
|
"OR D",
|
|
"OR E",
|
|
"OR H",
|
|
"OR L",
|
|
"OR (HL)",
|
|
"OR A",
|
|
"CP B",
|
|
"CP C",
|
|
"CP D",
|
|
"CP E",
|
|
"CP H",
|
|
"CP L",
|
|
"CP (HL)",
|
|
"CP A",
|
|
//12
|
|
"RET NZ",
|
|
"POP BC",
|
|
"JP NZ,a16",
|
|
"JP a16",
|
|
"CALL NZ,a16",
|
|
"PUSH BC",
|
|
"ADD A,d8",
|
|
"RST 00H",
|
|
"RET Z",
|
|
"RET",
|
|
"JP Z,a16",
|
|
"PREFIX CB",
|
|
"CALL Z,a16",
|
|
"CALL a16",
|
|
"ADC A,d8",
|
|
"RST",
|
|
//13
|
|
"RET NC",
|
|
"POP DE",
|
|
"JP NC,a16",
|
|
"*UNDEF*",
|
|
"CALL NC,a16",
|
|
"PUSH DE",
|
|
"SUB d8",
|
|
"RST 10H",
|
|
"RET C",
|
|
"RETI",
|
|
"JP C,a16",
|
|
"UNDEF*",
|
|
"CALL C,a16",
|
|
"*UNDEF*",
|
|
"SBC A,d8",
|
|
"RST 18H",
|
|
//14
|
|
"LDH (a8),A",
|
|
"POP HL",
|
|
"LD (0xff00 + C),A",
|
|
"*UNDEF*",
|
|
"*UNDEF*",
|
|
"PUSH HL",
|
|
"AND d8",
|
|
"RST 20H",
|
|
"ADD SP,r8",
|
|
"JP (HL)",
|
|
"LD (a16),A",
|
|
"*UNDEF*",
|
|
"*UNDEF*",
|
|
"*UNDEF*",
|
|
"XOR d8",
|
|
"RST 28H",
|
|
//15
|
|
"LDH A,(a8)",
|
|
"POP AF",
|
|
"LD A,(0xff00 + C)",
|
|
"DI",
|
|
"*UNDEF*",
|
|
"PUSH AF",
|
|
"OR d8",
|
|
"RST 30H",
|
|
"LD HL,SP+r8",
|
|
"LD SP,HL",
|
|
"LD A,(a16)",
|
|
"EI",
|
|
"*UNDEF*",
|
|
"*UNDEF*",
|
|
"CP d8",
|
|
"RST 38H"
|
|
};
|
|
|
|
static const char *ioreg[] = {
|
|
[0] = "P1",
|
|
[1] = "SB",
|
|
[2] = "SC",
|
|
[4] = "DIV",
|
|
[5] = "TIMA",
|
|
[6] = "TMA",
|
|
[7] = "TAC",
|
|
[0x0f] = "IF",
|
|
[0x10] = "NR 10",
|
|
[0x11] = "NR 11",
|
|
[0x12] = "NR 12",
|
|
[0x13] = "NR 13",
|
|
[0x14] = "NR 14",
|
|
[0x16] = "NR 21",
|
|
[0x17] = "NR 22",
|
|
[0x18] = "NR 23",
|
|
[0x19] = "NR 24",
|
|
[0x1A] = "NR 30",
|
|
[0x1B] = "NR 31",
|
|
[0x1C] = "NR 32",
|
|
[0x1D] = "NR 33",
|
|
[0x1E] = "NR 34",
|
|
[0x20] = "NR 41",
|
|
[0x21] = "NR 42",
|
|
[0x22] = "NR 43",
|
|
[0x23] = "NR 44",
|
|
[0x24] = "NR 50",
|
|
[0x25] = "NR 51",
|
|
[0x26] = "NR 52",
|
|
[0x30] = "WavePatternRam[0x0]",
|
|
[0x31] = "WavePatternRam[0x1]",
|
|
[0x32] = "WavePatternRam[0x2]",
|
|
[0x33] = "WavePatternRam[0x3]",
|
|
[0x34] = "WavePatternRam[0x4]",
|
|
[0x35] = "WavePatternRam[0x5]",
|
|
[0x36] = "WavePatternRam[0x6]",
|
|
[0x37] = "WavePatternRam[0x7]",
|
|
[0x38] = "WavePatternRam[0x8]",
|
|
[0x39] = "WavePatternRam[0x9]",
|
|
[0x3A] = "WavePatternRam[0xA]",
|
|
[0x3B] = "WavePatternRam[0xB]",
|
|
[0x3C] = "WavePatternRam[0xC]",
|
|
[0x3D] = "WavePatternRam[0xD]",
|
|
[0x3E] = "WavePatternRam[0xE]",
|
|
[0x3F] = "WavePatternRam[0xF]",
|
|
[0x40] = "LCDC",
|
|
[0x41] = "STAT",
|
|
[0x42] = "SCY",
|
|
[0x43] = "SCX",
|
|
[0x44] = "LC",
|
|
[0x45] = "LYC",
|
|
[0x46] = "DMA",
|
|
[0x47] = "BGP",
|
|
[0x48] = "OBP0",
|
|
[0x49] = "OBP1",
|
|
[0x4A] = "WY",
|
|
[0x4B] = "WX",
|
|
[0xFF] = "IE",
|
|
};
|
|
|
|
|
|
static const char *ioreg_str(uint16_t addr)
|
|
{
|
|
unsigned int offset;
|
|
|
|
if (addr > 0xff00) {
|
|
offset = addr & 0xff;
|
|
if (ioreg[offset] != NULL) {
|
|
return ioreg[offset];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
const char *gb_byte_to_opcode(uint16_t *addr, gb_byte_fetch_fn fetch, void *opaque)
|
|
{
|
|
char *buf = malloc(32);
|
|
uint8_t inst = fetch(opaque, (*addr)++);
|
|
const char *immediate;
|
|
uint8_t val;
|
|
size_t len;
|
|
const char *opcode = opcodes[inst];
|
|
|
|
/* TODO: DRY this code up a bit */
|
|
|
|
if (inst == 0xcb) {
|
|
/* CB-prefix instruction */
|
|
/* TODO: Right now, this does almost nothing */
|
|
strncpy(buf, opcode, 32);
|
|
(*addr)++;
|
|
|
|
} else if ((immediate = strstr(opcode, "d8")) != NULL) {
|
|
uint8_t val = fetch(opaque, (*addr)++);
|
|
len = immediate - opcode;
|
|
strncpy(buf, opcode, len);
|
|
snprintf(buf + len, 32 - len, "0x%02x", val);
|
|
strncat(buf, opcode + len + strlen("d8"), 32);
|
|
|
|
} else if ((immediate = strstr(opcode, "a8")) != NULL) {
|
|
uint16_t val = ((uint16_t)fetch(opaque, (*addr)++)) + 0xff00;
|
|
len = immediate - opcode;
|
|
strncpy(buf, opcode, len);
|
|
if (ioreg_str(val)) {
|
|
snprintf(buf + len, 32 - len, "0x%04x=%s", val, ioreg_str(val));
|
|
} else {
|
|
snprintf(buf + len, 32 - len, "0x%04x", val);
|
|
}
|
|
strncat(buf, opcode + len + strlen("a8"), 32);
|
|
|
|
} else if ((immediate = strstr(opcode, "r8")) != NULL) {
|
|
int16_t val = fetch(opaque, (*addr)++);
|
|
if (val & (1 << 7)) {
|
|
val |= 0xFF00;
|
|
}
|
|
len = immediate - opcode;
|
|
strncpy(buf, opcode, len);
|
|
snprintf(buf + len, 32 - len, "0x%04x", *addr + val);
|
|
strncat(buf, opcode + len + strlen("r8"), 32);
|
|
|
|
} else if ((immediate = strstr(opcode, "d16")) != NULL) {
|
|
uint16_t val = fetch(opaque, (*addr)++);
|
|
val |= ((uint16_t) fetch(opaque, (*addr)++)) << 8;
|
|
len = immediate - opcode;
|
|
strncpy(buf, opcode, len);
|
|
if (ioreg_str(val)) {
|
|
snprintf(buf + len, 32 - len, "0x%04x=%s", val, ioreg_str(val));
|
|
} else {
|
|
snprintf(buf + len, 32 - len, "0x%04x", val);
|
|
}
|
|
strncat(buf, opcode + len + strlen("a16"), 32);
|
|
|
|
} else if ((immediate = strstr(opcode, "a16")) != NULL) {
|
|
uint16_t val = fetch(opaque, (*addr)++);
|
|
val |= ((uint16_t) fetch(opaque, (*addr)++)) << 8;
|
|
len = immediate - opcode;
|
|
strncpy(buf, opcode, len);
|
|
snprintf(buf + len, 32 - len, "0x%04x", val);
|
|
strncat(buf, opcode + len + strlen("a16"), 32);
|
|
|
|
} else {
|
|
strncpy(buf, opcode, 32);
|
|
}
|
|
|
|
|
|
return buf;
|
|
}
|