diff --git a/NES Emulator/CMakeLists.txt b/NES Emulator/CMakeLists.txt index 3caca6e..8475916 100644 --- a/NES Emulator/CMakeLists.txt +++ b/NES Emulator/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.8) -add_executable (nesemu "main.c" "cpu.h" "types.h" "bus.h" "bus.c" "cartridge.h" "cpu.c" "cartridge.c") +add_executable (nesemu "main.c" "cpu.h" "types.h" "bus.h" "bus.c" "cartridge.h" "cpu.c" "cartridge.c" "opcodes.c") if(MSVC) target_compile_definitions(nesemu PUBLIC _CRT_SECURE_NO_WARNINGS) diff --git a/NES Emulator/bus.c b/NES Emulator/bus.c index 5ad9e53..cbce8d5 100644 --- a/NES Emulator/bus.c +++ b/NES Emulator/bus.c @@ -53,7 +53,7 @@ Byte readBus(struct Bus* bus, Word addr) } else if (0x4020 <= addr && addr <= 0xFFFF) // Cartridge space { - // rom->read() + val = readCartridge(bus->cartridge, addr); } else { @@ -73,7 +73,7 @@ void writeBus(struct Bus* bus, Word addr, Byte val) } else if (0x4020 <= addr && addr <= 0xFFFF) // Cartridge space { - // rom->write() + writeCartridge(bus->cartridge, addr, val); } else { @@ -81,3 +81,9 @@ void writeBus(struct Bus* bus, Word addr, Byte val) exit(1); } } + + +void tick(struct Bus* bus) +{ + tickInstr(bus->cpu); +} \ No newline at end of file diff --git a/NES Emulator/bus.h b/NES Emulator/bus.h index df9370a..93cc9ad 100644 --- a/NES Emulator/bus.h +++ b/NES Emulator/bus.h @@ -25,4 +25,8 @@ void destroyBus(struct Bus* bus); Byte readBus(struct Bus* bus, Word addr); void writeBus(struct Bus* bus, Word addr, Byte val); + +// Ticks the master clock 12 times (i.e. 1 CPU tick & 3 PPU dots) +void tick(struct Bus* bus); + #endif // _BUS_H_ \ No newline at end of file diff --git a/NES Emulator/cartridge.c b/NES Emulator/cartridge.c index 733326f..5cc1f40 100644 --- a/NES Emulator/cartridge.c +++ b/NES Emulator/cartridge.c @@ -40,10 +40,8 @@ struct Cartridge* createCartridge(struct Bus* parent, const char* filepath) exit(1); } - // Open ROM FILE* fp = fopen(filepath, "rb"); - // readCartridge header struct INES_Header header; fread(&header, sizeof(header), 1, fp); diff --git a/NES Emulator/cpu.c b/NES Emulator/cpu.c index 2d57c40..a067c5c 100644 --- a/NES Emulator/cpu.c +++ b/NES Emulator/cpu.c @@ -13,6 +13,9 @@ struct CPU* createCPU(struct Bus* parent) exit(1); } + // TODO: THIS IS JUST FOR THE TEST ROM + cpu->pc = 0xC000; + cpu->bus = parent; return cpu; } @@ -21,3 +24,39 @@ void destroyCPU(struct CPU* cpu) { free(cpu); } + +void tickCPU(struct CPU* cpu) +{ + if (cpu->fetchedVal != 0) + { + cpu->fetchedVal--; + return; + } + + fetch(cpu); + execute(cpu); +} + +void tickInstr(struct CPU* cpu) +{ + while (cpu->remainingCycles > 1) + tickCPU(cpu); +} + +void fetch(struct CPU* cpu) +{ + Byte opcodeVal = readBus(cpu->bus, cpu->pc); + cpu->currentOpcode = OPCODE_TABLE + opcodeVal; + + if (cpu->currentOpcode->op == Unknown) + { + fprintf(stderr, "Unknown opcode: %x", opcodeVal); + exit(1); + } + + +} + +void execute(struct CPU* cpu) +{ +} diff --git a/NES Emulator/cpu.h b/NES Emulator/cpu.h index 3a7e88e..b534e44 100644 --- a/NES Emulator/cpu.h +++ b/NES Emulator/cpu.h @@ -5,6 +5,35 @@ struct Bus; +typedef enum +{ + XXX = 0, + ADC, AND, ASL, BCC, BCS, BEQ, BIT, BMI, + BNE, BPL, BRK, BVC, BVS, CLC, CLD, CLI, + CLV, CMP, CPX, CPY, DEC, DEX, DEY, EOR, + INC, INX, INY, JMP, JSR, LDA, LDX, LDY, + LSR, NOP, ORA, PHA, PHP, PLA, PLP, ROL, + ROR, RTI, RTS, SBC, SEC, SED, SEI, STA, + STX, STY, TAX, TAY, TSX, TXA, TXS, TYA +} Operation; + +typedef enum +{ + ACC, ABS, ABX, ABY, IMM, IMP, IND, XIN, INY, REL, ZPG, ZPX, ZPY +} AddrMode; + +struct Opcode +{ + Operation op; + AddrMode addr; + Byte cycles; + + const char str[4]; +}; + +const struct Opcode OPCODE_MATRIX[512]; + + struct CPU { Byte acc; @@ -29,10 +58,21 @@ struct CPU Word pc; + Byte remainingCycles; + Byte fetchedVal; + Word fetchedAddress; + const struct Opcode* currentOpcode; + struct Bus* bus; }; struct CPU* createCPU(struct Bus* parent); void destroyCPU(struct CPU* cpu); +void tickCPU(struct CPU* cpu); +void tickInstr(struct CPU* cpu); + +void fetch(struct CPU* cpu); +void execute(struct CPU* cpu); + #endif // _CPU_H_ \ No newline at end of file diff --git a/NES Emulator/main.c b/NES Emulator/main.c index 2087b1f..75be372 100644 --- a/NES Emulator/main.c +++ b/NES Emulator/main.c @@ -3,6 +3,12 @@ int main() { struct Bus* bus = createBus(); + + for (;;) + { + tick(bus); + } + destroyBus(bus); return 0; diff --git a/NES Emulator/opcodes.c b/NES Emulator/opcodes.c new file mode 100644 index 0000000..31b8d46 --- /dev/null +++ b/NES Emulator/opcodes.c @@ -0,0 +1,142 @@ +#include "cpu.h" + +#define NEW_OPCODE(op, addr, cyc) {op, addr, cyc, #op} + +const struct Opcode OPCODE_TABLE[256] = +{ + /* 00 */ NEW_OPCODE(BRK, IMP, 7), + /* 01 */ NEW_OPCODE(ORA, XIN, 6), + /* 02 */ NEW_OPCODE(XXX, IMP, 0), + /* 03 */ NEW_OPCODE(XXX, IMP, 0), + /* 04 */ NEW_OPCODE(XXX, IMP, 0), + /* 05 */ NEW_OPCODE(ORA, ZPG, 3), + /* 06 */ NEW_OPCODE(ASL, ZPG, 5), + /* 07 */ NEW_OPCODE(XXX, IMP, 0), + /* 08 */ NEW_OPCODE(PHP, IMP, 3), + /* 09 */ NEW_OPCODE(ORA, IMM, 2), + /* 0A */ NEW_OPCODE(ASL, ACC, 2), + /* 0B */ NEW_OPCODE(XXX, IMP, 0), + /* 0C */ NEW_OPCODE(XXX, IMP, 0), + /* 0D */ NEW_OPCODE(ORA, ABS, 4), + /* 0E */ NEW_OPCODE(ASL, ABS, 6), + /* 0F */ NEW_OPCODE(XXX, IMP, 0), + + /* 10 */ NEW_OPCODE(BPL, REL, 2), + /* 11 */ NEW_OPCODE(ORA, INY, 5), + /* 12 */ NEW_OPCODE(XXX, IMP, 0), + /* 13 */ NEW_OPCODE(XXX, IMP, 0), + /* 14 */ NEW_OPCODE(XXX, IMP, 0), + /* 15 */ NEW_OPCODE(ORA, ZPX, 4), + /* 16 */ NEW_OPCODE(ASL, ZPX, 6), + /* 17 */ NEW_OPCODE(XXX, IMP, 0), + /* 18 */ NEW_OPCODE(CLC, IMP, 2), + /* 19 */ NEW_OPCODE(ORA, ABY, 4), + /* 1A */ NEW_OPCODE(XXX, IMP, 0), + /* 1B */ NEW_OPCODE(XXX, IMP, 0), + /* 1C */ NEW_OPCODE(XXX, IMP, 0), + /* 1D */ NEW_OPCODE(ORA, ABX, 4), + /* 1E */ NEW_OPCODE(ASL, ABX, 7), + /* 1F */ NEW_OPCODE(XXX, IMP, 0), + + ///* 20 */ NEW_OPCODE(JSR, ABS), + ///* 21 */ NEW_OPCODE(AND, XIN), + ///* 22 */ NEW_OPCODE(XXX, IMP), + ///* 23 */ NEW_OPCODE(XXX, IMP), + ///* 24 */ NEW_OPCODE(BIT, ZPG), + ///* 25 */ NEW_OPCODE(AND, ZPG), + ///* 26 */ NEW_OPCODE(ROL, ZPG), + ///* 27 */ NEW_OPCODE(XXX, IMP), + ///* 28 */ NEW_OPCODE(PLP, IMP), + ///* 29 */ NEW_OPCODE(AND, IMM), + ///* 2A */ NEW_OPCODE(ROL, ACC), + ///* 2B */ NEW_OPCODE(XXX, IMP), + ///* 2C */ NEW_OPCODE(BIT, ABS), + ///* 2D */ NEW_OPCODE(AND, ABS), + ///* 2E */ NEW_OPCODE(ROL, ABS), + ///* 2F */ NEW_OPCODE(XXX, IMP), + + ///* 30 */ NEW_OPCODE(BMI, REL), + ///* 31 */ NEW_OPCODE(AND, INY), + ///* 32 */ NEW_OPCODE(XXX, IMP), + ///* 33 */ NEW_OPCODE(XXX, IMP), + ///* 34 */ NEW_OPCODE(XXX, IMP), + ///* 35 */ NEW_OPCODE(AND, ZPX), + ///* 36 */ NEW_OPCODE(ROL, ZPX), + ///* 37 */ NEW_OPCODE(XXX, IMP), + ///* 38 */ NEW_OPCODE(SEC, IMP), + ///* 39 */ NEW_OPCODE(AND, ABY), + ///* 3A */ NEW_OPCODE(XXX, IMP), + ///* 3B */ NEW_OPCODE(XXX, IMP), + ///* 3C */ NEW_OPCODE(XXX, IMP), + ///* 3D */ NEW_OPCODE(AND, ABX), + ///* 3E */ NEW_OPCODE(ROL, ABX), + ///* 3F */ NEW_OPCODE(XXX, IMP), + + ///* 40 */ NEW_OPCODE(RTI, IMP), + ///* 41 */ NEW_OPCODE(EOR, XIN), + ///* 42 */ NEW_OPCODE(XXX, IMP), + ///* 43 */ NEW_OPCODE(XXX, IMP), + ///* 44 */ NEW_OPCODE(XXX, IMP), + ///* 45 */ NEW_OPCODE(EOR, ZPG), + ///* 46 */ NEW_OPCODE(LSR, ZPG), + ///* 47 */ NEW_OPCODE(XXX, IMP), + ///* 48 */ NEW_OPCODE(PHA, IMP), + ///* 49 */ NEW_OPCODE(EOR, IMM), + ///* 4A */ NEW_OPCODE(LSR, ACC), + ///* 4B */ NEW_OPCODE(XXX, IMP), + ///* 4C */ NEW_OPCODE(JMP, ABS), + ///* 4D */ NEW_OPCODE(EOR, ABS), + ///* 4E */ NEW_OPCODE(LSR, ABS), + ///* 4F */ NEW_OPCODE(XXX, IMP), + + ///* 50 */ NEW_OPCODE(BVC, REL), + ///* 51 */ NEW_OPCODE(EOR, INY), + ///* 52 */ NEW_OPCODE(XXX, IMP), + ///* 53 */ NEW_OPCODE(XXX, IMP), + ///* 54 */ NEW_OPCODE(XXX, IMP), + ///* 55 */ NEW_OPCODE(EOR, ZPX), + ///* 56 */ NEW_OPCODE(LSR, ZPX), + ///* 57 */ NEW_OPCODE(XXX, IMP), + ///* 58 */ NEW_OPCODE(CLI, IMP), + ///* 59 */ NEW_OPCODE(EOR, ABY), + ///* 5A */ NEW_OPCODE(XXX, IMP), + ///* 5B */ NEW_OPCODE(XXX, IMP), + ///* 5C */ NEW_OPCODE(XXX, IMP), + ///* 5D */ NEW_OPCODE(EOR, ABX), + ///* 5E */ NEW_OPCODE(LSR, ABX), + ///* 5F */ NEW_OPCODE(XXX, IMP), + + ///* 60 */ NEW_OPCODE(RTS, IMP), + ///* 61 */ NEW_OPCODE(ADC, XIN), + ///* 62 */ NEW_OPCODE(XXX, IMP), + ///* 63 */ NEW_OPCODE(XXX, IMP), + ///* 64 */ NEW_OPCODE(XXX, IMP), + ///* 65 */ NEW_OPCODE(ADC, ZPG), + ///* 66 */ NEW_OPCODE(ROR, ZPG), + ///* 67 */ NEW_OPCODE(XXX, IMP), + ///* 68 */ NEW_OPCODE(PLA, IMP), + ///* 69 */ NEW_OPCODE(ADC, IMM), + ///* 6A */ NEW_OPCODE(ROR, ACC), + ///* 6B */ NEW_OPCODE(XXX, IMP), + ///* 6C */ NEW_OPCODE(JMP, IND), + ///* 6D */ NEW_OPCODE(ADC, ABS), + ///* 6E */ NEW_OPCODE(ROR, ABS), + ///* 6F */ NEW_OPCODE(XXX, IMP), + + ///* 70 */ NEW_OPCODE(BVS, REL), + ///* 71 */ NEW_OPCODE(ADC, INY), + ///* 72 */ NEW_OPCODE(XXX, IMP), + ///* 73 */ NEW_OPCODE(XXX, IMP), + ///* 74 */ NEW_OPCODE(XXX, IMP), + ///* 75 */ NEW_OPCODE(ADC, ZPX), + ///* 76 */ NEW_OPCODE(ROR, ZPX), + ///* 77 */ NEW_OPCODE(XXX, IMP), + ///* 78 */ NEW_OPCODE(SEI, IMP), + ///* 79 */ NEW_OPCODE(ADC, ABY), + ///* 7A */ NEW_OPCODE(XXX, IMP), + ///* 7B */ NEW_OPCODE(XXX, IMP), + ///* 7C */ NEW_OPCODE(XXX, IMP), + ///* 7D */ NEW_OPCODE(ADC, ABX), + ///* 7E */ NEW_OPCODE(ROR, ABX), + ///* 7F */ NEW_OPCODE(XXX, IMP), +} \ No newline at end of file