Думав, що я б продовжував і розміщував власне виконання. Це ЦІЛЬКО неперевершене, але це повноцінна реалізація.
- 668 рядків C. (не рахуючи порожніх рядків або рядків із лише коментарями)
- Підтримує (я думаю) всі незадокументовані інструкції.
- Підтримує BCD.
- Час циклу роботи процесора. (включаючи коригування для певних обговорень сторінок)
- Виконувати вказівки можна однокроковим способом або вказавши кількість кліщів.
- Підтримується підключення зовнішньої функції, яка викликається після виконання кожної інструкції. Це було тому, що він спочатку був для емулятора NES, і я використовував це для аудіосигналу.
/ * Ядро емулятора процесора Fake6502 v1.1 *******************
* (c) 2011-2013 Майк Чемберс *
**************************************************** *** /
#include <stdio.h>
#include <stdint.h>
// функції, що постачаються зовні
extern uint8_t read6502 (адреса uint16_t);
extern void write6502 (адреса uint16_t, значення uint8_t);
// 6502 визначає
#define UNDOCUMENTED // коли це визначено, недокументовані коди обробляються.
// інакше вони просто трактуються як НОП.
// # визначте NES_CPU // коли це визначено, двійково кодований десятковий (BCD)
// Прапор статусу не вшановується ADC та SBC. 2A03
// ЦП у системі розваг Nintendo не робить
// підтримка роботи BCD.
#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)
// макрос модифікатор прапора
#define setcarry () статус | = FLAG_CARRY
#define clearcarry () статус & = (~ FLAG_CARRY)
#define setzero () статус | = FLAG_ZERO
#define clearzero () статус & = (~ FLAG_ZERO)
#define setinterrupt () статус | = FLAG_INTERRUPT
#define clearinterrupt () статус & = (~ FLAG_INTERRUPT)
#define setdecimal () статус | = FLAG_DECIMAL
#define cleardecimal () статус & = (~ FLAG_DECIMAL)
#define setoverflow () статус | = FLAG_OVERFLOW
#define clearroverflow () статус & = (~ FLAG_OVERFLOW)
#define setign () статус | = FLAG_SIGN
#define clearsign () статус & = (~ FLAG_SIGN)
// макрос обчислення прапора
#define zerocalc (n) {\
якщо ((n) & 0x00FF) clearzero (); \
else setzero (); \
}
#define signcalc (n) {\
якщо ((n) & 0x0080) setign (); \
else clearsign (); \
}
#define carrycalc (n) {\
якщо ((n) & 0xFF00) встановити (); \
інакше clearcarry (); \
}
#define overflowcalc (n, m, o) {/ * n = результат, m = акумулятор, o = пам'ять * / \
якщо (((n) ^ (uint16_t) (m)) & ((n) ^ (o)) & 0x0080) setoverflow (); \
інакше clearroverflow (); \
}
// 6502 регістри процесора
uint16_t шт;
uint8_t sp, a, x, y, статус = FLAG_CONSTANT;
// хелперні змінні
uint64_t інструкції = 0; // слідкувати за виконаними загальними інструкціями
uint32_t годинник6502 = 0, годинник6502 = 0;
uint16_t oldpc, ea, reladdr, значення, результат;
uint8_t opcode, oldstatus;
// кілька загальних функцій, які використовуються різними іншими функціями
пустота push16 (uint16_t pushval) {
write6502 (BASE_STACK + sp, (pushval >> 8) & 0xFF);
write6502 (BASE_STACK + ((sp - 1) & 0xFF), pushval & 0xFF);
sp - = 2;
}
недійсний push8 (uint8_t pushval) {
write6502 (BASE_STACK + sp--, pushval);
}
uint16_t pull16 () {
uint16_t temp16;
temp16 = read6502 (BASE_STACK + ((sp + 1) & 0xFF)) | ((uint16_t) read6502 (BASE_STACK + ((sp + 2) & 0xFF)) << 8);
sp + = 2;
повернення (темп16);
}
uint8_t pull8 () {
повернення (read6502 (BASE_STACK + ++ sp));
}
недійсна скидання6502 () {
pc = (uint16_t) read6502 (0xFFFC) | ((uint16_t) read6502 (0xFFFD) << 8);
a = 0;
х = 0;
у = 0;
sp = 0xFD;
статус | = FLAG_CONSTANT;
}
статична порожнеча (* додавана [256]) ();
статична порожнеча (* optable [256]) ();
uint8_t штрафop, penaladdr;
// функції режиму адресації, обчислює ефективні адреси
статичний void imp () {// мається на увазі
}
static void acc () {// акумулятор
}
static void immu () {// негайний
ea = ПК ++;
}
static void zp () {// zero-page
ea = (uint16_t) read6502 ((uint16_t) pc ++);
}
static void zpx () {// zero-page, X
ea = ((uint16_t) read6502 ((uint16_t) pc ++) + (uint16_t) x) & 0xFF; // нульова сторінка
}
static void zpy () {// zero-page, Y
ea = ((uint16_t) read6502 ((uint16_t) pc ++) + (uint16_t) y) & 0xFF; // нульова сторінка
}
static void rel () {// відносно для операцій гілки (8-бітове безпосереднє значення, розширене знаком)
reladdr = (uint16_t) read6502 (pc ++);
якщо (reladdr & 0x80) reladdr | = 0xFF00;
}
static void abso () {// абсолют
ea = (uint16_t) read6502 (шт) | ((uint16_t) read6502 (pc + 1) << 8);
pc + = 2;
}
static void absx () {// абсолют, X
uint16_t стартова сторінка;
ea = ((uint16_t) read6502 (pc) | ((uint16_t) read6502 (pc + 1) << 8));
startpage = ea & 0xFF00;
ea + = (uint16_t) x;
if (startpage! = (ea & 0xFF00)) {// одна циклічна олівця для перетину сторінок на деяких опкодах
штрафаддр = 1;
}
pc + = 2;
}
static void absy () {// абсолют, Y
uint16_t стартова сторінка;
ea = ((uint16_t) read6502 (pc) | ((uint16_t) read6502 (pc + 1) << 8));
startpage = ea & 0xFF00;
ea + = (uint16_t) y;
if (startpage! = (ea & 0xFF00)) {// одна циклічна олівця для перетину сторінок на деяких опкодах
штрафаддр = 1;
}
pc + = 2;
}
static void ind () {// непрямий
uint16_t eahelp, eahelp2;
eahelp = (uint16_t) read6502 (шт) | (uint16_t) ((uint16_t) read6502 (pc + 1) << 8);
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); // копіювати помилку обходу сторінки 6502
ea = (uint16_t) read6502 (eahelp) | ((uint16_t) read6502 (eahelp2) << 8);
pc + = 2;
}
static void indx () {// (непрямий, X)
uint16_t eahelp;
eahelp = (uint16_t) (((uint16_t) read6502 (pc ++) + (uint16_t) x) & 0xFF); // обгортання нульової сторінки для вказівника таблиці
ea = (uint16_t) read6502 (eahelp & 0x00FF) | ((uint16_t) read6502 ((eahelp + 1) & 0x00FF) << 8);
}
static void indy () {// (непрямий), Y
uint16_t eahelp, eahelp2, початок;
eahelp = (uint16_t) read6502 (pc ++);
eahelp2 = (eahelp & 0xFF00) | ((eahelp + 1) & 0x00FF); // нульова сторінка
ea = (uint16_t) read6502 (eahelp) | ((uint16_t) read6502 (eahelp2) << 8);
startpage = ea & 0xFF00;
ea + = (uint16_t) y;
if (startpage! = (ea & 0xFF00)) {// одна циклічна олівця для перетину сторінок на деяких опкодах
штрафаддр = 1;
}
}
статичний uint16_t getvalue () {
if (addrtable [opcode] == acc) return ((uint16_t) a);
else return ((uint16_t) read6502 (ea));
}
static void putvalue (uint16_t saveval) {
if (addrtable [opcode] == acc) a = (uint8_t) (saveval & 0x00FF);
else write6502 (ea, (saveval & 0x00FF));
}
// функції обробника інструкцій
static void adc () {
пенальті = 1;
value = отримати значення ();
result = (uint16_t) a + значення + (uint16_t) (статус & FLAG_CARRY);
nosecalc (результат);
zerocalc (результат);
overflowcalc (результат, а, значення);
signcalc (результат);
#ifndef NES_CPU
якщо (статус & FLAG_DECIMAL) {
прозорий перенос ();
якщо ((a & 0x0F)> 0x09) {
a + = 0x06;
}
якщо ((a & 0xF0)> 0x90) {
a + = 0x60;
setcarry ();
}
годинник6502 ++;
}
#endif
saveaccum (результат);
}
статична пустота і () {
пенальті = 1;
value = отримати значення ();
result = (uint16_t) a & value;
zerocalc (результат);
signcalc (результат);
saveaccum (результат);
}
static void asl () {
value = отримати значення ();
результат = значення << 1;
nosecalc (результат);
zerocalc (результат);
signcalc (результат);
цінність (результат);
}
static void bcc () {
if ((статус & FLAG_CARRY) == 0) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
статична пустота bcs () {
if ((статус & FLAG_CARRY) == FLAG_CARRY) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
статична пустота beq () {
if ((статус & FLAG_ZERO) == FLAG_ZERO) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
статичний біт void () {
value = отримати значення ();
result = (uint16_t) a & value;
zerocalc (результат);
status = (статус & 0x3F) | (uint8_t) (значення & 0xC0);
}
статична порожнеча bmi () {
if ((статус & FLAG_SIGN) == FLAG_SIGN) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
статична порожнеча bne () {
if ((статус & FLAG_ZERO) == 0) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
static void bpl () {
if ((статус & FLAG_SIGN) == 0) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
static void brk () {
ПК ++;
push16 (шт); // натисніть наступну інструкцію на стек
push8 (статус | FLAG_BREAK); // натисніть стан процесора на стек
setinterrupt (); // встановити прапор переривання
pc = (uint16_t) read6502 (0xFFFE) | ((uint16_t) read6502 (0xFFFF) << 8);
}
static void bvc () {
if ((статус & FLAG_OVERFLOW) == 0) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
static void bvs () {
if ((статус & FLAG_OVERFLOW) == FLAG_OVERFLOW) {
oldpc = шт;
pc + = reladdr;
if ((oldpc & 0xFF00)! = (pc & 0xFF00)) годинники6502 + = 2; // перевірити, чи стрибок перейшов межу сторінки
інше годинникові годинники6502 ++;
}
}
static void clc () {
прозорий перенос ();
}
static void cld () {
cleardecimal ();
}
static void cli () {
чітко перервати ();
}
static void clv () {
clearroverflow ();
}
статичний void cmp () {
пенальті = 1;
value = отримати значення ();
result = (uint16_t) a - значення;
if (a> = (uint8_t) (значення & 0x00FF)) setcarry ();
else clearcarry ();
if (a == (uint8_t) (значення & 0x00FF)) setzero ();
else clearzero ();
signcalc (результат);
}
static void cpx () {
value = отримати значення ();
result = (uint16_t) x - значення;
if (x> = (uint8_t) (значення & 0x00FF)) setcarry ();
else clearcarry ();
if (x == (uint8_t) (значення & 0x00FF)) setzero ();
else clearzero ();
signcalc (результат);
}
static void cpy () {
value = отримати значення ();
result = (uint16_t) y - значення;
якщо (y> = (uint8_t) (значення & 0x00FF)) setcarry ();
else clearcarry ();
if (y == (uint8_t) (значення & 0x00FF)) setzero ();
else clearzero ();
signcalc (результат);
}
static void dec () {
value = отримати значення ();
результат = значення - 1;
zerocalc (результат);
signcalc (результат);
цінність (результат);
}
static void dex () {
х--;
zerocalc (x);
signcalc (x);
}
static void dey () {
у--;
zerocalc (y);
signcalc (y);
}
static void eor () {
пенальті = 1;
value = отримати значення ();
result = (uint16_t) a ^ значення;
zerocalc (результат);
signcalc (результат);
saveaccum (результат);
}
static void inc () {
value = отримати значення ();
результат = значення + 1;
zerocalc (результат);
signcalc (результат);
цінність (результат);
}
static void inx () {
х ++;
zerocalc (x);
signcalc (x);
}
static void iny () {
y ++;
zerocalc (y);
signcalc (y);
}
статична порожнеча jmp () {
pc = ea;
}
static void jsr () {
push16 (шт - 1);
pc = ea;
}
static void lda () {
пенальті = 1;
value = отримати значення ();
a = (uint8_t) (значення & 0x00FF);
zerocalc (a);
signcalc (a);
}
static void ldx () {
пенальті = 1;
value = отримати значення ();
x = (uint8_t) (значення & 0x00FF);
zerocalc (x);
signcalc (x);
}
static void ldy () {
пенальті = 1;
value = отримати значення ();
y = (uint8_t) (значення & 0x00FF);
zerocalc (y);
signcalc (y);
}
статична порожнеча lsr () {
value = отримати значення ();
результат = значення >> 1;
if (значення & 1) setcarry ();
else clearcarry ();
zerocalc (результат);
signcalc (результат);
цінність (результат);
}
static void nop () {
перемикач (опкод) {
корпус 0x1C:
корпус 0x3C:
корпус 0x5C:
корпус 0x7C:
корпус 0xDC:
випадок 0xFC:
пенальті = 1;
перерву;
}
}
static void ora () {
пенальті = 1;
value = отримати значення ();
результат = (uint16_t) a | значення;
zerocalc (результат);
signcalc (результат);
saveaccum (результат);
}
статична порожнеча pha () {
push8 (a);
}
static void php () {
push8 (статус | FLAG_BREAK);
}
static void pla () {
a = pull8 ();
zerocalc (a);
signcalc (a);
}
static void plp () {
статус = pull8 () | FLAG_CONSTANT;
}
static void rol () {
value = отримати значення ();
результат = (значення << 1) | (статус & FLAG_CARRY);
nosecalc (результат);
zerocalc (результат);
signcalc (результат);
цінність (результат);
}
static void ror () {
value = отримати значення ();
результат = (значення >> 1) | ((статус & FLAG_CARRY) << 7);
if (значення & 1) setcarry ();
else clearcarry ();
zerocalc (результат);
signcalc (результат);
цінність (результат);
}
static void rti () {
статус = pull8 ();
значення = pull16 ();
pc = значення;
}
static void rts () {
значення = pull16 ();
pc = значення + 1;
}
static void sbc () {
пенальті = 1;
значення = отримати значення () ^ 0x00FF;
result = (uint16_t) a + значення + (uint16_t) (статус & FLAG_CARRY);
nosecalc (результат);
zerocalc (результат);
overflowcalc (результат, а, значення);
signcalc (результат);
#ifndef NES_CPU
якщо (статус & FLAG_DECIMAL) {
прозорий перенос ();
a - = 0x66;
якщо ((a & 0x0F)> 0x09) {
a + = 0x06;
}
якщо ((a & 0xF0)> 0x90) {
a + = 0x60;
setcarry ();
}
годинник6502 ++;
}
#endif
saveaccum (результат);
}
статична порожнеча sec () {
setcarry ();
}
static void sed () {
setdecimal ();
}
static void sei () {
setinterrupt ();
}
static void sta () {
цінність (а);
}
static void stx () {
цінність (x);
}
static void sty () {
цінність (у);
}
статичний недійсний податок () {
х = а;
zerocalc (x);
signcalc (x);
}
static void tay () {
у = а;
zerocalc (y);
signcalc (y);
}
статична порожнеча tsx () {
x = sp;
zerocalc (x);
signcalc (x);
}
статична порожнеча txa () {
a = x;
zerocalc (a);
signcalc (a);
}
статична порожнеча txs () {
sp = x;
}
статична порожнеча tya () {
a = y;
zerocalc (a);
signcalc (a);
}
// Незадокументовані інструкції
#ifdef НЕ ДОКУМЕНТОВАНО
static void lax () {
lda ();
ldx ();
}
static void sax () {
sta ();
stx ();
цінність (a & x);
if (penalop && kazneaddr) годинник6502--;
}
static void dcp () {
dec ();
cmp ();
if (penalop && kazneaddr) годинник6502--;
}
static void isb () {
inc ();
sbc ();
if (penalop && kazneaddr) годинник6502--;
}
static void slo () {
asl ();
ora ();
if (penalop && kazneaddr) годинник6502--;
}
static void rla () {
rol ();
і ();
if (penalop && kazneaddr) годинник6502--;
}
static void sre () {
lsr ();
eor ();
if (penalop && kazneaddr) годинник6502--;
}
static void rra () {
ror ();
adc ();
if (penalop && kazneaddr) годинник6502--;
}
#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
статична пустота (* додавана [256]) () = {
/ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | А | Б | C | Д | Е | Ж | * /
/ * 0 * / imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, / * 0 * /
/ * 1 * / rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, / * 1 * /
/ * 2 * / abso, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, / * 2 * /
/ * 3 * / rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, / * 3 * /
/ * 4 * / imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, abso, abso, abso, abso, / * 4 * /
/ * 5 * / rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, / * 5 * /
/ * 6 * / imp, indx, imp, indx, zp, zp, zp, zp, imp, imm, acc, imm, ind, abso, abso, abso, / * 6 * /
/ * 7 * / rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, / * 7 * /
/ * 8 * / imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, / * 8 * /
/ * 9 * / rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, / * 9 * /
/ * A * / imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, / * A * /
/ * B * / rel, indy, imp, indy, zpx, zpx, zpy, zpy, imp, absy, imp, absy, absx, absx, absy, absy, / * B * /
/* C */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* C */
/* D */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx, /* D */
/* E */ imm, indx, imm, indx, zp, zp, zp, zp, imp, imm, imp, imm, abso, abso, abso, abso, /* E */
/* F */ rel, indy, imp, indy, zpx, zpx, zpx, zpx, imp, absy, imp, absy, absx, absx, absx, absx /* F */
};
static void (*optable[256])() = {
/* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | */
/* 0 */ brk, ora, nop, slo, nop, ora, asl, slo, php, ora, asl, nop, nop, ora, asl, slo, /* 0 */
/* 1 */ bpl, ora, nop, slo, nop, ora, asl, slo, clc, ora, nop, slo, nop, ora, asl, slo, /* 1 */
/* 2 */ jsr, and, nop, rla, bit, and, rol, rla, plp, and, rol, nop, bit, and, rol, rla, /* 2 */
/* 3 */ bmi, and, nop, rla, nop, and, rol, rla, sec, and, nop, rla, nop, and, rol, rla, /* 3 */
/* 4 */ rti, eor, nop, sre, nop, eor, lsr, sre, pha, eor, lsr, nop, jmp, eor, lsr, sre, /* 4 */
/* 5 */ bvc, eor, nop, sre, nop, eor, lsr, sre, cli, eor, nop, sre, nop, eor, lsr, sre, /* 5 */
/* 6 */ rts, adc, nop, rra, nop, adc, ror, rra, pla, adc, ror, nop, jmp, adc, ror, rra, /* 6 */
/* 7 */ bvs, adc, nop, rra, nop, adc, ror, rra, sei, adc, nop, rra, nop, adc, ror, rra, /* 7 */
/* 8 */ nop, sta, nop, sax, sty, sta, stx, sax, dey, nop, txa, nop, sty, sta, stx, sax, /* 8 */
/* 9 */ bcc, sta, nop, nop, sty, sta, stx, sax, tya, sta, txs, nop, nop, sta, nop, nop, /* 9 */
/* A */ ldy, lda, ldx, lax, ldy, lda, ldx, lax, tay, lda, tax, nop, ldy, lda, ldx, lax, /* A */
/* B */ bcs, lda, nop, lax, ldy, lda, ldx, lax, clv, lda, tsx, lax, ldy, lda, ldx, lax, /* B */
/* C */ cpy, cmp, nop, dcp, cpy, cmp, dec, dcp, iny, cmp, dex, nop, cpy, cmp, dec, dcp, /* C */
/* D */ bne, cmp, nop, dcp, nop, cmp, dec, dcp, cld, cmp, nop, dcp, nop, cmp, dec, dcp, /* D */
/* E */ cpx, sbc, nop, isb, cpx, sbc, inc, isb, inx, sbc, nop, sbc, cpx, sbc, inc, isb, /* E */
/* F */ beq, sbc, nop, isb, nop, sbc, inc, isb, sed, sbc, nop, isb, nop, sbc, inc, isb /* F */
};
static const uint32_t ticktable[256] = {
/* | 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 */
};
void nmi6502() {
push16(pc);
push8(status);
status |= FLAG_INTERRUPT;
pc = (uint16_t)read6502(0xFFFA) | ((uint16_t)read6502(0xFFFB) << 8);
}
void irq6502() {
push16(pc);
push8(status);
status |= FLAG_INTERRUPT;
pc = (uint16_t)read6502(0xFFFE) | ((uint16_t)read6502(0xFFFF) << 8);
}
uint8_t callexternal = 0;
void (*loopexternal)();
void exec6502(uint32_t tickcount) {
clockgoal6502 += tickcount;
while (clockticks6502 < clockgoal6502) {
opcode = read6502(pc++);
penaltyop = 0;
penaltyaddr = 0;
(*addrtable[opcode])();
(*optable[opcode])();
clockticks6502 += ticktable[opcode];
if (penaltyop && penaltyaddr) clockticks6502++;
instructions++;
if (callexternal) (*loopexternal)();
}
}
void step6502() {
opcode = read6502(pc++);
penaltyop = 0;
penaltyaddr = 0;
(*addrtable[opcode])();
(*optable[opcode])();
clockticks6502 += ticktable[opcode];
if (penaltyop && penaltyaddr) clockticks6502++;
clockgoal6502 = clockticks6502;
instructions++;
if (callexternal) (*loopexternal)();
}
void hookexternal(void *funcptr) {
if (funcptr != (void *)NULL) {
loopexternal = funcptr;
callexternal = 1;
} else callexternal = 0;
}