backyard/6502_name_codec/decode-idk.c

185 lines
6.4 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define CHIPS_IMPL
#include "m6502.h"
#define lament(...) fprintf(stderr, __VA_ARGS__)
#define error_when(cond, ...) do { \
if ((cond) || errno) { \
lament(__VA_ARGS__); \
lament(": %s\n", strerror(errno)); \
goto error; \
} \
} while (0)
// setup 64 kBytes of memory
#define MEMSIZE 65536
static uint8_t mem[MEMSIZE] = {0};
// NOTE: renamed KIL to JAM for consistency.
static const char instrnames[] =
"BRK\0ORA\0JAM\0SLO\0NOP\0ORA\0ASL\0SLO\0PHP\0ORA\0ASL\0ANC\0NOP\0ORA\0ASL\0SLO\0"
"BPL\0ORA\0JAM\0SLO\0NOP\0ORA\0ASL\0SLO\0CLC\0ORA\0NOP\0SLO\0NOP\0ORA\0ASL\0SLO\0"
"JSR\0AND\0JAM\0RLA\0BIT\0AND\0ROL\0RLA\0PLP\0AND\0ROL\0ANC\0BIT\0AND\0ROL\0RLA\0"
"BMI\0AND\0JAM\0RLA\0NOP\0AND\0ROL\0RLA\0SEC\0AND\0NOP\0RLA\0NOP\0AND\0ROL\0RLA\0"
"RTI\0EOR\0JAM\0SRE\0NOP\0EOR\0LSR\0SRE\0PHA\0EOR\0LSR\0ALR\0JMP\0EOR\0LSR\0SRE\0"
"BVC\0EOR\0JAM\0SRE\0NOP\0EOR\0LSR\0SRE\0CLI\0EOR\0NOP\0SRE\0NOP\0EOR\0LSR\0SRE\0"
"RTS\0ADC\0JAM\0RRA\0NOP\0ADC\0ROR\0RRA\0PLA\0ADC\0ROR\0ARR\0JMP\0ADC\0ROR\0RRA\0"
"BVS\0ADC\0JAM\0RRA\0NOP\0ADC\0ROR\0RRA\0SEI\0ADC\0NOP\0RRA\0NOP\0ADC\0ROR\0RRA\0"
"NOP\0STA\0NOP\0SAX\0STY\0STA\0STX\0SAX\0DEY\0NOP\0TXA\0XAA\0STY\0STA\0STX\0SAX\0"
"BCC\0STA\0JAM\0AHX\0STY\0STA\0STX\0SAX\0TYA\0STA\0TXS\0TAS\0SHY\0STA\0SHX\0AHX\0"
"LDY\0LDA\0LDX\0LAX\0LDY\0LDA\0LDX\0LAX\0TAY\0LDA\0TAX\0LAX\0LDY\0LDA\0LDX\0LAX\0"
"BCS\0LDA\0JAM\0LAX\0LDY\0LDA\0LDX\0LAX\0CLV\0LDA\0TSX\0LAS\0LDY\0LDA\0LDX\0LAX\0"
"CPY\0CMP\0NOP\0DCP\0CPY\0CMP\0DEC\0DCP\0INY\0CMP\0DEX\0AXS\0CPY\0CMP\0DEC\0DCP\0"
"BNE\0CMP\0JAM\0DCP\0NOP\0CMP\0DEC\0DCP\0CLD\0CMP\0NOP\0DCP\0NOP\0CMP\0DEC\0DCP\0"
"CPX\0SBC\0NOP\0ISC\0CPX\0SBC\0INC\0ISC\0INX\0SBC\0NOP\0SBC\0CPX\0SBC\0INC\0ISC\0"
"BEQ\0SBC\0JAM\0ISC\0NOP\0SBC\0INC\0ISC\0SED\0SBC\0NOP\0ISC\0NOP\0SBC\0INC\0ISC";
static const char documented[] = {
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,
0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0,
1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0,
1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0
};
static int loadmem(const char *fp) {
FILE *f = NULL;
long size = MEMSIZE;
errno = 0;
f = fopen(fp, "rb");
error_when(f == NULL, "Error opening file: %s", fp);
error_when(fread(mem, 1, size, f) != (size_t)size, "Error reading %li bytes from file: %s", size, fp);
error_when(fclose(f) != 0, "Error closing file: %s", fp);
return 0;
error:
//return 65; // EX_DATAERR
return 66; // EX_NOINPUT
}
static void memdebug(const m6502_t cpu, long instrs) {
uint64_t pins = cpu.PINS;
uint16_t pc = cpu.PC;
uint8_t instr = cpu.IR >> 3;
int ic = cpu.IR & 7;
uint16_t addr = M6502_GET_ADDR(pins);
const char *mode = (pins & M6502_RW) ? "READ " : "WRITE ";
uint8_t value = (pins & M6502_RW) ? mem[addr] : M6502_GET_DATA(pins);
const char *instrname = instrnames + instr * 4;
const char *ok = documented[instr] ? "..." : "!!!";
lament("[%4li.%i:$%04X:$%02X (%s %s)] %s mem[0x%04X]=0x%02X;\n",
instrs, ic, pc, instr, instrname, ok, mode, addr, value);
}
static void xxd(const uint8_t *start, int length) {
while (length >= 16) {
printf("%08x: ", (unsigned int)(start - mem));
for (int i = 0; i < 16; i += 2) {
printf("%02x%02x ", start[i], start[i + 1]);
}
printf(" ");
for (int i = 0; i < 16; i++) {
uint8_t value = start[i];
if (value < 0x20 || value >= 0x7F) {
value = '.';
}
printf("%c", value);
}
printf("\n");
start += 16; // FIXME: can technically invoke undefined behavior on boundary.
length -= 16;
}
// TODO: handle the remainder.
//for (int i = 0; i < length; i += 2) {
//}
}
int main(int argc, char **argv) {
char *name = NULL;
long cycle = 0;
long oldcycle = 0;
long instrs = 0;
long instr_limit = 1000;
uint64_t pins;
m6502_t cpu;
m6502_desc_t desc = {0};
if (argc <= 0 || argv == NULL || argv[0] == NULL) {
lament("You've met with a terrible fate.\n");
return 64; // EX_USAGE
}
name = argv[0];
if (argc != 2 && argc != 3) {
lament("usage: %s {ram.bin} [instructions]\n", name);
return 64; // EX_USAGE
}
if (argc == 3) {
instr_limit = strtol(argv[2], NULL, 0); // can be negative, i guess.
if (errno) {
lament("%s: failed to parse integer: %s\n", name, argv[2]);
return 64; // EX_USAGE
}
}
{
int res = 0;
if ((res = loadmem(argv[1]))) return res;
}
// initialize the CPU
desc.bcd_disabled = true; // TODO: do this from instructions?
pins = m6502_init(&cpu, &desc);
for (;; cycle++) {
// run the CPU emulation for one tick
pins = m6502_tick(&cpu, pins);
// extract 16-bit address from pin mask
const uint16_t addr = M6502_GET_ADDR(pins);
// perform memory access
if (pins & M6502_RW) {
// a memory read
uint8_t value = mem[addr];
memdebug(cpu, instrs);
M6502_SET_DATA(pins, value);
} else {
// a memory write
uint8_t value = M6502_GET_DATA(pins);
memdebug(cpu, instrs);
mem[addr] = value;
}
if (cycle >= oldcycle + 8) {
lament("CPU is locked up!\n");
break;
}
if (pins & M6502_SYNC) {
instrs++;
oldcycle = cycle;
if (instrs >= instr_limit) break;
}
}
fflush(stdout);
fflush(stderr);
printf("cpu.PC=0x%04X, cpu.A=0x%02X, cpu.X=0x%02X, cpu.Y=0x%02X, cpu.S=0x%02X, cpu.P=0x%02X;\n",
cpu.PC, cpu.A, cpu.X, cpu.Y, cpu.S, cpu.P);
lament("exiting after %li instructions and %li cycles.\n", instrs, cycle + 1);
xxd(mem, 0x100);
return 0;
}