NESEmulator/NES Emulator/cpu.c
2021-10-22 17:49:20 +02:00

193 lines
3.3 KiB
C

#include "cpu.h"
#include <stdlib.h>
#include <stdio.h>
#include "log.h"
#include "bus.h"
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);
}
// TODO: THIS IS JUST FOR THE TEST ROM
cpu->pc = 0xC000;
cpu->status.raw = 0x34;
cpu->acc = 0;
cpu->x = 0;
cpu->y = 0;
cpu->remainingCycles = 7;
cpu->totalCycles = 0;
cpu->bus = parent;
return cpu;
}
void destroyCPU(struct CPU* cpu)
{
free(cpu);
}
int tickCPU(struct CPU* cpu)
{
cpu->remainingCycles--;
cpu->totalCycles += 1;
if (cpu->remainingCycles == 0)
{
fetch(cpu);
execute(cpu);
return 1;
}
return 0;
}
void tickInstr(struct CPU* cpu)
{
while (!tickCPU(cpu));
}
void fetch(struct CPU* cpu)
{
Byte opcodeVal = readBus(cpu->bus, cpu->pc++);
cpu->currentOpcode = OPCODE_TABLE + opcodeVal;
if (cpu->currentOpcode->op == XXX)
{
fprintf(stderr, "Unknown opcode: %x", opcodeVal);
exit(1);
}
cpu->remainingCycles = cpu->currentOpcode->cycles;
switch (cpu->currentOpcode->addr)
{
case ACC:
cpu->fetchedVal = cpu->acc;
break;
case ABS:
{
Byte lo = readBus(cpu->bus, cpu->pc++);
Byte hi = readBus(cpu->bus, cpu->pc++);
cpu->fetchedAddress = ((Word)hi << 8) | lo;
} break;
case ABX:
{
Byte lo = readBus(cpu->bus, cpu->pc++);
Byte hi = readBus(cpu->bus, cpu->pc++);
Word addr = ((Word)hi << 8) | lo;
cpu->fetchedAddress = addr + cpu->x;
if ((cpu->fetchedAddress & 0xFF00) != (addr & 0xFF00))
cpu->remainingCycles++;
} break;
case ABY:
{
Byte lo = readBus(cpu->bus, cpu->pc++);
Byte hi = readBus(cpu->bus, cpu->pc++);
Word addr = ((Word)hi << 8) | lo;
cpu->fetchedAddress = addr + cpu->y;
if ((cpu->fetchedAddress & 0xFF00) != (addr & 0xFF00))
cpu->remainingCycles++;
} break;
case IMM:
cpu->fetchedVal = readBus(cpu->bus, cpu->pc++);
break;
case IMP:
break;
case IND:
{
Byte lo = readBus(cpu->bus, cpu->pc++);
Byte hi = readBus(cpu->bus, cpu->pc++);
Word addr = ((Word)hi << 8) | lo;
cpu->fetchedAddress = readBus(cpu->bus, addr);
} break;
case INDX:
{
Byte op = readBus(cpu->bus, cpu->pc++);
Byte lo = readBus(cpu->bus, op + cpu->x);
Byte hi = readBus(cpu->bus, op + cpu->x + 1);
Word addr = ((Word)hi << 8) | lo;
cpu->fetchedAddress = readBus(cpu->bus, addr);
} break;
case INDY:
{
Byte op = readBus(cpu->bus, cpu->pc++);
Byte lo = readBus(cpu->bus, op);
Byte hi = readBus(cpu->bus, op + 1);
Word addr = ((Word)hi << 8) | lo;
addr = readBus(cpu->bus, addr);
cpu->fetchedAddress = addr + cpu->y;
if ((cpu->fetchedAddress & 0xFF00) != (addr & 0xFF00))
cpu->remainingCycles++;
} break;
case REL:
{
cpu->fetchedRelAddress = readBus(cpu->bus, cpu->pc++);
} break;
case ZPG:
cpu->fetchedAddress = readBus(cpu->bus, cpu->pc++);
break;
case ZPX:
{
cpu->fetchedAddress = readBus(cpu->bus, cpu->pc++) + cpu->x;
cpu->fetchedAddress |= 0xFF;
} break;
case ZPY:
{
cpu->fetchedAddress = readBus(cpu->bus, cpu->pc++) + cpu->y;
cpu->fetchedAddress |= 0xFF;
} break;
}
}
void execute(struct CPU* cpu)
{
LOG_BUS(cpu->bus);
switch (cpu->currentOpcode->op)
{
case JMP:
{
cpu->pc = cpu->fetchedAddress;
} break;
default:
fprintf(stderr, "Unknown instruction: %s", cpu->currentOpcode->str);
exit(1);
break;
}
}