bradgrantham-apple2e/apple2e.cpp

1155 lines
37 KiB
C++
Raw Normal View History

2016-11-06 07:53:43 +00:00
#include <cstdlib>
2016-11-06 20:37:19 +00:00
#include <string>
#include <set>
using namespace std;
2016-11-06 07:53:43 +00:00
#include "emulator.h"
const unsigned int DEBUG_RW = 0x01;
const unsigned int DEBUG_DECODE = 0x02;
const unsigned int DEBUG_STATE = 0x04;
const unsigned int DEBUG_ERROR = 0x08;
unsigned int debug = DEBUG_ERROR | DEBUG_DECODE | DEBUG_STATE;
2016-11-06 20:37:19 +00:00
struct SoftSwitch
{
string name;
int clear_address;
int set_address;
int read_address;
bool read_also_changes;
bool sw = false;
SoftSwitch(const char* name_, int clear, int on, int read, bool read_changes, vector<SoftSwitch*>& s) :
name(name_),
clear_address(clear),
set_address(on),
read_address(read),
read_also_changes(read_changes)
{
s.push_back(this);
}
operator bool() const
{
return sw;
}
};
const int textport_row_base_addresses[] =
{
0x400,
0x480,
0x500,
0x580,
0x600,
0x680,
0x700,
0x780,
0x428,
0x4A8,
0x528,
0x5A8,
0x628,
0x6A8,
0x728,
0x7A8,
0x450,
0x4D0,
0x550,
0x5D0,
0x650,
0x6D0,
0x750,
0x7D0,
};
2016-11-06 21:27:01 +00:00
void textport_change(unsigned char *textport)
2016-11-06 20:37:19 +00:00
{
printf("TEXTPORT:\n");
printf("------------------------------------------\n");
for(int row = 0; row < 24; row++) {
printf("|");
for(int col = 0; col < 40; col++) {
int addr = textport_row_base_addresses[row] + col;
2016-11-06 21:27:01 +00:00
int ch = textport[addr] & 0x7F;
printf("%c", isprint(ch) ? ch : '?');
2016-11-06 20:37:19 +00:00
}
printf("|\n");
}
printf("------------------------------------------\n");
}
2016-11-06 07:53:43 +00:00
struct MAINboard : board_base
{
static const int text1_base = 0x400;
static const int text1_size = 0x3FF;
static const int text2_base = 0x800;
static const int text2_size = 0xBFF;
static const int io_base = 0xC000;
static const int io_size = 0x0100;
static const int irom_base = 0xC100;
static const int irom_size = 0x0F00;
static const int rom_base = 0xD000;
static const int rom_size = 0x3000;
unsigned char rom_bytes[rom_size];
unsigned char irom_bytes[irom_size];
unsigned char ram_bytes[65536];
2016-11-06 20:37:19 +00:00
vector<SoftSwitch*> switches;
SoftSwitch CXROM {"CXROM", 0xC006, 0xC007, 0xC015, false, switches};
SoftSwitch STORE80 {"STORE80", 0xC000, 0xC001, 0xC018, false, switches};
SoftSwitch RAMRD {"RAMRD", 0xC002, 0xC003, 0xC013, false, switches};
SoftSwitch RAMWRT {"RAMWRT", 0xC004, 0xC005, 0xC014, false, switches};
SoftSwitch ALTZP {"ALTZP", 0xC008, 0xC009, 0xC016, false, switches};
SoftSwitch C3ROM {"C3ROM", 0xC00A, 0xC00B, 0xC017, false, switches};
SoftSwitch ALTCHAR {"ALTCHAR", 0xC00E, 0xC00F, 0xC01E, false, switches};
SoftSwitch VID80 {"VID80", 0xC00C, 0xC00D, 0xC01F, false, switches};
SoftSwitch TEXT {"TEXT", 0xC050, 0xC051, 0xC01A, true, switches};
SoftSwitch MIXED {"MIXED", 0xC052, 0xC053, 0xC01B, true, switches};
SoftSwitch PAGE2 {"PAGE2", 0xC054, 0xC055, 0xC01C, true, switches};
SoftSwitch HIRES {"HIRES", 0xC056, 0xC057, 0xC01D, true, switches};
set<int> ignore_mmio = {0xC058, 0xC05A, 0xC05D, 0xC05F, 0xC061, 0xC062};
MAINboard(unsigned char rom[32768])
2016-11-06 07:53:43 +00:00
{
memcpy(rom_bytes, rom + rom_base - 0x8000 , sizeof(rom_bytes));
memcpy(irom_bytes, rom + irom_base - 0x8000 , sizeof(irom_bytes));
2016-11-06 20:37:19 +00:00
memset(ram_bytes, 0x00, sizeof(ram_bytes));
2016-11-06 07:53:43 +00:00
}
virtual bool read(int addr, unsigned char &data)
{
if(debug & DEBUG_RW) printf("MAIN board read\n");
if(addr >= io_base && addr < io_base + io_size) {
2016-11-06 20:37:19 +00:00
for(auto it = switches.begin(); it != switches.end(); it++) {
SoftSwitch* sw = *it;
if(addr == sw->read_address) {
data = sw->sw ? 0x80 : 0x00;
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("Read status of %s = %02X\n", sw->name.c_str(), data);
2016-11-06 07:53:43 +00:00
return true;
2016-11-06 20:37:19 +00:00
} else if(sw->read_also_changes && addr == sw->set_address) {
data = 0xff;
sw->sw = true;
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("Set %s\n", sw->name.c_str());
2016-11-06 20:37:19 +00:00
return true;
} else if(sw->read_also_changes && addr == sw->clear_address) {
data = 0xff;
sw->sw = false;
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("Clear %s\n", sw->name.c_str());
2016-11-06 20:37:19 +00:00
return true;
}
}
if(ignore_mmio.find(addr) != ignore_mmio.end()) {
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("read %04X, ignored, return 0x00\n", addr);
2016-11-06 20:37:19 +00:00
data = 0x00;
return true;
}
if(addr == 0xC000) {
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("read KBD, force 0x00\n");
2016-11-06 20:37:19 +00:00
data = 0x00;
return true;
2016-11-06 07:53:43 +00:00
}
2016-11-06 20:44:32 +00:00
if(addr == 0xC030) {
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("read SPKR, force 0x00\n");
2016-11-06 20:44:32 +00:00
// click
data = 0x00;
return true;
}
2016-11-06 20:37:19 +00:00
if(addr == 0xC010) {
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("read KBDSTRB, force 0x00\n");
2016-11-06 20:37:19 +00:00
// reset keyboard latch
data = 0x00;
return true;
}
printf("unhandled MMIO Read at %04X\n", addr);
exit(0);
2016-11-06 07:53:43 +00:00
}
2016-11-06 20:37:19 +00:00
if(CXROM && addr >= irom_base && addr < irom_base + sizeof(irom_bytes)) {
2016-11-06 07:53:43 +00:00
data = irom_bytes[addr - irom_base];
if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from internal ROM\n", addr, data);
return true;
}
2016-11-06 20:37:19 +00:00
if(addr >= rom_base && addr < rom_base + sizeof(rom_bytes)) {
2016-11-06 07:53:43 +00:00
data = rom_bytes[addr - rom_base];
if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from ROM\n", addr, data);
return true;
}
if(addr >= 0 && addr < sizeof(ram_bytes)) {
data = ram_bytes[addr];
if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from RAM\n", addr, data);
return true;
}
return false;
}
virtual bool write(int addr, unsigned char data)
{
if(addr >= text1_base && addr < text1_base + text1_size) {
printf("TEXT1 WRITE!\n");
2016-11-06 21:55:29 +00:00
if(!PAGE2) textport_change(ram_bytes);
2016-11-06 07:53:43 +00:00
}
if(addr >= text2_base && addr < text2_base + text2_size) {
printf("TEXT2 WRITE!\n");
2016-11-06 21:55:29 +00:00
if(PAGE2) textport_change(ram_bytes);
2016-11-06 07:53:43 +00:00
}
if(addr >= io_base && addr < io_base + io_size) {
2016-11-06 20:37:19 +00:00
for(auto it = switches.begin(); it != switches.end(); it++) {
SoftSwitch* sw = *it;
if(addr == sw->set_address) {
data = 0xff;
sw->sw = true;
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("Set %s\n", sw->name.c_str());
2016-11-06 20:37:19 +00:00
return true;
} else if(addr == sw->clear_address) {
data = 0xff;
sw->sw = false;
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("Clear %s\n", sw->name.c_str());
2016-11-06 20:37:19 +00:00
return true;
}
2016-11-06 07:53:43 +00:00
}
2016-11-06 20:37:19 +00:00
if(addr == 0xC010) {
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("write KBDSTRB\n");
2016-11-06 20:37:19 +00:00
// reset keyboard latch
return true;
}
2016-11-06 20:44:32 +00:00
if(addr == 0xC030) {
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_RW) printf("write SPKR\n");
2016-11-06 20:44:32 +00:00
// click
return true;
}
2016-11-06 20:37:19 +00:00
printf("unhandled MMIO Write at %04X\n", addr);
exit(0);
2016-11-06 07:53:43 +00:00
}
2016-11-06 20:37:19 +00:00
if(addr >= rom_base && addr < rom_base + sizeof(rom_bytes)) {
2016-11-06 07:53:43 +00:00
return false;
}
2016-11-06 20:37:19 +00:00
if(CXROM && addr >= irom_base && addr < irom_base + sizeof(irom_bytes)) {
2016-11-06 07:53:43 +00:00
return false;
}
if(addr >= 0 && addr < sizeof(ram_bytes)) {
ram_bytes[addr] = data;
if(debug & DEBUG_RW) printf("wrote 0x%02X to RAM 0x%04X\n", data, addr);
return true;
}
return false;
}
};
struct bus_controller
{
std::vector<board_base*> boards;
unsigned char read(int addr)
{
for(auto b = boards.begin(); b != boards.end(); b++) {
unsigned char data = 0xaa;
if((*b)->read(addr, data))
return data;
}
if(debug & DEBUG_ERROR)
fprintf(stderr, "no ownership of read at %04X\n", addr);
return 0xAA;
}
void write(int addr, unsigned char data)
{
for(auto b = boards.begin(); b != boards.end(); b++) {
if((*b)->write(addr, data))
return;
}
if(debug & DEBUG_ERROR)
fprintf(stderr, "no ownership of write %02X at %04X\n", data, addr);
}
};
bus_controller bus;
struct CPU6502
{
unsigned char a, x, y, s, p;
static const unsigned char N = 0x80;
static const unsigned char V = 0x40;
static const unsigned char B = 0x10;
static const unsigned char D = 0x08;
static const unsigned char I = 0x04;
static const unsigned char Z = 0x02;
static const unsigned char C = 0x01;
int pc;
enum Exception {
NONE,
RESET,
NMI,
BRK,
INT,
} exception;
CPU6502() :
exception(RESET)
{
}
void stack_push(bus_controller& bus, unsigned char d)
{
bus.write(0x100 + s--, d);
}
unsigned char stack_pull(bus_controller& bus)
{
return bus.read(0x100 + ++s);
}
unsigned char read_pc_inc(bus_controller& bus)
{
return bus.read(pc++);
}
void flag_change(unsigned char flag, bool v)
{
if(v)
p |= flag;
else
p &= ~flag;
}
void flag_set(unsigned char flag)
{
p |= flag;
}
void flag_clear(unsigned char flag)
{
p &= ~flag;
}
void reset(bus_controller& bus)
{
s = 0xFD;
pc = bus.read(0xFFFC) + bus.read(0xFFFD) * 256;
exception = NONE;
}
enum Operand {
A,
IMPL,
REL,
ABS,
ABS_X,
ABS_Y,
IND,
X_IND,
IND_Y,
ZPG,
ZPG_X,
ZPG_Y,
IMM,
UND,
};
int carry()
{
return (p & C) ? 1 : 0;
}
bool isset(unsigned char flag)
{
return (p & flag) != 0;
}
#if 0
int get_operand(bus_controller& bus, Operand oper)
{
switch(oper)
{
case A: return 0;
case UND: return 0;
case IMPL: return 0;
case REL: return (bus.read(pc) + 128) % 256 - 128;
case ABS: return bus.read(pc) + bus.read(pc + 1) * 256;
case ABS_Y: return bus.read(pc) + bus.read(pc + 1) * 256 + y + carry;
case ABS_X: return bus.read(pc) + bus.read(pc + 1) * 256 + x + carry;
case ZPG: return bus.read(pc);
case ZPG_Y: return (bus.read(pc) + y) & 0xFF;
case ZPG_X: return (bus.read(pc) + x) & 0xFF;
case IND: return bus.read(bus.read(pc) + bus.read(pc + 1) * 256);
}
}
#endif
void cycle(bus_controller& bus)
{
if(exception == RESET) {
if(debug & DEBUG_STATE) printf("RESET\n");
reset(bus);
}
unsigned char inst = read_pc_inc(bus);
switch(inst) {
2016-11-06 20:37:19 +00:00
case 0xEA: {
if(debug & DEBUG_DECODE) printf("NOP\n");
break;
}
case 0x8A: {
if(debug & DEBUG_DECODE) printf("TXA\n");
a = x;
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
case 0xAA: {
if(debug & DEBUG_DECODE) printf("TAX\n");
x = a;
flag_change(Z, x == 0x00);
flag_change(N, x & 0x80);
break;
}
2016-11-06 21:55:29 +00:00
case 0x9A: {
if(debug & DEBUG_DECODE) printf("TXS\n");
s = x;
flag_change(Z, s == 0x00);
flag_change(N, s & 0x80);
break;
}
2016-11-06 20:37:19 +00:00
case 0xA8: {
if(debug & DEBUG_DECODE) printf("TAY\n");
y = a;
flag_change(Z, y == 0x00);
flag_change(N, y & 0x80);
break;
}
case 0x98: {
if(debug & DEBUG_DECODE) printf("TYA\n");
a = y;
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
case 0x18: {
if(debug & DEBUG_DECODE) printf("CLC\n");
flag_clear(C);
break;
}
case 0x38: {
if(debug & DEBUG_DECODE) printf("SEC\n");
flag_set(C);
break;
}
2016-11-06 07:53:43 +00:00
case 0xD8: {
if(debug & DEBUG_DECODE) printf("CLD\n");
flag_clear(D);
break;
}
2016-11-06 20:37:19 +00:00
case 0x58: {
if(debug & DEBUG_DECODE) printf("CLI\n");
flag_clear(I);
break;
}
case 0x78: {
if(debug & DEBUG_DECODE) printf("SEI\n");
flag_set(I);
break;
}
2016-11-06 21:27:01 +00:00
case 0xC6: {
int zpg = read_pc_inc(bus);
2016-11-06 21:55:29 +00:00
if(debug & DEBUG_DECODE) printf("DEC %02X\n", zpg);
2016-11-06 21:27:01 +00:00
unsigned char m = bus.read(zpg) - 1;
flag_change(Z, m == 0);
flag_change(N, m & 0x80);
bus.write(zpg, m);
break;
}
2016-11-06 07:53:43 +00:00
case 0xCE: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
2016-11-06 21:27:01 +00:00
if(debug & DEBUG_DECODE) printf("DEC %04X\n", addr);
2016-11-06 07:53:43 +00:00
unsigned char m = bus.read(addr) - 1;
flag_change(Z, m == 0);
flag_change(N, m & 0x80);
bus.write(addr, m);
break;
}
2016-11-06 21:55:29 +00:00
case 0xCA: {
if(debug & DEBUG_DECODE) printf("DEC X\n");
x = x - 1;
flag_change(Z, x == 0x00);
flag_change(N, x & 0x80);
break;
}
case 0xE6: {
int zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("INC %02X\n", zpg);
unsigned char m = bus.read(zpg) + 1;
flag_change(Z, m == 0);
flag_change(N, m & 0x80);
bus.write(zpg, m);
break;
}
case 0xC8: {
if(debug & DEBUG_DECODE) printf("INC Y\n");
y = y + 1;
flag_change(Z, y == 0x00);
flag_change(N, y & 0x80);
break;
}
2016-11-06 20:37:19 +00:00
case 0x10: {
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
if(debug & DEBUG_DECODE) printf("BPL %02X\n", rel);
if(!isset(N))
pc += rel;
break;
}
2016-11-06 07:53:43 +00:00
case 0x30: {
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
if(debug & DEBUG_DECODE) printf("BMI %02X\n", rel);
if(isset(N))
pc += rel;
break;
}
2016-11-06 22:14:17 +00:00
case 0xB5: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDA %02x, X\n", zpg);
int addr = zpg + y;
a = bus.read(addr & 0xFF);
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 21:27:01 +00:00
case 0xB1: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDA (%02x), Y\n", zpg);
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
a = bus.read(addr);
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 20:37:19 +00:00
case 0xA5: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDA %02X\n", zpg);
a = bus.read(zpg);
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 21:55:29 +00:00
case 0xDD: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("CMP %04X, X\n", addr);
unsigned char m = bus.read(addr + x);
flag_change(C, m <= a);
m = a - m;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
break;
}
2016-11-06 21:30:23 +00:00
case 0xD9: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("CMP %04X, Y\n", addr);
unsigned char m = bus.read(addr + y);
flag_change(C, m <= a);
m = a - m;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
break;
}
2016-11-06 07:53:43 +00:00
case 0xB9: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
2016-11-06 20:37:19 +00:00
if(debug & DEBUG_DECODE) printf("LDA %04X, Y\n", addr);
2016-11-06 07:53:43 +00:00
a = bus.read(addr + y);
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 21:27:01 +00:00
case 0xBD: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("LDA %04X, X\n", addr);
a = bus.read(addr + x);
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 20:37:19 +00:00
case 0x65: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("ADC %02X\n", zpg);
unsigned char m = bus.read(zpg);
int carry = isset(C) ? 1 : 0;
flag_change(C, (int)(a + m + carry) > 0xFF);
a = a + m + carry;
flag_change(N, a & 0x80);
flag_change(V, isset(C) != isset(N));
flag_change(Z, a == 0);
break;
}
2016-11-06 22:10:46 +00:00
case 0xED: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("SBC %04X\n", addr);
unsigned char imm = bus.read(addr);
int borrow = isset(C) ? 0 : 1;
flag_change(C, !(a < imm - borrow));
a = a - imm - borrow;
flag_change(N, a & 0x80);
flag_change(V, isset(C) != isset(N));
flag_change(Z, a == 0);
break;
}
2016-11-06 20:37:19 +00:00
case 0xE9: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("SBC %02X\n", imm);
int borrow = isset(C) ? 0 : 1;
flag_change(C, !(a < imm - borrow));
a = a - imm - borrow;
flag_change(N, a & 0x80);
flag_change(V, isset(C) != isset(N));
flag_change(Z, a == 0);
break;
}
2016-11-06 07:53:43 +00:00
case 0x69: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("ADC %02X\n", imm);
int carry = isset(C) ? 1 : 0;
flag_change(C, (int)(a + imm + carry) > 0xFF);
a = a + imm + carry;
flag_change(N, a & 0x80);
flag_change(V, isset(C) != isset(N));
flag_change(Z, a == 0);
break;
}
2016-11-06 20:37:19 +00:00
case 0x0A: {
if(debug & DEBUG_DECODE) printf("ASL A\n");
flag_change(C, a & 0x80);
a = a << 1;
flag_change(N, a & 0x80);
flag_change(Z, a == 0);
break;
}
2016-11-06 22:18:17 +00:00
case 0x4E: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("LSR %04X\n", addr);
unsigned char m = bus.read(addr);
flag_change(C, m & 0x01);
m = m >> 1;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
bus.write(addr, m);
break;
}
2016-11-06 07:53:43 +00:00
case 0x4A: {
2016-11-06 20:37:19 +00:00
if(debug & DEBUG_DECODE) printf("LSR A\n");
2016-11-06 07:53:43 +00:00
flag_change(C, a & 0x01);
a = a >> 1;
flag_change(N, a & 0x80);
flag_change(Z, a == 0);
break;
}
case 0x68: {
if(debug & DEBUG_DECODE) printf("PLA\n");
a = stack_pull(bus);
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
case 0x48: {
if(debug & DEBUG_DECODE) printf("PHA\n");
stack_push(bus, a);
break;
}
2016-11-06 20:37:19 +00:00
case 0x05: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("ORA %02X\n", zpg);
unsigned char m = bus.read(zpg);
a = a | m;
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 07:53:43 +00:00
case 0x09: {
unsigned char imm = read_pc_inc(bus);
2016-11-06 20:37:19 +00:00
if(debug & DEBUG_DECODE) printf("ORA %02X\n", imm);
2016-11-06 07:53:43 +00:00
a = a | imm;
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 21:55:29 +00:00
case 0x25: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("AND %02X\n", zpg);
a = a & bus.read(zpg);
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
2016-11-06 07:53:43 +00:00
case 0x29: {
unsigned char imm = read_pc_inc(bus);
2016-11-06 21:55:29 +00:00
if(debug & DEBUG_DECODE) printf("AND #%02X\n", imm);
2016-11-06 07:53:43 +00:00
a = a & imm;
flag_change(Z, a == 0x00);
flag_change(N, a & 0x80);
break;
}
case 0x88: {
if(debug & DEBUG_DECODE) printf("DEY\n");
y = y - 1;
flag_change(Z, y == 0x00);
flag_change(N, y & 0x80);
break;
}
case 0x76: {
unsigned char zpg = read_pc_inc(bus) + x;
if(debug & DEBUG_DECODE) printf("ROR %02X\n", zpg);
unsigned char m = bus.read(zpg);
bool c = isset(C);
flag_change(C, m & 0x01);
m = (c ? 0x80 : 0x00) | (m >> 1);
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
bus.write(zpg, m);
break;
}
case 0x4C: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("JMP %04X\n", addr);
pc = addr;
break;
}
2016-11-06 20:37:19 +00:00
case 0x6C: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
2016-11-06 21:55:29 +00:00
if(debug & DEBUG_DECODE) printf("JMP (%04X)\n", addr);
2016-11-06 20:37:19 +00:00
unsigned char addrl = bus.read(addr);
unsigned char addrh = bus.read(addr + 1);
addr = addrl + addrh * 256;
pc = addr;
break;
}
2016-11-06 21:27:01 +00:00
case 0x9D: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("STA %04x, X\n", addr);
bus.write(addr + x, a);
break;
}
case 0x99: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("STA %04x, Y\n", addr);
bus.write(addr + y, a);
break;
}
case 0x91: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("STA (%02x), Y\n", zpg);
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
bus.write(addr, a);
break;
}
2016-11-06 07:53:43 +00:00
case 0x8D: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("STA %04X\n", addr);
bus.write(addr, a);
break;
}
case 0x08: {
if(debug & DEBUG_DECODE) printf("PHP\n");
stack_push(bus, p);
break;
}
2016-11-06 20:37:19 +00:00
case 0x28: {
if(debug & DEBUG_DECODE) printf("PLP\n");
p = stack_pull(bus);
break;
}
2016-11-06 07:53:43 +00:00
case 0x2C: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("BIT #%04X\n", addr);
unsigned char m = bus.read(addr);
flag_change(Z, a & m);
flag_change(N, m & 0x80);
flag_change(V, m & 0x70);
break;
}
2016-11-06 22:14:17 +00:00
case 0xB4: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDY %02X,X\n", zpg);
y = bus.read(zpg + x);
flag_change(N, y & 0x80);
flag_change(Z, y == 0);
break;
}
2016-11-06 20:44:32 +00:00
case 0xA4: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDY %02X\n", zpg);
y = bus.read(zpg);
flag_change(N, y & 0x80);
flag_change(Z, y == 0);
break;
}
2016-11-06 20:37:19 +00:00
case 0xAC: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("LDY %04X\n", addr);
y = bus.read(addr);
flag_change(N, y & 0x80);
flag_change(Z, y == 0);
break;
}
case 0xA2: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDX #%02X\n", imm);
x = imm;
flag_change(N, x & 0x80);
flag_change(Z, x == 0);
break;
}
2016-11-06 07:53:43 +00:00
case 0xA0: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDY #%02X\n", imm);
y = imm;
flag_change(N, y & 0x80);
flag_change(Z, y == 0);
break;
}
case 0xA9: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("LDA #%02X\n", imm);
a = imm;
flag_change(N, a & 0x80);
flag_change(Z, a == 0);
break;
}
case 0xAD: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("LDA %04X\n", addr);
a = bus.read(addr);
flag_change(N, a & 0x80);
flag_change(Z, a == 0);
break;
}
2016-11-06 22:10:46 +00:00
case 0xCC: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("CPY %04X\n", addr);
unsigned char imm = bus.read(addr);
flag_change(C, imm <= a);
imm = a - imm;
flag_change(N, imm & 0x80);
flag_change(Z, imm == 0);
break;
}
2016-11-06 20:37:19 +00:00
case 0xC0: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("CPY %02X\n", imm);
flag_change(C, imm <= a);
imm = a - imm;
flag_change(N, imm & 0x80);
flag_change(Z, imm == 0);
break;
}
2016-11-06 22:18:17 +00:00
case 0x45: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("EOR %02X\n", zpg);
a = a ^ bus.read(zpg);
flag_change(N, a & 0x80);
flag_change(Z, a == 0);
break;
}
2016-11-06 20:44:32 +00:00
case 0x49: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("EOR #%02X\n", imm);
a = a ^ imm;
flag_change(N, a & 0x80);
flag_change(Z, a == 0);
break;
}
2016-11-06 21:55:29 +00:00
case 0x51: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("EOR (%02x), Y\n", zpg);
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
unsigned char m = bus.read(addr);
a = a ^ m;
flag_change(N, a & 0x80);
flag_change(Z, a == 0);
break;
}
case 0xD1: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("CMP (%02x), Y\n", zpg);
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
unsigned char m = bus.read(addr);
flag_change(C, m <= a);
m = a - m;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
break;
}
2016-11-06 21:27:01 +00:00
case 0xC5: {
unsigned char zpg = read_pc_inc(bus);
2016-11-06 21:55:29 +00:00
if(debug & DEBUG_DECODE) printf("CMP %02X\n", zpg);
2016-11-06 21:27:01 +00:00
unsigned char m = bus.read(zpg);
flag_change(C, m <= a);
m = a - m;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
break;
}
case 0xCD: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("CMP %04X\n", addr);
unsigned char m = bus.read(addr);
flag_change(C, m <= a);
m = a - m;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
break;
}
2016-11-06 20:37:19 +00:00
case 0xC9: {
unsigned char imm = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("CMP #%02X\n", imm);
flag_change(C, imm <= a);
imm = a - imm;
flag_change(N, imm & 0x80);
flag_change(Z, imm == 0);
break;
}
2016-11-06 07:53:43 +00:00
case 0xD5: {
unsigned char zpg = read_pc_inc(bus) + x;
if(debug & DEBUG_DECODE) printf("CMP %02X\n", zpg);
unsigned char m = bus.read(zpg);
2016-11-06 20:37:19 +00:00
flag_change(C, m <= a);
2016-11-06 07:53:43 +00:00
m = a - m;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
break;
}
2016-11-06 21:27:01 +00:00
case 0xC4: {
unsigned char zpg = read_pc_inc(bus) + x;
if(debug & DEBUG_DECODE) printf("CPY %02X\n", zpg);
unsigned char m = bus.read(zpg);
flag_change(C, m <= y);
m = y - m;
flag_change(N, m & 0x80);
flag_change(Z, m == 0);
break;
}
2016-11-06 07:53:43 +00:00
case 0x90: {
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
if(debug & DEBUG_DECODE) printf("BCC %02X\n", rel);
if(!isset(C))
pc += rel;
break;
}
case 0xB0: {
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
if(debug & DEBUG_DECODE) printf("BCS %02X\n", rel);
if(isset(C))
pc += rel;
break;
}
case 0xD0: {
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
if(debug & DEBUG_DECODE) printf("BNE %02X\n", rel);
if(!isset(Z))
pc += rel;
break;
}
case 0xF0: {
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
if(debug & DEBUG_DECODE) printf("BEQ %02X\n", rel);
if(isset(Z))
pc += rel;
break;
}
case 0x85: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("STA %02X\n", zpg);
bus.write(zpg, a);
break;
}
case 0x60: {
if(debug & DEBUG_DECODE) printf("RTS\n");
unsigned char pcl = stack_pull(bus);
unsigned char pch = stack_pull(bus);
2016-11-06 20:37:19 +00:00
pc = pcl + pch * 256 + 1;
2016-11-06 21:55:29 +00:00
printf("%02X %02X, %04X\n", pcl, pch, pc);
2016-11-06 20:37:19 +00:00
break;
}
case 0x95: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("STA %02X,X\n", zpg);
bus.write((zpg + x) % 0x100, a);
break;
}
case 0x94: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("STY %02X,X\n", zpg);
bus.write((zpg + x) % 0x100, y);
2016-11-06 07:53:43 +00:00
break;
}
2016-11-06 21:27:01 +00:00
case 0x86: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("STX %02X\n", zpg);
bus.write(zpg, x);
break;
}
2016-11-06 07:53:43 +00:00
case 0x84: {
unsigned char zpg = read_pc_inc(bus);
if(debug & DEBUG_DECODE) printf("STY %02X\n", zpg);
bus.write(zpg, y);
break;
}
2016-11-06 20:37:19 +00:00
case 0x8C: {
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("STY %04X\n", addr);
bus.write(addr, y);
break;
}
2016-11-06 07:53:43 +00:00
case 0x20: {
2016-11-06 20:37:19 +00:00
stack_push(bus, (pc + 1) >> 8);
stack_push(bus, (pc + 1) & 0xFF);
2016-11-06 07:53:43 +00:00
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
if(debug & DEBUG_DECODE) printf("JSR %04X\n", addr);
pc = addr;
break;
}
default:
printf("unhandled instruction %02X\n", inst);
exit(1);
}
if(debug & DEBUG_STATE) {
2016-11-06 21:55:29 +00:00
unsigned char s0 = bus.read(0x100 + s + 0);
unsigned char s1 = bus.read(0x100 + s + 1);
unsigned char s2 = bus.read(0x100 + s + 2);
2016-11-06 07:53:43 +00:00
unsigned char pc0 = bus.read(pc + 0);
unsigned char pc1 = bus.read(pc + 1);
unsigned char pc2 = bus.read(pc + 2);
printf("6502: A:%02X X:%02X Y:%02X P:", a, x, y);
printf("%s", (p & N) ? "N" : "n");
printf("%s", (p & V) ? "V" : "v");
printf("-");
printf("%s", (p & B) ? "B" : "b");
printf("%s", (p & D) ? "D" : "d");
printf("%s", (p & I) ? "I" : "i");
printf("%s", (p & Z) ? "Z" : "z");
printf("%s ", (p & C) ? "C" : "c");
2016-11-06 21:55:29 +00:00
printf("S:%02X (%02X %02X %02X ...) PC:%04X (%02X %02X %02X ...)\n", s, s0, s1, s2, pc, pc0, pc1, pc2);
2016-11-06 07:53:43 +00:00
}
}
};
void usage(char *progname)
{
printf("\n");
printf("usage: %s ROM.bin\n", progname);
printf("\n");
printf("\n");
}
int main(int argc, char **argv)
{
char *progname = argv[0];
argc -= 1;
argv += 1;
while((argc > 0) && (argv[0][0] == '-')) {
if(
(strcmp(argv[0], "-help") == 0) ||
(strcmp(argv[0], "-h") == 0) ||
(strcmp(argv[0], "-?") == 0))
{
usage(progname);
exit(EXIT_SUCCESS);
} else {
fprintf(stderr, "unknown parameter \"%s\"\n", argv[0]);
usage(progname);
exit(EXIT_FAILURE);
}
}
if(argc < 1) {
usage(progname);
exit(EXIT_FAILURE);
}
char *romname = argv[0];
unsigned char b[32768];
FILE *fp = fopen(romname, "rb");
if(fp == NULL) {
fprintf(stderr, "failed to open %s for reading\n", romname);
exit(EXIT_FAILURE);
}
size_t length = fread(b, 1, sizeof(b), fp);
if(length < MAINboard::rom_size) {
fprintf(stderr, "ROM read from %s was unexpectedly short (%zd bytes)\n", romname, length);
exit(EXIT_FAILURE);
}
fclose(fp);
bus.boards.push_back(new MAINboard(b));
for(auto b = bus.boards.begin(); b != bus.boards.end(); b++) {
(*b)->reset();
}
CPU6502 cpu;
while(1) {
cpu.cycle(bus);
2016-11-06 21:27:01 +00:00
// printf("> ");
// char line[512];
// fgets(line, sizeof(line) - 1, stdin);
2016-11-06 07:53:43 +00:00
}
}