1556 lines
22 KiB
C++
1556 lines
22 KiB
C++
|
|
/* Original source: https://create.arduino.cc/projecthub/janost/the-nano-vic-20-e37b39 */
|
||
|
|
|
||
|
|
#include "cpu.h"
|
||
|
|
#include "kernal.h"
|
||
|
|
//#include "char_rom.h"
|
||
|
|
#include "basic.h"
|
||
|
|
//#include "bitmap.h"
|
||
|
|
|
||
|
|
#define FLAG_CARRY 0x01
|
||
|
|
#define FLAG_ZERO 0x02
|
||
|
|
#define FLAG_INTERRUPT 0x04
|
||
|
|
#define FLAG_DECIMAL 0x08
|
||
|
|
#define FLAG_BREAK 0x10
|
||
|
|
#define FLAG_CONSTANT 0x20
|
||
|
|
#define FLAG_OVERFLOW 0x40
|
||
|
|
#define FLAG_SIGN 0x80
|
||
|
|
#define BASE_STACK 0x100
|
||
|
|
#define saveaccum(n) a = (uint8_t)((n)&0x00FF)
|
||
|
|
|
||
|
|
// flag modifier macros
|
||
|
|
#define setcarry() cpustatus |= FLAG_CARRY
|
||
|
|
#define clearcarry() cpustatus &= (~FLAG_CARRY)
|
||
|
|
#define setzero() cpustatus |= FLAG_ZERO
|
||
|
|
#define clearzero() cpustatus &= (~FLAG_ZERO)
|
||
|
|
#define setinterrupt() cpustatus |= FLAG_INTERRUPT
|
||
|
|
#define clearinterrupt() cpustatus &= (~FLAG_INTERRUPT)
|
||
|
|
#define setdecimal() cpustatus |= FLAG_DECIMAL
|
||
|
|
#define cleardecimal() cpustatus &= (~FLAG_DECIMAL)
|
||
|
|
#define setoverflow() cpustatus |= FLAG_OVERFLOW
|
||
|
|
#define clearoverflow() cpustatus &= (~FLAG_OVERFLOW)
|
||
|
|
#define setsign() cpustatus |= FLAG_SIGN
|
||
|
|
#define clearsign() cpustatus &= (~FLAG_SIGN)
|
||
|
|
|
||
|
|
// flag calculation macros
|
||
|
|
#define zerocalc(n) \
|
||
|
|
{ \
|
||
|
|
if ((n)&0x00FF) \
|
||
|
|
clearzero(); \
|
||
|
|
else \
|
||
|
|
setzero(); \
|
||
|
|
}
|
||
|
|
|
||
|
|
#define signcalc(n) \
|
||
|
|
{ \
|
||
|
|
if ((n)&0x0080) \
|
||
|
|
setsign(); \
|
||
|
|
else \
|
||
|
|
clearsign(); \
|
||
|
|
}
|
||
|
|
|
||
|
|
#define carrycalc(n) \
|
||
|
|
{ \
|
||
|
|
if ((n)&0xFF00) \
|
||
|
|
setcarry(); \
|
||
|
|
else \
|
||
|
|
clearcarry(); \
|
||
|
|
}
|
||
|
|
|
||
|
|
#define overflowcalc(n, m, o) \
|
||
|
|
{ \
|
||
|
|
if (((n) ^ (uint16_t)(m)) & ((n) ^ (o)) & 0x0080) \
|
||
|
|
setoverflow(); \
|
||
|
|
else \
|
||
|
|
clearoverflow(); \
|
||
|
|
}
|
||
|
|
|
||
|
|
// 6502 CPU registers
|
||
|
|
uint16_t pc;
|
||
|
|
uint8_t sp, a, x, y, cpustatus;
|
||
|
|
|
||
|
|
// helper variables
|
||
|
|
// uint32_t instructions = 0; //keep track of total instructions executed
|
||
|
|
// int32_t clockticks6502 = 0, clockgoal6502 = 0;
|
||
|
|
uint16_t oldpc, ea, reladdr, value, result;
|
||
|
|
uint8_t opcode, oldcpustatus, useaccum;
|
||
|
|
|
||
|
|
#if defined ARDUINO_AVR_MEGA2560
|
||
|
|
#define RAMSIZE 6001
|
||
|
|
#define EESIZE 0
|
||
|
|
VIC2 vic2; //Screen register
|
||
|
|
#else
|
||
|
|
#define RAMSIZE 101 //More memory will make it unstable
|
||
|
|
#define EESIZE 1024
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define LOW_MEM_TOP 0x333 // Page 0: 0x000-0xFF, stack: 0x100-0x1FF, Kernal & Basic working area: 0x200-0x3ff
|
||
|
|
#define RAMADDR 0x800
|
||
|
|
#define EEADDR RAMADDR + RAMSIZE
|
||
|
|
#define INLINE __attribute__((always_inline))
|
||
|
|
|
||
|
|
uint8_t sysram[LOW_MEM_TOP + 1];
|
||
|
|
uint8_t videomem[VIDEOLEN];
|
||
|
|
uint8_t basicram[RAMSIZE];
|
||
|
|
|
||
|
|
INLINE uint8_t mem_read(uint16_t address)
|
||
|
|
{
|
||
|
|
if (address <= LOW_MEM_TOP)
|
||
|
|
return (sysram[address]);
|
||
|
|
if ((address >= VIDEOADDR) && (address < VIDEOADDR + VIDEOLEN)) // 0x400
|
||
|
|
return videomem[address - VIDEOADDR];
|
||
|
|
if (address >= RAMADDR && address < RAMADDR + RAMSIZE)
|
||
|
|
return basicram[address - RAMADDR];
|
||
|
|
if ((address >= EEADDR && (address < EEADDR + EESIZE)))
|
||
|
|
return EEPROM.read(address - EEADDR);
|
||
|
|
if (address >= 0xA000 && address < 0xBFFF) // Basic
|
||
|
|
return pgm_read_byte_near(basic + (address - 0xA000));
|
||
|
|
#if defined ARDUINO_AVR_MEGA2560
|
||
|
|
if (address >= 0xD000 && address < 0xDFFF) // Registers
|
||
|
|
switch (address)
|
||
|
|
{
|
||
|
|
case 0xD011:
|
||
|
|
return vic2.scr1;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
if (address >= 0xE000 && address < 0xFFFF) // Kernal
|
||
|
|
return pgm_read_byte_near(kernal + (address - 0xE000));
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
void mem_write(uint16_t address, uint8_t value)
|
||
|
|
{
|
||
|
|
if (address < LOW_MEM_TOP)
|
||
|
|
sysram[address] = value;
|
||
|
|
else if ((address >= VIDEOADDR) && (address < VIDEOADDR + VIDEOLEN))
|
||
|
|
videomem[address - VIDEOADDR] = value;
|
||
|
|
else if (address >= RAMADDR && address < RAMADDR + RAMSIZE)
|
||
|
|
basicram[address - RAMADDR] = value;
|
||
|
|
else if ((address >= EEADDR && (address < EEADDR + EESIZE)))
|
||
|
|
EEPROM.write(address - EEADDR, value);
|
||
|
|
#if defined ARDUINO_AVR_MEGA2560
|
||
|
|
if (address >= 0xD000 && address < 0xDFFF) // Registers
|
||
|
|
switch (address)
|
||
|
|
{
|
||
|
|
case 0xD011:
|
||
|
|
vic2.scr1 = value;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
// a few general functions used by various other functions
|
||
|
|
void push16(uint16_t pushval)
|
||
|
|
{
|
||
|
|
mem_write(BASE_STACK + sp, (pushval >> 8) & 0xFF);
|
||
|
|
mem_write(BASE_STACK + ((sp - 1) & 0xFF), pushval & 0xFF);
|
||
|
|
sp -= 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
void push8(uint8_t pushval)
|
||
|
|
{
|
||
|
|
mem_write(BASE_STACK + sp--, pushval);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint16_t pull16()
|
||
|
|
{
|
||
|
|
uint16_t temp16;
|
||
|
|
temp16 = mem_read(BASE_STACK + ((sp + 1) & 0xFF)) | ((uint16_t)mem_read(BASE_STACK + ((sp + 2) & 0xFF)) << 8);
|
||
|
|
sp += 2;
|
||
|
|
return (temp16);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t pull8()
|
||
|
|
{
|
||
|
|
return (mem_read(BASE_STACK + ++sp));
|
||
|
|
}
|
||
|
|
|
||
|
|
void resetCPU()
|
||
|
|
{
|
||
|
|
pc = (uint16_t)mem_read(0xFFFC) | ((uint16_t)mem_read(0xFFFD) << 8);
|
||
|
|
a = 0;
|
||
|
|
x = 0;
|
||
|
|
y = 0;
|
||
|
|
sp = 0xFF;
|
||
|
|
cpustatus |= FLAG_CONSTANT;
|
||
|
|
}
|
||
|
|
|
||
|
|
// addressing mode functions, calculates effective addresses
|
||
|
|
void imp()
|
||
|
|
{ // implied
|
||
|
|
}
|
||
|
|
|
||
|
|
void acc()
|
||
|
|
{ // accumulator
|
||
|
|
useaccum = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void imm()
|
||
|
|
{ // immediate
|
||
|
|
ea = pc++;
|
||
|
|
}
|
||
|
|
|
||
|
|
void zp()
|
||
|
|
{ // zero-page
|
||
|
|
ea = (uint16_t)mem_read((uint16_t)pc++);
|
||
|
|
}
|
||
|
|
|
||
|
|
void zpx()
|
||
|
|
{ // zero-page,X
|
||
|
|
ea = ((uint16_t)mem_read((uint16_t)pc++) + (uint16_t)x) & 0xFF; // zero-page wraparound
|
||
|
|
}
|
||
|
|
|
||
|
|
void zpy()
|
||
|
|
{ // zero-page,Y
|
||
|
|
ea = ((uint16_t)mem_read((uint16_t)pc++) + (uint16_t)y) & 0xFF; // zero-page wraparound
|
||
|
|
}
|
||
|
|
|
||
|
|
void rel()
|
||
|
|
{ // relative for branch ops (8-bit immediate value, sign-extended)
|
||
|
|
reladdr = (uint16_t)mem_read(pc++);
|
||
|
|
if (reladdr & 0x80)
|
||
|
|
reladdr |= 0xFF00;
|
||
|
|
}
|
||
|
|
|
||
|
|
void abso()
|
||
|
|
{ // absolute
|
||
|
|
ea = (uint16_t)mem_read(pc) | ((uint16_t)mem_read(pc + 1) << 8);
|
||
|
|
pc += 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
void absx()
|
||
|
|
{ // absolute,X
|
||
|
|
uint16_t startpage;
|
||
|
|
ea = ((uint16_t)mem_read(pc) | ((uint16_t)mem_read(pc + 1) << 8));
|
||
|
|
startpage = ea & 0xFF00;
|
||
|
|
ea += (uint16_t)x;
|
||
|
|
|
||
|
|
pc += 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
void absy()
|
||
|
|
{ // absolute,Y
|
||
|
|
uint16_t startpage;
|
||
|
|
ea = ((uint16_t)mem_read(pc) | ((uint16_t)mem_read(pc + 1) << 8));
|
||
|
|
startpage = ea & 0xFF00;
|
||
|
|
ea += (uint16_t)y;
|
||
|
|
|
||
|
|
pc += 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ind()
|
||
|
|
{ // indirect
|
||
|
|
uint16_t eahelp, eahelp2;
|
||
|
|
eahelp = (uint16_t)mem_read(pc) | (uint16_t)((uint16_t)mem_read(pc + 1) << 8);
|
||
|
|
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); // replicate 6502 page-boundary wraparound bug
|
||
|
|
ea = (uint16_t)mem_read(eahelp) | ((uint16_t)mem_read(eahelp2) << 8);
|
||
|
|
pc += 2;
|
||
|
|
}
|
||
|
|
|
||
|
|
void indx()
|
||
|
|
{ // (indirect,X)
|
||
|
|
uint16_t eahelp;
|
||
|
|
eahelp = (uint16_t)(((uint16_t)mem_read(pc++) + (uint16_t)x) & 0xFF); // zero-page wraparound for table pointer
|
||
|
|
ea = (uint16_t)mem_read(eahelp & 0x00FF) | ((uint16_t)mem_read((eahelp + 1) & 0x00FF) << 8);
|
||
|
|
}
|
||
|
|
|
||
|
|
void indy()
|
||
|
|
{ // (indirect),Y
|
||
|
|
uint16_t eahelp, eahelp2, startpage;
|
||
|
|
eahelp = (uint16_t)mem_read(pc++);
|
||
|
|
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); // zero-page wraparound
|
||
|
|
ea = (uint16_t)mem_read(eahelp) | ((uint16_t)mem_read(eahelp2) << 8);
|
||
|
|
startpage = ea & 0xFF00;
|
||
|
|
ea += (uint16_t)y;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint16_t getvalue()
|
||
|
|
{
|
||
|
|
if (useaccum)
|
||
|
|
return ((uint16_t)a);
|
||
|
|
else
|
||
|
|
return ((uint16_t)mem_read(ea));
|
||
|
|
}
|
||
|
|
|
||
|
|
uint16_t getvalue16()
|
||
|
|
{
|
||
|
|
return ((uint16_t)mem_read(ea) | ((uint16_t)mem_read(ea + 1) << 8));
|
||
|
|
}
|
||
|
|
|
||
|
|
void putvalue(uint16_t saveval)
|
||
|
|
{
|
||
|
|
if (useaccum)
|
||
|
|
a = (uint8_t)(saveval & 0x00FF);
|
||
|
|
else
|
||
|
|
mem_write(ea, (saveval & 0x00FF));
|
||
|
|
}
|
||
|
|
|
||
|
|
// instruction handler functions
|
||
|
|
void adc()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)a + value + (uint16_t)(cpustatus & FLAG_CARRY);
|
||
|
|
|
||
|
|
carrycalc(result);
|
||
|
|
zerocalc(result);
|
||
|
|
overflowcalc(result, a, value);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
#ifndef NES_CPU
|
||
|
|
if (cpustatus & FLAG_DECIMAL)
|
||
|
|
{
|
||
|
|
clearcarry();
|
||
|
|
|
||
|
|
if ((a & 0x0F) > 0x09)
|
||
|
|
{
|
||
|
|
a += 0x06;
|
||
|
|
}
|
||
|
|
if ((a & 0xF0) > 0x90)
|
||
|
|
{
|
||
|
|
a += 0x60;
|
||
|
|
setcarry();
|
||
|
|
}
|
||
|
|
|
||
|
|
// clockticks6502++;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
saveaccum(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void op_and()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)a & value;
|
||
|
|
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
saveaccum(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void asl()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = value << 1;
|
||
|
|
|
||
|
|
carrycalc(result);
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
putvalue(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void bcc()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_CARRY) == 0)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void bcs()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_CARRY) == FLAG_CARRY)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void beq()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_ZERO) == FLAG_ZERO)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void op_bit()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)a & value;
|
||
|
|
|
||
|
|
zerocalc(result);
|
||
|
|
cpustatus = (cpustatus & 0x3F) | (uint8_t)(value & 0xC0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void bmi()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_SIGN) == FLAG_SIGN)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void bne()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_ZERO) == 0)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void bpl()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_SIGN) == 0)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void brk()
|
||
|
|
{
|
||
|
|
pc++;
|
||
|
|
push16(pc); // push next instruction address onto stack
|
||
|
|
push8(cpustatus | FLAG_BREAK); // push CPU cpustatus to stack
|
||
|
|
setinterrupt(); // set interrupt flag
|
||
|
|
pc = (uint16_t)mem_read(0xFFFE) | ((uint16_t)mem_read(0xFFFF) << 8);
|
||
|
|
}
|
||
|
|
|
||
|
|
void bvc()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_OVERFLOW) == 0)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void bvs()
|
||
|
|
{
|
||
|
|
if ((cpustatus & FLAG_OVERFLOW) == FLAG_OVERFLOW)
|
||
|
|
{
|
||
|
|
oldpc = pc;
|
||
|
|
pc += reladdr;
|
||
|
|
// if ((oldpc & 0xFF00) != (pc & 0xFF00)) clockticks6502 += 2; //check if jump crossed a page boundary
|
||
|
|
// else clockticks6502++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void clc()
|
||
|
|
{
|
||
|
|
clearcarry();
|
||
|
|
}
|
||
|
|
|
||
|
|
void cld()
|
||
|
|
{
|
||
|
|
cleardecimal();
|
||
|
|
}
|
||
|
|
|
||
|
|
void clv()
|
||
|
|
{
|
||
|
|
clearoverflow();
|
||
|
|
}
|
||
|
|
|
||
|
|
void cmp()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)a - value;
|
||
|
|
|
||
|
|
if (a >= (uint8_t)(value & 0x00FF))
|
||
|
|
setcarry();
|
||
|
|
else
|
||
|
|
clearcarry();
|
||
|
|
if (a == (uint8_t)(value & 0x00FF))
|
||
|
|
setzero();
|
||
|
|
else
|
||
|
|
clearzero();
|
||
|
|
signcalc(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void cpx()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)x - value;
|
||
|
|
|
||
|
|
if (x >= (uint8_t)(value & 0x00FF))
|
||
|
|
setcarry();
|
||
|
|
else
|
||
|
|
clearcarry();
|
||
|
|
if (x == (uint8_t)(value & 0x00FF))
|
||
|
|
setzero();
|
||
|
|
else
|
||
|
|
clearzero();
|
||
|
|
signcalc(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void cpy()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)y - value;
|
||
|
|
|
||
|
|
if (y >= (uint8_t)(value & 0x00FF))
|
||
|
|
setcarry();
|
||
|
|
else
|
||
|
|
clearcarry();
|
||
|
|
if (y == (uint8_t)(value & 0x00FF))
|
||
|
|
setzero();
|
||
|
|
else
|
||
|
|
clearzero();
|
||
|
|
signcalc(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void dec()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = value - 1;
|
||
|
|
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
putvalue(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void dex()
|
||
|
|
{
|
||
|
|
x--;
|
||
|
|
|
||
|
|
zerocalc(x);
|
||
|
|
signcalc(x);
|
||
|
|
}
|
||
|
|
|
||
|
|
void dey()
|
||
|
|
{
|
||
|
|
y--;
|
||
|
|
|
||
|
|
zerocalc(y);
|
||
|
|
signcalc(y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void eor()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)a ^ value;
|
||
|
|
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
saveaccum(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void inc()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = value + 1;
|
||
|
|
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
putvalue(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void inx()
|
||
|
|
{
|
||
|
|
x++;
|
||
|
|
|
||
|
|
zerocalc(x);
|
||
|
|
signcalc(x);
|
||
|
|
}
|
||
|
|
|
||
|
|
void iny()
|
||
|
|
{
|
||
|
|
y++;
|
||
|
|
|
||
|
|
zerocalc(y);
|
||
|
|
signcalc(y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void jmp()
|
||
|
|
{
|
||
|
|
pc = ea;
|
||
|
|
}
|
||
|
|
|
||
|
|
void jsr()
|
||
|
|
{
|
||
|
|
push16(pc - 1);
|
||
|
|
pc = ea;
|
||
|
|
}
|
||
|
|
|
||
|
|
void lda()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
a = (uint8_t)(value & 0x00FF);
|
||
|
|
|
||
|
|
zerocalc(a);
|
||
|
|
signcalc(a);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ldx()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
x = (uint8_t)(value & 0x00FF);
|
||
|
|
|
||
|
|
zerocalc(x);
|
||
|
|
signcalc(x);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ldy()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
y = (uint8_t)(value & 0x00FF);
|
||
|
|
|
||
|
|
zerocalc(y);
|
||
|
|
signcalc(y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void lsr()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = value >> 1;
|
||
|
|
|
||
|
|
if (value & 1)
|
||
|
|
setcarry();
|
||
|
|
else
|
||
|
|
clearcarry();
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
putvalue(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void nop()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
void ora()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (uint16_t)a | value;
|
||
|
|
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
saveaccum(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void pha()
|
||
|
|
{
|
||
|
|
push8(a);
|
||
|
|
}
|
||
|
|
|
||
|
|
void php()
|
||
|
|
{
|
||
|
|
push8(cpustatus | FLAG_BREAK);
|
||
|
|
}
|
||
|
|
|
||
|
|
void pla()
|
||
|
|
{
|
||
|
|
a = pull8();
|
||
|
|
|
||
|
|
zerocalc(a);
|
||
|
|
signcalc(a);
|
||
|
|
}
|
||
|
|
|
||
|
|
void plp()
|
||
|
|
{
|
||
|
|
cpustatus = pull8() | FLAG_CONSTANT;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rol()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (value << 1) | (cpustatus & FLAG_CARRY);
|
||
|
|
|
||
|
|
carrycalc(result);
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
putvalue(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ror()
|
||
|
|
{
|
||
|
|
value = getvalue();
|
||
|
|
result = (value >> 1) | ((cpustatus & FLAG_CARRY) << 7);
|
||
|
|
|
||
|
|
if (value & 1)
|
||
|
|
setcarry();
|
||
|
|
else
|
||
|
|
clearcarry();
|
||
|
|
zerocalc(result);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
putvalue(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void rti()
|
||
|
|
{
|
||
|
|
cpustatus = pull8();
|
||
|
|
value = pull16();
|
||
|
|
pc = value;
|
||
|
|
}
|
||
|
|
|
||
|
|
void rts()
|
||
|
|
{
|
||
|
|
value = pull16();
|
||
|
|
pc = value + 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void sbc()
|
||
|
|
{
|
||
|
|
value = getvalue() ^ 0x00FF;
|
||
|
|
result = (uint16_t)a + value + (uint16_t)(cpustatus & FLAG_CARRY);
|
||
|
|
|
||
|
|
carrycalc(result);
|
||
|
|
zerocalc(result);
|
||
|
|
overflowcalc(result, a, value);
|
||
|
|
signcalc(result);
|
||
|
|
|
||
|
|
#ifndef NES_CPU
|
||
|
|
if (cpustatus & FLAG_DECIMAL)
|
||
|
|
{
|
||
|
|
clearcarry();
|
||
|
|
|
||
|
|
a -= 0x66;
|
||
|
|
if ((a & 0x0F) > 0x09)
|
||
|
|
{
|
||
|
|
a += 0x06;
|
||
|
|
}
|
||
|
|
if ((a & 0xF0) > 0x90)
|
||
|
|
{
|
||
|
|
a += 0x60;
|
||
|
|
setcarry();
|
||
|
|
}
|
||
|
|
|
||
|
|
// clockticks6502++;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
saveaccum(result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void sec()
|
||
|
|
{
|
||
|
|
setcarry();
|
||
|
|
}
|
||
|
|
|
||
|
|
void sed()
|
||
|
|
{
|
||
|
|
setdecimal();
|
||
|
|
}
|
||
|
|
|
||
|
|
void sta()
|
||
|
|
{
|
||
|
|
putvalue(a);
|
||
|
|
}
|
||
|
|
|
||
|
|
void stx()
|
||
|
|
{
|
||
|
|
putvalue(x);
|
||
|
|
}
|
||
|
|
|
||
|
|
void sty()
|
||
|
|
{
|
||
|
|
putvalue(y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void tax()
|
||
|
|
{
|
||
|
|
x = a;
|
||
|
|
|
||
|
|
zerocalc(x);
|
||
|
|
signcalc(x);
|
||
|
|
}
|
||
|
|
|
||
|
|
void tay()
|
||
|
|
{
|
||
|
|
y = a;
|
||
|
|
|
||
|
|
zerocalc(y);
|
||
|
|
signcalc(y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void tsx()
|
||
|
|
{
|
||
|
|
x = sp;
|
||
|
|
|
||
|
|
zerocalc(x);
|
||
|
|
signcalc(x);
|
||
|
|
}
|
||
|
|
|
||
|
|
void txa()
|
||
|
|
{
|
||
|
|
a = x;
|
||
|
|
|
||
|
|
zerocalc(a);
|
||
|
|
signcalc(a);
|
||
|
|
}
|
||
|
|
|
||
|
|
void txs()
|
||
|
|
{
|
||
|
|
sp = x;
|
||
|
|
}
|
||
|
|
|
||
|
|
void tya()
|
||
|
|
{
|
||
|
|
a = y;
|
||
|
|
|
||
|
|
zerocalc(a);
|
||
|
|
signcalc(a);
|
||
|
|
}
|
||
|
|
|
||
|
|
// undocumented instructions
|
||
|
|
#ifdef UNDOCUMENTED
|
||
|
|
void lax()
|
||
|
|
{
|
||
|
|
lda();
|
||
|
|
ldx();
|
||
|
|
}
|
||
|
|
|
||
|
|
void sax()
|
||
|
|
{
|
||
|
|
sta();
|
||
|
|
stx();
|
||
|
|
putvalue(a & x);
|
||
|
|
}
|
||
|
|
|
||
|
|
void dcp()
|
||
|
|
{
|
||
|
|
dec();
|
||
|
|
cmp();
|
||
|
|
}
|
||
|
|
|
||
|
|
void isb()
|
||
|
|
{
|
||
|
|
inc();
|
||
|
|
sbc();
|
||
|
|
}
|
||
|
|
|
||
|
|
void slo()
|
||
|
|
{
|
||
|
|
asl();
|
||
|
|
ora();
|
||
|
|
}
|
||
|
|
|
||
|
|
void rla()
|
||
|
|
{
|
||
|
|
rol();
|
||
|
|
op_and();
|
||
|
|
}
|
||
|
|
|
||
|
|
void sre()
|
||
|
|
{
|
||
|
|
lsr();
|
||
|
|
eor();
|
||
|
|
}
|
||
|
|
|
||
|
|
void rra()
|
||
|
|
{
|
||
|
|
ror();
|
||
|
|
adc();
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
#define lax nop
|
||
|
|
#define sax nop
|
||
|
|
#define dcp nop
|
||
|
|
#define isb nop
|
||
|
|
#define slo nop
|
||
|
|
#define rla nop
|
||
|
|
#define sre nop
|
||
|
|
#define rra nop
|
||
|
|
#endif
|
||
|
|
|
||
|
|
void nmirq()
|
||
|
|
{
|
||
|
|
// push16(pc);
|
||
|
|
// push8(cpustatus);
|
||
|
|
cpustatus |= FLAG_INTERRUPT;
|
||
|
|
pc = (uint16_t)mem_read(0xFFFA) | ((uint16_t)mem_read(0xFFFB) << 8);
|
||
|
|
}
|
||
|
|
|
||
|
|
void intrq() // Interrupt Request
|
||
|
|
{
|
||
|
|
// push16(pc);
|
||
|
|
// push8(cpustatus);
|
||
|
|
cpustatus |= FLAG_INTERRUPT;
|
||
|
|
pc = (uint16_t)mem_read(0xFFFE) | ((uint16_t)mem_read(0xFFFF) << 8);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef USE_TIMING
|
||
|
|
prog_char ticktable[256] PROGMEM = {
|
||
|
|
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
|
||
|
|
/* 0 */ 7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, /* 0 */
|
||
|
|
/* 1 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 1 */
|
||
|
|
/* 2 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, /* 2 */
|
||
|
|
/* 3 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 3 */
|
||
|
|
/* 4 */ 6, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, /* 4 */
|
||
|
|
/* 5 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 5 */
|
||
|
|
/* 6 */ 6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, /* 6 */
|
||
|
|
/* 7 */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* 7 */
|
||
|
|
/* 8 */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* 8 */
|
||
|
|
/* 9 */ 2, 6, 2, 6, 4, 4, 4, 4, 2, 5, 2, 5, 5, 5, 5, 5, /* 9 */
|
||
|
|
/* A */ 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, /* A */
|
||
|
|
/* B */ 2, 5, 2, 5, 4, 4, 4, 4, 2, 4, 2, 4, 4, 4, 4, 4, /* B */
|
||
|
|
/* C */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* C */
|
||
|
|
/* D */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, /* D */
|
||
|
|
/* E */ 2, 6, 2, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 6, 6, /* E */
|
||
|
|
/* F */ 2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7 /* F */
|
||
|
|
};
|
||
|
|
#endif
|
||
|
|
|
||
|
|
void execCPU()
|
||
|
|
{
|
||
|
|
#ifdef USE_TIMING
|
||
|
|
clockgoal6502 += tickcount;
|
||
|
|
|
||
|
|
while (clockgoal6502 > 0)
|
||
|
|
{
|
||
|
|
#else
|
||
|
|
// while (tickcount--) {
|
||
|
|
#endif
|
||
|
|
opcode = mem_read(pc++);
|
||
|
|
// Debug.print(DBG_INFO, "PC: %04X, Opcode: %02X", pc, opcode);
|
||
|
|
|
||
|
|
cpustatus |= FLAG_CONSTANT;
|
||
|
|
|
||
|
|
useaccum = 0;
|
||
|
|
|
||
|
|
switch (opcode)
|
||
|
|
{
|
||
|
|
case 0x0:
|
||
|
|
imp();
|
||
|
|
brk();
|
||
|
|
break;
|
||
|
|
case 0x1:
|
||
|
|
indx();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0x5:
|
||
|
|
zp();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0x6:
|
||
|
|
zp();
|
||
|
|
asl();
|
||
|
|
break;
|
||
|
|
case 0x8:
|
||
|
|
imp();
|
||
|
|
php();
|
||
|
|
break;
|
||
|
|
case 0x9:
|
||
|
|
imm();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0xA:
|
||
|
|
acc();
|
||
|
|
asl();
|
||
|
|
break;
|
||
|
|
case 0xD:
|
||
|
|
abso();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0xE:
|
||
|
|
abso();
|
||
|
|
asl();
|
||
|
|
break;
|
||
|
|
case 0x10:
|
||
|
|
rel();
|
||
|
|
bpl();
|
||
|
|
break;
|
||
|
|
case 0x11:
|
||
|
|
indy();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0x15:
|
||
|
|
zpx();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0x16:
|
||
|
|
zpx();
|
||
|
|
asl();
|
||
|
|
break;
|
||
|
|
case 0x18:
|
||
|
|
imp();
|
||
|
|
clc();
|
||
|
|
break;
|
||
|
|
case 0x19:
|
||
|
|
absy();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0x1D:
|
||
|
|
absx();
|
||
|
|
ora();
|
||
|
|
break;
|
||
|
|
case 0x1E:
|
||
|
|
absx();
|
||
|
|
asl();
|
||
|
|
break;
|
||
|
|
case 0x20:
|
||
|
|
abso();
|
||
|
|
jsr();
|
||
|
|
break;
|
||
|
|
case 0x21:
|
||
|
|
indx();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x24:
|
||
|
|
zp();
|
||
|
|
op_bit();
|
||
|
|
break;
|
||
|
|
case 0x25:
|
||
|
|
zp();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x26:
|
||
|
|
zp();
|
||
|
|
rol();
|
||
|
|
break;
|
||
|
|
case 0x28:
|
||
|
|
imp();
|
||
|
|
plp();
|
||
|
|
break;
|
||
|
|
case 0x29:
|
||
|
|
imm();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x2A:
|
||
|
|
acc();
|
||
|
|
rol();
|
||
|
|
break;
|
||
|
|
case 0x2C:
|
||
|
|
abso();
|
||
|
|
op_bit();
|
||
|
|
break;
|
||
|
|
case 0x2D:
|
||
|
|
abso();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x2E:
|
||
|
|
abso();
|
||
|
|
rol();
|
||
|
|
break;
|
||
|
|
case 0x30:
|
||
|
|
rel();
|
||
|
|
bmi();
|
||
|
|
break;
|
||
|
|
case 0x31:
|
||
|
|
indy();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x35:
|
||
|
|
zpx();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x36:
|
||
|
|
zpx();
|
||
|
|
rol();
|
||
|
|
break;
|
||
|
|
case 0x38:
|
||
|
|
imp();
|
||
|
|
sec();
|
||
|
|
break;
|
||
|
|
case 0x39:
|
||
|
|
absy();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x3D:
|
||
|
|
absx();
|
||
|
|
op_and();
|
||
|
|
break;
|
||
|
|
case 0x3E:
|
||
|
|
absx();
|
||
|
|
rol();
|
||
|
|
break;
|
||
|
|
case 0x40:
|
||
|
|
imp();
|
||
|
|
rti();
|
||
|
|
break;
|
||
|
|
case 0x41:
|
||
|
|
indx();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x45:
|
||
|
|
zp();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x46:
|
||
|
|
zp();
|
||
|
|
lsr();
|
||
|
|
break;
|
||
|
|
case 0x48:
|
||
|
|
imp();
|
||
|
|
pha();
|
||
|
|
break;
|
||
|
|
case 0x49:
|
||
|
|
imm();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x4A:
|
||
|
|
acc();
|
||
|
|
lsr();
|
||
|
|
break;
|
||
|
|
case 0x4C:
|
||
|
|
abso();
|
||
|
|
jmp();
|
||
|
|
break;
|
||
|
|
case 0x4D:
|
||
|
|
abso();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x4E:
|
||
|
|
abso();
|
||
|
|
lsr();
|
||
|
|
break;
|
||
|
|
case 0x50:
|
||
|
|
rel();
|
||
|
|
bvc();
|
||
|
|
break;
|
||
|
|
case 0x51:
|
||
|
|
indy();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x55:
|
||
|
|
zpx();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x56:
|
||
|
|
zpx();
|
||
|
|
lsr();
|
||
|
|
break;
|
||
|
|
case 0x58:
|
||
|
|
imp();
|
||
|
|
clearinterrupt();
|
||
|
|
// cli();
|
||
|
|
break;
|
||
|
|
case 0x59:
|
||
|
|
absy();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x5D:
|
||
|
|
absx();
|
||
|
|
eor();
|
||
|
|
break;
|
||
|
|
case 0x5E:
|
||
|
|
absx();
|
||
|
|
lsr();
|
||
|
|
break;
|
||
|
|
case 0x60:
|
||
|
|
imp();
|
||
|
|
rts();
|
||
|
|
break;
|
||
|
|
case 0x61:
|
||
|
|
indx();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x65:
|
||
|
|
zp();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x66:
|
||
|
|
zp();
|
||
|
|
ror();
|
||
|
|
break;
|
||
|
|
case 0x68:
|
||
|
|
imp();
|
||
|
|
pla();
|
||
|
|
break;
|
||
|
|
case 0x69:
|
||
|
|
imm();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x6A:
|
||
|
|
acc();
|
||
|
|
ror();
|
||
|
|
break;
|
||
|
|
case 0x6C:
|
||
|
|
ind();
|
||
|
|
jmp();
|
||
|
|
break;
|
||
|
|
case 0x6D:
|
||
|
|
abso();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x6E:
|
||
|
|
abso();
|
||
|
|
ror();
|
||
|
|
break;
|
||
|
|
case 0x70:
|
||
|
|
rel();
|
||
|
|
bvs();
|
||
|
|
break;
|
||
|
|
case 0x71:
|
||
|
|
indy();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x75:
|
||
|
|
zpx();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x76:
|
||
|
|
zpx();
|
||
|
|
ror();
|
||
|
|
break;
|
||
|
|
case 0x78:
|
||
|
|
imp();
|
||
|
|
setinterrupt();
|
||
|
|
break;
|
||
|
|
case 0x79:
|
||
|
|
absy();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x7D:
|
||
|
|
absx();
|
||
|
|
adc();
|
||
|
|
break;
|
||
|
|
case 0x7E:
|
||
|
|
absx();
|
||
|
|
ror();
|
||
|
|
break;
|
||
|
|
case 0x81:
|
||
|
|
indx();
|
||
|
|
sta();
|
||
|
|
break;
|
||
|
|
case 0x84:
|
||
|
|
zp();
|
||
|
|
sty();
|
||
|
|
break;
|
||
|
|
case 0x85:
|
||
|
|
zp();
|
||
|
|
sta();
|
||
|
|
break;
|
||
|
|
case 0x86:
|
||
|
|
zp();
|
||
|
|
stx();
|
||
|
|
break;
|
||
|
|
case 0x88:
|
||
|
|
imp();
|
||
|
|
dey();
|
||
|
|
break;
|
||
|
|
case 0x8A:
|
||
|
|
imp();
|
||
|
|
txa();
|
||
|
|
break;
|
||
|
|
case 0x8C:
|
||
|
|
abso();
|
||
|
|
sty();
|
||
|
|
break;
|
||
|
|
case 0x8D:
|
||
|
|
abso();
|
||
|
|
sta();
|
||
|
|
break;
|
||
|
|
case 0x8E:
|
||
|
|
abso();
|
||
|
|
stx();
|
||
|
|
break;
|
||
|
|
case 0x90:
|
||
|
|
rel();
|
||
|
|
bcc();
|
||
|
|
break;
|
||
|
|
case 0x91:
|
||
|
|
indy();
|
||
|
|
sta();
|
||
|
|
break;
|
||
|
|
case 0x94:
|
||
|
|
zpx();
|
||
|
|
sty();
|
||
|
|
break;
|
||
|
|
case 0x95:
|
||
|
|
zpx();
|
||
|
|
sta();
|
||
|
|
break;
|
||
|
|
case 0x96:
|
||
|
|
zpy();
|
||
|
|
stx();
|
||
|
|
break;
|
||
|
|
case 0x98:
|
||
|
|
imp();
|
||
|
|
tya();
|
||
|
|
break;
|
||
|
|
case 0x99:
|
||
|
|
absy();
|
||
|
|
sta();
|
||
|
|
break;
|
||
|
|
case 0x9A:
|
||
|
|
imp();
|
||
|
|
txs();
|
||
|
|
break;
|
||
|
|
case 0x9D:
|
||
|
|
absx();
|
||
|
|
sta();
|
||
|
|
break;
|
||
|
|
case 0xA0:
|
||
|
|
imm();
|
||
|
|
ldy();
|
||
|
|
break;
|
||
|
|
case 0xA1:
|
||
|
|
indx();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xA2:
|
||
|
|
imm();
|
||
|
|
ldx();
|
||
|
|
break;
|
||
|
|
case 0xA4:
|
||
|
|
zp();
|
||
|
|
ldy();
|
||
|
|
break;
|
||
|
|
case 0xA5:
|
||
|
|
zp();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xA6:
|
||
|
|
zp();
|
||
|
|
ldx();
|
||
|
|
break;
|
||
|
|
case 0xA8:
|
||
|
|
imp();
|
||
|
|
tay();
|
||
|
|
break;
|
||
|
|
case 0xA9:
|
||
|
|
imm();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xAA:
|
||
|
|
imp();
|
||
|
|
tax();
|
||
|
|
break;
|
||
|
|
case 0xAC:
|
||
|
|
abso();
|
||
|
|
ldy();
|
||
|
|
break;
|
||
|
|
case 0xAD:
|
||
|
|
abso();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xAE:
|
||
|
|
abso();
|
||
|
|
ldx();
|
||
|
|
break;
|
||
|
|
case 0xB0:
|
||
|
|
rel();
|
||
|
|
bcs();
|
||
|
|
break;
|
||
|
|
case 0xB1:
|
||
|
|
indy();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xB4:
|
||
|
|
zpx();
|
||
|
|
ldy();
|
||
|
|
break;
|
||
|
|
case 0xB5:
|
||
|
|
zpx();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xB6:
|
||
|
|
zpy();
|
||
|
|
ldx();
|
||
|
|
break;
|
||
|
|
case 0xB8:
|
||
|
|
imp();
|
||
|
|
clv();
|
||
|
|
break;
|
||
|
|
case 0xB9:
|
||
|
|
absy();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xBA:
|
||
|
|
imp();
|
||
|
|
tsx();
|
||
|
|
break;
|
||
|
|
case 0xBC:
|
||
|
|
absx();
|
||
|
|
ldy();
|
||
|
|
break;
|
||
|
|
case 0xBD:
|
||
|
|
absx();
|
||
|
|
lda();
|
||
|
|
break;
|
||
|
|
case 0xBE:
|
||
|
|
absy();
|
||
|
|
ldx();
|
||
|
|
break;
|
||
|
|
case 0xC0:
|
||
|
|
imm();
|
||
|
|
cpy();
|
||
|
|
break;
|
||
|
|
case 0xC1:
|
||
|
|
indx();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xC4:
|
||
|
|
zp();
|
||
|
|
cpy();
|
||
|
|
break;
|
||
|
|
case 0xC5:
|
||
|
|
zp();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xC6:
|
||
|
|
zp();
|
||
|
|
dec();
|
||
|
|
break;
|
||
|
|
case 0xC8:
|
||
|
|
imp();
|
||
|
|
iny();
|
||
|
|
break;
|
||
|
|
case 0xC9:
|
||
|
|
imm();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xCA:
|
||
|
|
imp();
|
||
|
|
dex();
|
||
|
|
break;
|
||
|
|
case 0xCC:
|
||
|
|
abso();
|
||
|
|
cpy();
|
||
|
|
break;
|
||
|
|
case 0xCD:
|
||
|
|
abso();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xCE:
|
||
|
|
abso();
|
||
|
|
dec();
|
||
|
|
break;
|
||
|
|
case 0xD0:
|
||
|
|
rel();
|
||
|
|
bne();
|
||
|
|
break;
|
||
|
|
case 0xD1:
|
||
|
|
indy();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xD5:
|
||
|
|
zpx();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xD6:
|
||
|
|
zpx();
|
||
|
|
dec();
|
||
|
|
break;
|
||
|
|
case 0xD8:
|
||
|
|
imp();
|
||
|
|
cld();
|
||
|
|
break;
|
||
|
|
case 0xD9:
|
||
|
|
absy();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xDD:
|
||
|
|
absx();
|
||
|
|
cmp();
|
||
|
|
break;
|
||
|
|
case 0xDE:
|
||
|
|
absx();
|
||
|
|
dec();
|
||
|
|
break;
|
||
|
|
case 0xE0:
|
||
|
|
imm();
|
||
|
|
cpx();
|
||
|
|
break;
|
||
|
|
case 0xE1:
|
||
|
|
indx();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xE4:
|
||
|
|
zp();
|
||
|
|
cpx();
|
||
|
|
break;
|
||
|
|
case 0xE5:
|
||
|
|
zp();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xE6:
|
||
|
|
zp();
|
||
|
|
inc();
|
||
|
|
break;
|
||
|
|
case 0xE8:
|
||
|
|
imp();
|
||
|
|
inx();
|
||
|
|
break;
|
||
|
|
case 0xE9:
|
||
|
|
imm();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xEB:
|
||
|
|
imm();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xEC:
|
||
|
|
abso();
|
||
|
|
cpx();
|
||
|
|
break;
|
||
|
|
case 0xED:
|
||
|
|
abso();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xEE:
|
||
|
|
abso();
|
||
|
|
inc();
|
||
|
|
break;
|
||
|
|
case 0xF0:
|
||
|
|
rel();
|
||
|
|
beq();
|
||
|
|
break;
|
||
|
|
case 0xF1:
|
||
|
|
indy();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xF5:
|
||
|
|
zpx();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xF6:
|
||
|
|
zpx();
|
||
|
|
inc();
|
||
|
|
break;
|
||
|
|
case 0xF8:
|
||
|
|
imp();
|
||
|
|
sed();
|
||
|
|
break;
|
||
|
|
case 0xF9:
|
||
|
|
absy();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xFD:
|
||
|
|
absx();
|
||
|
|
sbc();
|
||
|
|
break;
|
||
|
|
case 0xFE:
|
||
|
|
absx();
|
||
|
|
inc();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
#ifdef USE_TIMING
|
||
|
|
clockgoal6502 -= (int32_t)pgm_read_byte_near(ticktable + opcode);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
uint16_t getpc()
|
||
|
|
{
|
||
|
|
return (pc);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t getop()
|
||
|
|
{
|
||
|
|
return (opcode);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*Stop the BASIC Program*/
|
||
|
|
void stop()
|
||
|
|
{
|
||
|
|
push16(pc);
|
||
|
|
setcarry(); // Break
|
||
|
|
setzero(); // Simulate CTRL-C
|
||
|
|
pc = 0xA832; // Jump to BASIC Stop routine
|
||
|
|
}
|