blob: 8dde563abdb8996c294d38926a9ea15b1d35100b [file] [log] [blame] [raw]
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "cpu.h"
// this one is much quicker
#define push(VALUE) (stack[SP--]=(VALUE))
#define pull() (stack[SP])
bool CPU::bp_active = false;
bool CPU::bp_reached = false;
const unsigned int CPU::nr_of_bps = 11;
static unsigned int stats[255];
template<> unsigned int LinkedList<Debuggable>::count = 0;
template<> Debuggable* LinkedList<Debuggable>::root = 0;
template<> Debuggable* LinkedList<Debuggable>::last = 0;
CPU::CPU( MemoryHandler *memhandler, unsigned char *irqreg, unsigned char *cpustack)
: mem(memhandler), irq_register(irqreg), stack(cpustack)
{
irq_sequence = 0;
IRQcount = 0;
cpu_jammed = false;
PC = 0xFFFF;
for(unsigned int i=0; i < nr_of_bps; i++) {
bp[i].address = 0x10000;
bp[i].enabled = false;
bp[i].slot_free = true;
}
nr_activebps = 0;
memset( stats, 0, sizeof(stats));
irqVector = INTERRUPT_IRQ;
nmiLevel = 0;
setId("CPU0");
}
unsigned int CPU::getcins()
{
// currins is set to 0x00 when in IRQ so we have to re-fetch the opcode
// this is only used for debugging & co.
return (currins==0) ? mem->Read((PC-1)&0xFFFF) : currins&0xFF;
}
void CPU::dumpState()
{
saveVar(&currins,sizeof(currins));
saveVar(&nextins,sizeof(nextins));
saveVar(&ptr,sizeof(ptr));
saveVar(&PC,sizeof(PC));
saveVar(&cycle,sizeof(cycle));
saveVar(&SP,sizeof(SP));
saveVar(&ST,sizeof(ST));
saveVar(&AC,sizeof(AC));
saveVar(&X,sizeof(X));
saveVar(&Y,sizeof(Y));
saveVar(&IRQcount, sizeof(IRQcount));
saveVar(&irq_sequence, sizeof(irq_sequence));
}
void CPU::readState()
{
readVar(&currins,sizeof(currins));
readVar(&nextins,sizeof(nextins));
readVar(&ptr,sizeof(ptr));
readVar(&PC,sizeof(PC));
PC &= 0xFFFF;
readVar(&cycle,sizeof(cycle));
readVar(&SP,sizeof(SP));
readVar(&ST,sizeof(ST));
ST &= 0xFF;
readVar(&AC,sizeof(AC));
readVar(&X,sizeof(X));
readVar(&Y,sizeof(Y));
readVar(&IRQcount, sizeof(IRQcount));
readVar(&irq_sequence, sizeof(irq_sequence));
}
// reset keeps all except for PC
void CPU::Reset()
{
ST=0x24;
softreset();
IRQcount = cycle = 0;
irq_sequence = 0;
}
void CPU::softreset()
{
// clear the BRK flag
ST&=0xEF;
setPC(mem->Read(0xFFFC)|(mem->Read(0xFFFD)<<8));
}
void CPU::setPC(unsigned int addr)
{
PC=addr;
cycle=0;
}
static unsigned int remained;
void CPU::process(unsigned int cycles)
{
remained = cycles;
while (remained-- && !bp_reached)
process();
}
unsigned int CPU::getRemainingCycles()
{
return remained;
}
inline void CPU::DoCompare(unsigned char reg, unsigned char value)
{
ST = (ST & 0xFE) | ( value<=reg);
SETFLAGS_ZN( reg - value);
}
void CPU::process()
{
if (IRQcount || (*irq_register && !irq_sequence && !(ST&0x04)))
IRQcount++;
if (!cycle) { // in the first cycle the CPU fetches the opcode
if (IRQcount>=3 && currins != 0x58) {
IRQcount = 0;
if (!(ST&0x04) || currins == 0x78 || irqVector == INTERRUPT_NMI) { //
irq_sequence = 0x10; // this is 0x10 to match the B flag later
currins = 0x00; // we could use BRK for the IRQ routine!
cycle = 1;
return;
}
}
currins=mem->Read(PC); // fetch opcode
nextins=mem->Read(PC+1); // prefetch next opcode/operand
cycle = 1; // increment the CPU cycle counter
PC=(PC+1)&0xFFFF;
#ifdef CPUS_STATS
stats[currins]++;
#endif
}
else
switch (currins){
case 0xea : // NOP
cycle=0;
break;
case 0x18 : // CLC
ST&=0xFE;
cycle=0;
break;
case 0x38 : // SEC
ST|=0x01;
cycle=0;
break;
case 0x58 : // CLI
ST&=0xFB;
cycle=0;
break;
case 0x78 : // SEI
ST|=0x04;
cycle=0;
// actually, IRQ can still occur right after the SEI instruction
// some programs (like Castle Master) rely on it.
// Therefore startIRQ is not set to 0 here.
//IRQcount = 0;
break;
case 0xb8 : // CLV
// This has to be more generic because the drive byte ready
// line is connected to the V flag pin on the disk drive CPU
ClearVFlag();
cycle=0;
break;
case 0xD8 : // CLD
ST&=0xF7;
cycle=0;
break;
case 0xF8 : // SED
ST|=0x08;
cycle=0;
break;
// branch functions (conditional jumps )
case 0x10 : // BPL
switch(cycle++) {
case 1: PC++;
if ((ST&0x80))
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
case 0x30 : // BMI
switch(cycle++) {
case 1: PC++;
if (!(ST&0x80))
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
case 0x50 : // BVC
switch(cycle++) {
// This has to be more generic because the drive byte ready
// line is connected to the V flag pin on the disk drive CPU
case 1: PC++;
if (CheckVFlag())
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
case 0x70 : // BVS
switch(cycle++) {
// This has to be more generic because the drive byte ready
// line is connected to the V flag pin on the disk drive CPU
case 1: PC++;
if (!(CheckVFlag()))
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
case 0x90 : // BCC
switch(cycle++) {
case 1: PC++;
if (ST&0x01)
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
case 0xB0 : // BCS
switch(cycle++) {
case 1: PC++;
if (!(ST&0x01))
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
case 0xD0 : // BNE
switch(cycle++) {
case 1: PC++;
if (ST&0x02)
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
case 0xF0 : // BEQ
switch(cycle++) {
case 1: PC++;
if (!(ST&0x02))
cycle=0;
break;
case 2: if (!(((PC&0xFF)+(signed char) nextins)&0xFF00)) {
PC+=(signed char) nextins;
cycle=0;
}
break;
case 3: PC+=(signed char) nextins;
cycle=0;
break;
}
break;
// manipulating index registers
case 0x88 : // DEY
--Y;
SETFLAGS_ZN(Y);
cycle=0;
break;
case 0xC8 : // INY
++Y;
SETFLAGS_ZN(Y);
cycle=0;
break;
case 0xCA : // DEX
--X;
SETFLAGS_ZN(X);
cycle=0;
break;
case 0xE8 : // INX
++X;
SETFLAGS_ZN(X);
cycle=0;
break;
case 0x00 : // BRK
switch (cycle++) {
case 1: if (!irq_sequence)
PC++;
break;
case 2: push(PC>>8);
break;
case 3: push(PC&0xFF);
break;
case 4: // BRK pushes the status register to the stack with the B bit set
// IRQ can still occur on BRK before saving the flags
// if (!(ST&0x04)) irq_sequence = 0x10;
push((ST|0x30)&~irq_sequence);
// and then masks the interrupt bit if not NMI
if (irqVector == INTERRUPT_IRQ)
ST |= 0x04;
break;
case 5: break;
case 6: PC=mem->Read(irqVector)|(mem->Read(irqVector|1)<<8);
if (irqVector != INTERRUPT_IRQ)
irqVector = INTERRUPT_IRQ;
irq_sequence = 0x0;
cycle=0;
break;
}
break;
/*case 0x00 : // BRK
switch (cycle++) {
case 1: PC++;
break;
case 2: push(PC>>8);
break;
case 3: push(PC&0xFF);
break;
case 4: // BRK pushes the status register to the stack with the B bit set
// IRQ can still occur on BRK before saving the flags
// if (!(ST&0x04)) irq_sequence = 0x10;
push((ST|0x30));
// and then masks the interrupt bit
ST|=0x04;
break;
case 5: break;
case 6: PC=mem->Read(0xFFFE)|(mem->Read(0xFFFF)<<8);
cycle=0;
break;
}
break;
case 0x100 : // IRQ - pseudo opcode
switch (cycle++) {
case 1: break;
case 2: push(PC>>8);
break;
case 3: push(PC&0xFF);
break;
case 4: push((ST|0x20)&0xEF);
// and then masks the interrupt bit
ST|=0x04;
break;
case 5: break;
case 6: PC=mem->Read(0xFFFE)|(mem->Read(0xFFFF)<<8);
//irq_sequence = 0x0;
cycle=0;
break;
}
break;*/
case 0x40 : // RTI
switch (cycle++) {
case 1: //PC++;
break;
case 2: //PC++;
SP++;
break;
case 3: // the B flag is already always cleared
ST=pull();//&0xEF;
SP++;
break;
case 4: PC=pull();
SP++;
break;
case 5: PC|=pull()<<8;
//ST&=0xFB;
cycle=0;
break;
}
break;
case 0x60 : // RTS
switch (cycle++) {
case 1: //PC++;
break;
case 2: //PC++;
SP++;
break;
case 3: PC=pull();
SP++;
break;
case 4: PC|=pull()<<8;
break;
case 5: PC++;
cycle=0;
break;
}
break;
// stack operations
case 0x08 : // PHP
if (cycle++==2) {
// the PHP always pushes the status with the B flag set...
//ST = (ST&0xBF)|CheckVFlag();
push(ST|0x30);
cycle=0;
}
break;
case 0x28 : // PLP
if (cycle++==3) {
SP++;
ST=(pull() /*&0xEF*/);//|(0x20);
cycle=0;
}
break;
case 0x48 : // PHA
if (cycle++==2) {
push(AC);
cycle=0;
}
break;
case 0x68 : // PLA
if (cycle++==3) {
SP++;
AC=pull();
SETFLAGS_ZN(AC);
cycle=0;
}
break;
// inter-register operations
case 0x8A : // TXA
AC=X;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0xAA : // TAX
X=AC;
SETFLAGS_ZN(X);
cycle=0;
break;
case 0x98 : // TYA
AC=Y;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0xA8 : // TAY
Y=AC;
SETFLAGS_ZN(Y);
cycle=0;
break;
case 0x9A : // TXS
SP=X;
cycle=0;
break;
case 0xBA : // TSX
X=SP;
SETFLAGS_ZN(X);
cycle=0;
break;
// subroutine & unconditional jump
case 0x20 : // JSR
switch (cycle++) {
case 1: PC++;
break;
case 2: // unknown
break;
case 3: push(PC>>8);
break;
case 4: push(PC&0xFF);
break;
case 5: PC=ptr=nextins|(mem->Read(PC)<<8);
cycle=0;
break;
}
break;
case 0x4C : // JMP $0000
if (cycle++==2) {
PC=nextins|(mem->Read(PC+1)<<8);
cycle=0;
}
break;
case 0x6C : // JMP ($0000)
if (cycle++==4) {
ptr=nextins|(mem->Read(PC+1)<<8);
// instruction does not handle page crossing
PC = mem->Read(ptr)|(mem->Read( (ptr & 0xFF00) | ((ptr+1)&0xFF) ) << 8);
cycle=0;
}
break;
// Accumulator operations with immediate addressing
case 0x09 : // ORA #$00
PC++;
AC|=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x29 : // AND #$00
PC++;
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x49 : // EOR #$00
PC++;
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x69 : // ADC #$00
PC++;
ADC(nextins);
cycle=0;
break;
case 0xC9 : // CMP #$00
PC++;
DoCompare(AC,nextins);
cycle=0;
break;
case 0xE9 : // SBC #$00
PC++;
SBC(nextins);
cycle=0;
break;
// rotations
case 0x0A : // ASL
AC&0x80 ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC<<=1;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x2A : // ROL
nextins=(AC<<1)|(ST&0x01);
AC&0x80 ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x4A : // LSR
AC&0x01 ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC=AC>>1;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x6A : // ROR
nextins=(AC>>1)|((ST&0x01)<<7);
AC&0x01 ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
// loads
case 0xA0 : // LDY
PC++;
Y=nextins;
SETFLAGS_ZN(Y);
cycle=0;
break;
case 0xA2 : // LDX
PC++;
X=nextins;
SETFLAGS_ZN(X);
cycle=0;
break;
case 0xA9 : // LDA
PC++;
AC=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
// comparisons with immediate addressing
case 0xC0 : // CPY
PC++;
DoCompare(Y,nextins);
cycle=0;
break;
case 0xE0 : // CPX
PC++;
DoCompare(X,nextins);
cycle=0;
break;
// BIT tests with accumulator
case 0x24 : // BIT $00
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins=mem->Read(nextins);
ST = (ST&0x3D)
| (nextins&0xC0)
| (((AC&nextins)==0)<<1);
/*if (!(ST&0x40))
ClearVFlag();*/
cycle=0;
break;
}
break;
case 0x2C : // BIT $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
ST = (ST&0x3D)
| (nextins&0xC0)
| (((AC&nextins)==0)<<1);
/*if (!(ST&0x40))
ClearVFlag();*/
cycle=0;
break;
}
break;
// Read instructions with absolute addressing
case 0x0D : // ORA $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: AC|=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x2D : // AND $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: AC&=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 0x4D : // EOR $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: AC^=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x6D : // ADC $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: ADC(mem->Read(ptr));
cycle=0;
break;
}
break;
case 0x99 : // STA $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: break;
case 4: mem->Write(ptr+Y,AC);
cycle=0;
break;
}
break;
case 0xAC : // LDY $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: Y=mem->Read(ptr);
SETFLAGS_ZN(Y);
cycle=0;
break;
}
break;
case 0xCC : // CPY $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: DoCompare(Y,mem->Read(ptr));
cycle=0;
break;
}
break;
case 0xEC : // CPX $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: DoCompare(X,mem->Read(ptr));
cycle=0;
break;
}
break;
case 0xAD : // LDA $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: AC=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xCD : // CMP $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: DoCompare(AC,mem->Read(ptr));
cycle=0;
break;
}
break;
case 0xED : // SBC $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: SBC(mem->Read(ptr));
cycle=0;
break;
}
break;
case 0x0E : // ASL $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
(nextins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
nextins<<=1;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x1E : // ASL $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: ptr+=X;
break;
case 4: nextins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,nextins);
(nextins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
nextins<<=1;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x2E : // ROL $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: farins=mem->Read(ptr);
nextins=(farins<<1)|(ST&0x01);
break;
case 4: mem->Write(ptr,farins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x3E : // ROL $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: ptr+=X;
break;
case 4: farins=mem->Read(ptr);
nextins=(farins<<1)|(ST&0x01);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,farins);
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x4E : // LSR $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
(nextins&0x01) ? ST|=0x01 : ST&=0xFE;; // the Carry flag
break;
case 4: mem->Write(ptr,nextins);
nextins=nextins>>1;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x5E : // LSR $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: ptr+=X;
break;
case 4: nextins=mem->Read(ptr);
(nextins&0x01) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,nextins);
nextins>>=1;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x6E : // ROR $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: farins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,farins);
nextins=(farins>>1)|((ST&0x01)<<7);
(farins&0x01) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x7E : // ROR $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: ptr+=X;
break;
case 4: farins=mem->Read(ptr);
nextins=(farins>>1)|((ST&0x01)<<7);
(farins&0x01) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,farins);
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xAE : // LDX $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: X=mem->Read(ptr);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xCE : // DEC $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
--nextins;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xDE : // DEC $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: ptr+=X;
break;
case 4: nextins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,nextins);
--nextins;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xEE : // INC $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
++nextins;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xFE : // INC $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: ptr+=X;
break;
case 4: nextins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,nextins);
++nextins;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
// zero page indexed with X or Y
case 0x94 : // STY $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: mem->Write(nextins,Y);
cycle=0;
break;
}
break;
case 0x95 : // STA $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: mem->Write(nextins,AC);
cycle=0;
break;
}
break;
case 0x96 : // STX $00,Y
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=Y;
break;
case 3: mem->Write(nextins,X);
cycle=0;
break;
}
break;
case 0xB4 : // LDY $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: Y=mem->Read(nextins);
SETFLAGS_ZN(Y);
cycle=0;
break;
}
break;
case 0xB5 : // LDA $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: AC=mem->Read(nextins);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xB6 : // LDX $00,Y
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=Y;
break;
case 3: X=mem->Read(nextins);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xD5 : // CMP $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: DoCompare(AC,mem->Read(nextins));
cycle=0;
break;
}
break;
case 0x15 : // ORA $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: AC|=(mem->Read(nextins));
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x35 : // AND $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: AC&=(mem->Read(nextins));
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x16 : // ASL $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: farins=mem->Read(nextins);
break;
case 4: mem->Write(nextins,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x36 : // ROL $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
ptr=nextins;
break;
case 3: farins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,farins);
nextins=(farins<<1)|((ST&0x01));
farins&0x80 ? ST|=0x01 : ST&=0xFE;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
// absolute addressing indexed with X or Y
case 0x19 : // ORA $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100) {
AC|=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC|=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x39 : // AND $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100) {
AC&=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC&=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x59 : // EOR $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100) {
AC^=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC^=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x79 : // ADC $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100) {
ADC(mem->Read(ptr));
cycle=0;
}
break;
case 4: ADC(mem->Read(ptr));
cycle=0;
break;
}
break;
case 0xB9 : // LDA $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100) {
AC=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x1D : // ORA $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: if (nextins+X<0x100) {
AC|=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC|=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x3D : // AND $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: if (nextins+X<0x100) {
AC&=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC&=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x5D : // EOR $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: if (nextins+X<0x100) {
AC^=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC^=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x7D : // ADC $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: if (nextins+X<0x100) {
ADC(mem->Read(ptr));
cycle=0;
}
break;
case 4: ADC(mem->Read(ptr));
cycle=0;
break;
}
break;
case 0xBC : // LDY $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: if (nextins+X<0x100) {
Y=mem->Read(ptr);
SETFLAGS_ZN(Y);
cycle=0;
}
break;
case 4: Y=mem->Read(ptr);
SETFLAGS_ZN(Y);
cycle=0;
break;
}
break;
case 0xBD : // LDA $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: if (nextins+X<0x100) {
AC=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xBE : // LDX $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100) {
X=mem->Read(ptr);
SETFLAGS_ZN(X);
cycle=0;
}
break;
case 4: X=mem->Read(ptr);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xD9 : // CMP $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: if (nextins+Y<0x100){
DoCompare(AC,mem->Read(ptr+Y));
cycle=0;
}
break;
case 4: DoCompare(AC,mem->Read(ptr+Y));
cycle=0;
break;
}
break;
case 0xF9 : // SBC $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100){
SBC(mem->Read(ptr));
cycle=0;
}
break;
case 4: SBC(mem->Read(ptr));
cycle=0;
break;
}
break;
case 0xDD : // CMP $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: if (nextins+X<0x100) {
DoCompare(AC,mem->Read(ptr+X));
cycle=0;
}
break;
case 4: DoCompare(AC,mem->Read(ptr+X));
cycle=0;
break;
}
break;
case 0xFD : // SBC $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: if (nextins+X<0x100) {
SBC(mem->Read(ptr));
cycle=0;
}
break;
case 4: SBC(mem->Read(ptr));
cycle=0;
break;
}
break;
// zero page operations
case 0xA4 : // LDY $00
switch (cycle++) {
case 1: PC++;
break;
case 2: Y=mem->Read(nextins);
SETFLAGS_ZN(Y);
cycle=0;
break;
}
break;
case 0xC4 : // CPY $00
switch (cycle++) {
case 1: PC++;
break;
case 2: DoCompare(Y,mem->Read(nextins));
cycle=0;
break;
}
break;
case 0x05 : // ORA $00
switch (cycle++) {
case 1: PC++;
break;
case 2: AC|=mem->Read(nextins);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x55 : // EOR $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: AC^=mem->Read(nextins);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x65 : // ADC $00
switch (cycle++) {
case 1: PC++;
break;
case 2: ADC(mem->Read(nextins));
cycle=0;
break;
}
break;
case 0x75 : // ADC $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ADC(mem->Read(nextins));
cycle=0;
break;
}
break;
case 0xA5 : // LDA $00
switch (cycle++) {
case 1: PC++;
break;
case 2: AC=mem->Read(nextins);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xC5 : // CMP $00
switch (cycle++) {
case 1: PC++;
break;
case 2: DoCompare(AC,mem->Read(nextins));
cycle=0;
break;
}
break;
case 0xE5 : // SBC $00
switch (cycle++) {
case 1: PC++;
break;
case 2: SBC(mem->Read(nextins));
cycle=0;
break;
}
break;
case 0xF5 : // SBC $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: SBC(mem->Read(nextins));
cycle=0;
break;
}
break;
case 0x06 : // ASL $00
switch (cycle++) {
case 1: PC++;
break;
case 2: farins=mem->Read(nextins);
farins&0x80 ? ST|=0x01 : ST&=0xFE;
break;
case 3: mem->Write(nextins,farins);
farins<<=1;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x26 : // ROL $00
switch (cycle++) {
case 1: PC++;
ptr=nextins;
break;
case 2: farins=mem->Read(ptr);
nextins=(farins<<1)|(ST&0x01);
break;
case 3: mem->Write(ptr,farins);
farins&0x80 ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 4: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x25 : // AND $00
switch (cycle++) {
case 1: PC++;
break;
case 2: AC&=mem->Read(nextins);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x45 : // EOR $00
switch (cycle++) {
case 1: PC++;
break;
case 2: AC^=mem->Read(nextins);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x46 : // LSR $00
switch (cycle++) {
case 1: PC++;
break;
case 2: farins=mem->Read(nextins);
farins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 3: mem->Write(nextins,farins);
farins>>=1;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x56 : // LSR $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: farins=mem->Read(nextins);
farins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 4: mem->Write(nextins,farins);
farins>>=1;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x66 : // ROR $00
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=nextins;
farins=mem->Read(ptr);
nextins=(farins>>1)|((ST&0x01)<<7);
break;
case 3: mem->Write(ptr,farins);
farins&0x01 ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 4: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x76 : // ROR $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
ptr=nextins;
break;
case 3: farins=mem->Read(ptr);
nextins=(farins>>1)|((ST&0x01)<<7);
break;
case 4: mem->Write(ptr,farins);
farins&0x01 ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xA6 : // LDX $00
switch (cycle++) {
case 1: PC++;
break;
case 2: X=mem->Read(nextins);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xC6 : // DEC $00
switch (cycle++) {
case 1: PC++;
break;
case 2: farins=mem->Read(nextins);
break;
case 3: mem->Write(nextins,farins);
--farins;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xE4 : // CPX $00
switch (cycle++) {
case 1: PC++;
break;
case 2: DoCompare(X,mem->Read(nextins));
cycle=0;
break;
}
break;
case 0xE6 : // INC $00
switch (cycle++) {
case 1: PC++;
break;
case 2: farins=mem->Read(nextins);
break;
case 3: mem->Write(nextins,farins);
++farins;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xD6 : // DEC $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: farins=mem->Read(nextins);
break;
case 4: mem->Write(nextins,farins);
--farins;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xF6 : // INC $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: farins=mem->Read(nextins);
break;
case 4: mem->Write(nextins,farins);
++farins;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
// indexed indirect
case 0x01 : // ORA ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: AC|=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x21 : // AND ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: AC&=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x41 : // EOR ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: AC^=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x61 : // ADC ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: ADC(mem->Read(ptr));
cycle=0;
break;
}
break;
case 0x81 : // STA ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: mem->Write(ptr,AC);
cycle=0;
break;
}
break;
case 0xA1 : // LDA ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: AC=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xC1 : // CMP ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: DoCompare(AC,mem->Read(ptr));
cycle=0;
break;
}
break;
case 0xE1 : // SBC ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins++);
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: SBC(mem->Read(ptr));
cycle=0;
break;
}
break;
// indirect indexed
case 0x11 : // ORA ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
AC|=mem->Read(ptr+Y);
cycle=0;
SETFLAGS_ZN(AC);
}
break;
case 5: AC|=mem->Read(ptr+Y);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x31 : // AND ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
AC&=mem->Read(ptr+Y);
cycle=0;
SETFLAGS_ZN(AC);
}
break;
case 5: AC&=mem->Read(ptr+Y);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x51 : // EOR ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
AC^=mem->Read(ptr+Y);
cycle=0;
SETFLAGS_ZN(AC);
}
break;
case 5: AC^=mem->Read(ptr+Y);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x71 : // ADC ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
ADC(mem->Read(ptr+Y));
cycle=0;
}
break;
case 5: ADC(mem->Read(ptr+Y));
cycle=0;
break;
}
break;
case 0x91 : // STA ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: break;
case 5: mem->Write(ptr+Y,AC);
cycle=0;
break;
}
break;
case 0xB1 : // LDA ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
AC=mem->Read(ptr+Y);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 5: AC=mem->Read(ptr+Y);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xD1 : // CMP ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
DoCompare(AC,mem->Read(ptr+Y));
cycle=0;
}
break;
case 5: DoCompare(AC,mem->Read(ptr+Y));
cycle=0;
break;
}
break;
case 0xF1 : // SBC ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
SBC(mem->Read(ptr+Y));
cycle=0;
}
break;
case 5: SBC(mem->Read(ptr+Y));
cycle=0;
break;
}
break;
// storage functions
case 0x84 : // STY $00
switch (cycle++) {
case 1: PC++;
break;
case 2: mem->Write(nextins,Y);
cycle=0;
break;
}
break;
case 0x85 : // STA $00
switch (cycle++) {
case 1: PC++;
break;
case 2: mem->Write(nextins,AC);
cycle=0;
break;
}
break;
case 0x86 : // STX $00
switch (cycle++) {
case 1: PC++;
break;
case 2: mem->Write(nextins,X);
cycle=0;
break;
}
break;
case 0x8C : // STY $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: mem->Write(ptr,Y);
cycle=0;
break;
}
break;
case 0x8D : // STA $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: mem->Write(ptr,AC);
cycle=0;
break;
}
break;
case 0x8E : // STX $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: mem->Write(ptr,X);
cycle=0;
break;
}
break;
case 0x9D : // STA $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: break;
case 4: mem->Write(ptr+X,AC);
cycle=0;
break;
}
break;
//----------------
// illegal opcodes
//----------------
case 0x03 : // ASO/SLO ($00,X) : A <- (M << 1) \/ A
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
break;
case 4: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 5: farins=mem->Read(ptr);
break;
case 6: mem->Write(ptr,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
break;
case 7: mem->Write(ptr,farins);
AC|=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x07 : // ASO/SLO $00 : A <- (M << 1) \/ A
switch (cycle++) {
case 1: PC++;
ptr=nextins;
break;
case 2: nextins=mem->Read(ptr);
break;
case 3: mem->Write(ptr,nextins);
(nextins)&0x80 ? ST|=0x01 : ST&=0xFE;
nextins<<=1;
break;
case 4: mem->Write(ptr,nextins);
AC|=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x0B : // ANN/ANC #$00
case 0x2B : // ANN/ANC #$00
PC++;
AC&=nextins;
(AC&0x80) ? ST|=0x01 : ST&=0xFE;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x0C : // NOP $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: cycle=0;
break;
}
break;
case 0x0F : // ASO/SLO $0000 : A <- (M << 1) \/ A
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
(nextins)&0x80 ? ST|=0x01 : ST&=0xFE;
nextins<<=1;
break;
case 5: mem->Write(ptr,nextins);
AC|=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x13 : // ASO/SLO ($00),Y : A <- (M << 1) \/ A
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: break;
case 5: farins=mem->Read(ptr+Y);
break;
case 6: mem->Write(ptr+Y,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
break;
case 7: mem->Write(ptr+Y,farins);
AC|=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x14 : // NOP $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: break;
case 3: cycle=0;
break;
}
break;
case 0x17 : // ASO/SLO $00,X : A <- (M << 1) \/ A
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=(nextins+X)&0xFF;
break;
case 3: farins = mem->Read(ptr);
break;
case 4: mem->Write(ptr,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
break;
case 5: mem->Write(ptr,farins);
AC|=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x80 : // NOP #$00
case 0x82 : // NOP #$00
case 0x89 : // NOP #$00
case 0xC2 : // NOP #$00
case 0xE2 : // NOP #$00
PC++;
case 0x1A : // NOP
case 0x3A : // NOP
case 0x5A : // NOP
case 0x7A : // NOP
case 0xDA : // NOP
case 0xFA : // NOP
cycle=0;
break;
case 0x1B : // ASO/SLO $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
break;
case 6: mem->Write(ptr,farins);
AC|=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x1C : // NOP $0000,X
case 0x3C : // NOP $0000,X
case 0x5C : // NOP $0000,X
case 0x7C : // NOP $0000,X
case 0xDC : // NOP $0000,X
case 0xFC : // NOP $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: if (nextins+X<0x100)
cycle=0;
break;
case 4: cycle=0;
break;
}
break;
case 0x1F : // ASO/SLO $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
ptr+=X;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
break;
case 6: mem->Write(ptr,farins);
AC|=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x23 : // RAN/RLA ($00,X) - ROL memory, AND accu, result into acc
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
break;
case 4: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
farins=mem->Read(ptr);
break;
case 5: nextins=(farins<<1)|(ST&0x01);
mem->Write(ptr,nextins);
break;
case 6: (farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 7: AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x27 : // RAN/RLA $00 - A <- (M << 1) /\ (A)
switch (cycle++) {
case 1: PC++;
ptr=nextins;
break;
case 2: farins=mem->Read(ptr);
break;
case 3: mem->Write(ptr,farins);
nextins=(farins<<1)|(ST&0x01);
break;
case 4: mem->Write(ptr,nextins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x2F : // RAN/RLA $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: farins=mem->Read(ptr);
break;
case 4: mem->Write(ptr, farins);
nextins=(farins<<1)|(ST&0x01);
break;
case 5: mem->Write(ptr,nextins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x33 : // RAN/RLA ($00),Y - A <- (M << 1) /\ (A) - not 100%
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: break;
case 5: farins=mem->Read(ptr+Y);
nextins=(farins<<1)|(ST&0x01);
break;
case 6: mem->Write(ptr+Y,farins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 7: mem->Write(ptr+Y,nextins);
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x34 : // NOP $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: break;
case 3: cycle=0;
break;
}
break;
case 0x37 : // RAN/RLA $00,X - A <- (M << 1) /\ (A)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
ptr=nextins;
break;
case 3: farins=mem->Read(ptr);
nextins=(farins<<1)|(ST&0x01);
break;
case 4: mem->Write(ptr,farins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,nextins);
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x3B : // RAN/RLA $0000,Y - A <- (M << 1) /\ (A)
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: break;
case 4: farins=mem->Read(ptr+Y);
break;
case 5: mem->Write(ptr+Y,farins);
nextins=(farins<<1)|(ST&0x01);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 6: mem->Write(ptr+Y,nextins);
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x3F : // RAN/RLA $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
nextins=(farins<<1)|(ST&0x01);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,farins);
break;
case 6: mem->Write(ptr,nextins);
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x43 : // LSE/SRE ($00,X) - A <- (M >> 1) ^ A
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
nextins += 1;
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: nextins=mem->Read(ptr);
break;
case 6: mem->Write(ptr, nextins);
nextins & 0x01 ? ST |= 0x01 : ST &= 0xFE;
nextins >>= 1;
break;
case 7: mem->Write(ptr, nextins);
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x47 : // LSE/SRE $00 - A <- (M >> 1) \-/ A
switch (cycle++) {
case 1: PC++;
ptr=nextins;
break;
case 2: nextins=mem->Read(ptr);
break;
case 3: mem->Write(ptr,nextins);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
nextins>>=1;
break;
case 4: mem->Write(ptr,nextins);
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x4B : // ANL/ASR #$00
PC++;
AC=(AC&nextins);
(AC&0x01) ? ST|=0x01 : ST&=0xFE;
AC>>=1;
SETFLAGS_ZN(AC);
cycle=0;
break;
case 0x4F : // LSE/SRE $0000 - A <- (M >> 1) \-/ A
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
nextins>>=1;
break;
case 5: mem->Write(ptr,nextins);
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x53 : // LSE/SRE ($00),Y - A <- (M >> 1) \-/ A - not 100%
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: break;
case 5: nextins=mem->Read(ptr+Y);
break;
case 6: mem->Write(ptr+Y,nextins);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
nextins>>=1;
break;
case 7: mem->Write(ptr+Y,nextins);
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x54 : // NOP $00,X
switch (cycle++) {
case 1: break;
case 2: PC++;
break;
case 3: cycle=0;
break;
}
break;
case 0x57 : // LSE/SRE $00,X - A <- (M >> 1) \-/ A - not 100%
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=nextins;
nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
nextins>>=1;
break;
case 5: mem->Write(ptr,nextins);
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x5B : // LSE/SRE $0000,Y - A <- (M >> 1) \-/ A
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
farins&0x01 ? ST|=0x01 : ST&=0xFE;
farins>>=1;
break;
case 6: mem->Write(ptr,farins);
AC^=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x5F : // LSE/SRE $0000,X - A <- (M >> 1) \-/ A
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
ptr+=X;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
farins&0x01 ? ST|=0x01 : ST&=0xFE;
farins>>=1;
break;
case 6: mem->Write(ptr,farins);
AC^=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x63 : // RAD/RRA ($00,X) - ROR memory, ADC accu, result into accu
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
break;
case 4: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 5: nextins=mem->Read(ptr);
farins=(nextins>>1)|((ST&0x01)<<7);
break;
case 6: nextins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 7: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x04 : // NOP $00
case 0x44 : // NOP $00
case 0x64 : // NOP $00
if (cycle++==2) {
PC++;
cycle=0;
}
break;
case 0x67 : // RAD/RRA $00
switch (cycle++) {
case 1: PC++;
ptr=nextins;
break;
case 2: nextins=mem->Read(ptr);
break;
case 3: mem->Write(ptr,nextins);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 4: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x6B : // ARR #$00
{
unsigned int tmp;
nextins=mem->Read(PC);
PC++;
AC &= nextins;
tmp = AC;
tmp |= (ST&1)<<8;
tmp >>= 1;
if (ST&0x08) {
// Set sign flag state to that of carry
ST = (ST & 0x7F)|(ST << 7);
// Set the zero flag
ST = (ST & 0xFD) | (tmp == 0 ? 2 : 0);
// Set the overflow flag
ST = (ST & 0xBF) | ((tmp ^ AC) & 0x40);
if (((AC & 0x0F) + (AC & 0x01)) > 0x05)
tmp = (tmp & 0xF0) | ((tmp + 0x06) & 0x0F);
if (((AC & 0xF0) + (AC & 0x10)) > 0x50) {
tmp = (tmp & 0x0F) | ((tmp + 0x60) & 0xF0);
ST |= 1;
} else
ST &= 0xFE;
} else {
SETFLAGS_ZN(tmp);
(tmp & 0x40) ? ST |= 0x01 : ST &= 0xFE;
(tmp & 0x40)^(((tmp & 0x20)<<1) & 0x40) ? SetVFlag() : ClearVFlag();
}
AC = tmp & 0xFF;
}
cycle=0;
break;
case 0x6F : // RAD/RRA $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 5: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x73 : // RAD/RRA ($00),Y - A <- (M >> 1) + (A) + C
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: break;
case 5: nextins=mem->Read(ptr+Y);
break;
case 6: mem->Write(ptr+Y,nextins);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 7: mem->Write(ptr+Y,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x74 : // NOP $00,X
switch (cycle++) {
case 1: PC++;
break;
case 2: break;
case 3: cycle=0;
break;
}
break;
case 0x77 : // RAD/RRA $00,X - A <- (M >> 1) + (A) + C - not good yet!!!!!!
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
ptr=nextins;
break;
case 3: nextins=mem->Read(ptr);
farins=(nextins>>1)|((ST&0x01)<<7);
break;
case 4: nextins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 5: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x7B : // RAD/RRA $0000,Y - A <- (M >> 1) + (A) + C - not good yet!!!!!!
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: break;
case 4: nextins=mem->Read(ptr);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 5: mem->Write(ptr,nextins);
break;
case 6: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x7F : // RAD/RRA $8000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: break;
case 4: nextins=mem->Read(ptr);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
break;
case 5: mem->Write(ptr, nextins);
break;
case 6: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x83 : // AXX/SAX ($00,X) - M <- (A) /\ (X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
nextins++;
break;
case 4: ptr|=(mem->Read(nextins)<<8);
break;
case 5: mem->Write(ptr,AC&X);
cycle=0;
break;
}
break;
case 0x87 : // AAX/AXR/SAX $00 - M <- (A) /\ (X)
switch (cycle++) {
case 1: PC++;
break;
case 2: mem->Write(nextins,AC&X);
cycle=0;
break;
}
break;
case 0x8B : // TAN/ANE/XAA $00 - M <-[(A)/\$EE] \/ (X)/\(M)
{
nextins=mem->Read(PC);
PC++;
AC=(X&nextins&(AC|0xEE))|( (X&nextins)&((AC<<1)&0x10) );
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 0x8F : // AAX/SAX $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: mem->Write(ptr,AC&X);
cycle=0;
break;
}
break;
/*
SHA $93,$9F Store (A & X & (ADDR_HI + 1))
SHX $9E Store (X & (ADDR_HI + 1))
SHY $9C Store (Y & (ADDR_HI + 1))
SHS $9B SHA and TXS, where X is replaced by (A & X).
Note: The value to be stored is copied also
to ADDR_HI if page boundary is crossed.
*/
case 0x93 : // AXI/SHA ($00),Y (A) /\ (X) /\ (PCH+1) vagy 0000,X ki tudja???
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
nextins+=1;
break;
case 3: ptr|=mem->Read(nextins)<<8;
break;
case 4: break;
case 5: mem->Write(ptr+Y,AC&X&((ptr >> 8)+1));//check this!
cycle=0;
break;
}
break;
case 0x97 : // AXY/SAX $00,Y
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=Y;
break;
case 3: mem->Write(nextins,AC&X);
cycle=0;
break;
}
break;
case 0x9B : // AXS/SHS $0000,Y - X <- (A) /\ (X), S <- (X) _plus_ M <- (X) /\ (PCH+1)
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
ptr+=Y;
break;
case 3: SP=AC&X;
break;
case 4: mem->Write(ptr,SP&((ptr >> 8)+1));
cycle=0;
break;
}
break;
case 0x9C : // AYI/SHY $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: break;
case 4: if (nextins+X<256) {
mem->Write(ptr+X,Y&(((ptr+X)>>8)+1));
} else {
unsigned char t = Y & (((ptr+X)>>8)+1);
mem->Write( (nextins+X)|(t << 8), t);
}
cycle=0;
break;
}
break;
case 0x9E : // SXI/SHX $0000,Y (X) /\ (((PC+Y)>>8)+1) vagy mi???
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: break;
case 4: if (nextins+Y<256) {
mem->Write(ptr+Y, X & (((ptr+Y)>>8)+1));
} else {
unsigned char t = X & (((ptr+Y)>>8)+1);
mem->Write( (nextins+Y)|(t << 8), t);
}
cycle=0;
break;
}
break;
// huh...????
case 0x9F : // AXI/SHA $0000,Y (A) /\ (X) /\ (((PC+Y)>>8)+1) vagy mi???
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: break;
case 4: if (nextins+Y<256) {
mem->Write(ptr+Y,AC&X&(((ptr+Y)>>8)+1));
} else {
unsigned char t = AC&X & (((ptr+Y)>>8)+1);
mem->Write( (nextins+Y)|(t << 8), t);
}
cycle=0;
break;
}
break;
case 0xA3 : // LDT/LAX ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
break;
case 4: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 5: X=AC=mem->Read(ptr);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xA7 : // LDT/LAX $00
switch (cycle++) {
case 1: nextins=mem->Read(PC);
PC++;
break;
case 2: X=AC=mem->Read(nextins);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xAB : // ANX/LXA #$00
switch (cycle++) {
case 1: PC++;
X=AC=(nextins&(AC|0xEE));
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xAF : // LDT/LAX $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: X=AC=mem->Read(ptr);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xB3 : // LDT/LAX ($00),Y
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: if ((ptr&0x00FF)+Y<0x100) {
X=AC=mem->Read(ptr+Y);
SETFLAGS_ZN(X);
cycle=0;
}
break;
case 5: X=AC=mem->Read(ptr+Y);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xB7 : // LDT/LAX $00,Y
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=Y;
break;
case 3: X=AC=mem->Read(nextins);
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xBB : // LAE/TSA Stack-Pointer AND with memory, TSX, TXA
switch (cycle++) {
case 1: nextins=mem->Read(PC);
PC++;
break;
case 2: ptr=nextins|(mem->Read(PC)<<8);
PC++;
ptr+=Y;
break;
case 3: if (nextins+Y<0x100) {
SP&=mem->Read(ptr);
AC=X=SP;
SETFLAGS_ZN(X);
cycle=0;
}
break;
case 4: SP&=mem->Read(ptr);
AC=X=SP;
SETFLAGS_ZN(X);
cycle=0;
break;
}
break;
case 0xBF : // LDT/LAX $0000,Y
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: if (nextins+Y<0x100) {
AC=X=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
}
break;
case 4: AC=X=mem->Read(ptr);
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0xC3 : // DEM/DCP ($00,X)
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
break;
case 4: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 5: nextins=mem->Read(ptr)-1;
break;
case 6: break;
case 7: mem->Write(ptr,nextins);
(AC>=nextins) ? ST|=0x01: ST&=0xFE;
farins=AC-nextins;
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xC7 : // DEM/DCP $00
switch (cycle++) {
case 1: PC++;
ptr=nextins;
break;
case 2: nextins=mem->Read(ptr);
break;
case 3: mem->Write(ptr,nextins);
nextins -= 1;
break;
case 4: mem->Write(ptr,nextins);
(AC>=nextins) ? ST|=0x01 : ST&=0xFE;
nextins=AC-nextins;
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xCB : // AXS/XAS/SBX - X <- (X)/\(A) - M
PC++;
((X&AC) >= nextins) ? ST|=0x01 : ST&=0xFE;
X = (X&AC) - nextins;
SETFLAGS_ZN(X);
cycle=0;
break;
case 0xCF : // DEM/DCP $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: farins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,farins);
farins -= 1;
break;
case 5: mem->Write(ptr,farins);
(AC>=farins) ? ST|=0x01 : ST&=0xFE;
farins=AC-farins;
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xD3 : // DEM/DCP ($00),Y - DEC memory, CMP memory
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: break;
case 5: farins=mem->Read(ptr+Y);
break;
case 6: mem->Write(ptr+Y,farins);
farins -= 1;
break;
case 7: mem->Write(ptr+Y,farins);
DoCompare(AC,farins);
cycle=0;
break;
}
break;
case 0xD4 : // NOP $0000,X
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: break;
case 3: cycle=0;
break;
}
break;
case 0xD7 : // DEM/DCP $00,X - M <- (M)-1, (A-M) -> NZC
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
ptr=nextins;
break;
case 3: nextins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,nextins);
nextins-=1;
break;
case 5: mem->Write(ptr,nextins);
(AC>=nextins) ? ST|=0x01 : ST&=0xFE;
nextins=AC-nextins;
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xDB : // DEM/DCP $0000,Y : M <- (M)-1, (A-M) -> NZC
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
farins -= 1;
break;
case 6: mem->Write(ptr,farins);
(AC>=farins) ? ST|=0x01 : ST&=0xFE;
farins=AC-farins;
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xDF : // DEM/DCP $0000,X : M <- (M)-1, (A-M) -> NZC
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=X;
PC++;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
farins -= 1;
break;
case 6: mem->Write(ptr,farins);
(AC>=farins) ? ST|=0x01 : ST&=0xFE;
farins=AC-farins;
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xE3 : // INB/ISB ($00,X) - M <- (M) + 1, A <- (A) - M - C
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: ptr=mem->Read(nextins);
break;
case 4: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 5: nextins=mem->Read(ptr);
break;
case 6: mem->Write(ptr,nextins);
nextins += 1;
break;
case 7: mem->Write(ptr,nextins);
SBC(nextins);
cycle=0;
break;
}
break;
case 0xE7 : // INB/ISB $00 - M <- (M) + 1, A <- (A) - M - C
switch (cycle++) {
case 1: PC++;
ptr=nextins;
break;
case 2: nextins=mem->Read(ptr);
break;
case 3: mem->Write(ptr,nextins);
nextins += 1;
break;
case 4: mem->Write(ptr,nextins);
SBC(nextins);
cycle=0;
break;
}
break;
case 0xEB : // SBC #$00 - illegal version
PC++;
SBC(nextins);
cycle=0;
break;
case 0xEF : // INB/ISB $0000
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
break;
case 3: farins=mem->Read(ptr);
break;
case 4: mem->Write(ptr,farins);
farins += 1;
break;
case 5: mem->Write(ptr,farins);
SBC(farins);
cycle=0;
break;
}
break;
case 0xF3 : // INB/ISB ($00),Y - increase and subtract from AC
switch (cycle++) {
case 1: PC++;
break;
case 2: ptr=mem->Read(nextins);
break;
case 3: nextins += 1;
ptr|=(mem->Read(nextins)<<8);
break;
case 4: break;
case 5: farins=mem->Read(ptr+Y);
break;
case 6: mem->Write(ptr+Y,farins);
farins+=1;
break;
case 7: mem->Write(ptr+Y,farins);
SBC(farins);
cycle=0;
break;
}
break;
case 0xF4 : // NOP $60,X
switch (cycle++) {
case 1: PC++;
break;
case 2: break;
case 3: cycle=0;
break;
}
break;
case 0xF7 : // INB/ISB $00,X - M <- (M) + 1, A <- (A) - M - C
switch (cycle++) {
case 1: PC++;
break;
case 2: nextins+=X;
break;
case 3: farins=mem->Read(nextins);
break;
case 4: mem->Write(nextins,farins);
farins += 1;
break;
case 5: mem->Write(nextins,farins);
SBC(farins);
cycle=0;
break;
}
break;
case 0xFB : // INB/ISB $0000,Y - increase and subtract from AC
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: ptr+=Y;
PC++;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
farins += 1;
break;
case 6: mem->Write(ptr,farins);
SBC(farins);
cycle=0;
break;
}
break;
case 0xFF : // INB/ISB $0000,X - increase and subtract from AC
switch (cycle++) {
case 1: PC++;
ptr=nextins|(mem->Read(PC)<<8);
break;
case 2: PC++;
ptr+=X;
break;
case 3: break;
case 4: farins=mem->Read(ptr);
break;
case 5: mem->Write(ptr,farins);
farins += 1;
break;
case 6: mem->Write(ptr,farins);
SBC(farins);
cycle=0;
break;
}
break;
case 0x02 : // ABS, JAM, KIL or whatever - jams the machine
case 0x12 : // ABS, JAM, KIL or whatever - jams the machine
case 0x22 : // ABS, JAM, KIL or whatever - jams the machine
case 0x32 : // ABS, JAM, KIL or whatever - jams the machine
case 0x42 : // ABS, JAM, KIL or whatever - jams the machine
case 0x52 : // ABS, JAM, KIL or whatever - jams the machine
case 0x62 : // ABS, JAM, KIL or whatever - jams the machine
case 0x72 : // ABS, JAM, KIL or whatever - jams the machine
case 0x92 : // ABS, JAM, KIL or whatever - jams the machine
case 0xB2 : // ABS, JAM, KIL or whatever - jams the machine
case 0xD2 : // ABS, JAM, KIL or whatever - jams the machine
case 0xF2 : // ABS, JAM, KIL or whatever - jams the machine
cycle = 0;
PC = (PC-1)&0xFFFF;
bp_reached = bp_active = cpu_jammed = true;
break;
default : cycle=1; // can't happen!
}
/*if ((*irq_register)&0x80 && cycle && !irq_sequence)
IRQcount = 1;*/
}
// in these cycles, only write operations are allowed for the CPU
void CPU::stopcycle()
{
//unsigned int old_cycle = cycle;
switch (currins) {
case 0x00 : // BRK
switch (cycle) {
case 2: push(PC>>8);
cycle++;
break;
case 3: push(PC&0xFF);
cycle++;
break;
case 4: // BRK pushes the status register to the stack with the B bit set
// if not an IRQ
push((ST|0x30)&~irq_sequence);
//push(ST&0xEF);
// and then masks the interrupt bit
ST|=0x04;
cycle++;
break;
}
break;
/*case 0x100 : // IRQ
switch (cycle) {
case 2: push(PC>>8);
cycle++;
break;
case 3: push(PC&0xFF);
cycle++;
break;
case 4: push((ST|0x20)&0xEF);
// and then masks the interrupt bit
ST|=0x04;
cycle++;
break;
}
break;
case 0x00 : // BRK
switch (cycle) {
case 2: push(PC>>8);
cycle++;
break;
case 3: push(PC&0xFF);
cycle++;
break;
case 4: // BRK pushes the status register to the stack with the B bit set
// if not an IRQ
push((ST|0x30));
// and then masks the interrupt bit
ST|=0x04;
cycle++;
break;
}
break;*/
case 0x08 : // PHP
if (cycle==2) {
// the PHP always pushes the status with the B flag set...
push(ST|0x30);
cycle=0;
}
break;
case 0x48 : // PHA
if (cycle==2) {
push(AC);
cycle=0;
}
break;
case 0x20 : // JSR
switch (cycle) {
case 3: push(PC>>8);
cycle++;
break;
case 4: push(PC&0xFF);
cycle++;
break;
}
break;
case 0x06 : // ASL $00
switch (cycle) {
case 3: mem->Write(nextins,farins);
farins<<=1;
++cycle;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x07 : // ASO/SLO $00 : A <- (M << 1) \/ A
switch (cycle) {
case 3: mem->Write(ptr,nextins);
(nextins)&0x80 ? ST|=0x01 : ST&=0xFE;
nextins<<=1;
cycle++;
break;
case 4: mem->Write(ptr,nextins);
AC|=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x0E : // ASL $0000
switch (cycle) {
case 4: mem->Write(ptr,nextins);
(nextins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
nextins<<=1;
++cycle;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x0F : // ASO/SLO $0000 : A <- (M << 1) \/ A
switch (cycle) {
case 4: mem->Write(ptr,nextins);
(nextins)&0x80 ? ST|=0x01 : ST&=0xFE;
nextins<<=1;
cycle++;
break;
case 5: mem->Write(ptr,nextins);
AC|=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x16 : // ASL $00,X
switch (cycle) {
case 4: mem->Write(nextins,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
++cycle;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x17 : // ASO/SLO $00,X : A <- (M << 1) \/ A
switch (cycle) {
case 4: mem->Write(ptr,farins);
(farins)&0x80 ? ST|=0x01 : ST&=0xFE;
farins<<=1;
cycle++;
break;
case 5: mem->Write(ptr,farins);
AC|=farins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x1E : // ASL $0000,X
switch (cycle) {
case 5: mem->Write(ptr,nextins);
(nextins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
nextins<<=1;
++cycle;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x26 : // ROL $00
switch (cycle) {
case 3: mem->Write(ptr,farins);
farins&0x80 ? ST|=0x01 : ST&=0xFE; // the Carry flag
++cycle;
break;
case 4: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x27 : // RAN/RLA $00 - A <- (M << 1) /\ (A)
switch (cycle) {
case 3: mem->Write(ptr,farins);
nextins=(farins<<1)|(ST&0x01);
cycle++;
break;
case 4: mem->Write(ptr,nextins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x2E : // ROL $0000
switch (cycle) {
case 4: mem->Write(ptr,farins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
++cycle;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x2F : // RAN/RLA $0000
switch (cycle) {
case 4: mem->Write(ptr, farins);
nextins=(farins<<1)|(ST&0x01);
cycle++;
break;
case 5: mem->Write(ptr,nextins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x36 : // ROL $00,X
switch (cycle) {
case 4: mem->Write(ptr,farins);
nextins=(farins<<1)|((ST&0x01));
farins&0x80 ? ST|=0x01 : ST&=0xFE;
++cycle;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x37 : // RAN/RLA $00,X - A <- (M << 1) /\ (A)
switch (cycle) {
case 4: mem->Write(ptr,farins);
(farins&0x80) ? ST|=0x01 : ST&=0xFE; // the Carry flag
cycle++;
break;
case 5: mem->Write(ptr,nextins);
AC&=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x3E : // ROL $0000,X
switch (cycle) {
case 5: mem->Write(ptr,farins);
++cycle;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x43: // LSE/SRE ($00,X) - A <- (M >> 1) ^ A
switch (cycle) {
case 6: mem->Write(ptr, nextins);
nextins & 0x01 ? ST |= 0x01 : ST &= 0xFE;
nextins >>= 1;
cycle++;
break;
case 7: mem->Write(ptr, nextins);
AC ^= nextins;
SETFLAGS_ZN(AC);
cycle = 0;
break;
}
break;
case 0x46 : // LSR $00
switch (cycle) {
case 3: mem->Write(nextins,farins);
farins>>=1;
++cycle;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x47 : // LSE/SRE $00 - A <- (M >> 1) \-/ A
switch (cycle) {
case 3: mem->Write(ptr,nextins);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
nextins>>=1;
cycle++;
break;
case 4: mem->Write(ptr,nextins);
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x4E : // LSR $0000
switch (cycle) {
case 4: mem->Write(ptr,nextins);
nextins=nextins>>1;
++cycle;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x4F : // LSE/SRE $0000 - A <- (M >> 1) \-/ A
switch (cycle) {
case 4: mem->Write(ptr,nextins);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
nextins>>=1;
cycle++;
break;
case 5: mem->Write(ptr,nextins);
AC^=nextins;
SETFLAGS_ZN(AC);
cycle=0;
break;
}
break;
case 0x56 : // LSR $00,X
switch (cycle) {
case 4: mem->Write(nextins,farins);
farins>>=1;
++cycle;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0x5E : // LSR $0000,X
switch (cycle) {
case 5: mem->Write(ptr,nextins);
nextins>>=1;
++cycle;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x66 : // ROR $00
switch (cycle) {
case 3: mem->Write(ptr,farins);
farins&0x01 ? ST|=0x01 : ST&=0xFE; // the Carry flag
++cycle;
break;
case 4: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x67 : // RAD/RRA $00
switch (cycle) {
case 3: mem->Write(ptr,nextins);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
cycle++;
break;
case 4: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x6E : // ROR $0000
switch (cycle) {
case 4: mem->Write(ptr,farins);
nextins=(farins>>1)|((ST&0x01)<<7);
(farins&0x01) ? ST|=0x01 : ST&=0xFE; // the Carry flag
++cycle;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x6F : // RAD/RRA $0000
switch (cycle) {
case 4: mem->Write(ptr,nextins);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
cycle++;
break;
case 5: mem->Write(ptr,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x73 : // RAD/RRA ($00),Y - A <- (M >> 1) + (A) + C
switch (cycle) {
case 6: mem->Write(ptr+Y,nextins);
farins=(nextins>>1)|((ST&0x01)<<7);
nextins&0x01 ? ST|=0x01 : ST&=0xFE;
cycle++;
break;
case 7: mem->Write(ptr+Y,farins);
ADC(farins);
cycle=0;
break;
}
break;
case 0x76 : // ROR $00,X
switch (cycle) {
case 4: mem->Write(ptr,farins);
farins&0x01 ? ST|=0x01 : ST&=0xFE; // the Carry flag
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0x7E : // ROR $0000,X
switch (cycle) {
case 5: mem->Write(ptr,farins);
++cycle;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
// indexed indirect
case 0x81 : // STA ($00,X)
if (cycle==5) {
mem->Write(ptr,AC);
cycle=0;
}
break;
case 0x83 : // AXX/SAX ($00,X) - M <- (A) /\ (X)
if (cycle==5) {
mem->Write(ptr,AC&X);
cycle=0;
}
break;
case 0x84 : // STY $00
if (cycle==2) {
mem->Write(nextins,Y);
cycle=0;
}
break;
case 0x85 : // STA $00
if (cycle==2) {
mem->Write(nextins,AC);
cycle=0;
}
break;
case 0x86 : // STX $00
if (cycle==2) {
mem->Write(nextins,X);
cycle=0;
}
break;
case 0x87 : // AAX/AXR/SAX $00 - M <- (A) /\ (X)
if (cycle==2) {
mem->Write(nextins,AC&X);
cycle=0;
}
break;
case 0x8C : // STY $0000
if (cycle==3) {
mem->Write(ptr,Y);
cycle=0;
}
break;
case 0x8D : // STA $0000
if (cycle==3) {
mem->Write(ptr,AC);
cycle=0;
}
break;
case 0x8E : // STX $0000
if (cycle==3) {
mem->Write(ptr,X);
cycle=0;
}
break;
case 0x8F : // AAX/SAX $0000
if (cycle==3) {
mem->Write(ptr,AC&X);
cycle=0;
}
break;
// indirect indexed
case 0x91 : // STA ($00),Y
if (cycle==5) {
mem->Write(ptr+Y,AC);
cycle=0;
}
break;
// zero page indexed with X or Y
case 0x94 : // STY $00,X
switch (cycle) {
case 3: mem->Write(nextins,Y);
cycle=0;
break;
}
break;
case 0x95 : // STA $00,X
switch (cycle) {
case 3: mem->Write(nextins,AC);
cycle=0;
break;
}
break;
case 0x96 : // STX $00,Y
switch (cycle) {
case 3: mem->Write(nextins,X);
cycle=0;
break;
}
break;
case 0x97 : // AXY/SAX $00,Y
if (cycle==3) {
mem->Write(nextins,AC&X);
cycle=0;
}
break;
case 0x99 : // STA $0000,Y
if (cycle==4) {
mem->Write(ptr+Y,AC);
cycle=0;
}
break;
case 0x9C : // AYI/SHY $0000,X
if (cycle==4) {
if (nextins+X<256)
mem->Write(ptr+X,Y&(nextins+1));
cycle=0;
}
break;
case 0x9D : // STA $0000,X
if (cycle==4) {
mem->Write(ptr+X,AC);
cycle=0;
}
break;
case 0xC6 : // DEC $00
switch (cycle) {
case 3: mem->Write(nextins,farins);
--farins;
++cycle;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xC7 : // DEM/DCP $00
switch (cycle) {
case 3: mem->Write(ptr,nextins);
nextins -= 1;
cycle++;
break;
case 4: mem->Write(ptr,nextins);
(AC>=nextins) ? ST|=0x01 : ST&=0xFE;
nextins=AC-nextins;
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xCE : // DEC $0000
switch (cycle) {
case 4: mem->Write(ptr,nextins);
--nextins;
++cycle;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xCF : // DEM/DCP $0000
switch (cycle) {
case 4: mem->Write(ptr,farins);
farins -= 1;
cycle++;
break;
case 5: mem->Write(ptr,farins);
(AC>=farins) ? ST|=0x01 : ST&=0xFE;
farins=AC-farins;
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xD6 : // DEC $00,X
switch (cycle) {
case 4: mem->Write(nextins,farins);
--farins;
++cycle;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xD7 : // DEM/DCP $00,X - M <- (M)-1, (A-M) -> NZC
switch (cycle) {
case 4: mem->Write(ptr,nextins);
nextins-=1;
cycle++;
break;
case 5: mem->Write(ptr,nextins);
(AC>=nextins) ? ST|=0x01 : ST&=0xFE;
nextins=AC-nextins;
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xDE : // DEC $0000,X
switch (cycle) {
case 5: mem->Write(ptr,nextins);
--nextins;
++cycle;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xE6 : // INC $00
switch (cycle) {
case 3: mem->Write(nextins,farins);
++farins;
++cycle;
break;
case 4: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xE7 : // INB/ISB $00 - M <- (M) + 1, A <- (A) - M - C
switch (cycle) {
case 3: mem->Write(ptr,nextins);
nextins += 1;
cycle++;
break;
case 4: mem->Write(ptr,nextins);
SBC(nextins);
cycle=0;
break;
}
break;
case 0xEE : // INC $0000
switch (cycle) {
case 4: mem->Write(ptr,nextins);
++nextins;
++cycle;
break;
case 5: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xEF : // INB/ISB $0000 - should be here but BAG protector won't work!
switch (cycle) {
case 4: mem->Write(ptr,farins);
farins += 1;
cycle++;
break;
case 5: mem->Write(ptr,farins);
SBC(farins);
cycle=0;
break;
}
break;
case 0xF6 : // INC $00,X
switch (cycle) {
case 4: mem->Write(nextins,farins);
++farins;
++cycle;
break;
case 5: mem->Write(nextins,farins);
SETFLAGS_ZN(farins);
cycle=0;
break;
}
break;
case 0xFE : // INC $0000,X
switch (cycle) {
case 5: mem->Write(ptr,nextins);
++nextins;
++cycle;
break;
case 6: mem->Write(ptr,nextins);
SETFLAGS_ZN(nextins);
cycle=0;
break;
}
break;
case 0xFF : // INB/ISB $0000,X - increase and subtract from AC
switch (cycle) {
case 5: mem->Write(ptr,farins);
farins += 1;
cycle++;
break;
case 6: mem->Write(ptr,farins);
SBC(farins);
cycle=0;
break;
default:
return;
}
break;
}
}
/*
void CPU::_stopcycle()
{
switch (currins) {
case 0:
if (cycle>1 && cycle<5)
process();
break;
case 0x20:
if (cycle==3 || cycle==4)
process();
break;
default:
switch (write_cycles[currins]) {
case 2:
break;
case 1:
break;
default:
break;
}
break;
}
}*/
CPU::~CPU()
{
}
// Drive CPU class overrides
DRIVECPU::DRIVECPU(MemoryHandler *memhandler, unsigned char *irqreg, unsigned char *cpustack,
unsigned char *vpin, unsigned char *so_enable, unsigned int id)
: CPU(memhandler, irqreg, cpustack)
{
char cpuid[8];
sprintf(cpuid, "CPU%u", id);
setId(cpuid);
irq_sequence = 0;
IRQcount = 0;
flag_v_pin_edge = vpin;
is_so_enable = so_enable;
}
unsigned char DRIVECPU::CheckVFlag()
{
// bit #1 of the VIA2 is connected to the V flag on the drive CPU
// The SO pin on the 6502 is input only
// as long as bit 1 of the byte in $1C0C is clear, SO cannot go low
if ( ((*is_so_enable)&0x02) && *flag_v_pin_edge) {
*flag_v_pin_edge = 0;
ST |=0x40;
}
return (ST&0x40);
}
void DRIVECPU::ClearVFlag()
{
*flag_v_pin_edge = 0;
ST &= 0xBF;
}