2020-08-08 20:01:55 +00:00
|
|
|
/*
|
|
|
|
puce6502 - MOS 6502 cpu emulator
|
2021-06-24 20:55:47 +00:00
|
|
|
Last modified 21st of June 2021
|
2023-09-10 10:49:26 +00:00
|
|
|
Copyright (c) 2018 Arthur Ferreira
|
2020-08-08 20:01:55 +00:00
|
|
|
|
2020-08-14 16:36:27 +00:00
|
|
|
This version has been modified for reinette II plus, a french Apple II plus
|
|
|
|
emulator using SDL2 (https://github.com/ArthurFerreira2/reinette-II-plus).
|
|
|
|
|
|
|
|
Please download the latest version from
|
|
|
|
https://github.com/ArthurFerreira2/puce6502
|
|
|
|
|
2020-08-08 20:01:55 +00:00
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2020-09-05 22:40:24 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
// set to zero for 'normal' use
|
|
|
|
// or to 1 if you want to run the functionnal tests
|
|
|
|
#define _FUNCTIONNAL_TESTS 0
|
2020-08-08 20:01:55 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
#include "puce6502.h"
|
2020-08-08 20:01:55 +00:00
|
|
|
|
|
|
|
#define CARRY 0x01
|
|
|
|
#define ZERO 0x02
|
|
|
|
#define INTR 0x04
|
|
|
|
#define DECIM 0x08
|
|
|
|
#define BREAK 0x10
|
|
|
|
#define UNDEF 0x20
|
|
|
|
#define OFLOW 0x40
|
|
|
|
#define SIGN 0x80
|
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
#if _FUNCTIONNAL_TESTS
|
2020-08-08 20:01:55 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
// for functionnal tests, see main()
|
|
|
|
uint8_t RAM[65536];
|
|
|
|
inline uint8_t readMem(uint16_t address) { return RAM[address]; }
|
|
|
|
inline void writeMem(uint16_t address, uint8_t value) { RAM[address] = value; }
|
2020-08-08 20:01:55 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
#else
|
2020-08-08 20:01:55 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
// user provided functions
|
|
|
|
extern uint8_t readMem(uint16_t address);
|
|
|
|
extern void writeMem(uint16_t address, uint8_t value);
|
2020-09-05 22:40:24 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
#endif
|
2020-09-05 22:40:24 +00:00
|
|
|
|
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
unsigned long long int ticks = 0; // accumulated number of clock cycles
|
2020-09-05 22:40:24 +00:00
|
|
|
|
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
static uint16_t PC; // Program Counter
|
|
|
|
static uint8_t A, X, Y, SP; // Accumulator, X and y indexes and Stack Pointer
|
|
|
|
static union {
|
|
|
|
uint8_t byte;
|
|
|
|
struct {
|
|
|
|
uint8_t C : 1; // Carry
|
|
|
|
uint8_t Z : 1; // Zero
|
|
|
|
uint8_t I : 1; // Interupt-disable
|
|
|
|
uint8_t D : 1; // Decimal
|
|
|
|
uint8_t B : 1; // Break
|
|
|
|
uint8_t U : 1; // Undefined
|
|
|
|
uint8_t V : 1; // Overflow
|
|
|
|
uint8_t S : 1; // Sign
|
|
|
|
};
|
|
|
|
} P; // Processor Status
|
2020-09-05 22:40:24 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
void puce6502RST() { // Reset
|
|
|
|
PC = readMem(0xFFFC) | (readMem(0xFFFD) << 8);
|
|
|
|
SP = 0xFD;
|
|
|
|
P.I = 1;
|
|
|
|
P.U = 1;
|
|
|
|
ticks += 7;
|
2020-08-08 20:01:55 +00:00
|
|
|
}
|
|
|
|
|
2020-09-05 22:40:24 +00:00
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
void puce6502IRQ() { // Interupt Request
|
|
|
|
if (!P.I) return;
|
|
|
|
P.I = 1;
|
|
|
|
PC++;
|
|
|
|
writeMem(0x100 + SP, (PC >> 8) & 0xFF);
|
|
|
|
SP--;
|
|
|
|
writeMem(0x100 + SP, PC & 0xFF);
|
|
|
|
SP--;
|
|
|
|
writeMem(0x100 + SP, P.byte & ~BREAK);
|
|
|
|
SP--;
|
|
|
|
PC = readMem(0xFFFE) | (readMem(0xFFFF) << 8);
|
|
|
|
ticks += 7;
|
2020-08-08 20:01:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
void puce6502NMI() { // Non Maskable Interupt
|
|
|
|
P.I = 1;
|
|
|
|
PC++;
|
|
|
|
writeMem(0x100 + SP, (PC >> 8) & 0xFF);
|
|
|
|
SP--;
|
|
|
|
writeMem(0x100 + SP, PC & 0xFF);
|
|
|
|
SP--;
|
|
|
|
writeMem(0x100 + SP, P.byte & ~BREAK);
|
|
|
|
SP--;
|
|
|
|
PC = readMem(0xFFFA) | (readMem(0xFFFB) << 8);
|
|
|
|
ticks += 7;
|
2020-08-08 20:01:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-24 20:55:47 +00:00
|
|
|
/*
|
|
|
|
Addressing modes abreviations used in the comments down below :
|
|
|
|
|
|
|
|
IMP : Implied or Implicit : DEX, RTS, CLC - 25 instructions
|
|
|
|
ACC : Accumulator : ASL A, ROR A, DEC A - 4 instructions
|
|
|
|
IMM : Immediate : LDA #$A5 - 11
|
|
|
|
ZPG : Zero Page : LDA $81 - 21 instructions
|
|
|
|
ZPX : Zero Page Indexed with X : LDA $55,X - 16 instructions
|
|
|
|
ZPY : Zero Page Indexed with Y : LDX $55,Y - 2 instructions
|
|
|
|
REL : Relative : BEQ LABEL12 - 8 instructions
|
|
|
|
ABS : Absolute : LDA $2000 - 23 instructions
|
|
|
|
ABX : Absolute Indexed with X : LDA $2000,X - 15 instructions
|
|
|
|
ABY : Absolute Indexed with Y : LDA $2000,Y - 9 instructions
|
|
|
|
IND : Indirect : JMP ($1020) - 1 instruction
|
|
|
|
IZX : ZP Indexed Indirect with X (Preindexed) : LDA ($55,X) - 8 instructions
|
|
|
|
IZY : ZP Indirect Indexed with Y (Postindexed) : LDA ($55),Y - 8 instructions
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint16_t puce6502Exec(unsigned long long int cycleCount) {
|
|
|
|
register uint16_t address;
|
|
|
|
register uint8_t value8;
|
|
|
|
register uint16_t value16;
|
|
|
|
|
|
|
|
cycleCount += ticks; // cycleCount becomes the targeted ticks value
|
|
|
|
while (ticks < cycleCount) {
|
|
|
|
|
|
|
|
switch (readMem(PC++)) { // fetch instruction and increment Program Counter
|
|
|
|
|
|
|
|
case 0x00 : // IMP BRK
|
|
|
|
PC++;
|
|
|
|
writeMem(0x100 + SP, ((PC) >> 8) & 0xFF);
|
|
|
|
SP--;
|
|
|
|
writeMem(0x100 + SP, PC & 0xFF);
|
|
|
|
SP--;
|
|
|
|
writeMem(0x100 + SP, P.byte | BREAK);
|
|
|
|
SP--;
|
|
|
|
P.I = 1;
|
|
|
|
P.D = 0;
|
|
|
|
PC = readMem(0xFFFE) | (readMem(0xFFFF) << 8);
|
|
|
|
ticks += 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x01 : // IZX ORA
|
|
|
|
value8 = readMem(PC) + X;
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
A |= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x05 : // ZPG ORA
|
|
|
|
A |= readMem(readMem(PC));
|
|
|
|
PC++;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x06 : // ZPG ASL
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
value16 = readMem(address) << 1;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x08 : // IMP PHP
|
|
|
|
writeMem(0x100 + SP, P.byte | BREAK);
|
|
|
|
SP--;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x09 : // IMM ORA
|
|
|
|
A |= readMem(PC);
|
|
|
|
PC++;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0A : // ACC ASL
|
|
|
|
value16 = A << 1;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0D : // ABS ORA
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
A |= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x0E : // ABS ASL
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
value16 = readMem(address) << 1;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x10 : // REL BPL
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
if (!P.S) { // jump taken
|
|
|
|
ticks++;
|
|
|
|
if (address & SIGN)
|
|
|
|
address |= 0xFF00; // jump backward
|
|
|
|
if (((PC & 0xFF) + address) & 0xFF00) // page crossing
|
|
|
|
ticks++;
|
|
|
|
PC += address;
|
|
|
|
}
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x11 : // IZY ORA
|
|
|
|
value8 = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
ticks += (((address & 0xFF) + Y) & 0xFF00) ? 6 : 5; // page crossing
|
|
|
|
address += Y;
|
|
|
|
A |= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x15 : // ZPX ORA
|
|
|
|
A |= readMem(readMem(PC) + X);
|
|
|
|
PC++;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x16 : // ZPX ASL
|
|
|
|
address = readMem(PC) + X;
|
|
|
|
PC++;
|
|
|
|
value16 = readMem(address) << 1;
|
|
|
|
writeMem(address, value16 & 0xFF);
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = (value16 & 0xFF) > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x18 : // IMP CLC
|
|
|
|
P.C = 0;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x19 : // ABY ORA
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
ticks += ((address + Y) & 0xFF00) ? 5 : 4; // page crossing
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += Y;
|
|
|
|
A |= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x1D : // ABX ORA
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
ticks += ((address + X) & 0xFF00) ? 5 : 4; // page crossing
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
A |= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x1E : // ABX ASL
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
value16 = readMem(address) << 1;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x20 : // ABS JSR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
writeMem(0x100 + SP, (PC >> 8) & 0xFF);
|
|
|
|
SP--;
|
|
|
|
writeMem(0x100 + SP, PC & 0xFF);
|
|
|
|
SP--;
|
|
|
|
PC = address;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x21 : // IZX AND
|
|
|
|
value8 = readMem(PC) + X;
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
A &= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x24 : // ZPG BIT
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
P.Z = (A & value8) == 0;
|
|
|
|
P.byte = (P.byte & 0x3F) | (value8 & 0xC0);
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x25 : // ZPG AND
|
|
|
|
A &= readMem(readMem(PC));
|
|
|
|
PC++;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x26 : // ZPG ROL
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
value16 = (readMem(address) << 1) | P.C;
|
|
|
|
P.C = (value16 & 0x100) != 0;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x28 : // IMP PLP
|
|
|
|
SP++;
|
|
|
|
P.byte = readMem(0x100 + SP) | UNDEF;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x29 : // IMM AND
|
|
|
|
A &= readMem(PC);
|
|
|
|
PC++;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x2A : // ACC ROL
|
|
|
|
value16 = (A << 1) | P.C;
|
|
|
|
P.C = (value16 & 0x100) != 0;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x2C : // ABS BIT
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
P.Z = (A & value8) == 0;
|
|
|
|
P.byte = (P.byte & 0x3F) | (value8 & 0xC0);
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x2D : // ABS AND
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
A &= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x2E : // ABS ROL
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
value16 = (readMem(address) << 1) | P.C;
|
|
|
|
P.C = (value16 & 0x100) != 0;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x30 : // REL BMI
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
if (P.S) { // branch taken
|
|
|
|
ticks++;
|
|
|
|
if (address & SIGN)
|
|
|
|
address |= 0xFF00; // jump backward
|
|
|
|
if (((PC & 0xFF) + address) & 0xFF00) // page crossing
|
|
|
|
ticks++;
|
|
|
|
PC += address;
|
|
|
|
}
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x31 : // IZY AND
|
|
|
|
value8 = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
ticks += (((address & 0xFF) + Y) & 0xFF00) ? 6 : 5; // page crossing
|
|
|
|
address += Y;
|
|
|
|
A &= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x35 : // ZPX AND
|
|
|
|
address = (readMem(PC) + X) & 0xFF;
|
|
|
|
PC++;
|
|
|
|
A &= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x36 : // ZPX ROL
|
|
|
|
address = (readMem(PC) + X) & 0xFF;
|
|
|
|
PC++;
|
|
|
|
value16 = (readMem(address) << 1) | P.C;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x38 : // IMP SEC
|
|
|
|
P.C = 1;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x39 : // ABY AND
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
ticks += ((address + Y) & 0xFF00) ? 5 : 4; // page crossing
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += Y;
|
|
|
|
A &= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3D : // ABX AND
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
ticks += ((address + X) & 0xFF00) ? 5 : 4; // page crossing
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
A &= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x3E : // ABX ROL
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
value16 = (readMem(address) << 1) | P.C;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x40 : // IMP RTI
|
|
|
|
SP++;
|
|
|
|
P.byte = readMem(0x100 + SP);
|
|
|
|
SP++;
|
|
|
|
PC = readMem(0x100 + SP);
|
|
|
|
SP++;
|
|
|
|
PC |= readMem(0x100 + SP) << 8;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x41 : // IZX EOR
|
|
|
|
value8 = readMem(PC) + X;
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
A ^= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x45 : // ZPG EOR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
A ^= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x46 : // ZPG LSR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
P.C = (value8 & 1) != 0;
|
|
|
|
value8 = value8 >> 1;
|
|
|
|
writeMem(address, value8);
|
|
|
|
P.Z = value8 == 0;
|
|
|
|
P.S = value8 > 0x7F;
|
|
|
|
ticks += 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x48 : // IMP PHA
|
|
|
|
writeMem(0x100 + SP, A);
|
|
|
|
SP--;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x49 : // IMM EOR
|
|
|
|
A ^= readMem(PC);
|
|
|
|
PC++;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x4A : // ACC LSR
|
|
|
|
P.C = (A & 1) != 0;
|
|
|
|
A = A >> 1;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x4C : // ABS JMP
|
|
|
|
PC = readMem(PC) | (readMem(PC + 1) << 8);
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x4D : // ABS EOR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
A ^= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x4E : // ABS LSR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
P.C = (value8 & 1) != 0;
|
|
|
|
value8 = value8 >> 1;
|
|
|
|
writeMem(address, value8);
|
|
|
|
P.Z = value8 == 0;
|
|
|
|
P.S = value8 > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x50 : // REL BVC
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
if (!P.V) { // branch taken
|
|
|
|
ticks++;
|
|
|
|
if (address & SIGN)
|
|
|
|
address |= 0xFF00; // jump backward
|
|
|
|
if (((PC & 0xFF) + address) & 0xFF00) // page crossing
|
|
|
|
ticks++;
|
|
|
|
PC += address;
|
|
|
|
}
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x51 : // IZY EOR
|
|
|
|
value8 = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
ticks += (((address & 0xFF) + Y) & 0xFF00) ? 6 : 5; // page crossing
|
|
|
|
A ^= readMem(address + Y);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x55 : // ZPX EOR
|
|
|
|
address = (readMem(PC) + X) & 0xFF;
|
|
|
|
PC++;
|
|
|
|
A ^= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x56 : // ZPX LSR
|
|
|
|
address = (readMem(PC) + X) & 0xFF;
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
P.C = (value8 & 1) != 0;
|
|
|
|
value8 = value8 >> 1;
|
|
|
|
writeMem(address, value8);
|
|
|
|
P.Z = value8 == 0;
|
|
|
|
P.S = value8 > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x58 : // IMP CLI
|
|
|
|
P.I = 0;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x59 : // ABY EOR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
ticks += ((address + Y) & 0xFF00) ? 5 : 4; // page crossing
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += Y;
|
|
|
|
A ^= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x5D : // ABX EOR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
ticks += ((address + X) & 0xFF00) ? 5 : 4; // page crossing
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
A ^= readMem(address);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x5E : // ABX LSR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
value8 = readMem(address);
|
|
|
|
P.C = (value8 & 1) != 0;
|
|
|
|
value8 = value8 >> 1;
|
|
|
|
writeMem(address, value8);
|
|
|
|
P.Z = value8 == 0;
|
|
|
|
P.S = value8 > 0x7F;
|
|
|
|
ticks += 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x60 : // IMP RTS
|
|
|
|
SP++;
|
|
|
|
PC = readMem(0x100 + SP);
|
|
|
|
SP++;
|
|
|
|
PC |= readMem(0x100 + SP) << 8;
|
|
|
|
PC++;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x61 : // IZX ADC
|
|
|
|
value8 = readMem(PC) + X;
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x65 : // ZPG ADC
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x66 : // ZPG ROR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = (value8 >> 1) | (P.C << 7);
|
|
|
|
P.C = (value8 & 0x1) != 0;
|
|
|
|
value16 &= 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x68 : // IMP PLA
|
|
|
|
SP++;
|
|
|
|
A = readMem(0x100 + SP);
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x69 : // IMM ADC
|
|
|
|
value8 = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x6A : // ACC ROR
|
|
|
|
value16 = (A >> 1) | (P.C << 7);
|
|
|
|
P.C = (A & 0x1) != 0;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x6C : // IND JMP
|
|
|
|
address = readMem(PC) | readMem(PC + 1) << 8;
|
|
|
|
PC = readMem(address) | (readMem(address + 1) << 8);
|
|
|
|
ticks += 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x6D : // ABS ADC
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x6E : // ABS ROR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = (value8 >> 1) | (P.C << 7);
|
|
|
|
P.C = (value8 & 0x1) != 0;
|
|
|
|
value16 = value16 & 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x70 : // REL BVS
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
if (P.V) { // branch taken
|
|
|
|
ticks++;
|
|
|
|
if (((PC & 0xFF) + address) & 0xFF00) // page crossing
|
|
|
|
ticks++;
|
|
|
|
if (address & SIGN)
|
|
|
|
address |= 0xFF00; // jump backward
|
|
|
|
PC += address;
|
|
|
|
}
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x71 : // IZY ADC
|
|
|
|
value8 = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
if ((address + Y) & 0xFF00) // page crossing
|
|
|
|
ticks++;
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
address += Y;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 5;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x75 : // ZPX ADC
|
|
|
|
address = (readMem(PC) + X) & 0xFF;
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x76 : // ZPX ROR
|
|
|
|
address = (readMem(PC) + X) & 0xFF;
|
|
|
|
PC++;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = (value8 >> 1) | (P.C << 7);
|
|
|
|
P.C = (value8 & 0x1) != 0;
|
|
|
|
value16 = value16 & 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x78 : // IMP SEI
|
|
|
|
P.I = 1;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x79 : // ABY ADC
|
|
|
|
if ((readMem(PC) + Y) & 0xFF00)
|
|
|
|
ticks++;
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += Y;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x7D : // ABX ADC
|
|
|
|
if ((readMem(PC) + X) & 0xFF00)
|
|
|
|
ticks++;
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = A + value8 + P.C;
|
|
|
|
P.V = ((value16 ^ A) & (value16 ^ value8) & 0x0080) != 0;
|
|
|
|
if (P.D)
|
|
|
|
value16 += ((((value16 + 0x66) ^ A ^ value8) >> 3) & 0x22) * 3;
|
|
|
|
P.C = value16 > 0xFF;
|
|
|
|
A = value16 & 0xFF;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x7E : // ABX ROR
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
address += X;
|
|
|
|
value8 = readMem(address);
|
|
|
|
value16 = (value8 >> 1) | (P.C << 7);
|
|
|
|
P.C = (value8 & 0x1) != 0; // TBR
|
|
|
|
value16 = value16 & 0xFF;
|
|
|
|
writeMem(address, value16);
|
|
|
|
P.Z = value16 == 0;
|
|
|
|
P.S = value16 > 0x7F;
|
|
|
|
ticks += 7;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x81 : // IZX STA
|
|
|
|
value8 = readMem(PC) + X;
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
writeMem(address, A);
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x84 : // ZPG STY
|
|
|
|
writeMem(readMem(PC), Y);
|
|
|
|
PC++;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x85 : // ZPG STA
|
|
|
|
writeMem(readMem(PC), A);
|
|
|
|
PC++;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x86 : // ZPG STX
|
|
|
|
writeMem(readMem(PC), X);
|
|
|
|
PC++;
|
|
|
|
ticks += 3;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x88 : // IMP DEY
|
|
|
|
Y--;
|
|
|
|
P.Z = (Y & 0xFF) == 0;
|
|
|
|
P.S = (Y & SIGN) != 0;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x8A : // IMP TXA
|
|
|
|
A = X;
|
|
|
|
P.Z = A == 0;
|
|
|
|
P.S = A > 0x7F;
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x8C : // ABS STY
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
writeMem(address, Y);
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x8D : // ABS STA
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
writeMem(address, A);
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x8E : // ABS STX
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address |= readMem(PC) << 8;
|
|
|
|
PC++;
|
|
|
|
writeMem(address, X);
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x90 : // REL BCC
|
|
|
|
address = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
if (!P.C) { // branch taken
|
|
|
|
ticks++;
|
|
|
|
if (((PC & 0xFF) + address) & 0xFF00) // page crossing
|
|
|
|
ticks++;
|
|
|
|
if (address & SIGN)
|
|
|
|
address |= 0xFF00; // jump backward
|
|
|
|
PC += address;
|
|
|
|
}
|
|
|
|
ticks += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x91 : // IZY STA
|
|
|
|
value8 = readMem(PC);
|
|
|
|
PC++;
|
|
|
|
address = readMem(value8);
|
|
|
|
value8++;
|
|
|
|
address |= readMem(value8) << 8;
|
|
|
|
address += Y;
|
|
|
|
writeMem(address, A);
|
|
|
|
ticks += 6;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x94 : // ZPX STY
|
|
|
|
address = (readMem(PC) + X) & 0xFF;
|
|
|
|
PC++;
|
|
|
|
writeMem(address, Y);
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 0x95 : // ZPX STA
|
|
|
|
writeMem((readMem(PC) + X) & 0xFF, A);
|
|
|
|
PC++;
|
|
|
|
ticks += 4;
|
|
|
|
break;
|
|