2016-11-06 07:53:43 +00:00
|
|
|
|
#include <cstdlib>
|
2016-11-09 11:46:26 +00:00
|
|
|
|
#include <cstring>
|
2016-11-06 20:37:19 +00:00
|
|
|
|
#include <string>
|
|
|
|
|
#include <set>
|
2016-11-07 18:44:29 +00:00
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <thread>
|
|
|
|
|
#include <ratio>
|
2016-11-08 05:22:21 +00:00
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <signal.h>
|
2016-11-06 20:37:19 +00:00
|
|
|
|
|
2016-11-08 21:35:35 +00:00
|
|
|
|
const int rom_image_size = 0x3000;
|
|
|
|
|
|
2016-11-06 20:37:19 +00:00
|
|
|
|
using namespace std;
|
2016-11-06 07:53:43 +00:00
|
|
|
|
|
|
|
|
|
#include "emulator.h"
|
2016-11-06 22:37:20 +00:00
|
|
|
|
#include "keyboard.h"
|
2016-11-08 05:22:21 +00:00
|
|
|
|
#include "dis6502.h"
|
2016-11-06 07:53:43 +00:00
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
const unsigned int DEBUG_ERROR = 0x01;
|
2016-11-06 07:53:43 +00:00
|
|
|
|
const unsigned int DEBUG_DECODE = 0x02;
|
|
|
|
|
const unsigned int DEBUG_STATE = 0x04;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
const unsigned int DEBUG_RW = 0x08;
|
2016-11-08 05:22:21 +00:00
|
|
|
|
const unsigned int DEBUG_BUS = 0x10;
|
2016-11-09 00:41:30 +00:00
|
|
|
|
volatile unsigned int debug = DEBUG_ERROR | DEBUG_DECODE | DEBUG_STATE | DEBUG_RW;
|
2016-11-06 07:53:43 +00:00
|
|
|
|
|
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;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
bool implemented;
|
|
|
|
|
SoftSwitch(const char* name_, int clear, int on, int read, bool read_changes, vector<SoftSwitch*>& s, bool implemented_ = false) :
|
2016-11-06 20:37:19 +00:00
|
|
|
|
name(name_),
|
|
|
|
|
clear_address(clear),
|
|
|
|
|
set_address(on),
|
|
|
|
|
read_address(read),
|
2016-11-08 21:22:46 +00:00
|
|
|
|
read_also_changes(read_changes),
|
|
|
|
|
implemented(implemented_)
|
2016-11-06 20:37:19 +00:00
|
|
|
|
{
|
|
|
|
|
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-08 21:22:46 +00:00
|
|
|
|
|
2016-11-09 15:05:18 +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++) {
|
2016-11-09 15:05:18 +00:00
|
|
|
|
int addr = textport_row_base_addresses[row] - 0x400 + 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-08 21:22:46 +00:00
|
|
|
|
|
2016-11-08 21:35:35 +00:00
|
|
|
|
struct region
|
|
|
|
|
{
|
2016-11-09 00:41:30 +00:00
|
|
|
|
string name;
|
2016-11-08 21:35:35 +00:00
|
|
|
|
int base;
|
|
|
|
|
int size;
|
|
|
|
|
bool contains(int addr) const
|
|
|
|
|
{
|
|
|
|
|
return addr >= base && addr < base + size;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-11-09 00:41:30 +00:00
|
|
|
|
typedef std::function<bool()> enabled_func;
|
|
|
|
|
|
2016-11-09 05:43:01 +00:00
|
|
|
|
enum MemoryType {RAM, ROM};
|
|
|
|
|
|
2016-11-08 21:35:35 +00:00
|
|
|
|
struct backed_region : region
|
|
|
|
|
{
|
2016-11-09 00:41:30 +00:00
|
|
|
|
vector<unsigned char> memory;
|
2016-11-09 05:43:01 +00:00
|
|
|
|
MemoryType type;
|
2016-11-09 00:41:30 +00:00
|
|
|
|
enabled_func enabled;
|
2016-11-08 21:35:35 +00:00
|
|
|
|
|
2016-11-09 05:43:01 +00:00
|
|
|
|
backed_region(const char* name, int base, int size, MemoryType type_, vector<backed_region*>& regions, enabled_func enabled_) :
|
2016-11-09 00:41:30 +00:00
|
|
|
|
region{name, base, size},
|
|
|
|
|
memory(size),
|
2016-11-09 05:43:01 +00:00
|
|
|
|
type(type_),
|
2016-11-09 00:41:30 +00:00
|
|
|
|
enabled(enabled_)
|
|
|
|
|
{
|
|
|
|
|
regions.push_back(this);
|
|
|
|
|
}
|
2016-11-08 21:35:35 +00:00
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
bool contains(int addr) const
|
|
|
|
|
{
|
|
|
|
|
return addr >= base && addr < base + size;
|
|
|
|
|
}
|
2016-11-08 21:35:35 +00:00
|
|
|
|
|
|
|
|
|
bool read(int addr, unsigned char& data)
|
|
|
|
|
{
|
2016-11-09 00:41:30 +00:00
|
|
|
|
if(contains(addr) && enabled()) {
|
2016-11-08 21:35:35 +00:00
|
|
|
|
data = memory[addr - base];
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool write(int addr, unsigned char data)
|
|
|
|
|
{
|
2016-11-09 05:43:01 +00:00
|
|
|
|
if((type == RAM) && contains(addr) && enabled()) {
|
2016-11-08 21:35:35 +00:00
|
|
|
|
memory[addr - base] = data;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-11-08 21:22:46 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-11-09 00:41:30 +00:00
|
|
|
|
const region hires1_region = {"hires1", 0x2000, 0x2000};
|
|
|
|
|
const region hires2_region = {"hires2", 0x4000, 0x2000};
|
|
|
|
|
const region text1_region = {"text1", 0x400, 0x400};
|
|
|
|
|
const region text2_region = {"text2", 0x800, 0x400};
|
|
|
|
|
const region io_region = {"io", 0xC000, 0x100};
|
2016-11-08 21:22:46 +00:00
|
|
|
|
|
2016-11-06 07:53:43 +00:00
|
|
|
|
struct MAINboard : board_base
|
|
|
|
|
{
|
2016-11-06 20:37:19 +00:00
|
|
|
|
vector<SoftSwitch*> switches;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
SoftSwitch CXROM {"CXROM", 0xC006, 0xC007, 0xC015, false, switches, true};
|
2016-11-09 15:05:18 +00:00
|
|
|
|
SoftSwitch STORE80 {"STORE80", 0xC000, 0xC001, 0xC018, false, switches, true};
|
2016-11-06 20:37:19 +00:00
|
|
|
|
SoftSwitch RAMRD {"RAMRD", 0xC002, 0xC003, 0xC013, false, switches};
|
|
|
|
|
SoftSwitch RAMWRT {"RAMWRT", 0xC004, 0xC005, 0xC014, false, switches};
|
|
|
|
|
SoftSwitch ALTZP {"ALTZP", 0xC008, 0xC009, 0xC016, false, switches};
|
2016-11-09 05:43:01 +00:00
|
|
|
|
SoftSwitch C3ROM {"C3ROM", 0xC00A, 0xC00B, 0xC017, false, switches, true};
|
2016-11-06 20:37:19 +00:00
|
|
|
|
SoftSwitch ALTCHAR {"ALTCHAR", 0xC00E, 0xC00F, 0xC01E, false, switches};
|
|
|
|
|
SoftSwitch VID80 {"VID80", 0xC00C, 0xC00D, 0xC01F, false, switches};
|
2016-11-08 21:22:46 +00:00
|
|
|
|
SoftSwitch TEXT {"TEXT", 0xC050, 0xC051, 0xC01A, true, switches, true};
|
2016-11-06 20:37:19 +00:00
|
|
|
|
SoftSwitch MIXED {"MIXED", 0xC052, 0xC053, 0xC01B, true, switches};
|
2016-11-09 15:05:18 +00:00
|
|
|
|
SoftSwitch PAGE2 {"PAGE2", 0xC054, 0xC055, 0xC01C, true, switches, true};
|
2016-11-06 20:37:19 +00:00
|
|
|
|
SoftSwitch HIRES {"HIRES", 0xC056, 0xC057, 0xC01D, true, switches};
|
2016-11-08 21:22:46 +00:00
|
|
|
|
|
2016-11-09 00:41:30 +00:00
|
|
|
|
vector<backed_region*> regions;
|
2016-11-09 05:43:01 +00:00
|
|
|
|
backed_region szp = {"szp", 0x0000, 0x0200, RAM, regions, [&](){return !ALTZP;}}; // stack and zero page
|
|
|
|
|
backed_region aszp = {"aszp", 0x0000, 0x0200, RAM, regions, [&](){return ALTZP;}}; // alternate stack and zero page
|
|
|
|
|
backed_region rom = {"rom", 0xD000, 0x3000, ROM, regions, []{return true;}};
|
|
|
|
|
backed_region i1rom = {"i1rom", 0xC100, 0x0F00, ROM, regions, [&]{return CXROM;}};
|
|
|
|
|
backed_region i3rom = {"i3rom", 0xC300, 0x0F00, ROM, regions, [&]{return !CXROM && !C3ROM;}};
|
|
|
|
|
backed_region ram = {"ram", 0x0200, 0xFE00, RAM, regions, []{return true;}};
|
2016-11-09 00:41:30 +00:00
|
|
|
|
|
2016-11-06 20:37:19 +00:00
|
|
|
|
set<int> ignore_mmio = {0xC058, 0xC05A, 0xC05D, 0xC05F, 0xC061, 0xC062};
|
2016-11-08 21:22:46 +00:00
|
|
|
|
|
2016-11-08 21:35:35 +00:00
|
|
|
|
MAINboard(unsigned char rom_image[32768])
|
2016-11-06 07:53:43 +00:00
|
|
|
|
{
|
2016-11-09 05:43:01 +00:00
|
|
|
|
std::copy(rom_image + rom.base - 0x8000, rom_image + rom.base - 0x8000 + rom.size, rom.memory.begin());
|
|
|
|
|
std::copy(rom_image + i1rom.base - 0x8000, rom_image + i1rom.base - 0x8000 + i1rom.size, i1rom.memory.begin());
|
|
|
|
|
std::copy(rom_image + i3rom.base - 0x8000, rom_image + i3rom.base - 0x8000 + i3rom.size, i3rom.memory.begin());
|
|
|
|
|
std::fill(ram.memory.begin(), ram.memory.end(), 0x00);
|
2016-11-06 22:37:20 +00:00
|
|
|
|
start_keyboard();
|
|
|
|
|
}
|
2016-11-08 21:22:46 +00:00
|
|
|
|
|
2016-11-06 22:37:20 +00:00
|
|
|
|
virtual ~MAINboard()
|
|
|
|
|
{
|
|
|
|
|
stop_keyboard();
|
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");
|
2016-11-08 21:22:46 +00:00
|
|
|
|
if(io_region.contains(addr)) {
|
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) {
|
2016-11-09 00:41:30 +00:00
|
|
|
|
if(!sw->implemented) { printf("%s ; set is unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
2016-11-06 20:37:19 +00:00
|
|
|
|
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) {
|
2016-11-09 00:41:30 +00:00
|
|
|
|
// if(!sw->implemented) { printf("%s ; unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
2016-11-06 20:37:19 +00:00
|
|
|
|
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 22:37:20 +00:00
|
|
|
|
data = get_keyboard_data_and_strobe();
|
|
|
|
|
if(debug & DEBUG_RW) printf("read KBD, return 0x%02X\n", data);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
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) {
|
|
|
|
|
// reset keyboard latch
|
2016-11-06 22:37:20 +00:00
|
|
|
|
data = get_any_key_down_and_clear_strobe();
|
|
|
|
|
if(debug & DEBUG_RW) printf("read KBDSTRB, return 0x%02X\n", data);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
printf("unhandled MMIO Read at %04X\n", addr);
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(0);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
2016-11-09 00:41:30 +00:00
|
|
|
|
for(auto it = regions.begin(); it != regions.end(); it++) {
|
|
|
|
|
backed_region* r = *it;
|
|
|
|
|
if(r->read(addr, data)) {
|
|
|
|
|
if(debug & DEBUG_RW) printf("read 0x%04X -> 0x%02X from %s\n", addr, data, r->name.c_str());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
virtual bool write(int addr, unsigned char data)
|
|
|
|
|
{
|
2016-11-08 21:22:46 +00:00
|
|
|
|
if(TEXT) {
|
|
|
|
|
// TEXT takes precedence over all other modes
|
|
|
|
|
if(text1_region.contains(addr)) {
|
|
|
|
|
printf("TEXT1 WRITE!\n");
|
2016-11-09 15:05:18 +00:00
|
|
|
|
if(!PAGE2) textport_change(&ram.memory[0x200]);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
}
|
|
|
|
|
if(text2_region.contains(addr)) {
|
|
|
|
|
printf("TEXT2 WRITE!\n");
|
2016-11-09 15:05:18 +00:00
|
|
|
|
if(PAGE2) textport_change(&ram.memory[0x600]);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// MIXED shows text in last 4 columns in both HIRES or LORES
|
|
|
|
|
if(MIXED) {
|
|
|
|
|
printf("MIXED WRITE, abort!\n");
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(0);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
} else {
|
|
|
|
|
if(HIRES) {
|
|
|
|
|
if(hires1_region.contains(addr)) {
|
|
|
|
|
printf("HIRES1 WRITE, abort!\n");
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(0);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
}
|
|
|
|
|
if(hires2_region.contains(addr)) {
|
|
|
|
|
printf("HIRES2 WRITE, abort!\n");
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(0);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if(text1_region.contains(addr)) {
|
|
|
|
|
printf("LORES1 WRITE, abort!\n");
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(0);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
}
|
|
|
|
|
if(text2_region.contains(addr)) {
|
|
|
|
|
printf("LORES2 WRITE, abort!\n");
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(0);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
2016-11-08 21:22:46 +00:00
|
|
|
|
if(io_region.contains(addr)) {
|
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) {
|
2016-11-09 00:41:30 +00:00
|
|
|
|
if(!sw->implemented) { printf("%s ; set is unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
2016-11-06 20:37:19 +00:00
|
|
|
|
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) {
|
2016-11-09 00:41:30 +00:00
|
|
|
|
// if(!sw->implemented) { printf("%s ; unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
2016-11-06 20:37:19 +00:00
|
|
|
|
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
|
2016-11-06 22:37:20 +00:00
|
|
|
|
get_any_key_down_and_clear_strobe();
|
2016-11-06 20:37:19 +00:00
|
|
|
|
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);
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(0);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
2016-11-09 00:41:30 +00:00
|
|
|
|
for(auto it = regions.begin(); it != regions.end(); it++) {
|
|
|
|
|
backed_region* r = *it;
|
|
|
|
|
if(r->write(addr, data)) {
|
|
|
|
|
if(debug & DEBUG_RW) printf("wrote %02X to 0x%04X in %s\n", addr, data, r->name.c_str());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
|
|
|
|
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;
|
2016-11-08 05:22:21 +00:00
|
|
|
|
if((*b)->read(addr, data)) {
|
|
|
|
|
if(debug & DEBUG_BUS) printf("read %04X returned %02X\n", addr, data);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
return data;
|
2016-11-08 05:22:21 +00:00
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
|
|
|
|
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++) {
|
2016-11-08 05:22:21 +00:00
|
|
|
|
if((*b)->write(addr, data)) {
|
|
|
|
|
if(debug & DEBUG_BUS) printf("write %04X %02X\n", addr, data);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
return;
|
2016-11-08 05:22:21 +00:00
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
|
|
|
|
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
|
2016-11-08 21:22:46 +00:00
|
|
|
|
void set_flags(unsigned char flags, unsigned char v)
|
|
|
|
|
{
|
|
|
|
|
if(flags & Z)
|
|
|
|
|
flag_change(Z, v == 0x00);
|
|
|
|
|
if(flags & N)
|
|
|
|
|
flag_change(N, v & 0x80);
|
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
void cycle(bus_controller& bus)
|
|
|
|
|
{
|
|
|
|
|
if(exception == RESET) {
|
|
|
|
|
if(debug & DEBUG_STATE) printf("RESET\n");
|
|
|
|
|
reset(bus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned char inst = read_pc_inc(bus);
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
unsigned char m;
|
2016-11-08 05:22:21 +00:00
|
|
|
|
|
|
|
|
|
int bytes;
|
|
|
|
|
string dis;
|
|
|
|
|
unsigned char buf[4];
|
|
|
|
|
buf[0] = inst;
|
|
|
|
|
buf[1] = bus.read(pc + 0);
|
|
|
|
|
buf[2] = bus.read(pc + 1);
|
|
|
|
|
buf[3] = bus.read(pc + 2);
|
|
|
|
|
tie(bytes, dis) = disassemble_6502(pc - 1, buf);
|
|
|
|
|
if(debug & DEBUG_DECODE) printf("%s\n", dis.c_str());
|
2016-11-06 07:53:43 +00:00
|
|
|
|
switch(inst) {
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xEA: { // NOP
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x8A: { // TXA
|
|
|
|
|
set_flags(N | Z, a = x);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xAA: { // TAX
|
|
|
|
|
set_flags(N | Z, x = a);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xBA: { // TSX
|
|
|
|
|
set_flags(N | Z, x = s);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x9A: { // TXS
|
|
|
|
|
set_flags(N | Z, s = x);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xA8: { // TAY
|
|
|
|
|
set_flags(N | Z, y = a);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x98: { // TYA
|
|
|
|
|
set_flags(N | Z, a = y);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x18: { // CLC
|
2016-11-06 20:37:19 +00:00
|
|
|
|
flag_clear(C);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x38: { // SEC
|
2016-11-06 20:37:19 +00:00
|
|
|
|
flag_set(C);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xD8: { // CLD
|
2016-11-06 07:53:43 +00:00
|
|
|
|
flag_clear(D);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x58: { // CLI
|
2016-11-06 20:37:19 +00:00
|
|
|
|
flag_clear(I);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x78: { // SEI
|
2016-11-06 20:37:19 +00:00
|
|
|
|
flag_set(I);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xB8: { // CLV
|
2016-11-08 05:22:21 +00:00
|
|
|
|
flag_clear(V);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xC6: { // DEC
|
2016-11-06 21:27:01 +00:00
|
|
|
|
int zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = bus.read(zpg) - 1);
|
2016-11-06 21:27:01 +00:00
|
|
|
|
bus.write(zpg, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xCE: { // DEC
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = bus.read(addr) - 1);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
bus.write(addr, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xCA: { // DEC
|
|
|
|
|
set_flags(N | Z, x = x - 1);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xE6: { // INC
|
2016-11-06 21:55:29 +00:00
|
|
|
|
int zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = bus.read(zpg) + 1);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
bus.write(zpg, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xE8: { // INX
|
|
|
|
|
set_flags(N | Z, x = x + 1);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xC8: { // INY
|
|
|
|
|
set_flags(N | Z, y = y + 1);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x10: { // BPL
|
2016-11-06 20:37:19 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(!isset(N))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x50: { // BVC
|
2016-11-08 05:22:21 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(!isset(V))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x70: { // BVS
|
2016-11-06 23:41:18 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(isset(V))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x30: { // BMI
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(isset(N))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xB5: { // LDA
|
2016-11-06 22:14:17 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
int addr = zpg + y;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = bus.read(addr & 0xFF));
|
2016-11-06 22:14:17 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xB1: { // LDA
|
2016-11-06 21:27:01 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = bus.read(addr));
|
2016-11-06 21:27:01 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xA5: { // LDA
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = bus.read(zpg));
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xDD: { // CMP
|
2016-11-06 21:55:29 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr + x);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
flag_change(C, m <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = a - m);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xD9: { // CMP
|
2016-11-06 21:30:23 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr + y);
|
2016-11-06 21:30:23 +00:00
|
|
|
|
flag_change(C, m <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = a - m);
|
2016-11-06 21:30:23 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xB9: { // LDA
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = bus.read(addr + y));
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xBD: { // LDA
|
2016-11-06 21:27:01 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = bus.read(addr + x));
|
2016-11-06 21:27:01 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x65: { // ADC
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
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-08 21:22:46 +00:00
|
|
|
|
case 0xF1: { // SBC
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
int borrow = isset(C) ? 0 : 1;
|
|
|
|
|
flag_change(C, !(a < m - borrow));
|
|
|
|
|
a = a - m - borrow;
|
|
|
|
|
flag_change(N, a & 0x80);
|
|
|
|
|
flag_change(V, isset(C) != isset(N));
|
|
|
|
|
flag_change(Z, a == 0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xED: { // SBC
|
2016-11-06 22:10:46 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
|
|
|
|
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-08 21:22:46 +00:00
|
|
|
|
case 0xE9: { // SBC
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
|
|
|
|
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-08 21:22:46 +00:00
|
|
|
|
case 0x69: { // ADC
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
|
|
|
|
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-08 21:22:46 +00:00
|
|
|
|
case 0x06: { // ASL
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
flag_change(C, m & 0x80);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = m << 1);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
bus.write(zpg, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x0A: { // ASL
|
2016-11-06 20:37:19 +00:00
|
|
|
|
flag_change(C, a & 0x80);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = a << 1);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x46: { // LSR
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
flag_change(C, m & 0x01);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = m >> 1);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
bus.write(zpg, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x4E: { // LSR
|
2016-11-06 22:18:17 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr);
|
2016-11-06 22:18:17 +00:00
|
|
|
|
flag_change(C, m & 0x01);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = m >> 1);
|
2016-11-06 22:18:17 +00:00
|
|
|
|
bus.write(addr, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x4A: { // LSR
|
2016-11-06 07:53:43 +00:00
|
|
|
|
flag_change(C, a & 0x01);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = a >> 1);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x68: { // PLA
|
|
|
|
|
set_flags(N | Z, a = stack_pull(bus));
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x48: { // PHA
|
2016-11-06 07:53:43 +00:00
|
|
|
|
stack_push(bus, a);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x05: { // ORA
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
|
|
|
|
set_flags(N | Z, a = a | m);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x09: { // ORA
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = a | imm);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x25: { // AND
|
2016-11-06 21:55:29 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = a & bus.read(zpg));
|
2016-11-06 21:55:29 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x29: { // AND
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = a & imm);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x88: { // DEY
|
|
|
|
|
set_flags(N | Z, y = y - 1);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x2A: { // ROL
|
2016-11-06 23:41:18 +00:00
|
|
|
|
bool c = isset(C);
|
|
|
|
|
flag_change(C, a & 0x80);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = (c ? 0x01 : 0x00) | (a << 1));
|
2016-11-06 23:41:18 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x6A: { // ROR
|
2016-11-08 05:22:21 +00:00
|
|
|
|
bool c = isset(C);
|
|
|
|
|
flag_change(C, a & 0x01);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = (c ? 0x80 : 0x00) | (a >> 1));
|
2016-11-08 05:22:21 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x76: { // ROR
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus) + x;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
bool c = isset(C);
|
|
|
|
|
flag_change(C, m & 0x01);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = (c ? 0x80 : 0x00) | (m >> 1));
|
2016-11-06 07:53:43 +00:00
|
|
|
|
bus.write(zpg, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x26: { // ROL
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus) + x;
|
|
|
|
|
bool c = isset(C);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
flag_change(C, m & 0x80);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = (c ? 0x01 : 0x00) | (m << 1));
|
2016-11-06 23:41:18 +00:00
|
|
|
|
bus.write(zpg, m);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-06 07:53:43 +00:00
|
|
|
|
case 0x4C: {
|
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
// JMP
|
2016-11-06 07:53:43 +00:00
|
|
|
|
pc = addr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x6C: { // JMP
|
2016-11-06 20:37:19 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
|
|
|
|
unsigned char addrl = bus.read(addr);
|
|
|
|
|
unsigned char addrh = bus.read(addr + 1);
|
|
|
|
|
addr = addrl + addrh * 256;
|
|
|
|
|
pc = addr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x9D: { // STA
|
2016-11-06 21:27:01 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
|
|
|
|
bus.write(addr + x, a);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x99: { // STA
|
2016-11-06 21:27:01 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
|
|
|
|
bus.write(addr + y, a);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x91: { // STA
|
2016-11-06 21:27:01 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
|
|
|
|
|
bus.write(addr, a);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x8D: { // STA
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
|
|
|
|
bus.write(addr, a);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x08: { // PHP
|
2016-11-06 07:53:43 +00:00
|
|
|
|
stack_push(bus, p);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x28: { // PLP
|
2016-11-06 20:37:19 +00:00
|
|
|
|
p = stack_pull(bus);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x24: { // BIT
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
flag_change(Z, a & m);
|
|
|
|
|
flag_change(N, m & 0x80);
|
|
|
|
|
flag_change(V, m & 0x70);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x2C: { // BIT
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
flag_change(Z, a & m);
|
|
|
|
|
flag_change(N, m & 0x80);
|
|
|
|
|
flag_change(V, m & 0x70);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xB4: { // LDY
|
2016-11-06 22:14:17 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, y = bus.read(zpg + x));
|
2016-11-06 22:14:17 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xA6: { // LDX
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, x = bus.read(zpg));
|
2016-11-06 23:41:18 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xA4: { // LDY
|
2016-11-06 20:44:32 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, y = bus.read(zpg));
|
2016-11-06 20:44:32 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xAC: { // LDY
|
2016-11-06 20:37:19 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, y = bus.read(addr));
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xA2: { // LDX
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, x = imm);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xA0: { // LDY
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, y = imm);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xA9: { // LDA
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = imm);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 0xAD: {
|
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
// LDA
|
|
|
|
|
set_flags(N | Z, a = bus.read(addr));
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xCC: { // CPY
|
2016-11-06 22:10:46 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
flag_change(C, m <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = a - m);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xE0: { // CPX
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
|
|
|
|
flag_change(C, imm <= x);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, imm = x - imm);
|
2016-11-06 22:10:46 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xC0: { // CPY
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
flag_change(C, imm <= y);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, imm = y - imm);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x45: { // EOR
|
2016-11-06 22:18:17 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = a ^ bus.read(zpg));
|
2016-11-06 22:18:17 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x49: { // EOR
|
2016-11-06 20:44:32 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, a = a ^ imm);
|
2016-11-06 20:44:32 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x51: { // EOR
|
2016-11-06 21:55:29 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr);
|
|
|
|
|
set_flags(N | Z, a = a ^ m);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xD1: { // CMP
|
2016-11-06 21:55:29 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
int addr = bus.read(zpg) + bus.read(zpg + 1) * 256 + y;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
flag_change(C, m <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = a - m);
|
2016-11-06 21:55:29 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xC5: { // CMP
|
2016-11-06 21:27:01 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 21:27:01 +00:00
|
|
|
|
flag_change(C, m <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = a - m);
|
2016-11-06 21:27:01 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xCD: { // CMP
|
2016-11-06 21:27:01 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(addr);
|
2016-11-06 21:27:01 +00:00
|
|
|
|
flag_change(C, m <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = a - m);
|
2016-11-06 21:27:01 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xC9: { // CMP
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char imm = read_pc_inc(bus);
|
|
|
|
|
flag_change(C, imm <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, imm = a - imm);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xD5: { // CMP
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus) + x;
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 20:37:19 +00:00
|
|
|
|
flag_change(C, m <= a);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = a - m);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2016-11-06 21:27:01 +00:00
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xE4: { // CPX
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
flag_change(C, m <= x);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = x - m);
|
2016-11-06 23:41:18 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xC4: { // CPY
|
2016-11-06 23:41:18 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
m = bus.read(zpg);
|
2016-11-06 21:27:01 +00:00
|
|
|
|
flag_change(C, m <= y);
|
2016-11-08 21:22:46 +00:00
|
|
|
|
set_flags(N | Z, m = y - m);
|
2016-11-06 21:27:01 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x90: { // BCC
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(!isset(C))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xB0: { // BCS
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(isset(C))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xD0: { // BNE
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(!isset(Z))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0xF0: { // BEQ
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int rel = (read_pc_inc(bus) + 128) % 256 - 128;
|
|
|
|
|
if(isset(Z))
|
|
|
|
|
pc += rel;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x85: { // STA
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
bus.write(zpg, a);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x60: { // RTS
|
2016-11-06 07:53:43 +00:00
|
|
|
|
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;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x95: { // STA
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
bus.write((zpg + x) % 0x100, a);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x94: { // STY
|
2016-11-06 20:37:19 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
bus.write((zpg + x) % 0x100, y);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x86: { // STX
|
2016-11-06 21:27:01 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
bus.write(zpg, x);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x84: { // STY
|
2016-11-06 07:53:43 +00:00
|
|
|
|
unsigned char zpg = read_pc_inc(bus);
|
|
|
|
|
bus.write(zpg, y);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x8C: { // STY
|
2016-11-06 20:37:19 +00:00
|
|
|
|
int addr = read_pc_inc(bus) + read_pc_inc(bus) * 256;
|
|
|
|
|
bus.write(addr, y);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 21:22:46 +00:00
|
|
|
|
case 0x20: { // JSR
|
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;
|
|
|
|
|
pc = addr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
printf("unhandled instruction %02X\n", inst);
|
2016-11-09 00:41:30 +00:00
|
|
|
|
fflush(stdout); exit(1);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
|
|
|
|
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");
|
2016-11-09 05:43:01 +00:00
|
|
|
|
printf("usage: %s [-debugger] ROM.bin\n", progname);
|
2016-11-06 07:53:43 +00:00
|
|
|
|
printf("\n");
|
|
|
|
|
printf("\n");
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-09 11:46:26 +00:00
|
|
|
|
bool debugging = false;
|
|
|
|
|
|
|
|
|
|
void cleanup(void)
|
|
|
|
|
{
|
|
|
|
|
if(!debugging) {
|
|
|
|
|
stop_keyboard();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-06 07:53:43 +00:00
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
char *progname = argv[0];
|
|
|
|
|
argc -= 1;
|
|
|
|
|
argv += 1;
|
|
|
|
|
|
2016-11-09 11:46:26 +00:00
|
|
|
|
atexit(cleanup);
|
2016-11-09 05:43:01 +00:00
|
|
|
|
|
2016-11-06 07:53:43 +00:00
|
|
|
|
while((argc > 0) && (argv[0][0] == '-')) {
|
2016-11-09 05:43:01 +00:00
|
|
|
|
if(strcmp(argv[0], "-debugger") == 0) {
|
|
|
|
|
debugging = true;
|
|
|
|
|
argv++;
|
|
|
|
|
argc--;
|
2016-11-09 11:46:26 +00:00
|
|
|
|
} else if(strcmp(argv[0], "-d") == 0) {
|
|
|
|
|
debug = atoi(argv[1]);
|
|
|
|
|
argv += 2;
|
|
|
|
|
argc -= 2;
|
2016-11-09 05:43:01 +00:00
|
|
|
|
} else if(
|
2016-11-06 07:53:43 +00:00
|
|
|
|
(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);
|
2016-11-08 21:35:35 +00:00
|
|
|
|
if(length < rom_image_size) {
|
2016-11-06 07:53:43 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2016-11-09 05:43:01 +00:00
|
|
|
|
if(debugging) {
|
|
|
|
|
clear_strobe();
|
|
|
|
|
stop_keyboard();
|
|
|
|
|
}
|
2016-11-08 05:22:21 +00:00
|
|
|
|
|
2016-11-06 07:53:43 +00:00
|
|
|
|
while(1) {
|
2016-11-08 05:22:21 +00:00
|
|
|
|
if(!debugging) {
|
|
|
|
|
poll_keyboard();
|
2016-11-07 18:44:29 +00:00
|
|
|
|
|
2016-11-08 05:22:21 +00:00
|
|
|
|
char key;
|
|
|
|
|
bool have_key = peek_key(&key);
|
|
|
|
|
|
|
|
|
|
if(have_key && (key == '')) {
|
|
|
|
|
debugging = true;
|
|
|
|
|
clear_strobe();
|
|
|
|
|
stop_keyboard();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chrono::time_point<chrono::system_clock> then;
|
|
|
|
|
for(int i = 0; i < 25575; i++) // ~ 1/10th second
|
|
|
|
|
cpu.cycle(bus);
|
|
|
|
|
chrono::time_point<chrono::system_clock> now;
|
|
|
|
|
|
|
|
|
|
auto elapsed_millis = chrono::duration_cast<chrono::milliseconds>(now - then);
|
|
|
|
|
this_thread::sleep_for(chrono::milliseconds(100) - elapsed_millis);
|
2016-11-07 18:44:29 +00:00
|
|
|
|
|
2016-11-08 05:22:21 +00:00
|
|
|
|
} else {
|
2016-11-07 18:44:29 +00:00
|
|
|
|
|
2016-11-08 05:22:21 +00:00
|
|
|
|
printf("> ");
|
|
|
|
|
char line[512];
|
2016-11-09 11:46:26 +00:00
|
|
|
|
if(fgets(line, sizeof(line) - 1, stdin) == NULL) {
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
2016-11-08 05:22:21 +00:00
|
|
|
|
line[strlen(line) - 1] = '\0';
|
|
|
|
|
if(strcmp(line, "go") == 0) {
|
|
|
|
|
printf("continuing\n");
|
|
|
|
|
debugging = false;
|
|
|
|
|
start_keyboard();
|
|
|
|
|
continue;
|
|
|
|
|
} else if(strncmp(line, "debug", 5) == 0) {
|
|
|
|
|
sscanf(line + 6, "%d", &debug);
|
|
|
|
|
printf("debug set to %02X\n", debug);
|
2016-11-09 05:43:01 +00:00
|
|
|
|
continue;
|
2016-11-08 05:22:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cpu.cycle(bus);
|
|
|
|
|
}
|
2016-11-06 07:53:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|