NESEmulator/NES Emulator/cpu.c

888 lines
17 KiB
C
Raw Permalink Normal View History

2021-10-20 20:39:29 +00:00
#include "cpu.h"
#include <stdlib.h>
#include <stdio.h>
2021-10-22 15:49:20 +00:00
#include "log.h"
2021-10-20 20:39:29 +00:00
#include "bus.h"
2021-10-29 20:17:01 +00:00
static inline void Push(struct Bus* bus, Byte val)
2021-10-22 22:47:33 +00:00
{
writeBus(bus, 0x0100 + (bus->cpu->sp--), val);
}
2021-10-29 20:17:01 +00:00
static inline Byte Pop(struct Bus* bus)
2021-10-22 22:47:33 +00:00
{
2021-10-30 17:49:02 +00:00
return readBus(bus, 0x0100 + (++bus->cpu->sp));
2021-10-22 22:47:33 +00:00
}
2021-10-20 20:39:29 +00:00
struct CPU* createCPU(struct Bus* parent)
{
struct CPU* cpu = (struct CPU*)malloc(sizeof(struct CPU));
if (cpu == NULL)
{
fprintf(stderr, "Failed to create CPU, aborting.\n");
exit(1);
}
2021-10-21 17:24:53 +00:00
// TODO: THIS IS JUST FOR THE TEST ROM
2021-10-23 18:36:38 +00:00
cpu->pc.word = 0xC000;
2021-10-30 17:49:02 +00:00
cpu->pc.word = ((Word)readBus(parent, 0xFFFD) << 8) | readBus(parent, 0xFFFC);
2021-10-21 17:24:53 +00:00
2021-10-22 15:49:20 +00:00
cpu->status.raw = 0x34;
cpu->acc = 0;
cpu->x = 0;
cpu->y = 0;
2021-10-22 22:47:33 +00:00
cpu->sp = 0xFD;
2021-10-22 15:49:20 +00:00
cpu->remainingCycles = 7;
cpu->totalCycles = 0;
2021-10-24 14:52:15 +00:00
cpu->irq = 0;
cpu->nmi = 0;
2021-10-20 20:39:29 +00:00
cpu->bus = parent;
return cpu;
}
void destroyCPU(struct CPU* cpu)
{
free(cpu);
}
2021-10-21 17:24:53 +00:00
2021-10-22 15:49:20 +00:00
int tickCPU(struct CPU* cpu)
2021-10-21 17:24:53 +00:00
{
2021-10-22 23:29:15 +00:00
if (cpu->remainingCycles == -1) // Jammed
return 1;
2021-10-22 15:49:20 +00:00
cpu->remainingCycles--;
cpu->totalCycles += 1;
2021-10-24 14:52:15 +00:00
if (cpu->remainingCycles == 1)
{
// Handle interrupts
if (cpu->nmi)
{
Push(cpu->bus, cpu->pc.hi);
Push(cpu->bus, cpu->pc.lo);
Push(cpu->bus, cpu->status.raw & 0b11101111);
cpu->nmi = 0;
2021-10-30 19:01:27 +00:00
// printf("NMI TRIGGERED FROM $%04x\n", cpu->pc.word);
2021-10-24 14:52:15 +00:00
cpu->pc.lo = readBus(cpu->bus, 0xFFFA);
cpu->pc.hi = readBus(cpu->bus, 0xFFFB);
return 0;
}
if (!cpu->status.id)
{
if (cpu->irq)
{
Push(cpu->bus, cpu->pc.hi);
Push(cpu->bus, cpu->pc.lo);
Push(cpu->bus, cpu->status.raw & 0b11101111);
cpu->status.id = 1;
cpu->pc.lo = readBus(cpu->bus, 0xFFFE);
cpu->pc.hi = readBus(cpu->bus, 0xFFFF);
cpu->irq = 0;
}
}
}
2021-10-22 15:49:20 +00:00
if (cpu->remainingCycles == 0)
2021-10-21 17:24:53 +00:00
{
prepareFetch(cpu);
2021-10-22 15:49:20 +00:00
execute(cpu);
return 1;
2021-10-21 17:24:53 +00:00
}
2021-10-22 15:49:20 +00:00
return 0;
2021-10-21 17:24:53 +00:00
}
void tickInstr(struct CPU* cpu)
{
2021-10-22 15:49:20 +00:00
while (!tickCPU(cpu));
2021-10-21 17:24:53 +00:00
}
void prepareFetch(struct CPU* cpu)
2021-10-21 17:24:53 +00:00
{
2021-10-22 22:47:33 +00:00
Byte opcodeVal = readBus(cpu->bus, cpu->pc.word);
2021-10-21 17:24:53 +00:00
cpu->currentOpcode = OPCODE_TABLE + opcodeVal;
2021-10-22 14:39:48 +00:00
if (cpu->currentOpcode->op == XXX)
2021-10-21 17:24:53 +00:00
{
2021-10-22 22:47:33 +00:00
fprintf(stderr, "Unknown opcode: %02X", opcodeVal);
2021-10-21 17:24:53 +00:00
exit(1);
}
2021-10-22 22:47:33 +00:00
cpu->pc.word++;
2021-10-22 14:39:48 +00:00
cpu->remainingCycles = cpu->currentOpcode->cycles;
2021-10-21 17:24:53 +00:00
2021-10-22 14:39:48 +00:00
switch (cpu->currentOpcode->addr)
{
case ACC:
cpu->fetchedVal = cpu->acc;
2021-10-22 22:47:33 +00:00
return;
2021-10-22 14:39:48 +00:00
case ABS:
{
2021-10-22 22:47:33 +00:00
Byte lo = readBus(cpu->bus, cpu->pc.word++);
Byte hi = readBus(cpu->bus, cpu->pc.word++);
2021-10-22 14:39:48 +00:00
cpu->fetchedAddress = ((Word)hi << 8) | lo;
} break;
case ABX:
{
2021-10-22 22:47:33 +00:00
Byte lo = readBus(cpu->bus, cpu->pc.word++);
Byte hi = readBus(cpu->bus, cpu->pc.word++);
2021-10-22 14:39:48 +00:00
Word addr = ((Word)hi << 8) | lo;
cpu->fetchedAddress = addr + cpu->x;
if ((cpu->fetchedAddress & 0xFF00) != (addr & 0xFF00))
cpu->remainingCycles++;
} break;
case ABY:
{
2021-10-22 22:47:33 +00:00
Byte lo = readBus(cpu->bus, cpu->pc.word++);
Byte hi = readBus(cpu->bus, cpu->pc.word++);
2021-10-22 14:39:48 +00:00
Word addr = ((Word)hi << 8) | lo;
cpu->fetchedAddress = addr + cpu->y;
if ((cpu->fetchedAddress & 0xFF00) != (addr & 0xFF00))
cpu->remainingCycles++;
} break;
case IMM:
cpu->fetchedAddress = cpu->pc.word++;
2021-10-22 22:47:33 +00:00
return;
2021-10-22 14:39:48 +00:00
case IMP:
2021-10-22 22:47:33 +00:00
return;
2021-10-22 14:39:48 +00:00
case IND:
{
2021-10-22 22:47:33 +00:00
Byte lo = readBus(cpu->bus, cpu->pc.word++);
Byte hi = readBus(cpu->bus, cpu->pc.word++);
Word addr = ((Word)hi << 8);
2021-10-22 14:39:48 +00:00
2021-10-22 22:47:33 +00:00
cpu->fetchedAddress = ((Word)readBus(cpu->bus, addr | ((lo + 1) & 0xFF)) << 8) | readBus(cpu->bus, addr | lo);
2021-10-22 14:39:48 +00:00
} break;
case INDX:
{
2021-10-22 22:47:33 +00:00
Byte op = readBus(cpu->bus, cpu->pc.word++);
Byte lo = readBus(cpu->bus, (op + cpu->x) & 0xFF);
Byte hi = readBus(cpu->bus, (op + cpu->x + 1) & 0xFF);
2021-10-22 14:39:48 +00:00
2021-10-22 22:47:33 +00:00
cpu->fetchedAddress = ((Word)hi << 8) | lo;
2021-10-22 14:39:48 +00:00
} break;
case INDY:
{
2021-10-22 22:47:33 +00:00
Byte op = readBus(cpu->bus, cpu->pc.word++);
2021-10-22 14:39:48 +00:00
Byte lo = readBus(cpu->bus, op);
2021-10-22 22:47:33 +00:00
Byte hi = readBus(cpu->bus, (op + 1) & 0xFF);
2021-10-22 14:39:48 +00:00
Word addr = ((Word)hi << 8) | lo;
cpu->fetchedAddress = addr + cpu->y;
if ((cpu->fetchedAddress & 0xFF00) != (addr & 0xFF00))
cpu->remainingCycles++;
} break;
case REL:
{
2021-10-22 22:47:33 +00:00
cpu->fetchedRelAddress = readBus(cpu->bus, cpu->pc.word++);
2021-10-22 14:39:48 +00:00
} break;
case ZPG:
2021-10-22 22:47:33 +00:00
cpu->fetchedAddress = readBus(cpu->bus, cpu->pc.word++);
2021-10-22 14:39:48 +00:00
break;
case ZPX:
{
2021-10-22 22:47:33 +00:00
cpu->fetchedAddress = (readBus(cpu->bus, cpu->pc.word++) + cpu->x) & 0xFF;
2021-10-22 14:39:48 +00:00
} break;
case ZPY:
{
2021-10-22 22:47:33 +00:00
cpu->fetchedAddress = (readBus(cpu->bus, cpu->pc.word++) + cpu->y) & 0xFF;
2021-10-22 14:39:48 +00:00
} break;
}
}
2021-10-22 22:47:33 +00:00
void fetch(struct CPU* cpu)
{
2021-10-30 19:01:27 +00:00
if(cpu->currentOpcode->addr != IMP && cpu->currentOpcode->addr != ACC)
cpu->fetchedVal = readBus(cpu->bus, cpu->fetchedAddress);
2021-10-21 17:24:53 +00:00
}
void execute(struct CPU* cpu)
{
2021-10-24 14:52:15 +00:00
// LOG_BUS(cpu->bus);
2021-10-22 15:49:20 +00:00
2021-10-22 14:39:48 +00:00
switch (cpu->currentOpcode->op)
{
2021-10-22 22:47:33 +00:00
case ADC:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
Word result = cpu->acc + cpu->fetchedVal + cpu->status.carry;
cpu->status.carry = (result > 0xFF);
cpu->status.overflow = ((~(cpu->acc ^ cpu->fetchedVal) & (cpu->acc ^ result) & 0x80) == 0x80);
cpu->status.negative = (result >> 7);
cpu->status.zero = ((result & 0xFF) == 0x00);
cpu->acc = result & 0xFF;
} break;
case AND:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->acc &= cpu->fetchedVal;
cpu->status.negative = (cpu->acc >> 7);
cpu->status.zero = (cpu->acc == 0x00);
} break;
case ASL:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->status.carry = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->fetchedVal <<= 1;
cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->status.zero = (cpu->fetchedVal == 0x00);
if (!cpu->currentOpcode->addr == ACC)
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
else
cpu->acc = cpu->fetchedVal;
} break;
case BCC:
{
if (!cpu->status.carry)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
case BCS:
{
if (cpu->status.carry)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
case BEQ:
{
if (cpu->status.zero)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
case BMI:
{
if (cpu->status.negative)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
case BPL:
{
if (!cpu->status.negative)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
2021-10-28 14:57:37 +00:00
case BRK:
{
cpu->pc.word++;
Push(cpu->bus, cpu->pc.hi);
Push(cpu->bus, cpu->pc.lo);
Push(cpu->bus, cpu->status.raw | 0b00110000);
cpu->status.id = 1;
cpu->pc.hi = readBus(cpu->bus, 0xFFFF);
cpu->pc.lo = readBus(cpu->bus, 0xFFFE);
} break;
2021-10-22 22:47:33 +00:00
case BVC:
{
if (!cpu->status.overflow)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
case BVS:
{
if (cpu->status.overflow)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
case BIT:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->status.negative = (cpu->fetchedVal >> 7);
cpu->status.overflow = (cpu->fetchedVal >> 6);
cpu->status.zero = ((cpu->acc & cpu->fetchedVal) == 0x00);
} break;
case BNE:
{
if (!cpu->status.zero)
{
Word target = cpu->pc.word + cpu->fetchedRelAddress;
cpu->remainingCycles++;
if ((target & 0xFF00) != (cpu->pc.word & 0xFF00))
cpu->remainingCycles++;
cpu->pc.word = target;
}
} break;
case CLC:
{
cpu->status.carry = 0;
} break;
case CLD:
{
cpu->status.decimal = 0;
} break;
case CLV:
{
cpu->status.overflow = 0;
} break;
case CMP:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
Byte result = cpu->acc - cpu->fetchedVal;
cpu->status.negative = (result >> 7);
cpu->status.zero = (result == 0x00);
cpu->status.carry = (cpu->fetchedVal <= cpu->acc);
} break;
case CPX:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
Byte result = cpu->x - cpu->fetchedVal;
cpu->status.negative = (result >> 7);
cpu->status.zero = (result == 0x00);
cpu->status.carry = (cpu->fetchedVal <= cpu->x);
} break;
case CPY:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
Byte result = cpu->y - cpu->fetchedVal;
cpu->status.negative = (result >> 7);
cpu->status.zero = (result == 0x00);
cpu->status.carry = (cpu->fetchedVal <= cpu->y);
} break;
case DCP:
{
fetch(cpu);
cpu->fetchedVal--;
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
Byte result = cpu->acc - cpu->fetchedVal;
cpu->status.negative = (result >> 7);
cpu->status.zero = (result == 0x00);
cpu->status.carry = (cpu->fetchedVal <= cpu->acc);
cpu->remainingCycles = cpu->currentOpcode->cycles;
} break;
2021-10-22 22:47:33 +00:00
case DEC:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->fetchedVal--;
cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->status.zero = (cpu->fetchedVal == 0x00);
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
} break;
case DEX:
{
cpu->x--;
cpu->status.negative = ((cpu->x & 0x80) == 0x80);
2021-10-23 13:55:54 +00:00
cpu->status.zero = (cpu->x == 0x00);
2021-10-22 22:47:33 +00:00
} break;
case DEY:
{
cpu->y--;
cpu->status.negative = ((cpu->y & 0x80) == 0x80);
2021-10-24 11:47:11 +00:00
cpu->status.zero = (cpu->y == 0x00);
2021-10-22 22:47:33 +00:00
} break;
case EOR:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->acc ^= cpu->fetchedVal;
cpu->status.negative = (cpu->acc >> 7);
cpu->status.zero = (cpu->acc == 0x00);
} break;
case INC:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->fetchedVal++;
cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->status.zero = (cpu->fetchedVal == 0x00);
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
} break;
case INX:
{
cpu->x++;
cpu->status.negative = ((cpu->x & 0x80) == 0x80);
cpu->status.zero = (cpu->x == 0x00);
} break;
case INY:
{
cpu->y++;
cpu->status.negative = ((cpu->y & 0x80) == 0x80);
cpu->status.zero = (cpu->y == 0x00);
} break;
case ISC:
{
fetch(cpu);
cpu->fetchedVal++;
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
Word result = cpu->acc + ~cpu->fetchedVal + cpu->status.carry;
cpu->status.carry = ((result & 0x8000) != 0x8000);
cpu->status.overflow = ((~(cpu->acc ^ ~cpu->fetchedVal) & (cpu->acc ^ result) & 0x80) == 0x80);
cpu->status.negative = ((result & 0x80) == 0x80);
cpu->status.zero = ((result & 0xFF) == 0x00);
cpu->acc = result & 0xFF;
cpu->remainingCycles = cpu->currentOpcode->cycles;
} break;
2021-10-22 14:39:48 +00:00
case JMP:
{
2021-10-22 22:47:33 +00:00
cpu->pc.word = cpu->fetchedAddress;
} break;
case JSR:
{
cpu->pc.word--;
Push(cpu->bus, cpu->pc.hi);
Push(cpu->bus, cpu->pc.lo);
cpu->pc.word = cpu->fetchedAddress;
} break;
2021-10-23 14:00:40 +00:00
case LAX:
{
fetch(cpu);
2021-10-23 14:00:40 +00:00
cpu->acc = cpu->fetchedVal;
cpu->x = cpu->fetchedVal;
cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
cpu->status.zero = (cpu->acc == 0x00);
} break;
2021-10-22 22:47:33 +00:00
case LDA:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->acc = cpu->fetchedVal;
cpu->status.negative = (cpu->acc >> 7);
cpu->status.zero = (cpu->acc == 0x00);
} break;
case LDX:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->x = cpu->fetchedVal;
cpu->status.negative = (cpu->x >> 7);
cpu->status.zero = (cpu->x == 0x00);
} break;
case LDY:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->y = cpu->fetchedVal;
cpu->status.negative = (cpu->y >> 7);
cpu->status.zero = (cpu->y == 0x00);
} break;
case LSR:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->status.negative = 0;
cpu->status.carry = ((cpu->fetchedVal & 0x01) == 0x01);
cpu->fetchedVal >>= 1;
cpu->status.zero = (cpu->fetchedVal == 0x00);
if (!cpu->currentOpcode->addr == ACC)
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
else
cpu->acc = cpu->fetchedVal;
} break;
case NOP:
{
} break;
case ORA:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
cpu->acc |= cpu->fetchedVal;
cpu->status.negative = (cpu->acc >> 7);
cpu->status.zero = (cpu->acc == 0x00);
} break;
case PHA:
{
Push(cpu->bus, cpu->acc);
} break;
case PHP:
{
Push(cpu->bus, cpu->status.raw | 0b00110000);
} break;
case PLA:
{
cpu->acc = Pop(cpu->bus);
cpu->status.negative = (cpu->acc >> 7);
cpu->status.zero = (cpu->acc == 0x00);
} break;
case PLP:
{
cpu->status.raw = Pop(cpu->bus) | 0b00110000;
} break;
case RLA:
{
fetch(cpu);
Byte oldCarry = cpu->status.carry;
cpu->status.carry = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->fetchedVal <<= 1;
cpu->fetchedVal |= oldCarry;
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
cpu->acc &= cpu->fetchedVal;
cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
cpu->status.zero = (cpu->acc == 0x00);
cpu->remainingCycles = cpu->currentOpcode->cycles;
} break;
2021-10-22 22:47:33 +00:00
case ROL:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
Byte oldCarry = cpu->status.carry;
cpu->status.carry = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->fetchedVal <<= 1;
cpu->fetchedVal |= oldCarry;
cpu->status.negative = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->status.zero = (cpu->fetchedVal == 0x00);
if (!cpu->currentOpcode->addr == ACC)
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
else
cpu->acc = cpu->fetchedVal;
} break;
case ROR:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
Byte oldCarry = cpu->status.carry;
cpu->status.negative = oldCarry;
cpu->status.carry = ((cpu->fetchedVal & 0x01) == 0x01);
cpu->fetchedVal >>= 1;
cpu->fetchedVal |= (oldCarry << 7);
cpu->status.zero = (cpu->fetchedVal == 0x00);
if (!cpu->currentOpcode->addr == ACC)
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
else
cpu->acc = cpu->fetchedVal;
} break;
case RRA:
{
fetch(cpu);
Byte oldCarry = cpu->status.carry;
cpu->status.carry = ((cpu->fetchedVal & 0x01) == 0x01);
cpu->fetchedVal >>= 1;
cpu->fetchedVal |= (oldCarry << 7);
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
Word result = cpu->acc + cpu->fetchedVal + cpu->status.carry;
cpu->status.carry = (result > 0xFF);
cpu->status.overflow = ((~(cpu->acc ^ cpu->fetchedVal) & (cpu->acc ^ result) & 0x80) == 0x80);
cpu->status.negative = (result >> 7);
cpu->status.zero = ((result & 0xFF) == 0x00);
cpu->acc = result & 0xFF;
cpu->remainingCycles = cpu->currentOpcode->cycles;
} break;
2021-10-22 22:47:33 +00:00
case RTI:
{
cpu->status.raw = Pop(cpu->bus) | 0b00110000;
cpu->pc.lo = Pop(cpu->bus);
cpu->pc.hi = Pop(cpu->bus);
} break;
case RTS:
{
cpu->pc.lo = Pop(cpu->bus);
cpu->pc.hi = Pop(cpu->bus);
cpu->pc.word++;
} break;
case SAX:
{
writeBus(cpu->bus, cpu->fetchedAddress, cpu->acc & cpu->x);
} break;
2021-10-22 22:47:33 +00:00
case SBC:
{
fetch(cpu);
2021-10-22 22:47:33 +00:00
Word result = cpu->acc + ~cpu->fetchedVal + cpu->status.carry;
cpu->status.carry = ((result & 0x8000) != 0x8000);
cpu->status.overflow = ((~(cpu->acc ^ ~cpu->fetchedVal) & (cpu->acc ^ result) & 0x80) == 0x80);
cpu->status.negative = ((result & 0x80) == 0x80);
cpu->status.zero = ((result & 0xFF) == 0x00);
cpu->acc = result & 0xFF;
} break;
case SEC:
{
cpu->status.carry = 1;
} break;
case SED:
{
cpu->status.decimal = 1;
} break;
case SEI:
{
cpu->status.id = 1;
} break;
case SLO:
{
fetch(cpu);
cpu->status.carry = ((cpu->fetchedVal & 0x80) == 0x80);
cpu->fetchedVal <<= 1;
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
cpu->acc |= cpu->fetchedVal;
cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
cpu->status.zero = (cpu->acc == 0x00);
cpu->remainingCycles = cpu->currentOpcode->cycles;
} break;
case SRE:
{
fetch(cpu);
cpu->status.carry = ((cpu->fetchedVal & 0x01) == 0x01);
cpu->fetchedVal >>= 1;
writeBus(cpu->bus, cpu->fetchedAddress, cpu->fetchedVal);
cpu->acc ^= cpu->fetchedVal;
cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
cpu->status.zero = (cpu->acc == 0x00);
cpu->remainingCycles = cpu->currentOpcode->cycles;
} break;
2021-10-22 22:47:33 +00:00
case STA:
{
writeBus(cpu->bus, cpu->fetchedAddress, cpu->acc);
cpu->remainingCycles = cpu->currentOpcode->cycles; // Correct "oops" cycle (store instr. always have it)
} break;
case STX:
{
writeBus(cpu->bus, cpu->fetchedAddress, cpu->x);
cpu->remainingCycles = cpu->currentOpcode->cycles; // Correct "oops" cycle (store instr. always have it)
} break;
case STY:
{
writeBus(cpu->bus, cpu->fetchedAddress, cpu->y);
cpu->remainingCycles = cpu->currentOpcode->cycles; // Correct "oops" cycle (store instr. always have it)
} break;
case TAX:
{
cpu->x = cpu->acc;
cpu->status.negative = ((cpu->x & 0x80) == 0x80);
cpu->status.zero = (cpu->x == 0x00);
} break;
case TAY:
{
cpu->y = cpu->acc;
cpu->status.negative = ((cpu->y & 0x80) == 0x80);
cpu->status.zero = (cpu->y == 0x00);
} break;
case TSX:
{
cpu->x = cpu->sp;
cpu->status.negative = ((cpu->x & 0x80) == 0x80);
cpu->status.zero = (cpu->x == 0x00);
} break;
case TXA:
{
cpu->acc = cpu->x;
cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
cpu->status.zero = (cpu->acc == 0x00);
} break;
case TXS:
{
cpu->sp = cpu->x;
} break;
case TYA:
{
cpu->acc = cpu->y;
cpu->status.negative = ((cpu->acc & 0x80) == 0x80);
cpu->status.zero = (cpu->acc == 0x00);
2021-10-22 14:39:48 +00:00
} break;
default:
fprintf(stderr, "Unknown instruction: %s", cpu->currentOpcode->str);
exit(1);
break;
}
2021-10-21 17:24:53 +00:00
}
2021-10-24 14:52:15 +00:00
void IRQ(struct CPU* cpu)
{
cpu->irq = 1;
}
void NMI(struct CPU* cpu)
{
cpu->nmi = 1;
}