NES emulator in progress
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
nesem/cpu.c

1884 lines
57 KiB

#include "cpu.h" //plsease read the header file before reading this file
#include "bus.h" //includes bus-wide definitions such as bus write/read functions and data types generic among all nes components
//Addressing modes
//Quick summary: I made a function pointer to one of these functions defined in init_opcodereg() as .mode, so when calling the function
//"addressing" from any opcode func, it returns a busTransaction type containing a value and adress (of that value on the bus), this is so that we
//dont have to resolve manually for each adressing mode of the opcode, we just call adressing and it points to one of the functions below,
//that resolves the adress for us and leaves us with a generic transaction type that we can then generically manipulate in each opcode func in a way that
//works with all addressing modes without having to branch code for each individual addressing type, exceptions include opcodes that may write to the accumulator,
//since the accumulator isn't on the bus, we need to (sadly) branch the code, we could mirror the accumulator to unused address on the bus, but thats overly-complicated
//and branching is just easier
//Quick tip: bytes is the arguments invoked, so for 0xFF 0xA0 0xE2 where 0xFF is the instruction, bytes is 0xA0 0xE2
//REMOVE AFTER DEBUGGING DONE
void print_stack(CPU * cpu);
busTransaction IMM(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = 0; //q: why do we set the address to 0 when its immediate (aka presented as an as-is argument without being tied to any bus address)? because any function that writes to its busTransaction types lacks an IMM mode bcuz you can't write data to nothingness (duh)
x.value = bytes;
return x;
}
busTransaction IMP(CPU * __restrict__ cpu, word bytes){
busTransaction x; //implied opcodes are opcodes that require no arguments, but to keep things uniform we made this too, IMP opcodes dont even use this at all so idk
return x;
}
busTransaction ACC(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = 0; //as explained above, the accumulator isnt on the bus, so we just branch manually for the opcodes that do this and write directly to the acc, thus the address goes unused
x.value = cpu->A;
return x;
}
busTransaction ZPG(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = bytes;
x.value = bus_read8(bytes);
return x;
}
busTransaction ZPGX(CPU * __restrict__ cpu, word bytes){ //not code related, but as a fun fact of the day, addr modes that get offsetted by X or Y were used to create simple arrays, kinda cool
busTransaction x;
bytes += cpu->X;
x.address = bytes;
x.value = bus_read8(bytes);
return x;
}
busTransaction ZPGY(CPU * __restrict__ cpu, word bytes){
busTransaction x;
bytes += cpu->Y;
x.address = bytes;
x.value = bus_read8(bytes);
return x;
}
busTransaction REL(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = 0;
x.value = cpu->PC + (char)bytes;
return x;
}
busTransaction ABS(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = bytes;
x.value = bus_read8(bytes);
return x;
}
busTransaction ABSX(CPU * __restrict__ cpu, word bytes){
busTransaction x;
bytes += cpu->X;
x.address = bytes;
x.value = bus_read8(bytes);
return x;
}
busTransaction ABSY(CPU * __restrict__ cpu, word bytes){
busTransaction x;
bytes += cpu->Y;
x.address = bytes;
x.value = bus_read8(bytes);
return x;
}
busTransaction IND(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = bus_read16(bytes);
x.value = bus_read8(x.address);
return x;
}
busTransaction INDX(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = bus_read8((bytes + cpu->X) % 256) + bus_read8((bytes + cpu->X + 1) % 256) * 256;
x.value = bus_read8(x.address);
return x;
}
busTransaction INDY(CPU * __restrict__ cpu, word bytes){
busTransaction x;
x.address = bus_read8(bytes) + bus_read8((bytes + 1) % 256) * 256 + cpu->Y;
x.value = bus_read8(x.address);
return x;
}
//Microcode Instructions
void ORA(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word)){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->A |= x.value;
cpu->SR.flags.Zero = !cpu->A;
cpu->SR.flags.Negative = cpu->A >> 7;
}
void ASL(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word)){
busTransaction y = addressing(cpu, bytes); //check line 85 for details
word x = y.value;
cpu->SR.flags.Carry = x >> 7;
x = x << 1;
if(addressing == &ACC) cpu->A = x;
else bus_write16(y.address, x);
cpu->SR.flags.Zero = !x;
cpu->SR.flags.Negative = x >> 7;
}
void AND(CPU *cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->A &= x.value;
cpu->SR.flags.Zero = !cpu->A;
cpu->SR.flags.Negative = cpu->A >> 7;
}
void BRK(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){ //0x00 Hardware interupt.
cpu->pcNeedsInc = false;
cpu->PC += 2;
cpu->SR.flags.Interrupt = 1;
byte pcLsb, pcMsb;
pcMsb = cpu->PC >> 8;
pcLsb = cpu->PC & 0x00FF;
bus_write8(cpu->SP + STACK_RAM_OFFSET, pcMsb);
cpu->SP--;
bus_write8(cpu->SP + STACK_RAM_OFFSET, pcLsb);
cpu->SP--;
cpu->SR.flags.Break = 1;
bus_write8(cpu->SP + STACK_RAM_OFFSET, cpu->SR.data);
cpu->SP--;
cpu->SR.flags.Break = 0;
word newPC = (bus_read8(0xFFFF) << 8); //read MSB
newPC |= bus_read8(0xFFFE); //read LSB
cpu->PC = newPC;
}
void PHP(CPU* cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){ //0x08 PHP Push Status register to the stack
cpu->SR.flags.Break = 1;
cpu->SR.flags.ignored = 1;
bus_write8(cpu->SP + STACK_RAM_OFFSET, cpu->SR.data);
cpu->SP--;
cpu->SR.flags.Break = 0;
#ifdef DEBUG
print_stack(cpu);
#endif
}
void BPL(CPU *cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(!cpu->SR.flags.Negative) cpu->PC = x.value;
}
void CLC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SR.flags.Carry = 0;
}
void JSR(CPU* cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){ //JSR - Jump to new absolute address
busTransaction x = addressing(cpu, bytes);
cpu->pcNeedsInc = false;
cpu->PC += 2;
byte pcLsb, pcMsb;
pcMsb = cpu->PC >> 8;
pcLsb = cpu->PC & 0x00FF;
bus_write8(cpu->SP + STACK_RAM_OFFSET, pcMsb);
cpu->SP--;
bus_write8(cpu->SP + STACK_RAM_OFFSET, pcLsb);
cpu->SP--;
cpu->PC = x.address;
}
void BIT(CPU *cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
cpu->SR.flags.Zero = !(cpu->A & x.value);
cpu->SR.flags.Negative = (x.value >> 7) & 1;
cpu->SR.flags.Overflow = (x.value >> 6) & 1;
#ifdef DEBUG
printf("\nVALUE: 0x%2X || OVF: %i || \"!!(x.value & 0b01000000)\": %i\n", x.value, cpu->SR.flags.Overflow, (!!(x.value & 0b0100000)));
#endif
}
void PLP(CPU *cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SP++;
cpu->SR.data = bus_read8(cpu->SP + STACK_RAM_OFFSET);
cpu->SR.flags.Break = 0;
cpu->SR.flags.ignored = 1;
#ifdef DEBUG
print_stack(cpu);
#endif
}
void PLA(CPU *cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SP++;
cpu->A = bus_read8(cpu->SP + STACK_RAM_OFFSET);
cpu->SR.flags.Negative = cpu->A > 7;
cpu->SR.flags.Zero = !cpu->A;
#ifdef DEBUG
print_stack(cpu);
#endif
}
void ROL(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->SR.flags.Carry = x.value >> 7;
x.value <<= 1;
x.value |= cpu->SR.flags.Carry;
cpu->SR.flags.Zero = !x.value;
cpu->SR.flags.Negative = x.value;
if(addressing == &ACC)
cpu->A = x.value;
else bus_write8(x.address, x.value);
}
void BMI(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(cpu->SR.flags.Negative) cpu->PC = x.value;
}
void ADC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word)){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
word tmp = cpu->A + x.value + cpu->SR.flags.Carry;
cpu->SR.flags.Overflow = tmp >= 128;
cpu->SR.flags.Carry = tmp > 255;
cpu->SR.flags.Zero = !((byte)tmp);
cpu->SR.flags.Negative = tmp >> 7; //check for bit 8
cpu->A = (byte)tmp;
}
void BCC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(!cpu->SR.flags.Carry) cpu->PC = x.value;
}
void BCS(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(cpu->SR.flags.Carry) cpu->PC = x.value;
}
void BEQ(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(cpu->SR.flags.Zero) cpu->PC = x.value;
}
void ROR(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
bool oldCarry = cpu->SR.flags.Carry;
cpu->SR.flags.Carry = x.value & 0b00000001;
x.value >>= 1;
#ifdef USE_OLD_ROR
x.value |= cpu->SR.flags.Carry;
cpu->SR.flags.Zero = !x.value;
cpu->SR.flags.Negative = x.value;
#else
x.value |= ((word)oldCarry) << 7;
cpu->SR.flags.Zero = (x.value == 0);
cpu->SR.flags.Negative = ((x.value & 0b10000000) != 0);
#endif
if(addressing == &ACC)
cpu->A = x.value;
else bus_write8(x.address, x.value);
}
void CLD(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SR.flags.Decimal = 0;
}
void EOR(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->A ^= x.value;
cpu->SR.flags.Zero = !cpu->A;
cpu->SR.flags.Negative = cpu->A >> 7;
}
void BNE(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(!cpu->SR.flags.Zero) cpu->PC = x.value;
}
void BVC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(!cpu->SR.flags.Overflow) cpu->PC = x.value;
}
void BVS(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes);
if(cpu->SR.flags.Overflow) cpu->PC = x.value;
}
void CLI(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SR.flags.Interrupt = 0;
}
void CLV(CPU * __restrict__ cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SR.flags.Overflow = 0;
}
void CMP(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->SR.flags.Negative = (cpu->A - x.value) >> 7;
cpu->SR.flags.Carry = (cpu->A >= x.value);
cpu->SR.flags.Zero = (cpu->A == x.value);
#ifdef DEBUG
printf("\n\n-----\nA: %i\nM: %i\n-----\n", cpu->A, x.value);
#endif
}
void CPX(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->SR.flags.Negative = (cpu->X - x.value) >> 7;
if(cpu->X < x.value){
cpu->SR.flags.Carry = 0;
cpu->SR.flags.Zero = 0;
}
if(cpu->X == x.value){
cpu->SR.flags.Carry = 1;
cpu->SR.flags.Zero = 1;
}
if(cpu->X > x.value){
cpu->SR.flags.Carry = 1;
cpu->SR.flags.Zero = 0;
}
}
void CPY(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->SR.flags.Negative = (cpu->Y - x.value) >> 7;
if(cpu->Y < x.value){
cpu->SR.flags.Carry = 0;
cpu->SR.flags.Zero = 0;
}
if(cpu->Y == x.value){
cpu->SR.flags.Carry = 1;
cpu->SR.flags.Zero = 1;
}
if(cpu->Y > x.value){
cpu->SR.flags.Carry = 1;
cpu->SR.flags.Zero = 0;
}
}
void DEC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
x.value--;
bus_write8(x.address, x.value);
cpu->SR.flags.Negative = (x.value >> 7);
cpu->SR.flags.Zero = (x.value == 0);
}
void DEX(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->X -= 1;
cpu->SR.flags.Negative = (cpu->X >> 7);
cpu->SR.flags.Zero = (cpu->X == 0);
}
void DEY(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->Y -= 1;
cpu->SR.flags.Negative = (cpu->Y >> 7);
cpu->SR.flags.Zero = (cpu->Y == 0);
}
void INC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
bus_write8(x.address, x.value + 1);
cpu->SR.flags.Zero = !x.value;
cpu->SR.flags.Negative = x.value >> 7;
}
void INX(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->X += 1;
cpu->SR.flags.Negative = (cpu->X >> 7);
cpu->SR.flags.Zero = (cpu->X == 0);
}
void INY(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->Y += 1;
cpu->SR.flags.Negative = (cpu->Y >> 7);
cpu->SR.flags.Zero = (cpu->Y == 0);
}
void JMP(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->PC = x.address;
cpu->pcNeedsInc = false;
}
void LDA(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
#ifdef DEBUG
//0x00D01C location of error
if(cpu->PC == 0x00D01C) {
printf("LDA A = %X, VAL = %X, VALUE HIGH BYTE = %X\n", cpu->A, x.value, debug_read_do_not_use_pls(0x200));
}
#endif
cpu->A = x.value;
cpu->SR.flags.Zero = (cpu->A == 0);
cpu->SR.flags.Negative = cpu->A >> 7;
}
void LDX(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->X = x.value;
cpu->SR.flags.Zero = !x.value;
cpu->SR.flags.Negative = x.value >> 7;
}
void LDY(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
cpu->Y = x.value;
cpu->SR.flags.Zero = !x.value;
cpu->SR.flags.Negative = x.value >> 7;
}
void LSR(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
byte new_val = (x.value >> 1);
bus_write8(x.address, new_val);
cpu->SR.flags.Carry = (x.value & 0b00000001);
cpu->SR.flags.Negative = 0;
cpu->SR.flags.Zero = (new_val == 0);
}
void NOP(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
//nothing to see here
}
void PHA(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
bus_write8(cpu->SP + STACK_RAM_OFFSET, cpu->A);
cpu->SP--;
#ifdef DEBUG
print_stack(cpu);
#endif
}
void RTI(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->pcNeedsInc = false;
cpu->SP++;
cpu->SR.data = bus_read8(cpu->SP + STACK_RAM_OFFSET);
cpu->SR.flags.ignored = 1;
cpu->SP++;
word newPC = bus_read8(cpu->SP + STACK_RAM_OFFSET); //read lsb
cpu->SP++;
newPC |= bus_read8(cpu->SP + STACK_RAM_OFFSET) << 8; //read msb
cpu->PC = newPC;
#ifdef DEBUG
printf("\n%04X\n", newPC);
print_stack(cpu);
#endif
}
void RTS(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SP++;
word newPC = bus_read8(cpu->SP + STACK_RAM_OFFSET);
#ifdef DEBUG
printf("\n%02X\n", newPC);
#endif
cpu->SP++;
newPC |= bus_read8(cpu->SP + STACK_RAM_OFFSET) << 8;
#ifdef DEBUG
printf("\n%04X\n", newPC);
print_stack(cpu);
#endif
cpu->PC = newPC;
}
void SBC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word)){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
word tmp = cpu->A + (x.value ^ 0xFF) + cpu->SR.flags.Carry;
cpu->SR.flags.Negative = ((byte)tmp) >> 7;
cpu->SR.flags.Zero = !((byte)tmp);
cpu->SR.flags.Carry = tmp > 0xFF;
cpu->SR.flags.Overflow = (~(cpu->A ^ x.value) & (cpu->A ^ tmp) & 0b10000000) != 0;
cpu->A = tmp;
}
void SEC(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word)){
cpu->SR.flags.Carry = 1;
}
void SEI(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word)){
cpu->SR.flags.Interrupt = 1;
}
void SED(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SR.flags.Decimal = 1;
}
void STA(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
bus_write8(x.address, cpu->A);
}
void STX(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
bus_write8(x.address, cpu->X);
}
void STY(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
busTransaction x = addressing(cpu, bytes); //check line 85 for details
bus_write8(x.address, cpu->Y);
}
void TAX(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->X = cpu->A;
cpu->SR.flags.Zero = !cpu->X;
cpu->SR.flags.Negative = cpu->X > 7;
}
void TAY(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->Y = cpu->A;
cpu->SR.flags.Zero = !cpu->Y;
cpu->SR.flags.Negative = cpu->Y > 7;
}
void TSX(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->X = cpu->SP;
cpu->SR.flags.Zero = !cpu->X;
cpu->SR.flags.Negative = cpu->X > 7;
}
void TXA(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->A = cpu->X;
cpu->SR.flags.Zero = !cpu->A;
cpu->SR.flags.Negative = cpu->A > 7;
}
void TXS(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->SP = cpu->X;
}
void TYA(CPU * cpu, word bytes, busTransaction (*addressing)(CPU *, word) ){
cpu->A = cpu->Y;
}
void init_opcodereg(CPU * cpu){ //opcode code defined starting line 139
cpu->opcodes = (struct instruction*)malloc(sizeof(struct instruction) * 0xFF); //allow memory for opcode array in cpu_opcodereg.h
#ifdef DEBUG
if(cpu->opcodes == NULL){
fprintf(stderr, "ERR: Out of Memory\n");
exit(EXIT_FAILURE);
}
#endif
//BRK codes
cpu->opcodes[0x00].microcode = &BRK;
cpu->opcodes[0x00].mode = &IMP;
cpu->opcodes[0x00].name = "Force Break";
cpu->opcodes[0x00].cycles = 7;
cpu->opcodes[0x00].bytes = 1;
//ORA codes
cpu->opcodes[0x01].microcode = &ORA;
cpu->opcodes[0x01].mode = &INDX;
cpu->opcodes[0x01].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x01].cycles = 6;
cpu->opcodes[0x01].bytes = 2;
cpu->opcodes[0x05].microcode = &ORA;
cpu->opcodes[0x05].mode = &ZPG;
cpu->opcodes[0x05].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x05].cycles = 3;
cpu->opcodes[0x05].bytes = 2;
cpu->opcodes[0x09].microcode = &ORA;
cpu->opcodes[0x09].mode = &IMM;
cpu->opcodes[0x09].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x09].cycles = 2;
cpu->opcodes[0x09].bytes = 2;
cpu->opcodes[0x0D].microcode = &ORA;
cpu->opcodes[0x0D].mode = &ABS;
cpu->opcodes[0x0D].name = "OR Accumulator with immidate";
cpu->opcodes[0x0D].cycles = 4;
cpu->opcodes[0x0D].bytes = 3;
cpu->opcodes[0x11].microcode = ORA;
cpu->opcodes[0x11].mode = &INDY;
cpu->opcodes[0x11].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x11].cycles = 5;
cpu->opcodes[0x11].bytes = 2;
cpu->opcodes[0x15].microcode = &ORA;
cpu->opcodes[0x15].mode = &ZPGX;
cpu->opcodes[0x15].name = "OR with zero page memory w/ Accumulator";
cpu->opcodes[0x15].cycles = 4;
cpu->opcodes[0x15].bytes = 2;
cpu->opcodes[0x1D].microcode = &ORA;
cpu->opcodes[0x1D].mode = &ABSX;
cpu->opcodes[0x1D].name = "OR Absolute Mem + X w/Accumulator";
cpu->opcodes[0x1D].cycles = 4;
cpu->opcodes[0x1D].bytes = 3;
cpu->opcodes[0x19].microcode = &ORA;
cpu->opcodes[0x19].mode = &ABSY;
cpu->opcodes[0x19].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x19].cycles = 4;
cpu->opcodes[0x19].bytes = 3;
//ASL codes
cpu->opcodes[0x06].microcode = &ASL;
cpu->opcodes[0x06].mode = &ZPG;
cpu->opcodes[0x06].name = "Shift Left One Bit";
cpu->opcodes[0x06].cycles = 5;
cpu->opcodes[0x06].bytes = 2;
cpu->opcodes[0x0A].microcode = &ASL;
cpu->opcodes[0x0A].mode = &ACC;
cpu->opcodes[0x0A].name = "Shift Left One Bit";
cpu->opcodes[0x0A].cycles = 2;
cpu->opcodes[0x0A].bytes = 1;
cpu->opcodes[0x0E].microcode = &ASL;
cpu->opcodes[0x0E].mode = &ABS;
cpu->opcodes[0x0E].name = "Shift Left One Bit";
cpu->opcodes[0x0E].cycles = 6;
cpu->opcodes[0x0E].bytes = 3;
cpu->opcodes[0x16].microcode = &ASL;
cpu->opcodes[0x16].mode = &ZPGX;
cpu->opcodes[0x16].name = "Shift Left One Bit zero page + X";
cpu->opcodes[0x16].cycles = 6;
cpu->opcodes[0x16].bytes = 2;
cpu->opcodes[0x1E].microcode = &ASL;
cpu->opcodes[0x1E].mode = &ABSX;
cpu->opcodes[0x1E].name = "Shift Left One Bit";
cpu->opcodes[0x1E].cycles = 7;
cpu->opcodes[0x1E].bytes = 3;
//PHP codes
cpu->opcodes[0x08].microcode = &PHP;
cpu->opcodes[0x08].mode = &IMP;
cpu->opcodes[0x08].name = "PHP Push Processor Status to Stack";
cpu->opcodes[0x08].cycles = 3;
cpu->opcodes[0x08].bytes = 1;
//BPL codes
cpu->opcodes[0x10].microcode = &BPL;
cpu->opcodes[0x10].mode = &REL;
cpu->opcodes[0x10].name = "BPL Branch on Negative";
cpu->opcodes[0x10].cycles = 2;
cpu->opcodes[0x10].bytes = 2;
//CLC codes
cpu->opcodes[0x18].microcode = &CLC;
cpu->opcodes[0x18].mode = &IMP;
cpu->opcodes[0x18].name = "Clear Carry Bit";
cpu->opcodes[0x18].cycles = 2;
cpu->opcodes[0x18].bytes = 1;
//JSR codes
cpu->opcodes[0x20].microcode = &JSR;
cpu->opcodes[0x20].mode = &ABS;
cpu->opcodes[0x20].name = "Jump and Save PC register";
cpu->opcodes[0x20].cycles = 6;
cpu->opcodes[0x20].bytes = 3;
//AND codes
cpu->opcodes[0x21].microcode = &AND;
cpu->opcodes[0x21].mode = &INDY;
cpu->opcodes[0x21].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x21].cycles = 6;
cpu->opcodes[0x21].bytes = 2;
cpu->opcodes[0x25].microcode = &AND;
cpu->opcodes[0x25].mode = &ZPG;
cpu->opcodes[0x25].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x25].cycles = 3;
cpu->opcodes[0x25].bytes = 2;
cpu->opcodes[0x29].microcode = &AND;
cpu->opcodes[0x29].mode = &IMM;
cpu->opcodes[0x29].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x29].cycles = 2;
cpu->opcodes[0x29].bytes = 2;
cpu->opcodes[0x2D].microcode = &AND;
cpu->opcodes[0x2D].mode = &ABS;
cpu->opcodes[0x2D].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x2D].cycles = 4;
cpu->opcodes[0x2D].bytes = 3;
cpu->opcodes[0x31].microcode = &AND;
cpu->opcodes[0x31].mode = &INDY;
cpu->opcodes[0x31].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x31].cycles = 5;
cpu->opcodes[0x31].bytes = 2;
cpu->opcodes[0x35].microcode = &AND;
cpu->opcodes[0x35].mode = &ZPGX;
cpu->opcodes[0x35].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x35].cycles = 4;
cpu->opcodes[0x35].bytes = 3;
cpu->opcodes[0x39].microcode = &AND;
cpu->opcodes[0x39].mode = &ABSY;
cpu->opcodes[0x39].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x39].cycles = 4;
cpu->opcodes[0x39].bytes = 3;
cpu->opcodes[0x3D].microcode = &AND;
cpu->opcodes[0x3D].mode = &ABSX;
cpu->opcodes[0x3D].name = "Perform AND logical operation on M byte over A byte";
cpu->opcodes[0x3D].cycles = 4;
cpu->opcodes[0x3D].bytes = 3;
//BIT codes
cpu->opcodes[0x24].microcode = &BIT;
cpu->opcodes[0x24].mode = &ZPG;
cpu->opcodes[0x24].name = "BIT test bits in accumulator";
cpu->opcodes[0x24].cycles = 3;
cpu->opcodes[0x24].bytes = 2;
cpu->opcodes[0x2C].microcode = &BIT;
cpu->opcodes[0x2C].mode = &ABS;
cpu->opcodes[0x2C].name = "BIT test bits in accumulator";
cpu->opcodes[0x2C].cycles = 4;
cpu->opcodes[0x2C].bytes = 3;
//ROL codes
cpu->opcodes[0x26].microcode = &ROL;
cpu->opcodes[0x26].mode = &ZPG;
cpu->opcodes[0x26].name = "Rotate bits left 1 bit zeropage";
cpu->opcodes[0x26].cycles = 5;
cpu->opcodes[0x26].bytes = 2;
cpu->opcodes[0x2A].microcode = &ROL;
cpu->opcodes[0x2A].mode = &ACC;
cpu->opcodes[0x2A].name = "Rotate bits left 1 bit zeropage";
cpu->opcodes[0x2A].cycles = 2;
cpu->opcodes[0x2A].bytes = 1;
cpu->opcodes[0x2E].microcode = &ROL;
cpu->opcodes[0x2E].mode = &ABS;
cpu->opcodes[0x2E].name = "Rotate bits left 1 bit zeropage";
cpu->opcodes[0x2E].cycles = 6;
cpu->opcodes[0x2E].bytes = 3;
cpu->opcodes[0x36].microcode = &ROL;
cpu->opcodes[0x36].mode = &ZPGX;
cpu->opcodes[0x36].name = "Rotate bits left 1 bit zeropage";
cpu->opcodes[0x36].cycles = 6;
cpu->opcodes[0x36].bytes = 2;
cpu->opcodes[0x3E].microcode = &ROL;
cpu->opcodes[0x3E].mode = &ABSX;
cpu->opcodes[0x3E].name = "Rotate bits left 1 bit zeropage";
cpu->opcodes[0x3E].cycles = 6;
cpu->opcodes[0x3E].bytes = 3;
//PLP codes
cpu->opcodes[0x28].microcode = &PLP;
cpu->opcodes[0x28].mode = &IMP;
cpu->opcodes[0x28].name = "Pull Processor Status from Stack";
cpu->opcodes[0x28].cycles = 4;
cpu->opcodes[0x28].bytes = 1;
//PLA codes
cpu->opcodes[0x68].microcode = &PLA;
cpu->opcodes[0x68].mode = &IMP;
cpu->opcodes[0x68].name = "Pull Processor Accumulator from Stack";
cpu->opcodes[0x68].cycles = 4;
cpu->opcodes[0x68].bytes = 1;
//BMI codes
cpu->opcodes[0x30].microcode = &BMI;
cpu->opcodes[0x30].mode = &REL;
cpu->opcodes[0x30].name = "Branch on Result Minus";
cpu->opcodes[0x30].cycles = 2;
cpu->opcodes[0x30].bytes = 2;
//ADC functions
cpu->opcodes[0x61].microcode = &ADC;
cpu->opcodes[0x61].name = "Add with cary Indirect X";
cpu->opcodes[0x61].mode = &ABSX;
cpu->opcodes[0x61].bytes = 2;
cpu->opcodes[0x61].cycles = 6;
cpu->opcodes[0x65].microcode = &ADC;
cpu->opcodes[0x65].mode = &ZPG;
cpu->opcodes[0x65].bytes = 2;
cpu->opcodes[0x65].cycles = 3;
cpu->opcodes[0x65].name = "Add with carry zero page";
cpu->opcodes[0x69].microcode = &ADC;
cpu->opcodes[0x69].mode = &IMM;
cpu->opcodes[0x69].name = "Add with carry Immeditae";
cpu->opcodes[0x69].bytes = 2;
cpu->opcodes[0x69].cycles = 2;
cpu->opcodes[0x6D].microcode = &ADC;
cpu->opcodes[0x6D].name = "Add with cary Absolute";
cpu->opcodes[0x6D].mode = &ABS;
cpu->opcodes[0x6D].bytes = 3;
cpu->opcodes[0x6D].cycles = 4;
cpu->opcodes[0x71].microcode = &ADC;
cpu->opcodes[0x71].name = "Add with cary Indirect Y";
cpu->opcodes[0x71].mode = &INDY;
cpu->opcodes[0x71].bytes = 2;
cpu->opcodes[0x71].cycles = 5;
cpu->opcodes[0x75].microcode = &ADC;
cpu->opcodes[0x75].name = "Add with cary Zero Page X";
cpu->opcodes[0x75].mode = &ZPGX;
cpu->opcodes[0x75].bytes = 2;
cpu->opcodes[0x75].cycles = 4;
cpu->opcodes[0x7D].microcode = &ADC;
cpu->opcodes[0x7D].name = "Add with cary Absolute X";
cpu->opcodes[0x7D].mode = &ABSX;
cpu->opcodes[0x7D].bytes = 3;
cpu->opcodes[0x7D].cycles = 4;
cpu->opcodes[0x79].microcode = &ADC;
cpu->opcodes[0x79].name = "Add with cary Absolute Y";
cpu->opcodes[0x79].mode = &ABSY;
cpu->opcodes[0x79].bytes = 3;
cpu->opcodes[0x79].cycles = 4;
//BCC codes
cpu->opcodes[0x90].microcode = &BCC;
cpu->opcodes[0x90].name = "branch on C = 0";
cpu->opcodes[0x90].mode = &REL;
cpu->opcodes[0x90].bytes = 2;
cpu->opcodes[0x90].cycles = 2;
//BCS codes
cpu->opcodes[0xB0].microcode = &BCS;
cpu->opcodes[0xB0].name = "branch on C = 1";
cpu->opcodes[0xB0].mode = &REL;
cpu->opcodes[0xB0].bytes = 2;
cpu->opcodes[0xB0].cycles = 2;
//BEQ codes
cpu->opcodes[0xF0].microcode = &BEQ;
cpu->opcodes[0xF0].name = "branch on Z = 1";
cpu->opcodes[0xF0].mode = &REL;
cpu->opcodes[0xF0].bytes = 2;
cpu->opcodes[0xF0].cycles = 2;
//ROR Codes
cpu->opcodes[0x66].microcode = &ROR;
cpu->opcodes[0x66].mode = &ZPG;
cpu->opcodes[0x66].name = "ROR Rotate bits right 1 bit zeropage";
cpu->opcodes[0x66].cycles = 5;
cpu->opcodes[0x66].bytes = 2;
cpu->opcodes[0x6A].microcode = &ROR;
cpu->opcodes[0x6A].mode = &ACC;
cpu->opcodes[0x6A].name = "Rotate bits right 1 bit accumulator";
cpu->opcodes[0x6A].cycles = 2;
cpu->opcodes[0x6A].bytes = 1;
cpu->opcodes[0x6E].microcode = &ROR;
cpu->opcodes[0x6E].mode = &ABS;
cpu->opcodes[0x6E].name = "Rotate bits right 1 bit absolute";
cpu->opcodes[0x6E].cycles = 6;
cpu->opcodes[0x6E].bytes = 3;
cpu->opcodes[0x76].microcode = &ROR;
cpu->opcodes[0x76].mode = &ZPGX;
cpu->opcodes[0x76].name = "Rotate bits right 1 bit zeropage X";
cpu->opcodes[0x76].cycles = 6;
cpu->opcodes[0x76].bytes = 2;
cpu->opcodes[0x7E].microcode = &ROR;
cpu->opcodes[0x7E].mode = &ABSX;
cpu->opcodes[0x7E].name = "Rotate bits right 1 bit absolute X";
cpu->opcodes[0x7E].cycles = 6;
cpu->opcodes[0x7E].bytes = 3;
//BNE codes
cpu->opcodes[0xD0].microcode = &BNE;
cpu->opcodes[0xD0].name = "branch on Z = 0";
cpu->opcodes[0xD0].mode = &REL;
cpu->opcodes[0xD0].bytes = 2;
cpu->opcodes[0xD0].cycles = 2;
//CLD
cpu->opcodes[0xD8].microcode = &CLD;
cpu->opcodes[0xD8].name = "Clear Decimal";
cpu->opcodes[0xD8].mode = &IMP;
cpu->opcodes[0xD8].bytes = 1;
cpu->opcodes[0xD8].cycles = 2;
//BPL codes
cpu->opcodes[0x10].microcode = &BPL;
cpu->opcodes[0x10].name = "Branch on Result Plus";
cpu->opcodes[0x10].mode = &REL;
cpu->opcodes[0x10].bytes = 2;
cpu->opcodes[0x10].cycles = 2;
//BVC codes
cpu->opcodes[0x50].microcode = &BVC;
cpu->opcodes[0x50].name = "branch on V = 0";
cpu->opcodes[0x50].mode = &REL;
cpu->opcodes[0x50].bytes = 2;
cpu->opcodes[0x50].cycles = 2;
//EOR codes
cpu->opcodes[0x41].microcode = &EOR;
cpu->opcodes[0x41].mode = &INDX;
cpu->opcodes[0x41].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x41].cycles = 6;
cpu->opcodes[0x41].bytes = 2;
cpu->opcodes[0x45].microcode = &EOR;
cpu->opcodes[0x45].mode = &ZPG;
cpu->opcodes[0x45].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x45].cycles = 3;
cpu->opcodes[0x45].bytes = 2;
cpu->opcodes[0x49].microcode = &EOR;
cpu->opcodes[0x49].mode = &IMM;
cpu->opcodes[0x49].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x49].cycles = 2;
cpu->opcodes[0x49].bytes = 2;
cpu->opcodes[0x4D].microcode = &EOR;
cpu->opcodes[0x4D].mode = &ABS;
cpu->opcodes[0x4D].name = "OR Accumulator with immidate";
cpu->opcodes[0x4D].cycles = 4;
cpu->opcodes[0x4D].bytes = 3;
cpu->opcodes[0x51].microcode = &EOR;
cpu->opcodes[0x51].mode = &INDY;
cpu->opcodes[0x51].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x51].cycles = 5;
cpu->opcodes[0x51].bytes = 2;
cpu->opcodes[0x55].microcode = &EOR;
cpu->opcodes[0x55].mode = &ZPGX;
cpu->opcodes[0x55].name = "OR with zero page memory w/ Accumulator";
cpu->opcodes[0x55].cycles = 4;
cpu->opcodes[0x55].bytes = 2;
cpu->opcodes[0x5D].microcode = &ORA;
cpu->opcodes[0x5D].mode = &ABSX;
cpu->opcodes[0x5D].name = "OR Absolute Mem + X w/Accumulator";
cpu->opcodes[0x5D].cycles = 4;
cpu->opcodes[0x5D].bytes = 3;
cpu->opcodes[0x59].microcode = &ORA;
cpu->opcodes[0x59].mode = &ABSY;
cpu->opcodes[0x59].name = "OR Mem w/ Accumulator";
cpu->opcodes[0x59].cycles = 4;
cpu->opcodes[0x59].bytes = 3;
//BVS codes
cpu->opcodes[0x70].microcode = &BVS;
cpu->opcodes[0x70].name = "branch on V = 1";
cpu->opcodes[0x70].mode = &REL;
cpu->opcodes[0x70].bytes = 2;
cpu->opcodes[0x70].cycles = 2;
//CLI codes
cpu->opcodes[0x58].microcode = &CLI;
cpu->opcodes[0x58].name = "Clear Interrupt Disable Bit";
cpu->opcodes[0x58].mode = &IMP;
cpu->opcodes[0x58].bytes = 1;
cpu->opcodes[0x58].cycles = 2;
//CLV codes
cpu->opcodes[0xB8].microcode = &CLV;
cpu->opcodes[0xB8].name = "Clear Interrupt Disable Bit";
cpu->opcodes[0xB8].mode = &IMP;
cpu->opcodes[0xB8].bytes = 1;
cpu->opcodes[0xB8].cycles = 2;
//CMP codes
cpu->opcodes[0xC9].microcode = &CMP;
cpu->opcodes[0xC9].name = "Compare Memory with Accumulator";
cpu->opcodes[0xC9].mode = &IMM;
cpu->opcodes[0xC9].bytes = 2;
cpu->opcodes[0xC9].cycles = 2;
cpu->opcodes[0xC5].microcode = &CMP;
cpu->opcodes[0xC5].name = "Compare Memory with Accumulator";
cpu->opcodes[0xC5].mode = &ZPG;
cpu->opcodes[0xC5].bytes = 2;
cpu->opcodes[0xC5].cycles = 3;
cpu->opcodes[0xD5].microcode = &CMP;
cpu->opcodes[0xD5].name = "Compare Memory with Accumulator";
cpu->opcodes[0xD5].mode = &ZPGX;
cpu->opcodes[0xD5].bytes = 2;
cpu->opcodes[0xD5].cycles = 4;
cpu->opcodes[0xCD].microcode = &CMP;
cpu->opcodes[0xCD].name = "Compare Memory with Accumulator";
cpu->opcodes[0xCD].mode = &ABS;
cpu->opcodes[0xCD].bytes = 3;
cpu->opcodes[0xCD].cycles = 4;
cpu->opcodes[0xDD].microcode = &CMP;
cpu->opcodes[0xDD].name = "Compare Memory with Accumulator";
cpu->opcodes[0xDD].mode = &ABSX;
cpu->opcodes[0xDD].bytes = 3;
cpu->opcodes[0xDD].cycles = 4;
cpu->opcodes[0xD9].microcode = &CMP;
cpu->opcodes[0xD9].name = "Compare Memory with Accumulator";
cpu->opcodes[0xD9].mode = &ABSY;
cpu->opcodes[0xD9].bytes = 3;
cpu->opcodes[0xD9].cycles = 4;
cpu->opcodes[0xC1].microcode = &CMP;
cpu->opcodes[0xC1].name = "Compare Memory with Accumulator";
cpu->opcodes[0xC1].mode = &INDX;
cpu->opcodes[0xC1].bytes = 2;
cpu->opcodes[0xC1].cycles = 6;
cpu->opcodes[0xD1].microcode = &CMP;
cpu->opcodes[0xD1].name = "Compare Memory with Accumulator";
cpu->opcodes[0xD1].mode = &INDY;
cpu->opcodes[0xD1].bytes = 2;
cpu->opcodes[0xD1].cycles = 5;
//CPX codes
cpu->opcodes[0xE0].microcode = &CPX;
cpu->opcodes[0xE0].name = "Compare Memory with X";
cpu->opcodes[0xE0].mode = &IMM;
cpu->opcodes[0xE0].bytes = 2;
cpu->opcodes[0xE0].cycles = 2;
cpu->opcodes[0xE4].microcode = &CPX;
cpu->opcodes[0xE4].name = "Compare Memory with X";
cpu->opcodes[0xE4].mode = &ZPG;
cpu->opcodes[0xE4].bytes = 2;
cpu->opcodes[0xE4].cycles = 3;
cpu->opcodes[0xEC].microcode = &CPX;
cpu->opcodes[0xEC].name = "Compare Memory with X";
cpu->opcodes[0xEC].mode = &ABS;
cpu->opcodes[0xEC].bytes = 3;
cpu->opcodes[0xEC].cycles = 4;
//CPY codes
cpu->opcodes[0xC0].microcode = &CPY;
cpu->opcodes[0xC0].name = "Compare Memory with Y";
cpu->opcodes[0xC0].mode = &IMM;
cpu->opcodes[0xC0].bytes = 2;
cpu->opcodes[0xC0].cycles = 2;
cpu->opcodes[0xC4].microcode = &CPY;
cpu->opcodes[0xC4].name = "Compare Memory with Y";
cpu->opcodes[0xC4].mode = &ZPG;
cpu->opcodes[0xC4].bytes = 2;
cpu->opcodes[0xC4].cycles = 3;
cpu->opcodes[0xCC].microcode = &CPY;
cpu->opcodes[0xCC].name = "Compare Memory with Y";
cpu->opcodes[0xCC].mode = &ABS;
cpu->opcodes[0xCC].bytes = 3;
cpu->opcodes[0xCC].cycles = 4;
//DEC flags
cpu->opcodes[0xC6].microcode = &DEC;
cpu->opcodes[0xC6].name = "Decrement Memory by 1";
cpu->opcodes[0xC6].mode = &ZPG;
cpu->opcodes[0xC6].bytes = 2;
cpu->opcodes[0xC6].cycles = 5;
cpu->opcodes[0xD6].microcode = &DEC;
cpu->opcodes[0xD6].name = "Decrement Memory by 1";
cpu->opcodes[0xD6].mode = &ZPGX;
cpu->opcodes[0xD6].bytes = 2;
cpu->opcodes[0xD6].cycles = 6;
cpu->opcodes[0xCE].microcode = &DEC;
cpu->opcodes[0xCE].name = "Decrement Memory by 1";
cpu->opcodes[0xCE].mode = &ABS;
cpu->opcodes[0xCE].bytes = 3;
cpu->opcodes[0xCE].cycles = 3;
cpu->opcodes[0xDE].microcode = &DEC;
cpu->opcodes[0xDE].name = "Decrement Memory by 1";
cpu->opcodes[0xDE].mode = &ABSX;
cpu->opcodes[0xDE].bytes = 3;
cpu->opcodes[0xDE].cycles = 7;
//DEX codes
cpu->opcodes[0xCA].microcode = &DEX;
cpu->opcodes[0xCA].name = "Decrement X by 1";
cpu->opcodes[0xCA].mode = &IMP;
cpu->opcodes[0xCA].bytes = 1;
cpu->opcodes[0xCA].cycles = 2;
//DEY codes
cpu->opcodes[0x88].microcode = &DEY;
cpu->opcodes[0x88].name = "Decrement Y by 1";
cpu->opcodes[0x88].mode = &IMP;
cpu->opcodes[0x88].bytes = 1;
cpu->opcodes[0x88].cycles = 2;
//EOR
cpu->opcodes[0x49].microcode = &EOR;
cpu->opcodes[0x49].mode = &IMM;
cpu->opcodes[0x49].bytes = 2;
cpu->opcodes[0x49].cycles = 2;
cpu->opcodes[0x49].name = "XOR mem with A";
cpu->opcodes[0x45].microcode = &EOR;
cpu->opcodes[0x45].mode = &ZPG;
cpu->opcodes[0x45].bytes = 2;
cpu->opcodes[0x45].cycles = 3;
cpu->opcodes[0x45].name = "XOR mem with A";
cpu->opcodes[0x55].microcode = &EOR;
cpu->opcodes[0x55].mode = &ZPGX;
cpu->opcodes[0x55].bytes = 2;
cpu->opcodes[0x55].cycles = 4;
cpu->opcodes[0x55].name = "XOR mem with A";
cpu->opcodes[0x4D].microcode = &EOR;
cpu->opcodes[0x4D].mode = &ABS;
cpu->opcodes[0x4D].bytes = 3;
cpu->opcodes[0x4D].cycles = 4;
cpu->opcodes[0x4D].name = "XOR mem with A";
cpu->opcodes[0x5D].microcode = &EOR;
cpu->opcodes[0x5D].mode = &ABSX;
cpu->opcodes[0x5D].bytes = 3;
cpu->opcodes[0x5D].cycles = 4;
cpu->opcodes[0x5D].name = "XOR mem with A";
cpu->opcodes[0x59].microcode = &EOR;
cpu->opcodes[0x59].mode = &ABSY;
cpu->opcodes[0x59].bytes = 3;
cpu->opcodes[0x59].cycles = 4;
cpu->opcodes[0x59].name = "XOR mem with A";
cpu->opcodes[0x41].microcode = &EOR;
cpu->opcodes[0x41].mode = &INDX;
cpu->opcodes[0x41].bytes = 2;
cpu->opcodes[0x41].cycles = 6;
cpu->opcodes[0x41].name = "XOR mem with A";
cpu->opcodes[0x51].microcode = &EOR;
cpu->opcodes[0x51].mode = &INDY;
cpu->opcodes[0x51].bytes = 2;
cpu->opcodes[0x51].cycles = 5;
cpu->opcodes[0x51].name = "XOR mem with A";
//INC codes
cpu->opcodes[0xE6].microcode = &INC;
cpu->opcodes[0xE6].name = "Increment Memory by 1";
cpu->opcodes[0xE6].mode = &ZPG;
cpu->opcodes[0xE6].bytes = 2;
cpu->opcodes[0xE6].cycles = 5;
cpu->opcodes[0xF6].microcode = &INC;
cpu->opcodes[0xF6].name = "Increment Memory by 1";
cpu->opcodes[0xF6].mode = &ZPGX;
cpu->opcodes[0xF6].bytes = 2;
cpu->opcodes[0xF6].cycles = 6;
cpu->opcodes[0xEE].microcode = &INC;
cpu->opcodes[0xEE].name = "Increment Memory by 1";
cpu->opcodes[0xEE].mode = &ABS;
cpu->opcodes[0xEE].bytes = 3;
cpu->opcodes[0xEE].cycles = 6;
cpu->opcodes[0xFE].microcode = &INC;
cpu->opcodes[0xFE].name = "Increment Memory by 1";
cpu->opcodes[0xFE].mode = &ABSX;
cpu->opcodes[0xFE].bytes = 3;
cpu->opcodes[0xFE].cycles = 7;
//INX codes
cpu->opcodes[0xE8].microcode = &INX;
cpu->opcodes[0xE8].name = "Increment X by 1 imm";
cpu->opcodes[0xE8].mode = &IMM;
cpu->opcodes[0xE8].bytes = 1;
cpu->opcodes[0xE8].cycles = 2;
//INY codes
cpu->opcodes[0xC8].microcode = &INY;
cpu->opcodes[0xC8].name = "Increment Y by 1 imm";
cpu->opcodes[0xC8].mode = &IMM;
cpu->opcodes[0xC8].bytes = 1;
cpu->opcodes[0xC8].cycles = 2;
//JMP codes
cpu->opcodes[0x4C].microcode = &JMP;
cpu->opcodes[0x4C].mode = &ABS;
cpu->opcodes[0x4C].bytes = 3;
cpu->opcodes[0x4C].cycles = 3;
cpu->opcodes[0x4C].name = "JMP to new PC";
cpu->opcodes[0x6C].microcode = &JMP;
cpu->opcodes[0x6C].mode = &IND;
cpu->opcodes[0x6C].bytes = 3;
cpu->opcodes[0x6C].cycles = 5;
cpu->opcodes[0x6C].name = "JMP to new PC";
//LDA codes
cpu->opcodes[0xA9].microcode = &LDA;
cpu->opcodes[0xA9].mode = &IMM;
cpu->opcodes[0xA9].bytes = 2;
cpu->opcodes[0xA9].cycles = 2;
cpu->opcodes[0xA9].name = "Load value in A";
cpu->opcodes[0xA5].microcode = &LDA;
cpu->opcodes[0xA5].mode = &ZPG;
cpu->opcodes[0xA5].bytes = 2;
cpu->opcodes[0xA5].cycles = 3;
cpu->opcodes[0xA5].name = "Load value in A";
cpu->opcodes[0xB5].microcode = &LDA;
cpu->opcodes[0xB5].mode = &ZPGX;
cpu->opcodes[0xB5].bytes = 2;
cpu->opcodes[0xB5].cycles = 4;
cpu->opcodes[0xB5].name = "Load value in A";
cpu->opcodes[0xAD].microcode = &LDA;
cpu->opcodes[0xAD].mode = &ABS;
cpu->opcodes[0xAD].bytes = 3;
cpu->opcodes[0xAD].cycles = 4;
cpu->opcodes[0xAD].name = "Load value in A";
cpu->opcodes[0xBD].microcode = &LDA;
cpu->opcodes[0xBD].mode = &ABSX;
cpu->opcodes[0xBD].bytes = 3;
cpu->opcodes[0xBD].cycles = 4;
cpu->opcodes[0xBD].name = "Load value in A";
cpu->opcodes[0xB9].microcode = &LDA;
cpu->opcodes[0xB9].mode = &ABSY;
cpu->opcodes[0xB9].bytes = 3;
cpu->opcodes[0xB9].cycles = 4;
cpu->opcodes[0xB9].name = "Load value in A";
cpu->opcodes[0xA1].microcode = &LDA;
cpu->opcodes[0xA1].mode = &INDX;
cpu->opcodes[0xA1].bytes = 2;
cpu->opcodes[0xA1].cycles = 6;
cpu->opcodes[0xA1].name = "Load value in A";
cpu->opcodes[0xB1].microcode = &LDA;
cpu->opcodes[0xB1].mode = &INDY;
cpu->opcodes[0xB1].bytes = 2;
cpu->opcodes[0xB1].cycles = 5;
cpu->opcodes[0xB1].name = "Load value in A";
//LDX codes
cpu->opcodes[0xA2].microcode = &LDX;
cpu->opcodes[0xA2].mode = &IMM;
cpu->opcodes[0xA2].bytes = 2;
cpu->opcodes[0xA2].cycles = 2;
cpu->opcodes[0xA2].name = "Load value in X";
cpu->opcodes[0xA6].microcode = &LDX;
cpu->opcodes[0xA6].mode = &ZPG;
cpu->opcodes[0xA6].bytes = 2;
cpu->opcodes[0xA6].cycles = 3;
cpu->opcodes[0xA6].name = "Load value in X";
cpu->opcodes[0xB6].microcode = &LDX;
cpu->opcodes[0xB6].mode = &ZPGY;
cpu->opcodes[0xB6].bytes = 2;
cpu->opcodes[0xB6].cycles = 4;
cpu->opcodes[0xB6].name = "Load value in X";
cpu->opcodes[0xAE].microcode = &LDX;
cpu->opcodes[0xAE].mode = &ABS;
cpu->opcodes[0xAE].bytes = 3;
cpu->opcodes[0xAE].cycles = 4;
cpu->opcodes[0xAE].name = "Load value in X";
cpu->opcodes[0xBE].microcode = &LDX;
cpu->opcodes[0xBE].mode = &ABSY;
cpu->opcodes[0xBE].bytes = 3;
cpu->opcodes[0xBE].cycles = 4;
cpu->opcodes[0xBE].name = "Load value in X";
//LDY codes
cpu->opcodes[0xA0].microcode = &LDY;
cpu->opcodes[0xA0].mode = &IMM;
cpu->opcodes[0xA0].bytes = 2;
cpu->opcodes[0xA0].cycles = 2;
cpu->opcodes[0xA0].name = "Load value in Y";
cpu->opcodes[0xA4].microcode = &LDY;
cpu->opcodes[0xA4].mode = &ZPG;
cpu->opcodes[0xA4].bytes = 2;
cpu->opcodes[0xA4].cycles = 3;
cpu->opcodes[0xA4].name = "Load value in Y";
cpu->opcodes[0xB4].microcode = &LDY;
cpu->opcodes[0xB4].mode = &ZPGY;
cpu->opcodes[0xB4].bytes = 2;
cpu->opcodes[0xB4].cycles = 4;
cpu->opcodes[0xB4].name = "Load value in Y";
cpu->opcodes[0xAC].microcode = &LDY;
cpu->opcodes[0xAC].mode = &ABS;
cpu->opcodes[0xAC].bytes = 3;
cpu->opcodes[0xAC].cycles = 4;
cpu->opcodes[0xAC].name = "Load value in Y";
cpu->opcodes[0xBC].microcode = &LDY;
cpu->opcodes[0xBC].mode = &ABSY;
cpu->opcodes[0xBC].bytes = 3;
cpu->opcodes[0xBC].cycles = 4;
cpu->opcodes[0xBC].name = "Load value in Y";
//LSR Codes
cpu->opcodes[0x4A].microcode = &LSR;
cpu->opcodes[0x4A].mode = &ACC;
cpu->opcodes[0x4A].bytes = 1;
cpu->opcodes[0x4A].cycles = 2;
cpu->opcodes[0x4A].name = "LSR shift right";
cpu->opcodes[0x46].microcode = &LSR;
cpu->opcodes[0x46].mode = &ZPG;
cpu->opcodes[0x46].bytes = 2;
cpu->opcodes[0x46].cycles = 3;
cpu->opcodes[0x46].name = "LSR shift right";
cpu->opcodes[0x56].microcode = &LSR;
cpu->opcodes[0x56].mode = &ZPGY;
cpu->opcodes[0x56].bytes = 2;
cpu->opcodes[0x56].cycles = 4;
cpu->opcodes[0x56].name = "LSR shift right";
cpu->opcodes[0x4E].microcode = &LSR;
cpu->opcodes[0x4E].mode = &ABS;
cpu->opcodes[0x4E].bytes = 3;
cpu->opcodes[0x4E].cycles = 4;
cpu->opcodes[0x4E].name = "LSR shift right";
cpu->opcodes[0x5E].microcode = &LSR;
cpu->opcodes[0x5E].mode = &ABSY;
cpu->opcodes[0x5E].bytes = 3;
cpu->opcodes[0x5E].cycles = 4;
cpu->opcodes[0x5E].name = "Load value in Y";
//NOP
cpu->opcodes[0xEA].microcode = &NOP;
cpu->opcodes[0xEA].mode = &IMP;
cpu->opcodes[0xEA].bytes = 1;
cpu->opcodes[0xEA].cycles = 2;
cpu->opcodes[0xEA].name = "NOP do nothing";
//PHA codes
cpu->opcodes[0x48].microcode = &PHA;
cpu->opcodes[0x48].mode = &IMP;
cpu->opcodes[0x48].bytes = 1;
cpu->opcodes[0x48].cycles = 3;
cpu->opcodes[0x48].name = "Push Acc to Stack";
//RTI codes
cpu->opcodes[0x40].microcode = &RTI;
cpu->opcodes[0x40].mode = &IMP;
cpu->opcodes[0x40].bytes = 1;
cpu->opcodes[0x40].cycles = 6;
cpu->opcodes[0x40].name = "Pull SR and PC from stack";
//SBC codes
cpu->opcodes[0xE9].microcode = &SBC;
cpu->opcodes[0xE9].bytes = 2;
cpu->opcodes[0xE9].cycles = 2;
cpu->opcodes[0xE9].mode = &IMM;
cpu->opcodes[0xE9].name = "Subtract Memory from Accumulator with Borrow";
cpu->opcodes[0xE5].microcode = &SBC;
cpu->opcodes[0xE5].bytes = 2;
cpu->opcodes[0xE5].cycles = 3;
cpu->opcodes[0xE5].mode = &ZPG;
cpu->opcodes[0xE5].name = "Subtract Memory from Accumulator with Borrow";
cpu->opcodes[0xF5].microcode = &SBC;
cpu->opcodes[0xF5].bytes = 2;
cpu->opcodes[0xF5].cycles = 4;
cpu->opcodes[0xF5].mode = &ZPGX;
cpu->opcodes[0xF5].name = "Subtract Memory from Accumulator with Borrow";
cpu->opcodes[0xED].microcode = &SBC;
cpu->opcodes[0xED].bytes = 3;
cpu->opcodes[0xED].cycles = 4;
cpu->opcodes[0xED].mode = &ABS;
cpu->opcodes[0xED].name = "Subtract Memory from Accumulator with Borrow";
cpu->opcodes[0xFD].microcode = &SBC;
cpu->opcodes[0xFD].bytes = 3;
cpu->opcodes[0xFD].cycles = 4;
cpu->opcodes[0xFD].mode = &ABSX;
cpu->opcodes[0xFD].name = "Subtract Memory from Accumulator with Borrow";
cpu->opcodes[0xF9].microcode = &SBC;
cpu->opcodes[0xF9].bytes = 3;
cpu->opcodes[0xF9].cycles = 4;
cpu->opcodes[0xF9].mode = &ABSY;
cpu->opcodes[0xF9].name = "Subtract Memory from Accumulator with Borrow";
cpu->opcodes[0xE1].microcode = &SBC;
cpu->opcodes[0xE1].bytes = 2;
cpu->opcodes[0xE1].cycles = 6;
cpu->opcodes[0xE1].mode = &INDX;
cpu->opcodes[0xE1].name = "Subtract Memory from Accumulator with Borrow";
cpu->opcodes[0xF1].microcode = &SBC;
cpu->opcodes[0xF1].bytes = 2;
cpu->opcodes[0xF1].cycles = 5;
cpu->opcodes[0xF1].mode = &INDY;
cpu->opcodes[0xF1].name = "Subtract Memory from Accumulator with Borrow";
//SEC codes
cpu->opcodes[0x38].microcode = &SEC;
cpu->opcodes[0x38].name = "Set Carry";
cpu->opcodes[0x38].bytes = 1;
cpu->opcodes[0x38].cycles = 2;
cpu->opcodes[0x38].mode = &IMP;
//SED codes
cpu->opcodes[0xF8].microcode = &SED;
cpu->opcodes[0xF8].name = "Set Decimal";
cpu->opcodes[0xF8].bytes = 1;
cpu->opcodes[0xF8].cycles = 2;
cpu->opcodes[0xF8].mode = &IMP;
//SEI codes
cpu->opcodes[0x78].microcode = &SEI;
cpu->opcodes[0x78].name = "Set Interrupt";
cpu->opcodes[0x78].bytes = 1;
cpu->opcodes[0x78].cycles = 2;
cpu->opcodes[0x78].mode = &IMP;
//STA codes
cpu->opcodes[0x85].microcode = &STA;
cpu->opcodes[0x85].name = "Store Acc in Mem";
cpu->opcodes[0x85].mode = &ZPG;
cpu->opcodes[0x85].bytes = 2;
cpu->opcodes[0x85].cycles = 3;
cpu->opcodes[0x95].microcode = &STA;
cpu->opcodes[0x95].name = "Store Acc in Mem";
cpu->opcodes[0x95].mode = &ZPGX;
cpu->opcodes[0x95].bytes = 2;
cpu->opcodes[0x95].cycles = 4;
cpu->opcodes[0x8D].microcode = &STA;
cpu->opcodes[0x8D].name = "Store Acc in Mem";
cpu->opcodes[0x8D].mode = &ABS;
cpu->opcodes[0x8D].bytes = 3;
cpu->opcodes[0x8D].cycles = 4;
cpu->opcodes[0x9D].microcode = &STA;
cpu->opcodes[0x9D].name = "Store Acc in Mem";
cpu->opcodes[0x9D].mode = &ABSX;
cpu->opcodes[0x9D].bytes = 3;
cpu->opcodes[0x9D].cycles = 5;
cpu->opcodes[0x99].microcode = &STA;
cpu->opcodes[0x99].name = "Store Acc in Mem";
cpu->opcodes[0x99].mode = &ABSY;
cpu->opcodes[0x99].bytes = 3;
cpu->opcodes[0x99].cycles = 5;
cpu->opcodes[0x81].microcode = &STA;
cpu->opcodes[0x81].name = "Store Acc in Mem";
cpu->opcodes[0x81].mode = &INDX;
cpu->opcodes[0x81].bytes = 2;
cpu->opcodes[0x81].cycles = 6;
cpu->opcodes[0x91].microcode = &STA;
cpu->opcodes[0x91].name = "Store Acc in Mem";
cpu->opcodes[0x91].mode = &INDY;
cpu->opcodes[0x91].bytes = 2;
cpu->opcodes[0x91].cycles = 6;
//STX codes
cpu->opcodes[0x86].microcode = &STX;
cpu->opcodes[0x86].name = "Write X reg to bus";
cpu->opcodes[0x86].mode = &ZPG;
cpu->opcodes[0x86].bytes = 2;
cpu->opcodes[0x86].cycles = 3;
cpu->opcodes[0x96].microcode = &STX;
cpu->opcodes[0x96].name = "Write X reg to bus1";
cpu->opcodes[0x96].mode = &ZPGX;
cpu->opcodes[0x96].bytes = 2;
cpu->opcodes[0x96].cycles = 4;
cpu->opcodes[0x8E].microcode = &STX;
cpu->opcodes[0x8E].name = "Write X reg to bus";
cpu->opcodes[0x8E].mode = &ABS;
cpu->opcodes[0x8E].bytes = 3;
cpu->opcodes[0x8E].cycles = 4;
//STY codes
cpu->opcodes[0x84].microcode = &STY;
cpu->opcodes[0x84].name = "Write Y reg to bus";
cpu->opcodes[0x84].mode = &ZPG;
cpu->opcodes[0x84].bytes = 2;
cpu->opcodes[0x84].cycles = 3;
cpu->opcodes[0x94].microcode = &STY;
cpu->opcodes[0x94].name = "Write Y reg to bus1";
cpu->opcodes[0x94].mode = &ZPGX;
cpu->opcodes[0x94].bytes = 2;
cpu->opcodes[0x94].cycles = 4;
cpu->opcodes[0x8C].microcode = &STY;
cpu->opcodes[0x8C].name = "Write Y reg to bus";
cpu->opcodes[0x8C].mode = &ABS;
cpu->opcodes[0x8C].bytes = 3;
cpu->opcodes[0x8C].cycles = 4;
//TAX codes (lmao)
cpu->opcodes[0xAA].microcode = &TAX;
cpu->opcodes[0xAA].mode = &IMP;
cpu->opcodes[0xAA].name = "Transfer Accumulator to X";
cpu->opcodes[0xAA].cycles = 2;
cpu->opcodes[0xAA].bytes = 1;
//TAY codes
cpu->opcodes[0xA8].microcode = &TAY;
cpu->opcodes[0xA8].mode = &IMP;
cpu->opcodes[0xA8].name = "Transfer Accumulator to Y";
cpu->opcodes[0xA8].cycles = 2;
cpu->opcodes[0xA8].bytes = 1;
//TSX codes
cpu->opcodes[0xBA].microcode = &TSX;
cpu->opcodes[0xBA].mode = &IMP;
cpu->opcodes[0xBA].name = "Transfer SP to X";
cpu->opcodes[0xBA].cycles = 2;
cpu->opcodes[0xBA].bytes = 1;
//TXA codes
cpu->opcodes[0x8A].microcode = &TXA;
cpu->opcodes[0x8A].mode = &IMP;
cpu->opcodes[0x8A].name = "Transfer X to Acc";
cpu->opcodes[0x8A].cycles = 2;
cpu->opcodes[0x8A].bytes = 1;
//TXS codes
cpu->opcodes[0x9A].microcode = &TXS;
cpu->opcodes[0x9A].mode = &IMP;
cpu->opcodes[0x9A].name = "Transfer X to Stack Register";
cpu->opcodes[0x9A].cycles = 2;
cpu->opcodes[0x9A].bytes = 1;
//TYA codes
cpu->opcodes[0x98].microcode = &TYA;
cpu->opcodes[0x98].mode = &IMP;
cpu->opcodes[0x98].name = "Transfer Y to Acc";
cpu->opcodes[0x98].cycles = 2;
cpu->opcodes[0x98].bytes = 1;
//RTS codes
cpu->opcodes[0x60].microcode = &RTS;
cpu->opcodes[0x60].mode = &IMP;
cpu->opcodes[0x60].name = "Return from subroutine";
cpu->opcodes[0x60].cycles = 6;
cpu->opcodes[0x60].bytes = 1;
}
void print_registers(CPU * __restrict__ cpu){
printf("N: %i\n", cpu->SR.flags.Negative);
printf("V: %i\n", cpu->SR.flags.Overflow);
printf("B: %i\n", cpu->SR.flags.Break);
printf("D: %i\n", cpu->SR.flags.Decimal);
printf("I: %i\n", cpu->SR.flags.Interrupt);
printf("Z: %i\n", cpu->SR.flags.Zero);
printf("C: %i\n", cpu->SR.flags.Carry);
}
void print_cpu(CPU * __restrict__ cpu){
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte_) \
(byte_ & 0x80 ? '1' : '0'), \
(byte_ & 0x40 ? '1' : '0'), \
(byte_ & 0x20 ? '1' : '0'), \
(byte_ & 0x10 ? '1' : '0'), \
(byte_ & 0x08 ? '1' : '0'), \
(byte_ & 0x04 ? '1' : '0'), \
(byte_ & 0x02 ? '1' : '0'), \
(byte_ & 0x01 ? '1' : '0')
printf("PC: %#08x\n", cpu->PC);
printf("SP: %i hex %02X, (%i)\n", cpu->SP, cpu->SP, 0xFFFF - cpu->SP);
printf("A: %i hex %02X\n", cpu->A, cpu->A);
printf("X: %i\n", cpu->X);
printf("Y: %i\n", cpu->Y);
printf("SR: "BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(cpu->SR.data));
#undef BYTE_TO_BINARY_PATTERN
#undef BYTE_TO_BINARY
}
void raise_error(unsigned int err, CPU * __restrict__ cpu){
const char * ERROR_STR[13]= {
"Unknown Error",
"Tried to access a opcode that doesn't exist",
"Tried to access bus data that is out of range",
"Micro code was not allocated / set",
"Mode code was not allocated",
"Name was not allocated",
"Opcode was not allocated",
"Instruction was not allocated",
"CPU was not allocated",
"Microcode is in valid range but doesn't point to a valid microcode",
"Mode is in valid range but doesn't point to a vaild mode",
"Bytes was allocated but not set",
"Cycles was allocated but not set",
};
perror(ERROR_STR[err]);
fprintf(stderr, "CRASH!!!!\n\n");
fprintf(stderr, "\tLOCATION: %#06x\n", cpu->PC);
fprintf(stderr, "\tOPCODE: %#06x\n", bus_read8(cpu->PC));
fprintf(stderr, "\tNAME: \"%s\"\n", cpu->opcodes[bus_read8(cpu->PC)].name);
fprintf(stderr, "\tMICRO: %p\n", cpu->opcodes[bus_read8(cpu->PC)].microcode);
fprintf(stderr, "\tMODE: %p\n", cpu->opcodes[bus_read8(cpu->PC)].mode);
exit(err);
}
void print_stack(CPU * __restrict__ cpu){
char x[2] = {'.', '.'};
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
for(word i = STACK_RAM_OFFSET; i < STACK_RAM_OFFSET + 0xFF; i++){
if(i == cpu->SP + STACK_RAM_OFFSET){
x[0] = '[';
x[1] = ']';
}
printf(" %c%02X%c ", x[0], bus_read8(i), x[1]);
x[0] = '.';
x[1] = '.';
}
printf("\n");
}
void handle_errors(CPU * __restrict__ cpu){
enum ERRORS{
NORMAL,
OPCODES_OB,
BUS_OB,
UNALLOC_MICRO,
UNALLOC_MODE,
UNALLOC_NAME,
UNALLOC_OP,
UNALLOC_INST,
UNALLOC_CPU,
UNKNOWN_MICRO,
UNKNOWN_MODE,
UNKNOWN_BYTES,
UNKNOWN_CYCLES
};
if(cpu == NULL){
raise_error(UNALLOC_CPU, cpu);
}
if(cpu->PC > BUS_SIZE){
raise_error(BUS_OB, cpu);
}
if(cpu->opcodes == NULL){
raise_error(UNALLOC_OP, cpu);
}
struct instruction cur_inst = cpu->opcodes[bus_read8(cpu->PC)];
if(cur_inst.microcode == NULL){
raise_error(UNALLOC_MICRO, cpu);
}
if(cur_inst.mode == NULL){
raise_error(UNALLOC_MODE, cpu);
}
if(cur_inst.name == NULL){
raise_error(UNALLOC_NAME, cpu);
}
if(cur_inst.cycles == 0){
raise_error(UNKNOWN_CYCLES, cpu);
}
if(cur_inst.bytes == 0){
raise_error(UNKNOWN_BYTES, cpu);
}
if(cur_inst.microcode < ORA || cur_inst.microcode > TYA){
raise_error(UNKNOWN_MICRO, cpu);
}
printf("OP: %x\n", bus_read8(cpu->PC));
}
/*void printErrorCodes(CPU * cpu){
printf("0x02 = %02X, 0x03 = %03X\n", )
}*/
void init_cpu(CPU * __restrict__ cpu){
cpu->PC = 0;
cpu->A = 0;
cpu->X = 0;
cpu->Y = 0;
cpu->SR.data = 0x6C;
cpu->SP = 0xFD;
init_opcodereg(cpu);//import the stuff about each microcode, stuff like bytes per instruction, cycles, adressing mode, and operation in the array, where the value in the array is the byte that triggers that action for the CPU
}
void cpu_clock(CPU * cpu){
#ifdef DEBUG
handle_errors(cpu);
#endif
cpu->pcNeedsInc = true;
word args = 0;
if(cpu->opcodes[bus_read8(cpu->PC)].bytes > 2){ //if args is 16bit shifts the first byte to the hi byte (they get reversed basically)
args = bus_read8(cpu->PC + 2) << 8;
}
args |= bus_read8(cpu->PC + 1); //add first arg byte
#ifdef DEBUG
printf("\nBYTES: 0x%04X", args);
#endif
byte sizeOfInstruction = cpu->opcodes[bus_read8(cpu->PC)].bytes;
//EXECUTION HERE
cpu->opcodes[bus_read8(cpu->PC)].microcode(cpu, args, cpu->opcodes[bus_read8(cpu->PC)].mode); //execute opcode function
//EXECUTION DONE
if(cpu->pcNeedsInc){
cpu->PC += sizeOfInstruction;
#ifdef DEBUG
printf("\n%04X %04X\n", cpu->PC - sizeOfInstruction, cpu->PC);
#endif
} //increase program counter
}