kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
2717 wiersze
46 KiB
C++
Executable File
2717 wiersze
46 KiB
C++
Executable File
/*
|
|
Copyright Mike Chambers, Frank Bösing, 2017
|
|
Parts of this file are based on "Fake6502 CPU emulator core v1.1" by Mike Chambers
|
|
|
|
|
|
This file is part of Teensy64.
|
|
|
|
Teensy64 is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Teensy64 is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Teensy64. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Diese Datei ist Teil von Teensy64.
|
|
|
|
Teensy64 ist Freie Software: Sie können es unter den Bedingungen
|
|
der GNU General Public License, wie von der Free Software Foundation,
|
|
Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren
|
|
veröffentlichten Version, weiterverbreiten und/oder modifizieren.
|
|
|
|
Teensy64 wird in der Hoffnung, dass es nützlich sein wird, aber
|
|
OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
|
|
Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
|
|
Siehe die GNU General Public License für weitere Details.
|
|
|
|
Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
|
|
Programm erhalten haben. Wenn nicht, siehe <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
/* Fake6502 CPU emulator core v1.1 *******************
|
|
* (c)2011 Mike Chambers (miker00lz@gmail.com) *
|
|
*****************************************************
|
|
* LICENSE: This source code is released into the *
|
|
* public domain, but if you use it please do give *
|
|
* credit. I put a lot of effort into writing this! *
|
|
* *
|
|
*****************************************************
|
|
*/
|
|
|
|
#include "cpu.h"
|
|
|
|
#define FLAG_CARRY 0x01
|
|
#define FLAG_ZERO 0x02
|
|
#define FLAG_INTERRUPT 0x04
|
|
#define FLAG_DECIMAL 0x08
|
|
#define FLAG_BREAK 0x10
|
|
#define FLAG_CONSTANT 0x20
|
|
#define FLAG_OVERFLOW 0x40
|
|
#define FLAG_SIGN 0x80
|
|
|
|
//flag modifier macros
|
|
#define setcarry() cpu.cpustatus |= FLAG_CARRY
|
|
#define clearcarry() cpu.cpustatus &= (~FLAG_CARRY)
|
|
#define setzero() cpu.cpustatus |= FLAG_ZERO
|
|
#define clearzero() cpu.cpustatus &= (~FLAG_ZERO)
|
|
#define setinterrupt() cpu.cpustatus |= FLAG_INTERRUPT
|
|
#define clearinterrupt() cpu.cpustatus &= (~FLAG_INTERRUPT)
|
|
#define setdecimal() cpu.cpustatus |= FLAG_DECIMAL
|
|
#define cleardecimal() cpu.cpustatus &= (~FLAG_DECIMAL)
|
|
#define setoverflow() cpu.cpustatus |= FLAG_OVERFLOW
|
|
#define clearoverflow() cpu.cpustatus &= (~FLAG_OVERFLOW)
|
|
#define setsign() cpu.cpustatus |= FLAG_SIGN
|
|
#define clearsign() cpu.cpustatus &= (~FLAG_SIGN)
|
|
|
|
|
|
//flag calculation macros
|
|
#define zerocalc(n) { if ((n) & 0x00FF) clearzero(); else setzero(); }
|
|
//#define signcalc(n) { if ((n) & 0x0080) setsign(); else clearsign(); }
|
|
#define signcalc(n) { cpu.cpustatus =( cpu.cpustatus & 0x7f) | (n & 0x80); }
|
|
#define carrycalc(n) { if ((n) & 0xFF00) setcarry(); else clearcarry(); }
|
|
//#define carrycalc(n) {cpu.cpustatus =( cpu.cpustatus & 0xfe) | (n >> 8); }
|
|
#define overflowcalc(n, m, o) { if (((n) ^ (uint16_t)(m)) & ((n) ^ (o)) & 0x0080) setoverflow(); else clearoverflow(); }
|
|
|
|
#define saveaccum(n) cpu.a = (uint8_t)((n) & 0x00FF)
|
|
|
|
#define UNSUPPORTED { printf("Unsupported Opcode\n"); while(1){;} }
|
|
|
|
void logAddr(const uint32_t address, const uint8_t value, const uint8_t rw) {
|
|
if (rw) printf("Write "); else printf("Read ");
|
|
printf("0x%d=0x%d\n",address,value);
|
|
|
|
}
|
|
struct tcpu cpu;
|
|
struct tio io;
|
|
|
|
void reset6502();
|
|
void cpu_nmi();
|
|
static inline void cpu_irq();
|
|
|
|
INLINEOP uint8_t read6502(const uint32_t address) __attribute__ ((hot));
|
|
INLINEOP uint8_t read6502(const uint32_t address) {
|
|
return (*cpu.plamap_r)[address >> 8](address);
|
|
}
|
|
|
|
INLINEOP uint8_t read6502ZP(const uint32_t address) __attribute__ ((hot)); //Zeropage
|
|
INLINEOP uint8_t read6502ZP(const uint32_t address) {
|
|
return cpu.RAM[address & 0xff];
|
|
}
|
|
|
|
/* Ein Schreibzugriff auf einen ROM-Bereich speichert das Byte im „darunterliegenden” RAM. */
|
|
INLINEOP void write6502(const uint32_t address, const uint8_t value) __attribute__ ((hot));
|
|
INLINEOP void write6502(const uint32_t address, const uint8_t value) {
|
|
(*cpu.plamap_w)[address>>8](address, value);
|
|
}
|
|
|
|
//a few general functions used by various other functions
|
|
INLINEOP void push16(const uint16_t pushval) {
|
|
cpu.RAM[BASE_STACK + cpu.sp] = (pushval >> 8) & 0xFF;
|
|
cpu.RAM[BASE_STACK + ((cpu.sp - 1) & 0xFF)] = pushval & 0xFF;
|
|
cpu.sp -= 2;
|
|
}
|
|
|
|
INLINEOP uint16_t pull16() {
|
|
uint16_t temp16;
|
|
temp16 = cpu.RAM[BASE_STACK + ((cpu.sp + 1) & 0xFF)] | ((uint16_t)cpu.RAM[BASE_STACK + ((cpu.sp + 2) & 0xFF)] << 8);
|
|
cpu.sp += 2;
|
|
return(temp16);
|
|
}
|
|
|
|
INLINEOP void push8(uint8_t pushval) {
|
|
cpu.RAM[BASE_STACK + (cpu.sp--)] = pushval;
|
|
|
|
}
|
|
|
|
INLINEOP uint8_t pull8() {
|
|
return cpu.RAM[BASE_STACK + (++cpu.sp)];
|
|
}
|
|
|
|
/********************************************************************************************************************/
|
|
/*addressing mode functions, calculates effective addresses */
|
|
/********************************************************************************************************************/
|
|
|
|
INLINEOP void imp() { //implied
|
|
}
|
|
|
|
INLINEOP void acc() { //accumulator
|
|
}
|
|
|
|
INLINEOP void imm() { //immediate
|
|
cpu.ea = cpu.pc++;
|
|
}
|
|
|
|
INLINEOP void zp() { //zero-page
|
|
cpu.ea = read6502(cpu.pc++) & 0xFF;
|
|
}
|
|
|
|
INLINEOP void zpx() { //zero-page,X
|
|
cpu.ea = (read6502(cpu.pc++) + cpu.x) & 0xFF; //zero-page wraparound
|
|
}
|
|
|
|
INLINEOP void zpy() { //zero-page,Y
|
|
cpu.ea = (read6502(cpu.pc++) + cpu.y) & 0xFF; //zero-page wraparound
|
|
}
|
|
|
|
INLINEOP void rel() { //relative for branch ops (8-bit immediate value, sign-extended)
|
|
cpu.reladdr = read6502(cpu.pc++);
|
|
if (cpu.reladdr & 0x80) cpu.reladdr |= 0xFF00;
|
|
}
|
|
|
|
INLINEOP void abso() { //absolute
|
|
cpu.ea = read6502(cpu.pc) | (read6502(cpu.pc + 1) << 8);
|
|
cpu.pc += 2;
|
|
}
|
|
|
|
INLINEOP void absx() { //absolute,X
|
|
cpu.ea = (read6502(cpu.pc) | (read6502(cpu.pc + 1) << 8)) + cpu.x;
|
|
cpu.pc += 2;
|
|
}
|
|
|
|
INLINEOP void absx_t() { //absolute,X with extra cycle
|
|
uint16_t h = read6502(cpu.pc) + cpu.x;
|
|
if (h & 0x100) cpu.ticks += 1;
|
|
cpu.ea = h + (read6502(cpu.pc + 1) << 8);
|
|
cpu.pc += 2;
|
|
}
|
|
|
|
INLINEOP void absy() { //absolute,Y
|
|
cpu.ea = (read6502(cpu.pc) + (read6502(cpu.pc + 1) << 8)) + cpu.y;
|
|
cpu.pc += 2;
|
|
}
|
|
|
|
INLINEOP void absy_t() { //absolute,Y with extra cycle
|
|
uint16_t h = read6502(cpu.pc) + cpu.y;
|
|
if (h & 0x100) cpu.ticks += 1;
|
|
cpu.ea = h + (read6502(cpu.pc + 1) << 8);
|
|
cpu.pc += 2;
|
|
}
|
|
|
|
INLINEOP void ind() { //indirect
|
|
uint16_t eahelp, eahelp2;
|
|
eahelp = read6502(cpu.pc) | (read6502(cpu.pc + 1) << 8);
|
|
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); //replicate 6502 page-boundary wraparound bug
|
|
cpu.ea = read6502(eahelp) | (read6502(eahelp2) << 8);
|
|
cpu.pc += 2;
|
|
}
|
|
|
|
INLINEOP void indx() { // (indirect,X)
|
|
uint32_t eahelp;
|
|
eahelp = (read6502(cpu.pc++) + cpu.x) & 0xFF; //zero-page wraparound for table pointer
|
|
cpu.ea = read6502ZP((uint8_t)eahelp) | (read6502ZP((uint8_t)(eahelp + 1)) << 8);
|
|
}
|
|
|
|
INLINEOP void indy() { // (zeropage indirect),Y
|
|
uint8_t zp = read6502(cpu.pc++);
|
|
cpu.ea = read6502ZP((uint16_t) zp++);
|
|
cpu.ea += (uint16_t) read6502ZP((uint16_t) zp) << 8;
|
|
cpu.ea += cpu.y;
|
|
}
|
|
|
|
INLINEOP void indy_t() { // (zeropage indirect),Y with extra cycle
|
|
uint8_t zp = read6502(cpu.pc++);
|
|
uint16_t h;
|
|
h = read6502ZP((uint16_t) zp++);
|
|
h += (uint16_t) read6502ZP((uint16_t) zp) << 8;
|
|
if (((h + cpu.y) & 0xff) != (h & 0xff)) cpu.ticks += 1;
|
|
cpu.ea = h + cpu.y;
|
|
}
|
|
|
|
INLINEOP uint32_t getvalue() __attribute__ ((hot));
|
|
INLINEOP uint32_t getvalue() {
|
|
return read6502(cpu.ea);
|
|
}
|
|
|
|
INLINEOP uint32_t getvalueZP() __attribute__ ((hot));
|
|
INLINEOP uint32_t getvalueZP() {
|
|
return read6502ZP(cpu.ea);
|
|
}
|
|
|
|
INLINEOP void putvalue(const uint8_t saveval) __attribute__ ((hot));
|
|
INLINEOP void putvalue(const uint8_t saveval) {
|
|
write6502(cpu.ea, saveval);
|
|
}
|
|
|
|
|
|
/********************************************************************************************************************/
|
|
/* instruction handler functions */
|
|
/********************************************************************************************************************/
|
|
|
|
/*
|
|
Aliases used in other illegal opcode sources:
|
|
|
|
SLO = ASO
|
|
SRE = LSE
|
|
ISC = ISB
|
|
ALR = ASR
|
|
SHX = A11 (A11 was a result of only having tested this one on adress $1000)
|
|
SHY = A11
|
|
LAS = LAR
|
|
KIL = JAM, HLT
|
|
*/
|
|
|
|
#define SETFLAGS(data) \
|
|
{ \
|
|
if (!(data)) \
|
|
cpu.cpustatus = (cpu.cpustatus & ~FLAG_SIGN) | FLAG_ZERO; \
|
|
else \
|
|
cpu.cpustatus = (cpu.cpustatus & ~(FLAG_SIGN|FLAG_ZERO)) | \
|
|
((data) & FLAG_SIGN); \
|
|
}
|
|
|
|
|
|
INLINEOP void _adc(unsigned data) {
|
|
unsigned tempval = data;
|
|
unsigned temp;
|
|
if (cpu.cpustatus & FLAG_DECIMAL) {
|
|
temp = (cpu.a & 0x0f) + (tempval & 0x0f) + (cpu.cpustatus & FLAG_CARRY);
|
|
if (temp > 9) temp += 6;
|
|
if (temp <= 0x0f)
|
|
temp = (temp & 0xf) + (cpu.a & 0xf0) + (tempval & 0xf0);
|
|
else
|
|
temp = (temp & 0xf) + (cpu.a & 0xf0) + (tempval & 0xf0) + 0x10;
|
|
if (!((cpu.a + tempval + (cpu.cpustatus & FLAG_CARRY)) & 0xff))
|
|
setzero();
|
|
else
|
|
clearzero();
|
|
signcalc(temp);
|
|
if (((cpu.a ^ temp) & 0x80) && !((cpu.a ^ tempval) & 0x80))
|
|
setoverflow();
|
|
else
|
|
clearoverflow();
|
|
if ((temp & 0x1f0) > 0x90) temp += 0x60;
|
|
if ((temp & 0xff0) > 0xf0)
|
|
setcarry();
|
|
else
|
|
clearcarry();
|
|
} else {
|
|
temp = tempval + cpu.a + (cpu.cpustatus & FLAG_CARRY);
|
|
SETFLAGS(temp & 0xff);
|
|
if (!((cpu.a ^ tempval) & 0x80) && ((cpu.a ^ temp) & 0x80))
|
|
setoverflow();
|
|
else
|
|
clearoverflow();
|
|
if (temp > 0xff)
|
|
setcarry();
|
|
else
|
|
clearcarry();
|
|
}
|
|
saveaccum(temp);
|
|
}
|
|
|
|
INLINEOP void _sbc(unsigned data) {
|
|
unsigned tempval = data;
|
|
unsigned temp;
|
|
|
|
temp = cpu.a - tempval - ((cpu.cpustatus & FLAG_CARRY) ^ FLAG_CARRY);
|
|
|
|
if (cpu.cpustatus & FLAG_DECIMAL) {
|
|
unsigned tempval2;
|
|
tempval2 = (cpu.a & 0x0f) - (tempval & 0x0f) - ((cpu.cpustatus & FLAG_CARRY) ^ FLAG_CARRY);
|
|
if (tempval2 & 0x10)
|
|
tempval2 = ((tempval2 - 6) & 0xf) | ((cpu.a & 0xf0) - (tempval & 0xf0) - 0x10);
|
|
else
|
|
tempval2 = (tempval2 & 0xf) | ((cpu.a & 0xf0) - (tempval & 0xf0));
|
|
if (tempval2 & 0x100)
|
|
tempval2 -= 0x60;
|
|
if (temp < 0x100)
|
|
setcarry();
|
|
else
|
|
clearcarry();
|
|
SETFLAGS(temp & 0xff);
|
|
if (((cpu.a ^ temp) & 0x80) && ((cpu.a ^ tempval) & 0x80))
|
|
setoverflow();
|
|
else
|
|
clearoverflow();
|
|
saveaccum(tempval2);
|
|
} else {
|
|
SETFLAGS(temp & 0xff);
|
|
if (temp < 0x100)
|
|
setcarry();
|
|
else
|
|
clearcarry();
|
|
if (((cpu.a ^ temp) & 0x80) && ((cpu.a ^ tempval) & 0x80))
|
|
setoverflow();
|
|
else
|
|
clearoverflow();
|
|
saveaccum(temp);
|
|
}
|
|
|
|
}
|
|
|
|
INLINEOP void adc() {
|
|
unsigned data = getvalue();
|
|
_adc(data);
|
|
}
|
|
|
|
INLINEOP void adcZP() {
|
|
unsigned data = getvalueZP();
|
|
_adc(data);
|
|
|
|
}
|
|
|
|
INLINEOP void op_and() {
|
|
uint32_t result = cpu.a & getvalue();
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void op_andZP() {
|
|
uint32_t result = cpu.a & getvalueZP();
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void asl() {
|
|
uint32_t result = getvalue();
|
|
result <<=1;
|
|
carrycalc(result);
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void aslZP() {
|
|
uint32_t result = getvalueZP();
|
|
result <<=1;
|
|
carrycalc(result);
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void asla() {
|
|
uint32_t result = cpu.a << 1;
|
|
carrycalc(result);
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void bcc() {
|
|
if ((cpu.cpustatus & FLAG_CARRY) == 0) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void bcs() {
|
|
if ((cpu.cpustatus & FLAG_CARRY) == FLAG_CARRY) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void beq() {
|
|
if ((cpu.cpustatus & FLAG_ZERO) == FLAG_ZERO) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void op_bit() {
|
|
unsigned value = getvalue();
|
|
cpu.cpustatus = (cpu.cpustatus & ~(FLAG_SIGN|FLAG_OVERFLOW)) | (value & (FLAG_SIGN|FLAG_OVERFLOW));
|
|
if (!(value & cpu.a))
|
|
setzero();
|
|
else
|
|
clearzero();
|
|
/*
|
|
uint32_t value = getvalue();
|
|
uint32_t result = (uint16_t)cpu.a & value;
|
|
|
|
zerocalc(result);
|
|
cpu.cpustatus = (cpu.cpustatus & 0x3F) | (uint8_t)(value & 0xC0);
|
|
*/
|
|
}
|
|
|
|
INLINEOP void op_bitZP() {
|
|
unsigned value = getvalueZP();
|
|
cpu.cpustatus = (cpu.cpustatus & ~(FLAG_SIGN|FLAG_OVERFLOW)) | (value & (FLAG_SIGN|FLAG_OVERFLOW));
|
|
if (!(value & cpu.a))
|
|
setzero();
|
|
else
|
|
clearzero();
|
|
}
|
|
|
|
INLINEOP void bmi() {
|
|
if ((cpu.cpustatus & FLAG_SIGN) == FLAG_SIGN) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void bne() {
|
|
if ((cpu.cpustatus & FLAG_ZERO) == 0) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void bpl() {
|
|
if ((cpu.cpustatus & FLAG_SIGN) == 0) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void brk() {
|
|
cpu.pc++;
|
|
push16(cpu.pc); //push next instruction address onto stack
|
|
push8(cpu.cpustatus | FLAG_BREAK); //push CPU cpustatus to stack
|
|
setinterrupt(); //set interrupt flag
|
|
cpu.pc = read6502(0xFFFE) | (read6502(0xFFFF) << 8);
|
|
}
|
|
|
|
INLINEOP void bvc() {
|
|
if ((cpu.cpustatus & FLAG_OVERFLOW) == 0) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void bvs() {
|
|
if ((cpu.cpustatus & FLAG_OVERFLOW) == FLAG_OVERFLOW) {
|
|
uint32_t oldpc = cpu.pc;
|
|
cpu.pc += cpu.reladdr;
|
|
if ((oldpc & 0xFF00) != (cpu.pc & 0xFF00)) cpu.ticks += 2; //check if jump crossed a page boundary
|
|
else cpu.ticks++;
|
|
}
|
|
}
|
|
|
|
INLINEOP void clc() {
|
|
clearcarry();
|
|
}
|
|
|
|
INLINEOP void cld() {
|
|
cleardecimal();
|
|
}
|
|
|
|
INLINEOP void cli_() {
|
|
clearinterrupt();
|
|
}
|
|
|
|
INLINEOP void clv() {
|
|
clearoverflow();
|
|
}
|
|
|
|
INLINEOP void cmp() {
|
|
uint16_t value = getvalue();
|
|
uint32_t result = (uint16_t)cpu.a - value;
|
|
|
|
if (cpu.a >= (uint8_t)(value & 0x00FF)) setcarry();
|
|
else clearcarry();
|
|
if (cpu.a == (uint8_t)(value & 0x00FF)) setzero();
|
|
else clearzero();
|
|
signcalc(result);
|
|
}
|
|
|
|
INLINEOP void cmpZP() {
|
|
uint16_t value = getvalueZP();
|
|
uint32_t result = (uint16_t)cpu.a - value;
|
|
|
|
if (cpu.a >= (uint8_t)(value & 0x00FF)) setcarry();
|
|
else clearcarry();
|
|
if (cpu.a == (uint8_t)(value & 0x00FF)) setzero();
|
|
else clearzero();
|
|
signcalc(result);
|
|
}
|
|
|
|
INLINEOP void cpx() {
|
|
uint16_t value = getvalue();
|
|
uint16_t result = (uint16_t)cpu.x - value;
|
|
|
|
if (cpu.x >= (uint8_t)(value & 0x00FF)) setcarry();
|
|
else clearcarry();
|
|
if (cpu.x == (uint8_t)(value & 0x00FF)) setzero();
|
|
else clearzero();
|
|
signcalc(result);
|
|
}
|
|
|
|
INLINEOP void cpxZP() {
|
|
uint16_t value = getvalueZP();
|
|
uint16_t result = (uint16_t)cpu.x - value;
|
|
|
|
if (cpu.x >= (uint8_t)(value & 0x00FF)) setcarry();
|
|
else clearcarry();
|
|
if (cpu.x == (uint8_t)(value & 0x00FF)) setzero();
|
|
else clearzero();
|
|
signcalc(result);
|
|
}
|
|
|
|
INLINEOP void cpy() {
|
|
uint16_t value = getvalue();
|
|
uint16_t result = (uint16_t)cpu.y - value;
|
|
|
|
if (cpu.y >= (uint8_t)(value & 0x00FF)) setcarry();
|
|
else clearcarry();
|
|
if (cpu.y == (uint8_t)(value & 0x00FF)) setzero();
|
|
else clearzero();
|
|
signcalc(result);
|
|
}
|
|
|
|
INLINEOP void cpyZP() {
|
|
uint16_t value = getvalueZP();
|
|
uint16_t result = (uint16_t)cpu.y - value;
|
|
|
|
if (cpu.y >= (uint8_t)(value & 0x00FF)) setcarry();
|
|
else clearcarry();
|
|
if (cpu.y == (uint8_t)(value & 0x00FF)) setzero();
|
|
else clearzero();
|
|
signcalc(result);
|
|
}
|
|
|
|
INLINEOP void dec() {
|
|
uint32_t result = getvalue() - 1;
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void decZP() {
|
|
uint32_t result = getvalueZP() - 1;
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void dex() {
|
|
cpu.x--;
|
|
|
|
zerocalc(cpu.x);
|
|
signcalc(cpu.x);
|
|
}
|
|
|
|
INLINEOP void dey() {
|
|
cpu.y--;
|
|
|
|
zerocalc(cpu.y);
|
|
signcalc(cpu.y);
|
|
}
|
|
|
|
INLINEOP void eor() {
|
|
uint32_t result = cpu.a ^ getvalue();
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void eorZP() {
|
|
uint32_t result = cpu.a ^ getvalueZP();
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void inc() {
|
|
uint32_t result = getvalue() + 1;
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void incZP() {
|
|
uint32_t result = getvalueZP() + 1;
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void inx() {
|
|
cpu.x++;
|
|
|
|
zerocalc(cpu.x);
|
|
signcalc(cpu.x);
|
|
}
|
|
|
|
INLINEOP void iny() {
|
|
cpu.y++;
|
|
|
|
zerocalc(cpu.y);
|
|
signcalc(cpu.y);
|
|
}
|
|
|
|
INLINEOP void jmp() {
|
|
cpu.pc = cpu.ea;
|
|
}
|
|
|
|
INLINEOP void jsr() {
|
|
push16(cpu.pc - 1);
|
|
cpu.pc = cpu.ea;
|
|
}
|
|
|
|
INLINEOP void lda() {
|
|
cpu.a = getvalue();
|
|
|
|
zerocalc(cpu.a);
|
|
signcalc(cpu.a);
|
|
}
|
|
|
|
INLINEOP void ldaZP() {
|
|
cpu.a = getvalueZP();
|
|
|
|
zerocalc(cpu.a);
|
|
signcalc(cpu.a);
|
|
}
|
|
|
|
INLINEOP void ldx() {
|
|
cpu.x = getvalue();
|
|
|
|
zerocalc(cpu.x);
|
|
signcalc(cpu.x);
|
|
}
|
|
|
|
INLINEOP void ldxZP() {
|
|
cpu.x = getvalue();
|
|
|
|
zerocalc(cpu.x);
|
|
signcalc(cpu.x);
|
|
}
|
|
|
|
INLINEOP void ldy() {
|
|
cpu.y = getvalue();
|
|
|
|
zerocalc(cpu.y);
|
|
signcalc(cpu.y);
|
|
}
|
|
|
|
INLINEOP void ldyZP() {
|
|
cpu.y = getvalueZP();
|
|
|
|
zerocalc(cpu.y);
|
|
signcalc(cpu.y);
|
|
}
|
|
|
|
INLINEOP void lsr() {
|
|
uint32_t value = getvalue();
|
|
uint32_t result = value >> 1;
|
|
|
|
if (value & 1) setcarry();
|
|
else clearcarry();
|
|
zerocalc(result);
|
|
//clearsign();
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void lsrZP() {
|
|
uint32_t value = getvalue();
|
|
uint32_t result = value >> 1;
|
|
|
|
if (value & 1) setcarry();
|
|
else clearcarry();
|
|
zerocalc(result);
|
|
//clearsign();
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void lsra() {
|
|
uint8_t value = cpu.a;
|
|
uint8_t result = value >> 1;
|
|
|
|
if (value & 1) setcarry();
|
|
else clearcarry();
|
|
zerocalc(result);
|
|
//clearsign();
|
|
signcalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void ora() {
|
|
|
|
uint32_t result = cpu.a | getvalue();
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void oraZP() {
|
|
|
|
uint32_t result = cpu.a | getvalueZP();
|
|
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void pha() {
|
|
push8(cpu.a);
|
|
}
|
|
|
|
INLINEOP void php() {
|
|
push8(cpu.cpustatus | FLAG_BREAK);
|
|
}
|
|
|
|
INLINEOP void pla() {
|
|
cpu.a = pull8();
|
|
|
|
zerocalc(cpu.a);
|
|
signcalc(cpu.a);
|
|
}
|
|
|
|
INLINEOP void plp() {
|
|
cpu.cpustatus = (pull8() & 0xef) | FLAG_CONSTANT;
|
|
}
|
|
|
|
INLINEOP void rol() {
|
|
uint16_t value = getvalue();
|
|
uint16_t result = (value << 1) | (cpu.cpustatus & FLAG_CARRY);
|
|
|
|
carrycalc(result);
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void rolZP() {
|
|
uint16_t value = getvalueZP();
|
|
uint16_t result = (value << 1) | (cpu.cpustatus & FLAG_CARRY);
|
|
|
|
carrycalc(result);
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void rola() {
|
|
uint16_t value = cpu.a;
|
|
uint16_t result = (value << 1) | (cpu.cpustatus & FLAG_CARRY);
|
|
|
|
carrycalc(result);
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void ror() {
|
|
uint32_t value = getvalue();
|
|
uint16_t result = (value >> 1) | ((cpu.cpustatus & FLAG_CARRY) << 7);
|
|
|
|
if (value & 1) setcarry();
|
|
else clearcarry();
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void rorZP() {
|
|
uint32_t value = getvalueZP();
|
|
uint16_t result = (value >> 1) | ((cpu.cpustatus & FLAG_CARRY) << 7);
|
|
|
|
if (value & 1) setcarry();
|
|
else clearcarry();
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
|
|
putvalue(result);
|
|
}
|
|
|
|
INLINEOP void rora() {
|
|
uint32_t value = cpu.a;
|
|
uint16_t result = (value >> 1) | ((cpu.cpustatus & FLAG_CARRY) << 7);
|
|
|
|
if (value & 1) setcarry();
|
|
else clearcarry();
|
|
zerocalc(result);
|
|
signcalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
|
|
INLINEOP void rti() {
|
|
cpu.cpustatus = pull8();
|
|
cpu.pc = pull16();
|
|
}
|
|
|
|
INLINEOP void rts() {
|
|
cpu.pc = pull16() + 1;
|
|
}
|
|
|
|
INLINEOP void sbc() {
|
|
unsigned data = getvalue();
|
|
_sbc(data);
|
|
}
|
|
|
|
INLINEOP void sbcZP() {
|
|
unsigned data = getvalueZP();
|
|
_sbc(data);
|
|
}
|
|
|
|
|
|
INLINEOP void sec() {
|
|
setcarry();
|
|
}
|
|
|
|
INLINEOP void sed() {
|
|
setdecimal();
|
|
}
|
|
|
|
INLINEOP void sei_() {
|
|
setinterrupt();
|
|
}
|
|
|
|
INLINEOP void sta() {
|
|
putvalue(cpu.a);
|
|
}
|
|
|
|
INLINEOP void stx() {
|
|
putvalue(cpu.x);
|
|
}
|
|
|
|
INLINEOP void sty() {
|
|
putvalue(cpu.y);
|
|
}
|
|
|
|
INLINEOP void tax() {
|
|
cpu.x = cpu.a;
|
|
|
|
zerocalc(cpu.x);
|
|
signcalc(cpu.x);
|
|
}
|
|
|
|
INLINEOP void tay() {
|
|
cpu.y = cpu.a;
|
|
|
|
zerocalc(cpu.y);
|
|
signcalc(cpu.y);
|
|
}
|
|
|
|
INLINEOP void tsx() {
|
|
|
|
cpu.x = cpu.sp;
|
|
|
|
zerocalc(cpu.x);
|
|
signcalc(cpu.x);
|
|
|
|
}
|
|
|
|
INLINEOP void txa() {
|
|
cpu.a = cpu.x;
|
|
|
|
zerocalc(cpu.a);
|
|
signcalc(cpu.a);
|
|
}
|
|
|
|
INLINEOP void txs() {
|
|
cpu.sp = cpu.x;
|
|
}
|
|
|
|
INLINEOP void tya() {
|
|
cpu.a = cpu.y;
|
|
|
|
zerocalc(cpu.a);
|
|
signcalc(cpu.a);
|
|
}
|
|
|
|
|
|
//undocumented instructions
|
|
INLINEOP void lax() {
|
|
lda();
|
|
ldx();
|
|
}
|
|
|
|
INLINEOP void sax() {
|
|
sta();
|
|
stx();
|
|
putvalue(cpu.a & cpu.x);
|
|
}
|
|
|
|
INLINEOP void dcp() {
|
|
dec();
|
|
cmp();
|
|
}
|
|
|
|
INLINEOP void isb() {
|
|
inc();
|
|
sbc();
|
|
}
|
|
|
|
INLINEOP void slo() {
|
|
asl();
|
|
ora();
|
|
}
|
|
|
|
INLINEOP void rla() {
|
|
rol();
|
|
op_and();
|
|
}
|
|
|
|
INLINEOP void sre() {
|
|
lsr();
|
|
eor();
|
|
}
|
|
|
|
INLINEOP void rra() {
|
|
ror();
|
|
adc();
|
|
}
|
|
|
|
INLINEOP void alr() { // (FB)
|
|
|
|
uint32_t result = cpu.a & getvalue() ;
|
|
|
|
if (result & 1) setcarry();
|
|
else clearcarry();
|
|
|
|
result = result / 2;
|
|
|
|
clearsign();
|
|
zerocalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void arr() { //This one took me hours.. finally taken from VICE (FB)
|
|
uint32_t result;
|
|
result = cpu.a & getvalue();
|
|
if (!(cpu.cpustatus & FLAG_DECIMAL)) {
|
|
result >>= 1;
|
|
result |= ((cpu.cpustatus & FLAG_CARRY) << 7);
|
|
signcalc(result);
|
|
zerocalc(result);
|
|
if (result & 0x40) setcarry(); else clearcarry();
|
|
if ((result & 0x40) ^ ((result & 0x20)<<1)) setoverflow(); else clearoverflow();
|
|
saveaccum(result);
|
|
} else {
|
|
uint32_t t2 = result;
|
|
t2 >>= 1;
|
|
t2 |= ((cpu.cpustatus & FLAG_CARRY) << 7);
|
|
if (cpu.cpustatus & FLAG_CARRY) setsign(); else clearsign();
|
|
zerocalc(t2);
|
|
if ((t2 ^ result) & 0x40) setoverflow(); else clearoverflow();
|
|
if (((result & 0xf) + (result & 0x1)) > 0x5) {
|
|
t2 = (t2 & 0xf0) | ((t2 + 0x6) & 0xf);
|
|
}
|
|
if (((result & 0xf0) + (result & 0x10)) > 0x50) {
|
|
t2 = (t2 & 0x0f) | ((t2 + 0x60) & 0xf0);
|
|
setcarry();
|
|
} else {
|
|
clearcarry();
|
|
}
|
|
saveaccum(t2);
|
|
}
|
|
|
|
}
|
|
|
|
INLINEOP void xaa() { // AKA ANE
|
|
const uint32_t val = 0xee; // VICE uses 0xff - but this results in an error in the testsuite (FB)
|
|
uint32_t result = (cpu.a | val) & cpu.x & getvalue();
|
|
signcalc(result);
|
|
zerocalc(result);
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void lxa() {
|
|
const uint32_t val = 0xee;
|
|
uint32_t result = (cpu.a | val) & getvalue();
|
|
signcalc(result);
|
|
zerocalc(result);
|
|
cpu.x = result;
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void axs() { //aka SBX
|
|
uint32_t result = getvalue();
|
|
result = (cpu.a & cpu.x) - result;
|
|
cpu.x = result;
|
|
if (result < 0x100) setcarry(); else clearcarry();
|
|
zerocalc(cpu.x);
|
|
signcalc(cpu.x);
|
|
}
|
|
|
|
INLINEOP void ahx() { //todo (is unstable)
|
|
UNSUPPORTED
|
|
}
|
|
|
|
INLINEOP void anc() {
|
|
uint32_t result = cpu.a & getvalue();
|
|
signcalc(result)
|
|
zerocalc(result);
|
|
if (cpu.cpustatus & FLAG_SIGN) setcarry(); else clearcarry();
|
|
saveaccum(result);
|
|
}
|
|
|
|
INLINEOP void las() {
|
|
uint32_t result = cpu.sp & getvalue();
|
|
signcalc(result);
|
|
zerocalc(result);
|
|
cpu.sp = result;
|
|
cpu.x = result;
|
|
saveaccum(result);
|
|
}
|
|
|
|
/********************************************************************************************************************/
|
|
/* OPCODES */
|
|
/********************************************************************************************************************/
|
|
|
|
OPCODE void opKIL(void) {
|
|
printf("CPU JAM @ $%d\n",cpu.pc);
|
|
cpu_reset();
|
|
}
|
|
|
|
OPCODE void op0x0(void) {
|
|
cpu.ticks = 7;
|
|
imp();
|
|
brk();
|
|
}
|
|
|
|
OPCODE void op0x1(void) {
|
|
cpu.ticks = 6;
|
|
indx();
|
|
ora();
|
|
}
|
|
|
|
OPCODE void op0x3(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indx();
|
|
slo();
|
|
}
|
|
|
|
OPCODE void op0x4(void) { //nop read zeropage
|
|
cpu.ticks = 3;
|
|
zp();
|
|
}
|
|
|
|
OPCODE void op0x5(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
oraZP();
|
|
}
|
|
|
|
OPCODE void op0x6(void) {
|
|
cpu.ticks = 5;
|
|
zp();
|
|
aslZP();
|
|
}
|
|
|
|
OPCODE void op0x7(void) { //undocumented SLO
|
|
cpu.ticks = 5;
|
|
zp();
|
|
slo();
|
|
}
|
|
|
|
OPCODE void op0x8(void) {
|
|
cpu.ticks = 3;
|
|
imp();
|
|
php();
|
|
}
|
|
|
|
OPCODE void op0x9(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
ora();
|
|
}
|
|
|
|
OPCODE void op0xA(void) {
|
|
cpu.ticks = 2;
|
|
//acc();
|
|
asla();
|
|
}
|
|
|
|
OPCODE void op0xB(void) { //undocumented
|
|
cpu.ticks = 2;
|
|
imm();
|
|
anc();
|
|
}
|
|
|
|
OPCODE void op0xC(void) { //nop
|
|
cpu.ticks = 4;
|
|
abso();
|
|
}
|
|
|
|
OPCODE void op0xD(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
ora();
|
|
}
|
|
|
|
OPCODE void op0xE(void) {
|
|
cpu.ticks = 6;
|
|
abso();
|
|
asl();
|
|
}
|
|
|
|
OPCODE void op0xF(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
abso();
|
|
slo();
|
|
}
|
|
|
|
OPCODE void op0x10(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
bpl();
|
|
}
|
|
|
|
OPCODE void op0x11(void) {
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
ora();
|
|
}
|
|
|
|
OPCODE void op0x13(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indy();
|
|
slo();
|
|
}
|
|
|
|
OPCODE void op0x14(void) { //nop
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
}
|
|
|
|
OPCODE void op0x15(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
ora();
|
|
}
|
|
|
|
OPCODE void op0x16(void) {
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
asl();
|
|
}
|
|
|
|
OPCODE void op0x17(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
//zpy(); bug
|
|
zpx();
|
|
slo();
|
|
}
|
|
|
|
OPCODE void op0x18(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
clc();
|
|
}
|
|
|
|
OPCODE void op0x19(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
ora();
|
|
}
|
|
|
|
OPCODE void op0x1A(void) { //nop
|
|
cpu.ticks = 2;
|
|
}
|
|
|
|
OPCODE void op0x1B(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absy();
|
|
slo();
|
|
}
|
|
|
|
OPCODE void op0x1C(void) { //nop
|
|
cpu.ticks = 4;
|
|
//();
|
|
}
|
|
|
|
OPCODE void op0x1D(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
ora();
|
|
}
|
|
|
|
OPCODE void op0x1E(void) {
|
|
cpu.ticks = 7;
|
|
absx();
|
|
asl();
|
|
}
|
|
|
|
|
|
OPCODE void op0x1F(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absx();
|
|
slo();
|
|
}
|
|
|
|
OPCODE void op0x20(void) {
|
|
cpu.ticks = 6;
|
|
abso();
|
|
jsr();
|
|
}
|
|
|
|
OPCODE void op0x21(void) {
|
|
cpu.ticks = 6;
|
|
indx();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x23(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indx();
|
|
rla();
|
|
}
|
|
|
|
OPCODE void op0x24(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
op_bitZP();
|
|
}
|
|
|
|
OPCODE void op0x25(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x26(void) {
|
|
cpu.ticks = 5;
|
|
zp();
|
|
rolZP();
|
|
}
|
|
|
|
OPCODE void op0x27(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
zp();
|
|
rla();
|
|
}
|
|
|
|
OPCODE void op0x28(void) {
|
|
cpu.ticks = 4;
|
|
imp();
|
|
plp();
|
|
}
|
|
|
|
OPCODE void op0x29(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x2A(void) {
|
|
cpu.ticks = 2;
|
|
//acc();
|
|
rola();
|
|
}
|
|
|
|
OPCODE void op0x2B(void) { //undocumented
|
|
cpu.ticks = 2;
|
|
imm();
|
|
anc();
|
|
}
|
|
|
|
OPCODE void op0x2C(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
op_bit();
|
|
}
|
|
|
|
OPCODE void op0x2D(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x2E(void) {
|
|
cpu.ticks = 6;
|
|
abso();
|
|
rol();
|
|
}
|
|
|
|
OPCODE void op0x2F(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
abso();
|
|
rla();
|
|
}
|
|
|
|
OPCODE void op0x30(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
bmi();
|
|
}
|
|
|
|
OPCODE void op0x31(void) {
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x33(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indy();
|
|
rla();
|
|
}
|
|
|
|
OPCODE void op0x34(void) { //nop
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
}
|
|
|
|
OPCODE void op0x35(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x36(void) {
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
rol();
|
|
}
|
|
|
|
OPCODE void op0x37(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
rla();
|
|
}
|
|
|
|
OPCODE void op0x38(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
sec();
|
|
}
|
|
|
|
OPCODE void op0x39(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x3A(void) { //nop
|
|
cpu.ticks = 2;
|
|
}
|
|
|
|
OPCODE void op0x3B(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absy();
|
|
rla();
|
|
}
|
|
|
|
OPCODE void op0x3C(void) { //nop
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
}
|
|
|
|
OPCODE void op0x3D(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
op_and();
|
|
}
|
|
|
|
OPCODE void op0x3E(void) {
|
|
cpu.ticks = 7;
|
|
absx();
|
|
rol();
|
|
}
|
|
|
|
OPCODE void op0x3F(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absx();
|
|
rla();
|
|
}
|
|
|
|
OPCODE void op0x40(void) {
|
|
cpu.ticks = 6;
|
|
imp();
|
|
rti();
|
|
}
|
|
|
|
OPCODE void op0x41(void) {
|
|
cpu.ticks = 6;
|
|
indx();
|
|
eor();
|
|
}
|
|
|
|
OPCODE void op0x43(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indx();
|
|
sre();
|
|
}
|
|
|
|
OPCODE void op0x44(void) { //nop
|
|
cpu.ticks = 3;
|
|
zp();
|
|
}
|
|
|
|
OPCODE void op0x45(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
eorZP();
|
|
}
|
|
|
|
OPCODE void op0x46(void) {
|
|
cpu.ticks = 5;
|
|
zp();
|
|
lsrZP();
|
|
}
|
|
|
|
OPCODE void op0x47(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
zp();
|
|
sre();
|
|
}
|
|
|
|
OPCODE void op0x48(void) {
|
|
cpu.ticks = 3;
|
|
imp();
|
|
pha();
|
|
}
|
|
|
|
OPCODE void op0x49(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
eor();
|
|
}
|
|
|
|
OPCODE void op0x4A(void) {
|
|
cpu.ticks = 2;
|
|
// acc();
|
|
lsra();
|
|
}
|
|
|
|
OPCODE void op0x4B(void) { //undocumented
|
|
cpu.ticks = 2;
|
|
imm();
|
|
alr();
|
|
}
|
|
|
|
OPCODE void op0x4C(void) {
|
|
cpu.ticks = 3;
|
|
abso();
|
|
jmp();
|
|
}
|
|
|
|
OPCODE void op0x4D(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
eor();
|
|
}
|
|
|
|
OPCODE void op0x4E(void) {
|
|
cpu.ticks = 6;
|
|
abso();
|
|
lsr();
|
|
}
|
|
|
|
OPCODE void op0x4F(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
abso();
|
|
sre();
|
|
}
|
|
|
|
OPCODE void op0x50(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
bvc();
|
|
}
|
|
|
|
OPCODE void op0x51(void) {
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
eor();
|
|
}
|
|
|
|
OPCODE void op0x53(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
//zp(); BUG
|
|
indy();
|
|
sre();
|
|
}
|
|
|
|
OPCODE void op0x54(void) { //nop
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
}
|
|
|
|
OPCODE void op0x55(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
eor();
|
|
}
|
|
|
|
OPCODE void op0x56(void) {
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
lsr();
|
|
}
|
|
|
|
OPCODE void op0x57(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
sre();
|
|
}
|
|
|
|
OPCODE void op0x58(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
cli_();
|
|
}
|
|
|
|
OPCODE void op0x59(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
eor();
|
|
}
|
|
|
|
OPCODE void op0x5A(void) { //nop
|
|
cpu.ticks = 2;
|
|
}
|
|
|
|
OPCODE void op0x5B(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absy();
|
|
sre();
|
|
}
|
|
|
|
OPCODE void op0x5C(void) { //nop
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
}
|
|
|
|
OPCODE void op0x5D(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
eor();
|
|
}
|
|
|
|
OPCODE void op0x5E(void) {
|
|
cpu.ticks = 7;
|
|
absx();
|
|
lsr();
|
|
}
|
|
|
|
OPCODE void op0x5F(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absx();
|
|
sre();
|
|
}
|
|
|
|
OPCODE void op0x60(void) {
|
|
cpu.ticks = 6;
|
|
imp();
|
|
rts();
|
|
}
|
|
|
|
OPCODE void op0x61(void) {
|
|
cpu.ticks = 6;
|
|
indx();
|
|
adc();
|
|
}
|
|
|
|
OPCODE void op0x63(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indx();
|
|
rra();
|
|
}
|
|
|
|
OPCODE void op0x64(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
}
|
|
|
|
OPCODE void op0x65(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
adcZP();
|
|
}
|
|
|
|
OPCODE void op0x66(void) {
|
|
cpu.ticks = 5;
|
|
zp();
|
|
rorZP();
|
|
}
|
|
|
|
OPCODE void op0x67(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
zp();
|
|
rra();
|
|
}
|
|
|
|
OPCODE void op0x68(void) {
|
|
cpu.ticks = 4;
|
|
imp();
|
|
pla();
|
|
}
|
|
|
|
OPCODE void op0x69(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
adc();
|
|
}
|
|
|
|
OPCODE void op0x6A(void) {
|
|
cpu.ticks = 2;
|
|
// acc();
|
|
rora();
|
|
}
|
|
|
|
OPCODE void op0x6B(void) { //undocumented
|
|
cpu.ticks = 2;
|
|
imm();
|
|
arr();
|
|
}
|
|
|
|
OPCODE void op0x6C(void) {
|
|
cpu.ticks = 5;
|
|
ind();
|
|
jmp();
|
|
}
|
|
|
|
OPCODE void op0x6D(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
adc();
|
|
}
|
|
|
|
OPCODE void op0x6E(void) {
|
|
cpu.ticks = 6;
|
|
abso();
|
|
ror();
|
|
}
|
|
|
|
OPCODE void op0x6F(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
abso();
|
|
rra();
|
|
}
|
|
|
|
OPCODE void op0x70(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
bvs();
|
|
}
|
|
|
|
OPCODE void op0x71(void) {
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
adc();
|
|
}
|
|
|
|
OPCODE void op0x73(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indy();
|
|
rra();
|
|
}
|
|
|
|
OPCODE void op0x74(void) { //nop
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
}
|
|
|
|
OPCODE void op0x75(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
adc();
|
|
}
|
|
|
|
OPCODE void op0x76(void) {
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
ror();
|
|
}
|
|
|
|
OPCODE void op0x77(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
rra();
|
|
}
|
|
|
|
OPCODE void op0x78(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
sei_();
|
|
}
|
|
|
|
OPCODE void op0x79(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
adc();
|
|
}
|
|
|
|
OPCODE void op0x7A(void) { //nop
|
|
cpu.ticks = 2;
|
|
}
|
|
|
|
OPCODE void op0x7B(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absy();
|
|
rra();
|
|
}
|
|
|
|
OPCODE void op0x7C(void) { //nop
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
}
|
|
|
|
OPCODE void op0x7D(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
adc();
|
|
}
|
|
|
|
OPCODE void op0x7E(void) {
|
|
cpu.ticks = 7;
|
|
absx();
|
|
ror();
|
|
}
|
|
|
|
OPCODE void op0x7F(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absx();
|
|
rra();
|
|
}
|
|
|
|
OPCODE void op0x80(void) { //nop
|
|
cpu.ticks = 2;
|
|
imm();
|
|
}
|
|
|
|
OPCODE void op0x81(void) {
|
|
cpu.ticks = 6;
|
|
indx();
|
|
sta();
|
|
}
|
|
|
|
OPCODE void op0x82(void) { //nop
|
|
cpu.ticks = 2;
|
|
imm();
|
|
}
|
|
|
|
OPCODE void op0x83(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
indx();
|
|
sax();
|
|
}
|
|
|
|
OPCODE void op0x84(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
sty();
|
|
}
|
|
|
|
OPCODE void op0x85(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
sta();
|
|
}
|
|
|
|
OPCODE void op0x86(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
stx();
|
|
}
|
|
|
|
OPCODE void op0x87(void) { //undocumented
|
|
cpu.ticks = 3;
|
|
zp();
|
|
sax();
|
|
}
|
|
|
|
OPCODE void op0x88(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
dey();
|
|
}
|
|
|
|
OPCODE void op0x89(void) { //nop
|
|
cpu.ticks = 2;
|
|
imm();
|
|
}
|
|
|
|
OPCODE void op0x8A(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
txa();
|
|
}
|
|
|
|
OPCODE void op0x8B(void) { //undocumented
|
|
cpu.ticks = 2;
|
|
imm();
|
|
xaa();
|
|
}
|
|
|
|
OPCODE void op0x8C(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
sty();
|
|
}
|
|
|
|
OPCODE void op0x8D(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
sta();
|
|
}
|
|
|
|
OPCODE void op0x8E(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
stx();
|
|
}
|
|
|
|
OPCODE void op0x8F(void) { //undocumented
|
|
cpu.ticks = 4;
|
|
abso();
|
|
sax();
|
|
}
|
|
|
|
OPCODE void op0x90(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
bcc();
|
|
}
|
|
|
|
OPCODE void op0x91(void) {
|
|
cpu.ticks = 6;
|
|
indy();
|
|
sta();
|
|
}
|
|
|
|
OPCODE void op0x93(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
indy();
|
|
ahx();
|
|
}
|
|
|
|
OPCODE void op0x94(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
sty();
|
|
}
|
|
|
|
OPCODE void op0x95(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
sta();
|
|
}
|
|
|
|
OPCODE void op0x96(void) {
|
|
cpu.ticks = 4;
|
|
zpy();
|
|
stx();
|
|
}
|
|
|
|
OPCODE void op0x97(void) { //undocumented
|
|
cpu.ticks = 4;
|
|
zpy();
|
|
sax();
|
|
}
|
|
|
|
OPCODE void op0x98(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
tya();
|
|
}
|
|
|
|
OPCODE void op0x99(void) {
|
|
cpu.ticks = 5;
|
|
absy();
|
|
sta();
|
|
}
|
|
|
|
OPCODE void op0x9A(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
txs();
|
|
}
|
|
|
|
OPCODE void op0x9B(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
absy();
|
|
//tas();
|
|
UNSUPPORTED;
|
|
}
|
|
|
|
OPCODE void op0x9C(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
absy();
|
|
//shy();
|
|
UNSUPPORTED;
|
|
}
|
|
|
|
OPCODE void op0x9D(void) {
|
|
cpu.ticks = 5;
|
|
absx();
|
|
sta();
|
|
}
|
|
|
|
OPCODE void op0x9E(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
absx();
|
|
//shx();
|
|
}
|
|
|
|
OPCODE void op0x9F(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
absx();
|
|
ahx();
|
|
}
|
|
|
|
OPCODE void op0xA0(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
ldy();
|
|
}
|
|
|
|
OPCODE void op0xA1(void) {
|
|
cpu.ticks = 6;
|
|
indx();
|
|
lda();
|
|
}
|
|
|
|
OPCODE void op0xA2(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
ldx();
|
|
}
|
|
|
|
OPCODE void op0xA3(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
indx();
|
|
lax();
|
|
}
|
|
|
|
OPCODE void op0xA4(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
ldyZP();
|
|
}
|
|
|
|
OPCODE void op0xA5(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
ldaZP();
|
|
}
|
|
|
|
OPCODE void op0xA6(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
ldxZP();
|
|
}
|
|
|
|
OPCODE void op0xA7(void) { //undocumented
|
|
cpu.ticks = 3;
|
|
zp();
|
|
lax();
|
|
}
|
|
|
|
OPCODE void op0xA8(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
tay();
|
|
}
|
|
|
|
OPCODE void op0xA9(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
lda();
|
|
}
|
|
|
|
OPCODE void op0xAA(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
tax();
|
|
}
|
|
|
|
OPCODE void op0xAB(void) { //undocumented
|
|
cpu.ticks = 2;
|
|
imm();
|
|
lxa();
|
|
}
|
|
|
|
OPCODE void op0xAC(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
ldy();
|
|
}
|
|
|
|
OPCODE void op0xAD(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
lda();
|
|
}
|
|
|
|
OPCODE void op0xAE(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
ldx();
|
|
}
|
|
|
|
OPCODE void op0xAF(void) { //undocumented
|
|
cpu.ticks = 4;
|
|
abso();
|
|
lax();
|
|
}
|
|
|
|
OPCODE void op0xB0(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
bcs();
|
|
}
|
|
|
|
OPCODE void op0xB1(void) {
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
lda();
|
|
}
|
|
|
|
OPCODE void op0xB3(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
lax();
|
|
}
|
|
|
|
OPCODE void op0xB4(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
ldy();
|
|
}
|
|
|
|
OPCODE void op0xB5(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
lda();
|
|
}
|
|
|
|
OPCODE void op0xB6(void) {
|
|
cpu.ticks = 4;
|
|
zpy();
|
|
ldx();
|
|
}
|
|
|
|
OPCODE void op0xB7(void) { //undocumented
|
|
cpu.ticks = 4;
|
|
zpy();
|
|
lax();
|
|
}
|
|
|
|
OPCODE void op0xB8(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
clv();
|
|
}
|
|
|
|
OPCODE void op0xB9(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
lda();
|
|
}
|
|
|
|
OPCODE void op0xBA(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
tsx();
|
|
}
|
|
|
|
OPCODE void op0xBB(void) { //undocumented
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
las();
|
|
}
|
|
|
|
OPCODE void op0xBC(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
ldy();
|
|
}
|
|
|
|
OPCODE void op0xBD(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
lda();
|
|
}
|
|
|
|
OPCODE void op0xBE(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
ldx();
|
|
}
|
|
|
|
OPCODE void op0xBF(void) { //undocumented
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
lax();
|
|
}
|
|
|
|
OPCODE void op0xC0(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
cpy();
|
|
}
|
|
|
|
OPCODE void op0xC1(void) {
|
|
cpu.ticks = 6;
|
|
indx();
|
|
cmp();
|
|
}
|
|
|
|
OPCODE void op0xC2(void) { //nop
|
|
cpu.ticks = 2;
|
|
imm();
|
|
}
|
|
|
|
OPCODE void op0xC3(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indx();
|
|
dcp();
|
|
}
|
|
|
|
OPCODE void op0xC4(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
cpyZP();
|
|
}
|
|
|
|
OPCODE void op0xC5(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
cmpZP();
|
|
}
|
|
|
|
OPCODE void op0xC6(void) {
|
|
cpu.ticks = 5;
|
|
zp();
|
|
decZP();
|
|
}
|
|
|
|
OPCODE void op0xC7(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
zp();
|
|
dcp();
|
|
}
|
|
|
|
OPCODE void op0xC8(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
iny();
|
|
}
|
|
|
|
OPCODE void op0xC9(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
cmp();
|
|
}
|
|
|
|
OPCODE void op0xCA(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
dex();
|
|
}
|
|
|
|
OPCODE void op0xCB(void) { //undocumented
|
|
cpu.ticks = 2;
|
|
imm();
|
|
axs();
|
|
}
|
|
|
|
OPCODE void op0xCC(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
cpy();
|
|
}
|
|
|
|
OPCODE void op0xCD(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
cmp();
|
|
}
|
|
|
|
OPCODE void op0xCE(void) {
|
|
cpu.ticks = 6;
|
|
abso();
|
|
dec();
|
|
}
|
|
|
|
OPCODE void op0xCF(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
abso();
|
|
dcp();
|
|
}
|
|
|
|
OPCODE void op0xD0(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
bne();
|
|
}
|
|
|
|
OPCODE void op0xD1(void) {
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
cmp();
|
|
}
|
|
|
|
OPCODE void op0xD3(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indy();
|
|
dcp();
|
|
}
|
|
|
|
OPCODE void op0xD4(void) { //nop
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
}
|
|
|
|
OPCODE void op0xD5(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
cmp();
|
|
}
|
|
|
|
OPCODE void op0xD6(void) {
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
dec();
|
|
}
|
|
|
|
OPCODE void op0xD7(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
dcp();
|
|
}
|
|
|
|
OPCODE void op0xD8(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
cld();
|
|
}
|
|
|
|
OPCODE void op0xD9(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
cmp();
|
|
}
|
|
|
|
OPCODE void op0xDA(void) { //nop
|
|
cpu.ticks = 2;
|
|
}
|
|
|
|
OPCODE void op0xDB(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absy();
|
|
dcp();
|
|
}
|
|
|
|
OPCODE void op0xDC(void) { //nop
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
}
|
|
|
|
OPCODE void op0xDD(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
cmp();
|
|
}
|
|
|
|
OPCODE void op0xDE(void) {
|
|
cpu.ticks = 7;
|
|
absx();
|
|
dec();
|
|
}
|
|
|
|
OPCODE void op0xDF(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absx();
|
|
dcp();
|
|
}
|
|
|
|
OPCODE void op0xE0(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
cpx();
|
|
}
|
|
|
|
OPCODE void op0xE1(void) {
|
|
cpu.ticks = 5;
|
|
indx();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xE2(void) { //NOP
|
|
cpu.ticks = 2;
|
|
imm();
|
|
}
|
|
|
|
OPCODE void op0xE3(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indx();
|
|
isb();
|
|
}
|
|
|
|
OPCODE void op0xE4(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
cpxZP();
|
|
}
|
|
|
|
OPCODE void op0xE5(void) {
|
|
cpu.ticks = 3;
|
|
zp();
|
|
sbcZP();
|
|
}
|
|
|
|
OPCODE void op0xE6(void) {
|
|
cpu.ticks = 5;
|
|
zp();
|
|
incZP();
|
|
}
|
|
|
|
OPCODE void op0xE7(void) { //undocumented
|
|
cpu.ticks = 5;
|
|
zp();
|
|
isb();
|
|
}
|
|
|
|
OPCODE void op0xE8(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
inx();
|
|
}
|
|
|
|
OPCODE void op0xE9(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xEA(void) {
|
|
cpu.ticks = 2;
|
|
}
|
|
|
|
OPCODE void op0xEB(void) {
|
|
cpu.ticks = 2;
|
|
imm();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xEC(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
cpx();
|
|
}
|
|
|
|
OPCODE void op0xED(void) {
|
|
cpu.ticks = 4;
|
|
abso();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xEE(void) {
|
|
cpu.ticks = 6;
|
|
abso();
|
|
inc();
|
|
}
|
|
|
|
OPCODE void op0xEF(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
abso();
|
|
isb();
|
|
}
|
|
|
|
OPCODE void op0xF0(void) {
|
|
cpu.ticks = 2;
|
|
rel();
|
|
beq();
|
|
}
|
|
|
|
OPCODE void op0xF1(void) {
|
|
cpu.ticks = 5;
|
|
indy_t();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xF3(void) { //undocumented
|
|
cpu.ticks = 8;
|
|
indy();
|
|
isb();
|
|
}
|
|
|
|
OPCODE void op0xF4(void) { //nop
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
}
|
|
|
|
OPCODE void op0xF5(void) {
|
|
cpu.ticks = 4;
|
|
zpx();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xF6(void) {
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
inc();
|
|
}
|
|
|
|
OPCODE void op0xF7(void) { //undocumented
|
|
cpu.ticks = 6;
|
|
zpx();
|
|
isb();
|
|
}
|
|
|
|
OPCODE void op0xF8(void) {
|
|
cpu.ticks = 2;
|
|
imp();
|
|
sed();
|
|
}
|
|
|
|
OPCODE void op0xF9(void) {
|
|
cpu.ticks = 4;
|
|
absy_t();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xFA(void) { //nop
|
|
cpu.ticks = 2;
|
|
}
|
|
|
|
OPCODE void op0xFB(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absy();
|
|
isb();
|
|
}
|
|
|
|
OPCODE void op0xFC(void) { //nop
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
}
|
|
|
|
OPCODE void op0xFD(void) {
|
|
cpu.ticks = 4;
|
|
absx_t();
|
|
sbc();
|
|
}
|
|
|
|
OPCODE void op0xFE(void) {
|
|
cpu.ticks = 7;
|
|
absx();
|
|
inc();
|
|
}
|
|
|
|
OPCODE void op0xFF(void) { //undocumented
|
|
cpu.ticks = 7;
|
|
absx();
|
|
isb();
|
|
}
|
|
|
|
OPCODE void opPATCHD2(void) {
|
|
#if APPLY_PATCHES
|
|
patchLOAD();
|
|
#else
|
|
opKIL();
|
|
#endif
|
|
}
|
|
|
|
OPCODE void opPATCHF2(void) {
|
|
#if APPLY_PATCHES
|
|
patchSAVE();
|
|
#else
|
|
opKIL();
|
|
#endif
|
|
}
|
|
|
|
typedef void (*op_ptr_t)( void );
|
|
|
|
static const op_ptr_t opcodetable[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
|
/* 0 */ op0x0 , op0x1, opKIL , op0x3, op0x4 , op0x5, op0x6, op0x7, op0x8, op0x9, op0xA, op0xB , op0xC , op0xD , op0xE , op0xF,
|
|
/* 1 */ op0x10, op0x11, opKIL , op0x13, op0x14, op0x15, op0x16, op0x17, op0x18, op0x19, op0x1A, op0x1B, op0x1C, op0x1D, op0x1E, op0x1F,
|
|
/* 2 */ op0x20, op0x21, opKIL , op0x23, op0x24, op0x25, op0x26, op0x27, op0x28, op0x29, op0x2A, op0x2B, op0x2C, op0x2D, op0x2E, op0x2F,
|
|
/* 3 */ op0x30, op0x31, opKIL , op0x33, op0x34, op0x35, op0x36, op0x37, op0x38, op0x39, op0x3A, op0x3B, op0x3C, op0x3D, op0x3E, op0x3F,
|
|
/* 4 */ op0x40, op0x41, opKIL , op0x43, op0x44, op0x45, op0x46, op0x47, op0x48, op0x49, op0x4A, op0x4B, op0x4C, op0x4D, op0x4E, op0x4F,
|
|
/* 5 */ op0x50, op0x51, opKIL , op0x53, op0x54, op0x55, op0x56, op0x57, op0x58, op0x59, op0x5A, op0x5B, op0x5C, op0x5D, op0x5E, op0x5F,
|
|
/* 6 */ op0x60, op0x61, opKIL , op0x63, op0x64, op0x65, op0x66, op0x67, op0x68, op0x69, op0x6A, op0x6B, op0x6C, op0x6D, op0x6E, op0x6F,
|
|
/* 7 */ op0x70, op0x71, opKIL , op0x73, op0x74, op0x75, op0x76, op0x77, op0x78, op0x79, op0x7A, op0x7B, op0x7C, op0x7D, op0x7E, op0x7F,
|
|
/* 8 */ op0x80, op0x81, op0x82, op0x83, op0x84, op0x85, op0x86, op0x87, op0x88, op0x89, op0x8A, op0x8B, op0x8C, op0x8D, op0x8E, op0x8F,
|
|
/* 9 */ op0x90, op0x91, opKIL , op0x93, op0x94, op0x95, op0x96, op0x97, op0x98, op0x99, op0x9A, op0x9B, op0x9C, op0x9D, op0x9E, op0x9F,
|
|
/* A */ op0xA0, op0xA1, op0xA2, op0xA3, op0xA4, op0xA5, op0xA6, op0xA7, op0xA8, op0xA9, op0xAA, op0xAB, op0xAC, op0xAD, op0xAE, op0xAF,
|
|
/* B */ op0xB0, op0xB1, opKIL , op0xB3, op0xB4, op0xB5, op0xB6, op0xB7, op0xB8, op0xB9, op0xBA, op0xBB, op0xBC, op0xBD, op0xBE, op0xBF,
|
|
/* C */ op0xC0, op0xC1, op0xC2, op0xC3, op0xC4, op0xC5, op0xC6, op0xC7, op0xC8, op0xC9, op0xCA, op0xCB, op0xCC, op0xCD, op0xCE, op0xCF,
|
|
/* D */ op0xD0, op0xD1, opPATCHD2 , op0xD3, op0xD4, op0xD5, op0xD6, op0xD7, op0xD8, op0xD9, op0xDA, op0xDB, op0xDC, op0xDD, op0xDE, op0xDF,
|
|
/* E */ op0xE0, op0xE1, op0xE2, op0xE3, op0xE4, op0xE5, op0xE6, op0xE7, op0xE8, op0xE9, op0xEA, op0xEB, op0xEC, op0xED, op0xEE, op0xEF,
|
|
/* F */ op0xF0, op0xF1, opPATCHF2 , op0xF3, op0xF4, op0xF5, op0xF6, op0xF7, op0xF8, op0xF9, op0xFA, op0xFB, op0xFC, op0xFD, op0xFE, op0xFF
|
|
};
|
|
|
|
static const uint8_t cyclesTable[256] =
|
|
{
|
|
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, // $00
|
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 5, 5, 7, 7, // $10
|
|
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, // $20
|
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 5, 5, 7, 7, // $30
|
|
6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, // $40
|
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 5, 5, 7, 7, // $50
|
|
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, // $60
|
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 5, 5, 7, 7, // $70
|
|
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, // $80
|
|
2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, // $90
|
|
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, // $A0
|
|
2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 5, 4, 4, 4, 4, // $B0
|
|
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, // $C0
|
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 5, 5, 7, 7, // $D0
|
|
2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, // $E0
|
|
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 5, 5, 7, 7 // $F0
|
|
};
|
|
|
|
static const uint8_t writeCycleTable[256] =
|
|
{
|
|
3, 0, 0, 2, 0, 0, 2, 2, 1, 0, 0, 0, 0, 0, 2, 2, // $00
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, // $10
|
|
2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, // $20
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, // $30
|
|
0, 0, 0, 2, 0, 0, 2, 2, 1, 0, 0, 0, 0, 0, 2, 2, // $40
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, // $50
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, // $60
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, // $70
|
|
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, // $80
|
|
0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, // $90
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // $A0
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // $B0
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, // $C0
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2, // $D0
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, // $E0
|
|
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 2, 0, 0, 2, 2 // $F0
|
|
};
|
|
|
|
|
|
void cpu_nmi() {
|
|
cpu.nmiLine = 1;
|
|
printf("nmiLine=1\n");
|
|
}
|
|
void cpu_clearNmi() {
|
|
cpu.nmi = 0;
|
|
}
|
|
|
|
void cpu_nmi_do() {
|
|
if (cpu.nmi) return;
|
|
cpu.nmi = 1;
|
|
cpu.nmiLine = 0;
|
|
push16(cpu.pc);
|
|
push8(cpu.cpustatus & ~FLAG_BREAK);
|
|
cpu.cpustatus |= FLAG_INTERRUPT;
|
|
cpu.pc = read6502(0xFFFA) | (read6502(0xFFFB) << 8);
|
|
cpu.ticks = 7;
|
|
}
|
|
|
|
static inline void cpu_irq() {
|
|
push16(cpu.pc);
|
|
push8(cpu.cpustatus & ~FLAG_BREAK);
|
|
cpu.cpustatus |= FLAG_INTERRUPT;
|
|
cpu.pc = read6502(0xFFFE) | (read6502(0xFFFF) << 8);
|
|
cpu.ticks = 7;
|
|
}
|
|
|
|
inline void cia_clock(void) __attribute__((always_inline));
|
|
|
|
void cia_clock(void) {
|
|
cia1_clock(1);
|
|
cia2_clock(1);
|
|
}
|
|
|
|
void cia_clockt(int ticks) {
|
|
cia1_clock(ticks);
|
|
cia2_clock(ticks);
|
|
}
|
|
|
|
void cpu_clock(int cycles) {
|
|
static int c = 0;
|
|
static int writeCycles = 0;
|
|
cpu.lineCyclesAbs += cycles;
|
|
c+=cycles;
|
|
while (c > 0) {
|
|
|
|
uint8_t opcode ;
|
|
cpu.ticks = 0;
|
|
|
|
//NMI
|
|
|
|
if (!cpu.nmi && ((cpu.cia2.R[0x0D] & 0x80) | cpu.nmiLine)) {
|
|
cpu_nmi_do();
|
|
goto noOpcode;
|
|
}
|
|
|
|
if (!(cpu.cpustatus & FLAG_INTERRUPT)) {
|
|
if (((cpu.vic.R[0x19] | cpu.cia1.R[0x0D]) & 0x80)) {
|
|
cpu_irq();
|
|
goto noOpcode;
|
|
}
|
|
}
|
|
|
|
cpu.cpustatus |= FLAG_CONSTANT;
|
|
opcode = read6502(cpu.pc++);
|
|
opcodetable[opcode]();
|
|
writeCycles = writeCycleTable[opcode];
|
|
noOpcode:
|
|
|
|
cia_clockt(cpu.ticks);
|
|
c-= cpu.ticks;
|
|
cpu.lineCycles += cpu.ticks;
|
|
#define US_C64_CYCLE (1000000.0f / CLOCKSPEED) // Duration (µs) of a C64 Cycle
|
|
if (cpu.exactTiming) {
|
|
uint32_t t = cpu.lineCycles * US_C64_CYCLE;
|
|
while (fbmicros() - cpu.lineStartTime < t){;}
|
|
}
|
|
|
|
};
|
|
|
|
return;
|
|
}
|
|
|
|
//Enable "ExactTiming" Mode
|
|
void cpu_setExactTiming() {
|
|
if (!cpu.exactTiming) {
|
|
//enable exact timing
|
|
setAudioOff();
|
|
vic_displaySimpleModeScreen();
|
|
|
|
}
|
|
cpu.exactTiming = 1;
|
|
cpu.exactTimingStartTime = fbmicros();
|
|
//cpu.exactTiming = 0;
|
|
}
|
|
|
|
//Disable "ExactTiming" Mode
|
|
void cpu_disableExactTiming() {
|
|
cpu.exactTiming = 0;
|
|
setAudioOn();
|
|
}
|
|
|
|
void cpu_reset() {
|
|
enableCycleCounter();
|
|
cpu.exactTiming = 0;
|
|
cpu.nmi = 0;
|
|
cpu.cpustatus = FLAG_CONSTANT;
|
|
cpu.pc = read6502(0xFFFC) | (read6502(0xFFFD) << 8);
|
|
cpu.sp = 0xFD;
|
|
} |