fixed timing issues

This commit is contained in:
ArthurFerreira2 2021-06-25 00:08:30 +02:00 committed by GitHub
parent a5c58da8d6
commit a531330d0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 237 additions and 54 deletions

View File

@ -1,9 +1,14 @@
/* /*
puce6502 - MOS 6502 cpu emulator puce6502 - MOS 6502 cpu emulator
Last modified 1st of August 2020 Last modified 21st of June 2021
Copyright (c) 2018 Arthur Ferreira (arthur.ferreira2@gmail.com) Copyright (c) 2018 Arthur Ferreira (arthur.ferreira2@gmail.com)
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
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
@ -21,14 +26,39 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 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 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
// set to zero for 'normal' use
// or to 1 if you want to run the functionnal tests
#define _FUNCTIONNAL_TESTS 1
#include "puce6502.h" #include "puce6502.h"
// function to be provided by user to handle read and writes to locations not #define CARRY 0x01
// in ROM or in RAM : Soft Switches, extension cards ROMs, PIA, VIA, ACIA etc... #define ZERO 0x02
extern uint8_t softSwitches(uint16_t address, uint8_t value); #define INTR 0x04
#define DECIM 0x08
#define BREAK 0x10
#define UNDEF 0x20
#define OFLOW 0x40
#define SIGN 0x80
#if _FUNCTIONNAL_TESTS
// 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; }
#else
// user provided functions
extern uint8_t readMem(uint16_t address);
extern void writeMem(uint16_t address, uint8_t value);
#endif
#define CARRY 0x01 #define CARRY 0x01
@ -40,27 +70,23 @@ extern uint8_t softSwitches(uint16_t address, uint8_t value);
#define OFLOW 0x40 #define OFLOW 0x40
#define SIGN 0x80 #define SIGN 0x80
struct Operand {
static struct Operand {
uint8_t code; uint8_t code;
bool setAcc;
uint8_t value; uint8_t value;
uint16_t address; uint16_t address;
bool setAcc;
} ope; } ope;
struct Register { static struct Register {
uint8_t A,X,Y,SR,SP; uint8_t A,X,Y,SR,SP;
uint16_t PC; uint16_t PC;
} reg; } reg;
// instruction timing : unsigned long long int ticks; // exportable to user modules
// http://nparker.llx.com/a2/opcodes.html
// http://wouter.bbcmicro.net/general/6502/6502_opcodes.html
// NOT IMPLEMENTED :
// Absolute-X, absolute-Y, and Zpage-Y addressing modes need an extra cycle
// if indexing crosses a page boundary, or if the instruction writes to memory.
static int cycles[256] = { // cycle count per instruction static const int cycles[256] = { // cycles per instruction
7,6,0,0,0,3,5,0,3,2,2,0,0,4,6,0,3,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, 7,6,0,0,0,3,5,0,3,2,2,0,0,4,6,0,3,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0,
6,6,0,0,3,3,5,0,4,2,2,0,4,4,6,0,3,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, 6,6,0,0,3,3,5,0,4,2,2,0,4,4,6,0,3,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0,
6,6,0,0,0,3,5,0,3,2,2,0,3,4,6,0,3,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0, 6,6,0,0,0,3,5,0,3,2,2,0,3,4,6,0,3,5,0,0,0,4,6,0,2,4,0,0,0,4,7,0,
@ -72,20 +98,6 @@ static int cycles[256] = { // cycle count per instruction
}; };
//=============================================================== MEMORY AND I/O
inline static uint8_t readMem(uint16_t address){
if (address < RAMSIZE) return(ram[address]);
if (address >= ROMSTART) return(rom[address - ROMSTART]);
return softSwitches(address, 0); // MEMORY MAPPED I/O
}
inline static void writeMem(uint16_t address, uint8_t value){
if (address < RAMSIZE) ram[address] = value;
else if (address < ROMSTART) softSwitches(address, value);
}
//=============================================== STACK, SIGN AND OTHER ROUTINES //=============================================== STACK, SIGN AND OTHER ROUTINES
inline static void push(uint8_t value){ inline static void push(uint8_t value){
@ -96,7 +108,7 @@ inline static uint8_t pull(){
return(readMem(0x100 + ++reg.SP)); return(readMem(0x100 + ++reg.SP));
} }
inline static void setSZ(uint8_t value){ // update both the Sign & Zero FLAGS inline static void setSZ(uint8_t value){ // updates both the Sign & Zero FLAGS
if (value & 0x00FF) reg.SR &= ~ZERO; if (value & 0x00FF) reg.SR &= ~ZERO;
else reg.SR |= ZERO; else reg.SR |= ZERO;
if (value & 0x80) reg.SR |= SIGN; if (value & 0x80) reg.SR |= SIGN;
@ -109,7 +121,7 @@ inline static void branch(){ // used by the 8 branch instructions
reg.PC += ope.address; reg.PC += ope.address;
} }
inline static void makeUpdates(uint8_t val){ // used by ASL, LSR, ROL and ROR inline static void makeUpdates(uint8_t val){ // used by ASL, LSR, ROL and ROR
if (ope.setAcc){ if (ope.setAcc){
reg.A = val; reg.A = val;
ope.setAcc = false; ope.setAcc = false;
@ -145,6 +157,7 @@ static void ZPX(){ // Zero Page,X
} }
static void ZPY(){ // Zero Page,Y static void ZPY(){ // Zero Page,Y
if (readMem(reg.PC) + reg.Y > 0xFF) ticks++;
ope.address = (readMem(reg.PC++) + reg.Y) & 0xFF; ope.address = (readMem(reg.PC++) + reg.Y) & 0xFF;
ope.value = readMem(ope.address); ope.value = readMem(ope.address);
} }
@ -161,12 +174,14 @@ static void ABS(){ // ABSolute
} }
static void ABX(){ // ABsolute,X static void ABX(){ // ABsolute,X
if (readMem(reg.PC) + reg.X > 0xFF) ticks++;
ope.address = (readMem(reg.PC) | (readMem(reg.PC + 1) << 8)) + reg.X; ope.address = (readMem(reg.PC) | (readMem(reg.PC + 1) << 8)) + reg.X;
ope.value = readMem(ope.address); ope.value = readMem(ope.address);
reg.PC += 2; reg.PC += 2;
} }
static void ABY(){ // ABsolute,Y static void ABY(){ // ABsolute,Y
if (readMem(reg.PC) + reg.Y > 0xFF) ticks++;
ope.address = (readMem(reg.PC) | (readMem(reg.PC + 1) << 8)) + reg.Y; ope.address = (readMem(reg.PC) | (readMem(reg.PC + 1) << 8)) + reg.Y;
ope.value = readMem(ope.address); ope.value = readMem(ope.address);
reg.PC += 2; reg.PC += 2;
@ -204,7 +219,7 @@ void BRK(){ // BReaK
push(reg.PC & 0xFF); push(reg.PC & 0xFF);
push(reg.SR | BREAK); push(reg.SR | BREAK);
reg.SR |= INTR; reg.SR |= INTR;
reg.PC = readMem(0xFFFE) | (readMem(0xFFFF) << 8); reg.PC = readMem(0xFFFE) | ((readMem(0xFFFF) << 8)); // IRQ/BRK vect @FFFE/FF
} }
static void CLD(){ // CLear Decimal static void CLD(){ // CLear Decimal
@ -482,7 +497,7 @@ static void UND(){ // UNDefined (not a valid or supported 6502 opcode)
//================================================================== JUMP TABLES //================================================================== JUMP TABLES
static void (*instruction[])(void) = { static void (*instruction[256])(void) = {
BRK, ORA, UND, UND, UND, ORA, ASL, UND, PHP, ORA, ASL, UND, UND, ORA, ASL, UND, BRK, ORA, UND, UND, UND, ORA, ASL, UND, PHP, ORA, ASL, UND, UND, ORA, ASL, UND,
BPL, ORA, UND, UND, UND, ORA, ASL, UND, CLC, ORA, UND, UND, UND, ORA, ASL, UND, BPL, ORA, UND, UND, UND, ORA, ASL, UND, CLC, ORA, UND, UND, UND, ORA, ASL, UND,
JSR, AND, UND, UND, BIT, AND, ROL, UND, PLP, AND, ROL, UND, BIT, AND, ROL, UND, JSR, AND, UND, UND, BIT, AND, ROL, UND, PLP, AND, ROL, UND, BIT, AND, ROL, UND,
@ -501,7 +516,7 @@ static void (*instruction[])(void) = {
BEQ, SBC, UND, UND, UND, SBC, INC, UND, SED, SBC, UND, UND, UND, SBC, INC, UND BEQ, SBC, UND, UND, UND, SBC, INC, UND, SED, SBC, UND, UND, UND, SBC, INC, UND
}; };
static void (*addressing[])(void) = { static void (*addressing[256])(void) = {
IMP, IDX, IMP, IMP, IMP, ZPG, ZPG, IMP, IMP, IMM, ACC, IMP, IMP, ABS, ABS, IMP, IMP, IDX, IMP, IMP, IMP, ZPG, ZPG, IMP, IMP, IMM, ACC, IMP, IMP, ABS, ABS, IMP,
REL, IDY, IMP, IMP, IMP, ZPX, ZPX, IMP, IMP, ABY, IMP, IMP, IMP, ABX, ABX, IMP, REL, IDY, IMP, IMP, IMP, ZPX, ZPX, IMP, IMP, ABY, IMP, IMP, IMP, ABX, ABX, IMP,
ABS, IDX, IMP, IMP, ZPG, ZPG, ZPG, IMP, IMP, IMM, ACC, IMP, ABS, ABS, ABS, IMP, ABS, IDX, IMP, IMP, ZPG, ZPG, ZPG, IMP, IMP, IMM, ACC, IMP, ABS, ABS, ABS, IMP,
@ -523,15 +538,8 @@ static void (*addressing[])(void) = {
//========================================================= USER INTERFACE (API) //========================================================= USER INTERFACE (API)
void puce6502Reset(){
reg.PC = readMem(0xFFFC) | (readMem(0xFFFD) << 8);
reg.SP = 0xFF;
reg.SR = (reg.SR | INTR) & ~DECIM;
ope.setAcc = false;
ticks += 7;
}
void puce6502Exec(long long int cycleCount){ uint16_t puce6502Exec(unsigned long long int cycleCount){
cycleCount += ticks; // cycleCount becomes the target ticks value cycleCount += ticks; // cycleCount becomes the target ticks value
while (ticks < cycleCount) { while (ticks < cycleCount) {
ope.code = readMem(reg.PC++); // FETCH and increment the Program Counter ope.code = readMem(reg.PC++); // FETCH and increment the Program Counter
@ -539,4 +547,171 @@ void puce6502Exec(long long int cycleCount){
instruction[ope.code](); // EXECUTE the instruction instruction[ope.code](); // EXECUTE the instruction
ticks += cycles[ope.code]; // update ticks count ticks += cycles[ope.code]; // update ticks count
} }
return reg.PC;
} }
void puce6502RST() {
reg.PC = readMem(0xFFFC) | (readMem(0xFFFD) << 8);
reg.SP = 0xFF;
reg.SR = (reg.SR | INTR | BREAK | UNDEF) & ~DECIM;
ticks += 7;
}
void puce6502NMI() {
writeMem(0x100 + reg.SP--, ((reg.PC) >> 8) & 0xFF);
writeMem(0x100 + reg.SP--, reg.PC & 0xFF);
writeMem(0x100 + reg.SP--, reg.SR);
reg.PC = readMem(0xFFFA) | (readMem(0xFFFB) << 8);
ticks += 7;
}
void puce6502IRQ() {
if (!(reg.SR & INTR)) return;
writeMem(0x100 + reg.SP--, ((reg.PC) >> 8) & 0xFF);
writeMem(0x100 + reg.SP--, reg.PC & 0xFF);
writeMem(0x100 + reg.SP--, reg.SR);
reg.PC = readMem(0xFFFE) | (readMem(0xFFFF) << 8);
ticks += 7;
}
// ALL the code down below was used during developpment for test and debug
// and is not required for normal operation
#include <stdio.h>
static const char* mn[256] = {
"BRK","ORA","UND","UND","UND","ORA","ASL","UND","PHP","ORA","ASL","UND","UND","ORA","ASL","UND",
"BPL","ORA","UND","UND","UND","ORA","ASL","UND","CLC","ORA","UND","UND","UND","ORA","ASL","UND",
"JSR","AND","UND","UND","BIT","AND","ROL","UND","PLP","AND","ROL","UND","BIT","AND","ROL","UND",
"BMI","AND","UND","UND","UND","AND","ROL","UND","SEC","AND","UND","UND","UND","AND","ROL","UND",
"RTI","EOR","UND","UND","UND","EOR","LSR","UND","PHA","EOR","LSR","UND","JMP","EOR","LSR","UND",
"BVC","EOR","UND","UND","UND","EOR","LSR","UND","CLI","EOR","UND","UND","UND","EOR","LSR","UND",
"RTS","ADC","UND","UND","UND","ADC","ROR","UND","PLA","ADC","ROR","UND","JMP","ADC","ROR","UND",
"BVS","ADC","UND","UND","UND","ADC","ROR","UND","SEI","ADC","UND","UND","UND","ADC","ROR","UND",
"UND","STA","UND","UND","STY","STA","STX","UND","DEY","UND","TXA","UND","STY","STA","STX","UND",
"BCC","STA","UND","UND","STY","STA","STX","UND","TYA","STA","TXS","UND","UND","STA","UND","UND",
"LDY","LDA","LDX","UND","LDY","LDA","LDX","UND","TAY","LDA","TAX","UND","LDY","LDA","LDX","UND",
"BCS","LDA","UND","UND","LDY","LDA","LDX","UND","CLV","LDA","TSX","UND","LDY","LDA","LDX","UND",
"CPY","CMP","UND","UND","CPY","CMP","DEC","UND","INY","CMP","DEX","UND","CPY","CMP","DEC","UND",
"BNE","CMP","UND","UND","UND","CMP","DEC","UND","CLD","CMP","UND","UND","UND","CMP","DEC","UND",
"CPX","SBC","UND","UND","CPX","SBC","INC","UND","INX","SBC","NOP","UND","CPX","SBC","INC","UND",
"BEQ","SBC","UND","UND","UND","SBC","INC","UND","SED","SBC","UND","UND","UND","SBC","INC","UND"
};
static const int am[256] = {
0x0 , 0xC , 0x0 , 0x0 , 0x0 , 0x3 , 0x3 , 0x0 , 0x0 , 0x2 , 0x1 , 0x0 , 0x0 , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x0 , 0x4 , 0x4 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x0 , 0x8 , 0x8 , 0x0 ,
0x7 , 0xC , 0x0 , 0x0 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x2 , 0x1 , 0x0 , 0x7 , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x0 , 0x4 , 0x4 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x0 , 0x8 , 0x8 , 0x0 ,
0x0 , 0xC , 0x0 , 0x0 , 0x0 , 0x3 , 0x3 , 0x0 , 0x0 , 0x2 , 0x1 , 0x0 , 0x7 , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x0 , 0x4 , 0x4 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x0 , 0x8 , 0x8 , 0x0 ,
0x0 , 0xC , 0x0 , 0x0 , 0x0 , 0x3 , 0x3 , 0x0 , 0x0 , 0x2 , 0x1 , 0x0 , 0xA , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x0 , 0x4 , 0x4 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x0 , 0x8 , 0x8 , 0x0 ,
0x0 , 0xC , 0x0 , 0x0 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x7 , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x4 , 0x4 , 0x5 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x0 , 0x8 , 0x0 , 0x0 ,
0x2 , 0xC , 0x2 , 0x0 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x2 , 0x0 , 0x0 , 0x7 , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x4 , 0x4 , 0x5 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x8 , 0x8 , 0x9 , 0x0 ,
0x2 , 0xC , 0x0 , 0x0 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x2 , 0x0 , 0x0 , 0x7 , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x0 , 0x4 , 0x4 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x0 , 0x8 , 0x8 , 0x0 ,
0x2 , 0xC , 0x0 , 0x0 , 0x3 , 0x3 , 0x3 , 0x0 , 0x0 , 0x2 , 0x0 , 0x0 , 0x7 , 0x7 , 0x7 , 0x0 ,
0x6 , 0xD , 0x0 , 0x0 , 0x0 , 0x4 , 0x4 , 0x0 , 0x0 , 0x9 , 0x0 , 0x0 , 0x0 , 0x8 , 0x8 , 0x0
};
void dasm(uint16_t address) {
uint8_t op = readMem(address);
uint8_t b1 = readMem((address + 1) & 0xFFFF);
uint8_t b2 = readMem((address + 2) & 0xFFFF);
printf("%04X %02X ", address, op);
switch(am[op]) {
case 0x0: printf(" %s ", mn[op] ); break; // implied
case 0x1: printf(" %s A ", mn[op] ); break; // accumulator
case 0x2: printf("%02X %s #$%02X ", b1, mn[op],b1 ); break; // immediate
case 0x3: printf("%02X %s $%02X ", b1, mn[op],b1 ); break; // zero page
case 0x4: printf("%02X %s $%02X,X ", b1, mn[op],b1 ); break; // zero page, X indexed
case 0x5: printf("%02X %s $%02X,Y ", b1, mn[op],b1 ); break; // zero page, Y indexed
case 0x6: printf("%02X %s $%02X ", b1, mn[op],b1 ); break; // relative
case 0xC: printf("%02X %s ($%02X,X) ", b1, mn[op],b1 ); break; // X indexed, indirect
case 0xD: printf("%02X %s ($%02X),Y ", b1, mn[op],b1 ); break; // indirect, Y indexed
case 0x7: printf("%02X%02X %s $%02X%02X ",b1,b2,mn[op],b2,b1); break; // absolute
case 0x8: printf("%02X%02X %s $%02X%02X,X ",b1,b2,mn[op],b2,b1); break; // absolute, X indexed
case 0x9: printf("%02X%02X %s $%02X%02X,Y ",b1,b2,mn[op],b2,b1); break; // absolute, Y indexed
case 0xA: printf("%02X%02X %s ($%02X%02X) ",b1,b2,mn[op],b2,b1); break; // indirect
}
}
void printRegs() {
printf("A=%02X X=%02X Y=%02X S=%02X *S=%02X %c%c%c%c%c%c%c%c", \
reg.A, reg.X, reg.Y, reg.SP, readMem(0x100 + reg.SP), \
reg.SR&SIGN?'N':'-', reg.SR&OFLOW?'V':'-',reg.SR&UNDEF?'U':'.',reg.SR&BREAK?'B':'-', \
reg.SR&DECIM?'D':'-',reg.SR&INTR?'I':'-', reg.SR&ZERO?'Z':'-', reg.SR&CARRY?'C':'-');
}
void setPC(uint16_t address) {
reg.PC = address;
}
uint16_t getPC(){
return reg.PC;
}
#if _FUNCTIONNAL_TESTS
// 6502 functonnal tests
// using Klaus Dormann's functonnal tests published at :
// https://github.com/Klaus2m5/6502_65C02_functional_tests
int main(int argc, char* argv[]){
char *filename = "6502_functional_test.bin";
FILE *f = fopen(filename, "rb");
if (!f || fread(RAM, 1, 65536, f) != 65536) {
printf("ERROR : can't load %s\n", filename);
return(0);
}
fclose(f);
puce6502RST(); // reset the CPU
reg.PC = 0x0400; // set Program Counter to start of code
unsigned long long int oldticks = ticks;
uint16_t oldPC = 0x0400, newPC = 0x0400; // to detect the BNE $FE when an error occurs
while(1) {
dasm(newPC);
printf(" ");
newPC = puce6502Exec(1);
printRegs();
printf(" Cycles: %llu Total: %llu\n", ticks - oldticks, ticks);
oldticks = ticks;
if (newPC == 0x3469){ // 6502_functional_test SUCCESS
printf("\nReached end of 6502_functional_test @ %04X : SUCCESS !\n", newPC);
break;
}
if (newPC == oldPC ) {
printf("\n\nLoop detected @ %04X - Press ENTER to proceed with next test or CTRL<C> to stop\n\n", newPC);
return(-1);
getchar();
reg.PC = newPC + 2;
}
oldPC = newPC;
}
return(0);
}
#endif

View File

@ -3,6 +3,12 @@
Last modified 1st of August 2020 Last modified 1st of August 2020
Copyright (c) 2018 Arthur Ferreira (arthur.ferreira2@gmail.com) Copyright (c) 2018 Arthur Ferreira (arthur.ferreira2@gmail.com)
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
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
@ -22,22 +28,24 @@
THE SOFTWARE. THE SOFTWARE.
*/ */
#ifndef _CPU_H
#define _CPU_H #ifndef _PUCE6502_H
#define _PUCE6502_H
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
typedef unsigned short uint16_t; typedef unsigned short uint16_t;
typedef enum {false, true} bool; typedef enum { false, true } bool;
#define ROMSTART 0xD000 extern unsigned long long int ticks;
#define ROMSIZE 0x3000
#define RAMSIZE 0xC000
uint8_t rom[ROMSIZE]; uint16_t puce6502Exec(unsigned long long int cycleCount);
uint8_t ram[RAMSIZE]; void puce6502RST();
void puce6502IRQ();
void puce6502NMI();
long long int ticks; // void printRegs();
// void dasm(uint16_t address);
// void setPC(uint16_t address);
// uint16_t getPC();
void puce6502Reset();
void puce6502Exec(long long int cycleCount);
#endif #endif