| #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 |
| cycle++; |
| 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; |
| } |
| |