diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 507a580..18dcf2d 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -12,6 +12,7 @@
+
@@ -22,26 +23,25 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -78,35 +78,38 @@
- {
- "keyToString": {
- "ASKED_ADD_EXTERNAL_FILES": "true",
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.cidr.known.project.marker": "true",
- "cf.first.check.clang-format": "false",
- "cidr.known.project.marker": "true",
- "com.jfrog.conanplugin.addconansupport": "true",
- "com.jfrog.conanplugin.automanage.cmake.advanced.settings": "true",
- "com.jfrog.conanplugin.conanexecutable": "conan",
- "com.jfrog.conanplugin.hasbeensetup": "true",
- "git-widget-placeholder": "master",
- "last_opened_file_path": "/d/p/nes/CMakeLists.txt",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "settings.editor.selected.configurable": "preferences.pluginManager",
- "vue.rearranger.settings.migration": "true"
+
+}]]>
-
+
+
-
@@ -118,19 +121,143 @@
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -151,6 +278,14 @@
+
+
+
+
+
+
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fee3e08..f188b6f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,13 +2,16 @@ cmake_minimum_required(VERSION 3.10)
project(NESEmulator VERSION 0.1)
add_subdirectory(cpu)
-list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/cpu")
+add_subdirectory(mappers)
+list(APPEND EXTRA_INCLUDES
+ "${PROJECT_SOURCE_DIR}/cpu"
+ "${PROJECT_SOURCE_DIR}/mappers")
add_executable(NESEmulator main.c)
find_package(log.c)
-target_link_libraries(NESEmulator CPU log.c::log.c)
+target_link_libraries(NESEmulator CPU Mappers log.c::log.c)
target_include_directories(NESEmulator PUBLIC
"${PROJECT_BINARY_DIR}"
${EXTRA_INCLUDES})
diff --git a/cpu/CMakeLists.txt b/cpu/CMakeLists.txt
index 344b450..79a7e5a 100644
--- a/cpu/CMakeLists.txt
+++ b/cpu/CMakeLists.txt
@@ -1,4 +1,9 @@
add_library(CPU
cpu.c
op.c
- mem.c)
\ No newline at end of file
+ ram.c
+ memory.c
+ cpu.h)
+
+find_package(log.c)
+target_link_libraries(CPU log.c::log.c)
\ No newline at end of file
diff --git a/cpu/cpu.c b/cpu/cpu.c
index 9483412..9a582e6 100644
--- a/cpu/cpu.c
+++ b/cpu/cpu.c
@@ -1,3 +1,7 @@
+#include "../include/cpu.h"
+#include "cpu.h"
+#include "memory.h"
+
/*
* =====================================================================================
*
@@ -15,13 +19,86 @@
*
* =====================================================================================
*/
-#include
-#include
-#include "../include/cpu/op.h"
+CpuRegisters registers;
+Mapper mapper;
-long cpu_clock = 0;
-
-void cpu_step_to(long cycle) {
+void cpu_init() {
+ registers.program_counter = 0x0000;
+ registers.stack_pointer = 0xff;
+ registers.accumulator = 0x00;
+ registers.x = 0x00;
+ registers.y = 0x00;
+ registers.status = 0x00;
}
+// === Registers ===
+CpuRegisters* cpu_get_registers() {
+ return ®isters;
+}
+
+byte cpu_get_flag(byte mask) {
+ return registers.status & mask;
+}
+
+void cpu_set_flag(bool set, byte mask) {
+ if (set) {
+ registers.status |= mask;
+ } else {
+ registers.status &= ~mask;
+ }
+}
+
+// === Memory ===
+byte cpu_get_next_byte() {
+ byte next_byte = mem_get_byte(&mapper, registers.program_counter);
+ registers.program_counter++;
+ return next_byte;
+}
+
+word cpu_get_next_word() {
+ word next_word = mem_get_word(&mapper, registers.program_counter);
+ registers.program_counter += 2;
+ return next_word;
+}
+
+byte cpu_peek_byte(address addr) {
+ return mem_get_byte(&mapper, addr);
+}
+
+word cpu_peek_word(address addr) {
+ return mem_get_word(&mapper, addr);
+}
+
+void cpu_push_byte(byte value, address addr) {
+ mem_set_byte(&mapper, addr, value);
+}
+
+// === Stack ===
+void cpu_stack_push(byte value) {
+ address mem_addr = CPU_STACK_ADDR | registers.stack_pointer;
+ cpu_push_byte(value, mem_addr);
+ registers.stack_pointer--;
+}
+
+byte cpu_stack_pop() {
+ address mem_addr = CPU_STACK_ADDR | registers.stack_pointer;
+ byte value = cpu_peek_byte(mem_addr);
+ registers.stack_pointer++;
+ return value;
+}
+
+void cpu_stack_push_context() {
+ cpu_stack_push(registers.program_counter >> 8);
+ cpu_stack_push(registers.program_counter & 0xff);
+ cpu_stack_push(registers.status);
+}
+
+void cpu_stack_pop_context() {
+ registers.status = cpu_stack_pop();
+
+ byte lo = cpu_stack_pop();
+ address pc = cpu_stack_pop() << 8;
+ pc += lo;
+ registers.program_counter = pc;
+}
\ No newline at end of file
diff --git a/cpu/cpu.h b/cpu/cpu.h
new file mode 100644
index 0000000..eaad67b
--- /dev/null
+++ b/cpu/cpu.h
@@ -0,0 +1,60 @@
+//
+// Created by william on 10/15/23.
+//
+
+#ifndef CPU_CPU_H
+#define CPU_CPU_H
+
+#include
+
+// Reference: https://www.nesdev.org/wiki/Status_flags
+#define CPU_STATUS_CARRY_MASK 0x01
+#define CPU_STATUS_ZERO_MASK 0x02
+#define CPU_STATUS_INTERRUPT_DISABLE_MASK 0x04
+#define CPU_STATUS_DECIMAL_MASK 0x08
+#define CPU_STATUS_B_MASK 0x10
+#define CPU_STATUS_I_MASK 0x20
+#define CPU_STATUS_OVERFLOW_MASK 0x40
+#define CPU_STATUS_NEGATIVE_MASK 0x80
+
+#define CPU_STACK_ADDR 0x0100
+
+// Reference: https://www.nesdev.org/obelisk-6502-guide/registers.html
+typedef struct {
+ address program_counter;
+ byte stack_pointer;
+ byte accumulator;
+ byte x;
+ byte y;
+ byte status;
+} CpuRegisters;
+
+enum OperandType {
+ OPERAND_TYPE_ACCUMULATOR,
+ OPERAND_TYPE_IMMEDIATE,
+ OPERAND_TYPE_ADDRESS
+};
+
+typedef struct {
+ word value;
+ enum OperandType type;
+ bool is_page_crossing;
+} Operand;
+
+CpuRegisters* cpu_get_registers();
+byte cpu_get_flag(byte mask);
+void cpu_set_flag(bool set, byte mask);
+
+byte cpu_get_next_byte();
+word cpu_get_next_word();
+
+byte cpu_peek_byte(address addr);
+word cpu_peek_word(address addr);
+void cpu_push_byte(byte value, address addr);
+
+void cpu_stack_push(byte value);
+void cpu_stack_push_context();
+byte cpu_stack_pop();
+void cpu_stack_pop_context();
+
+#endif //CPU_CPU_H
diff --git a/cpu/mem.c b/cpu/mem.c
deleted file mode 100644
index acaad3f..0000000
--- a/cpu/mem.c
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Created by william on 30/09/23.
-//
-
-#include "../include/cpu/mem.h"
-#include "../include/cpu/op.h"
-
-#include "../include/cpu/cpu.h"
-
-unsigned short get_memory_address(addr_mode_t addr_mode, unsigned short operand) {
- if (addr_mode == ADDR_MODE_ABSOLUTE) {
- cpu_add_cycles(4);
- return operand;
- } else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_X) {
- unsigned char x = cpu_get_registers()->x;
- cpu_add_cycles(4);
- return operand + x;
- } else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_Y) {
- unsigned char y = cpu_get_registers()->y;
- cpu_add_cycles(4);
- return operand + y;
- } else if (addr_mode == ADDR_MODE_INDEXED_INDIRECT) {
-
- }
-
-}
\ No newline at end of file
diff --git a/cpu/memory.c b/cpu/memory.c
new file mode 100644
index 0000000..00df8c7
--- /dev/null
+++ b/cpu/memory.c
@@ -0,0 +1,21 @@
+//
+// Created by william on 10/15/23.
+//
+
+#include "memory.h"
+#include "ram.h"
+
+byte mem_get_byte(Mapper *mapper, address addr) {
+ address redirected_addr = mapper->redirect_addr(addr);
+ return ram_get_byte(redirected_addr);
+}
+
+word mem_get_word(Mapper *mapper, address addr) {
+ address redirected_addr = mapper->redirect_addr(addr);
+ return ram_get_word(redirected_addr);
+}
+
+void mem_set_byte(Mapper *mapper, address addr, byte byte) {
+ address redirected_addr = mapper->redirect_addr(addr);
+ ram_set_byte(redirected_addr, byte);
+}
\ No newline at end of file
diff --git a/cpu/memory.h b/cpu/memory.h
new file mode 100644
index 0000000..c440d43
--- /dev/null
+++ b/cpu/memory.h
@@ -0,0 +1,14 @@
+//
+// Created by william on 10/15/23.
+//
+
+#include "../include/mapper.h"
+
+#ifndef NESEMULATOR_MEMORY_H
+#define NESEMULATOR_MEMORY_H
+
+byte mem_get_byte(Mapper *mapper, address addr);
+word mem_get_word(Mapper *mapper, address addr);
+void mem_set_byte(Mapper *mapper, address addr, byte byte);
+
+#endif //NESEMULATOR_MEMORY_H
diff --git a/cpu/op.c b/cpu/op.c
index 33a18c5..d94e36c 100644
--- a/cpu/op.c
+++ b/cpu/op.c
@@ -1,6 +1,13 @@
-#include "../include/cpu/op.h"
+#include
+#include
+#include
+
+#include "op.h"
+#include "cpu.h"
+#include "../include/cpu.h"
// Reference: https://www.nesdev.org/wiki/CPU_unofficial_opcodes
+// https://www.middle-engine.com/blog/posts/2020/06/23/programming-the-nes-the-6502-in-detail
#define IS_OP_CODE_MODE(op, op_code, addr_mode) \
case op_code: \
@@ -14,20 +21,20 @@
IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## op + offset, addr_mode)
#define IS_ALU_OP_CODE(op) \
- IS_ALU_OP_CODE_(op, 0x01, INDEXED_INDIRECT) \
+ IS_ALU_OP_CODE_(op, 0x01, INDIRECT_X) \
IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \
IS_ALU_OP_CODE_(op, 0x09, IMMEDIATE) \
IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \
- IS_ALU_OP_CODE_(op, 0x11, INDIRECT_INDEXED) \
+ IS_ALU_OP_CODE_(op, 0x11, INDIRECT_Y) \
IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \
IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \
IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X)
#define IS_ALU_OP_CODE_NO_IMMEDIATE(op) \
- IS_ALU_OP_CODE_(op, 0x01, INDEXED_INDIRECT) \
+ IS_ALU_OP_CODE_(op, 0x01, INDIRECT_X) \
IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \
IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \
- IS_ALU_OP_CODE_(op, 0x11, INDIRECT_INDEXED) \
+ IS_ALU_OP_CODE_(op, 0x11, INDIRECT_Y) \
IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \
IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \
IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X)
@@ -46,316 +53,760 @@
IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## line + offset, addr_mode)
#define IS_UNOFFICIAL_OP_CODE(op, line) \
- IS_UNOFFICIAL_OP_CODE_(op, line, 0x03, INDEXED_INDIRECT) \
+ IS_UNOFFICIAL_OP_CODE_(op, line, 0x03, INDIRECT_X) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x07, ZERO_PAGE) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x0f, ABSOLUTE) \
- IS_UNOFFICIAL_OP_CODE_(op, line, 0x13, INDIRECT_INDEXED) \
+ IS_UNOFFICIAL_OP_CODE_(op, line, 0x13, INDIRECT_Y) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x17, ZERO_PAGE_INDEXED_X) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x1b, ABSOLUTE_INDEXED_Y) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x1f, ABSOLUTE_INDEXED_X)
-void op_ADC(addr_mode_t addr_mode) {
+address decode_operand_addr(AddressingMode addr_mode, bool *page_crossing) {
+ CpuRegisters *registers = cpu_get_registers();
+
+ if (addr_mode == ADDR_MODE_ZERO_PAGE) {
+ return cpu_get_next_byte();
+ } else if (addr_mode == ADDR_MODE_ZERO_PAGE_INDEXED_X) {
+ return (cpu_get_next_byte() + registers->x) & 0xff;
+ } else if (addr_mode == ADDR_MODE_ZERO_PAGE_INDEXED_Y) {
+ return (cpu_get_next_byte() + registers->y) & 0xff;
+ } else if (addr_mode == ADDR_MODE_ABSOLUTE || addr_mode == ADDR_MODE_ABSOLUTE_JUMP) {
+ return cpu_get_next_word();
+ } else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_X) {
+ word addr = cpu_get_next_word();
+ word new_addr = addr + registers->x;
+
+ *page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
+
+ return new_addr;
+ } else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_Y) {
+ word addr = cpu_get_next_word();
+ word new_addr = addr + registers->y;
+
+ *page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
+
+ return new_addr;
+ } else if (addr_mode == ADDR_MODE_INDIRECT_JUMP) {
+ word addr = cpu_get_next_word();
+ if ((addr & 0xff) == 0xff) {
+ // Error in NES CPU for JMP op
+ word result = cpu_peek_byte(addr);
+ result += cpu_peek_byte(addr & 0xff00) << 8;
+ return result;
+ }
+ return cpu_peek_word(addr);
+ } else if (addr_mode == ADDR_MODE_INDIRECT_X) {
+ byte addr = cpu_get_next_byte();
+ word result = cpu_peek_byte((addr + registers->x) & 0xff);
+ result += cpu_peek_byte((addr + registers->x + 1) & 0xff) << 8;
+ return result;
+ } else if (addr_mode == ADDR_MODE_INDIRECT_Y) {
+ byte arg_addr = cpu_get_next_byte();
+ word addr = cpu_peek_byte(arg_addr) + (cpu_peek_byte((arg_addr + 1) & 0xff) << 8);
+ word new_addr = addr + registers->y;
+
+ *page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
+
+ return new_addr;
+ } else {
+ assert(false);
+ }
+}
+
+Operand decode_operand(AddressingMode addr_mode) {
+ Operand operand;
+
+ if (addr_mode == ADDR_MODE_ACCUMULATOR) {
+ operand.type = OPERAND_TYPE_ACCUMULATOR;
+ operand.value = 0;
+ operand.is_page_crossing = false;
+ } else if (addr_mode == ADDR_MODE_IMMEDIATE) {
+ operand.type = OPERAND_TYPE_IMMEDIATE;
+ operand.value = cpu_get_next_byte();
+ operand.is_page_crossing = false;
+ } else {
+ operand.type = OPERAND_TYPE_ADDRESS;
+ operand.value = decode_operand_addr(addr_mode, &operand.is_page_crossing);
+ }
+
+ return operand;
+}
+
+byte read_operand(Operand operand) {
+ switch (operand.type) {
+ case OPERAND_TYPE_ACCUMULATOR:
+ return cpu_get_registers()->accumulator;
+ case OPERAND_TYPE_IMMEDIATE:
+ return (byte) operand.value;
+ case OPERAND_TYPE_ADDRESS:
+ return cpu_peek_byte(operand.value);
+ default:
+ assert(false);
+ }
+}
+
+void write_operand(Operand operand, byte value) {
+ switch (operand.type) {
+ case OPERAND_TYPE_ACCUMULATOR:
+ cpu_get_registers()->accumulator = value;
+ break;
+ case OPERAND_TYPE_ADDRESS:
+ cpu_push_byte(operand.value, value);
+ break;
+ default:
+ assert(false);
+ }
+}
+
+bool is_sign_overflow(byte val1, byte val2, byte result) {
+ return ((val1 & 0x80) == (val2 & 0x80)) &&
+ ((val1 & 0x80) != (result & 0x80));
+}
+
+byte get_cycle_count(Operand operand, AddressingMode addr_mode) {
+ switch (addr_mode) {
+ case ADDR_MODE_ACCUMULATOR:
+ case ADDR_MODE_IMPLICIT:
+ return 2;
+ case ADDR_MODE_ZERO_PAGE:
+ return 3;
+ case ADDR_MODE_ZERO_PAGE_INDEXED_X:
+ case ADDR_MODE_ZERO_PAGE_INDEXED_Y:
+ case ADDR_MODE_ABSOLUTE:
+ return 4;
+ case ADDR_MODE_ABSOLUTE_INDEXED_X:
+ case ADDR_MODE_ABSOLUTE_INDEXED_Y:
+ return operand.is_page_crossing ? 5 : 4;
+ case ADDR_MODE_INDIRECT_X:
+ return 6;
+ case ADDR_MODE_INDIRECT_Y:
+ return operand.is_page_crossing ? 6 : 5;
+ default:
+ assert(false);
+ }
+}
+
+byte get_shift_cycle_count(AddressingMode addr_mode) {
+ switch (addr_mode) {
+ case ADDR_MODE_ACCUMULATOR:
+ return 2;
+ case ADDR_MODE_ZERO_PAGE:
+ return 5;
+ case ADDR_MODE_ZERO_PAGE_INDEXED_X:
+ case ADDR_MODE_ABSOLUTE:
+ return 6;
+ case ADDR_MODE_ABSOLUTE_INDEXED_X:
+ return 7;
+ default:
+ assert(false);
+ }
+}
+void set_acl_flags(byte result) {
+ cpu_set_flag(result == 0, CPU_STATUS_ZERO_MASK);
+ cpu_set_flag(result & 0x80, CPU_STATUS_NEGATIVE_MASK);
}
-/* === CTRL === */
-void op_BRK(addr_mode_t addr_mode) {
+byte get_branch_cycle_count(bool branching, char offset) {
+ address target = cpu_get_registers()->program_counter;
+ byte cycle_count = 2;
-}
+ if (branching) {
+ cycle_count += 1;
-void op_BPL(addr_mode_t addr_mode) {
+ if ((target & 0xff00) != ((target - offset) & 0xff00)) {
+ cycle_count += 2;
+ }
+ }
+ return cycle_count;
}
-void op_BIT(addr_mode_t addr_mode) {
+void op_branch(bool branching) {
+ char offset = (char) cpu_get_next_byte();
+ if (branching) {
+ address counter = cpu_get_registers()->program_counter;
+ address target = counter + offset;
+ cpu_get_registers()->program_counter = target;
+ }
+
+ cpu_add_cycles(get_branch_cycle_count(branching, offset));
}
-void op_BMI(addr_mode_t addr_mode) {
+void add_with_carry(byte value) {
+ byte acc = cpu_get_registers()->accumulator;
-}
+ byte addition = acc + value;
+ bool overflow = false;
-void op_BVC(addr_mode_t addr_mode) {
+ // Check for overflow
+ if (addition < acc) {
+ overflow = true;
+ }
-}
+ // Add carry flag and check for overflow again
+ byte result = addition + cpu_get_flag(CPU_STATUS_CARRY_MASK);
+ if (result < addition) {
+ overflow = true;
+ }
+
+ cpu_get_registers()->accumulator = acc;
-void op_BVS(addr_mode_t addr_mode) {
+ cpu_set_flag(overflow, CPU_STATUS_CARRY_MASK);
+ cpu_set_flag(is_sign_overflow(acc, value, result));
+ set_acl_flags(result);
}
-void op_BCC(addr_mode_t addr_mode) {
+void op_ADC(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
-}
+ byte value = read_operand(operand);
+ add_with_carry(value);
-void op_BCS(addr_mode_t addr_mode) {
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
+}
+void op_AHX(AddressingMode addr_mode) {
+ assert(false);
}
-void op_BNE(addr_mode_t addr_mode) {
+void op_ALR(AddressingMode addr_mode) {
+ assert(false);
+}
+void op_ANC(AddressingMode addr_mode) {
+ assert(false);
}
-void op_BEQ(addr_mode_t addr_mode) {
+void op_AND(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte acc = cpu_get_registers()->accumulator;
-}
+ byte result = acc & value;
+ cpu_get_registers()->accumulator = result;
-void op_PHP(addr_mode_t addr_mode) {
+ set_acl_flags(result);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
+}
+void op_ARR(AddressingMode addr_mode) {
+ assert(false);
}
-void op_CLC(addr_mode_t addr_mode) {
+void op_ASL(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+
+ byte result = value << 1;
+ write_operand(operand, result);
+ cpu_set_flag(value & 0x80, CPU_STATUS_CARRY_MASK);
+ set_acl_flags(result);
+ cpu_add_cycles(get_shift_cycle_count(addr_mode));
}
-void op_JSR(addr_mode_t addr_mode) {
+void op_AXS(AddressingMode addr_mode) {
+ assert(false);
+}
+void op_BCC(AddressingMode addr_mode) {
+ op_branch(!cpu_get_flag(CPU_STATUS_CARRY_MASK));
}
-void op_PLP(addr_mode_t addr_mode) {
+void op_BCS(AddressingMode addr_mode) {
+ op_branch(cpu_get_flag(CPU_STATUS_CARRY_MASK));
+}
+void op_BEQ(AddressingMode addr_mode) {
+ op_branch(cpu_get_flag(CPU_STATUS_ZERO_MASK));
}
-void op_SEC(addr_mode_t addr_mode) {
+void op_BIT(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte acc = cpu_get_registers()->accumulator;
-}
+ byte result = value & acc;
-void op_RTI(addr_mode_t addr_mode) {
+ cpu_set_flag(result == 0, CPU_STATUS_ZERO_MASK);
+ cpu_set_flag(result & 0x40, CPU_STATUS_OVERFLOW_MASK);
+ cpu_set_flag(result & 0x80, CPU_STATUS_NEGATIVE_MASK);
+}
+void op_BMI(AddressingMode addr_mode) {
+ op_branch(cpu_get_flag(CPU_STATUS_NEGATIVE_MASK));
}
-void op_PHA(addr_mode_t addr_mode) {
+void op_BNE(AddressingMode addr_mode) {
+ op_branch(!cpu_get_flag(CPU_STATUS_ZERO_MASK));
+}
+void op_BPL(AddressingMode addr_mode) {
+ op_branch(!cpu_get_flag(CPU_STATUS_NEGATIVE_MASK));
}
-void op_JMP(addr_mode_t addr_mode) {
+// Stops program execution, useful for debugging
+void op_BRK(AddressingMode addr_mode) {
+ cpu_stack_push_context();
+ // TODO Load IRQ interrupt vector in PC at $FFFE/F
+
+ cpu_set_flag(true, CPU_STATUS_B_MASK);
+ cpu_add_cycles(7);
}
-void op_CLI(addr_mode_t addr_mode) {
+void op_BVC(AddressingMode addr_mode) {
+ op_branch(!cpu_get_flag(CPU_STATUS_OVERFLOW_MASK));
+}
+void op_BVS(AddressingMode addr_mode) {
+ op_branch(cpu_get_flag(CPU_STATUS_OVERFLOW_MASK));
}
-void op_RTS(addr_mode_t addr_mode) {
+void op_CLC(AddressingMode addr_mode) {
+ cpu_set_flag(false, CPU_STATUS_CARRY_MASK);
+ cpu_add_cycles(2);
+}
+void op_CLD(AddressingMode addr_mode) {
+ cpu_set_flag(false, CPU_STATUS_DECIMAL_MASK);
+ cpu_add_cycles(2);
}
-void op_PLA(addr_mode_t addr_mode) {
+void op_CLI(AddressingMode addr_mode) {
+ cpu_set_flag(false, CPU_STATUS_INTERRUPT_DISABLE_MASK);
+ cpu_add_cycles(2);
+}
+void op_CLV(AddressingMode addr_mode) {
+ cpu_set_flag(false, CPU_STATUS_OVERFLOW_MASK);
+ cpu_add_cycles(2);
}
-void op_SEI(addr_mode_t addr_mode) {
+void op_CMP(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte acc = cpu_get_registers()->accumulator;
-}
+ byte result = acc - value;
-void op_STY(addr_mode_t addr_mode) {
+ cpu_set_flag(acc >= value, CPU_STATUS_CARRY_MASK);
+ cpu_set_flag(result == 0, CPU_STATUS_ZERO_MASK);
+ cpu_set_flag(result & 0x80, CPU_STATUS_NEGATIVE_MASK);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_DEY(addr_mode_t addr_mode) {
+void op_CPX(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte x = cpu_get_registers()->x;
-}
+ byte result = x - value;
-void op_TYA(addr_mode_t addr_mode) {
+ cpu_set_flag(x >= value, CPU_STATUS_CARRY_MASK);
+ cpu_set_flag(result == 0, CPU_STATUS_ZERO_MASK);
+ cpu_set_flag(result & 0x80, CPU_STATUS_NEGATIVE_MASK);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_LDY(addr_mode_t addr_mode) {
+void op_CPY(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte y = cpu_get_registers()->y;
-}
+ byte result = y - value;
-void op_TAY(addr_mode_t addr_mode) {
+ cpu_set_flag(y >= value, CPU_STATUS_CARRY_MASK);
+ cpu_set_flag(result == 0, CPU_STATUS_ZERO_MASK);
+ cpu_set_flag(result & 0x80, CPU_STATUS_NEGATIVE_MASK);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_CLV(addr_mode_t addr_mode) {
-
+void op_DCP(AddressingMode addr_mode) {
+ assert(false);
}
-void op_CPY(addr_mode_t addr_mode) {
+void op_DEC(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+
+ byte result = value - 1;
+ set_acl_flags(result);
+ write_operand(operand, result);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_INY(addr_mode_t addr_mode) {
+void op_DEX(AddressingMode addr_mode) {
+ byte x = cpu_get_registers()->x;
+ byte result = x - 1;
+ cpu_get_registers()->x = result;
+
+ set_acl_flags(result);
+ cpu_add_cycles(2);
}
-void op_CLD(addr_mode_t addr_mode) {
+void op_DEY(AddressingMode addr_mode) {
+ byte y = cpu_get_registers()->y;
+
+ byte result = y - 1;
+ cpu_get_registers()->y = result;
+ set_acl_flags(result);
+ cpu_add_cycles(2);
}
-void op_CPX(addr_mode_t addr_mode) {
+void op_EOR(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte acc = cpu_get_registers()->accumulator;
+
+ acc ^= value;
+ cpu_get_registers()->accumulator = acc;
+ set_acl_flags(acc);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_INX(addr_mode_t addr_mode) {
+void op_INC(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ value += 1;
+ write_operand(operand, value);
+
+ set_acl_flags(value);
+ cpu_add_cycles(get_shift_cycle_count(addr_mode));
}
-void op_SED(addr_mode_t addr_mode) {
+void op_INX(AddressingMode addr_mode) {
+ byte x = cpu_get_registers()->x;
+
+ x += 1;
+ cpu_get_registers()->x = x;
+ set_acl_flags(x);
+ cpu_add_cycles(2);
}
-/* === ALU === */
-void op_ORA(addr_mode_t addr_mode) {
+void op_INY(AddressingMode addr_mode) {
+ byte y = cpu_get_registers()->y;
-}
+ y += 1;
+ cpu_get_registers()->y = y;
-void op_AND(addr_mode_t addr_mode) {
+ set_acl_flags(y);
+ cpu_add_cycles(2);
+}
+void op_ISC(AddressingMode addr_mode) {
+ assert(false);
}
-void op_EOR(addr_mode_t addr_mode) {
+void op_JMP(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte addr = read_operand(operand);
+ cpu_get_registers()->program_counter = addr;
+
+ // TODO WN: Handle CPU bug?
+ // > An original 6502 has does not correctly fetch the target address if the indirect vector falls on a page boundary (e.g. $xxFF where xx is any value from $00 to $FF).
+ // > In this case fetches the LSB from $xxFF as expected but takes the MSB from $xx00.
+ // > This is fixed in some later chips like the 65SC02 so for compatibility always ensure the indirect vector is not at the end of the page.
}
-void op_ADC(addr_mode_t addr_mode) {
+void op_JSR(AddressingMode addr_mode) {
+ // Push the program counter on the stack
+ address program_counter = cpu_get_registers()->program_counter - 1;
+ cpu_stack_push(program_counter >> 8);
+ cpu_stack_push(program_counter & 0xff);
-}
+ // Updates the program counter to the address in the operand
+ address addr = decode_operand_addr(addr_mode, NULL);
+ cpu_get_registers()->program_counter = addr;
-void op_STA(addr_mode_t addr_mode) {
+ cpu_add_cycles(6);
+}
+void op_LAX(AddressingMode addr_mode) {
+ assert(false);
}
-void op_LDA(addr_mode_t addr_mode) {
+void op_LDA(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+
+ cpu_get_registers()->accumulator = value;
+ set_acl_flags(value);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_CMP(addr_mode_t addr_mode) {
+void op_LDX(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ cpu_get_registers()->x = value;
+
+ set_acl_flags(value);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_SBC(addr_mode_t addr_mode) {
+void op_LDY(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+
+ cpu_get_registers()->y = value;
+ set_acl_flags(value);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_NOP(addr_mode_t addr_mode) {
+void op_LSR(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
-}
+ // Put bit 0 in the carry flag
+ cpu_set_flag(value & 0x01, CPU_STATUS_CARRY_MASK);
-/* RMW */
-void op_ASL(addr_mode_t addr_mode) {
+ value >>= 1;
+ write_operand(operand, value);
+ set_acl_flags(value);
+ cpu_add_cycles(get_shift_cycle_count(addr_mode));
}
-void op_ROL(addr_mode_t addr_mode) {
+void op_NOP(AddressingMode addr_mode) {
+ cpu_add_cycles(2);
+}
-}
+void op_ORA(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte acc = cpu_get_registers()->accumulator;
-void op_LSR(addr_mode_t addr_mode) {
+ acc |= value;
+ cpu_get_registers()->accumulator = acc;
+ set_acl_flags(acc);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_ROR(addr_mode_t addr_mode) {
+void op_PHA(AddressingMode addr_mode) {
+ byte acc = cpu_get_registers()->accumulator;
+ cpu_stack_push(acc);
+ cpu_add_cycles(3);
}
-void op_STX(addr_mode_t addr_mode) {
+void op_PHP(AddressingMode addr_mode) {
+ byte status = cpu_get_registers()->status;
+ cpu_stack_push(status);
+ cpu_add_cycles(3);
}
-void op_TXA(addr_mode_t addr_mode) {
+void op_PLA(AddressingMode addr_mode) {
+ byte value = cpu_stack_pop();
+ cpu_get_registers()->accumulator = value;
+ cpu_add_cycles(4);
}
-void op_TXS(addr_mode_t addr_mode) {
+void op_PLP(AddressingMode addr_mode) {
+ byte value = cpu_stack_pop();
+ cpu_get_registers()->status = value;
+ cpu_add_cycles(4);
}
-void op_SHX(addr_mode_t addr_mode) {
-
+void op_RLA(AddressingMode addr_mode) {
+ assert(false);
}
-void op_LDX(addr_mode_t addr_mode) {
-
-}
+void op_ROL(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte carry = cpu_get_flag(CPU_STATUS_CARRY_MASK);
-void op_TAX(addr_mode_t addr_mode) {
+ cpu_set_flag(value & 0x80, CPU_STATUS_CARRY_MASK);
+ value = (value << 1) | carry;
+ write_operand(operand, value);
+ set_acl_flags(value);
+ cpu_add_cycles(get_shift_cycle_count(addr_mode));
}
-void op_TSX(addr_mode_t addr_mode) {
+void op_ROR(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
+ byte carry = cpu_get_flag(CPU_STATUS_CARRY_MASK);
+ cpu_set_flag(value & 0x01, CPU_STATUS_CARRY_MASK);
+ value = (value >> 1) | (carry << 7);
+ write_operand(operand, value);
+
+ set_acl_flags(value);
+ cpu_add_cycles(get_shift_cycle_count(addr_mode));
}
-void op_DEC(addr_mode_t addr_mode) {
+void op_RRA(AddressingMode addr_mode) {
+ assert(false);
+}
+void op_RTI(AddressingMode addr_mode) {
+ cpu_stack_pop_context();
+ cpu_add_cycles(6);
}
-void op_DEX(addr_mode_t addr_mode) {
+void op_RTS(AddressingMode addr_mode) {
+ byte lo = cpu_stack_pop();
+ address pc = cpu_stack_pop() << 8;
+ pc += lo;
+ cpu_get_registers()->program_counter = pc - 1;
+ cpu_add_cycles(6);
}
-void op_INC(addr_mode_t addr_mode) {
-
+void op_SAX(AddressingMode addr_mode) {
+ assert(false);
}
-// Unofficial
-void op_STP(addr_mode_t addr_mode) {
+void op_SBC(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte value = read_operand(operand);
-}
+ add_with_carry(~value);
-void op_SHY(addr_mode_t addr_mode) {
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
+}
+void op_SEC(AddressingMode addr_mode) {
+ cpu_set_flag(1, CPU_STATUS_CARRY_MASK);
+ cpu_add_cycles(2);
}
-void op_SLO(addr_mode_t addr_mode) {
+void op_SED(AddressingMode addr_mode) {
+ cpu_set_flag(1, CPU_STATUS_DECIMAL_MASK);
+ cpu_add_cycles(2);
+}
+void op_SEI(AddressingMode addr_mode) {
+ cpu_set_flag(1, CPU_STATUS_INTERRUPT_DISABLE_MASK);
+ cpu_add_cycles(2);
}
-void op_RLA(addr_mode_t addr_mode) {
+void op_SHX(AddressingMode addr_mode) {
+ assert(false);
+}
+void op_SHY(AddressingMode addr_mode) {
+ assert(false);
}
-void op_SRE(addr_mode_t addr_mode) {
+void op_SLO(AddressingMode addr_mode) {
+ assert(false);
+}
+void op_SRE(AddressingMode addr_mode) {
+ assert(false);
}
-void op_RRA(addr_mode_t addr_mode) {
+void op_STA(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte acc = cpu_get_registers()->accumulator;
+ assert(operand.type == OPERAND_TYPE_ADDRESS);
-}
+ cpu_push_byte(acc, operand.value);
-void op_SAX(addr_mode_t addr_mode) {
+ operand.is_page_crossing = true;
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
+}
+void op_STP(AddressingMode addr_mode) {
+ assert(false);
}
-void op_LAX(addr_mode_t addr_mode) {
+void op_STX(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte x = cpu_get_registers()->x;
+ assert(operand.type == OPERAND_TYPE_ADDRESS);
+
+ cpu_push_byte(x, operand.value);
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
}
-void op_DCP(addr_mode_t addr_mode) {
+void op_STY(AddressingMode addr_mode) {
+ Operand operand = decode_operand(addr_mode);
+ byte y = cpu_get_registers()->y;
+ assert(operand.type == OPERAND_TYPE_ADDRESS);
-}
+ cpu_push_byte(y, operand.value);
-void op_ISC(addr_mode_t addr_mode) {
+ cpu_add_cycles(get_cycle_count(operand, addr_mode));
+}
+void op_TAS(AddressingMode addr_mode) {
+ assert(false);
}
-void op_ANC(addr_mode_t addr_mode) {
+void op_TAX(AddressingMode addr_mode) {
+ byte acc = cpu_get_registers()->accumulator;
+ cpu_get_registers()->x = acc;
+ set_acl_flags(acc);
+ cpu_add_cycles(2);
}
-void op_ALR(addr_mode_t addr_mode) {
+void op_TAY(AddressingMode addr_mode) {
+ byte acc = cpu_get_registers()->accumulator;
+ cpu_get_registers()->y = acc;
+ set_acl_flags(acc);
+ cpu_add_cycles(2);
}
-void op_ARR(addr_mode_t addr_mode) {
+void op_TSX(AddressingMode addr_mode) {
+ byte value = cpu_stack_pop();
+ cpu_get_registers()->x = value;
+ set_acl_flags(value);
+ cpu_add_cycles(2);
}
-void op_XAA(addr_mode_t addr_mode) {
+void op_TXA(AddressingMode addr_mode) {
+ byte x = cpu_get_registers()->x;
+ cpu_get_registers()->accumulator = x;
+ set_acl_flags(x);
+ cpu_add_cycles(2);
}
-void op_AXS(addr_mode_t addr_mode) {
+void op_TXS(AddressingMode addr_mode) {
+ byte x = cpu_get_registers()->x;
+ cpu_stack_push(x);
+ cpu_add_cycles(2);
}
-void op_AHX(addr_mode_t addr_mode) {
+void op_TYA(AddressingMode addr_mode) {
+ byte y = cpu_get_registers()->y;
+ cpu_get_registers()->accumulator = y;
+ set_acl_flags(y);
+ cpu_add_cycles(2);
}
-void op_TAS(addr_mode_t addr_mode) {
-
+void op_XAA(AddressingMode addr_mode) {
+ assert(false);
}
void process_op_code(int op) {
@@ -402,7 +853,7 @@ void process_op_code(int op) {
IS_OP_CODE_MODE(CPX, 0xe4, ZERO_PAGE)
IS_OP_CODE_MODE(CPX, 0xec, ABSOLUTE)
- IS_OP_CODE_MODE(BPL, 0x10, RELATIVE)
+ IS_OP_CODE_MODE(BPL, 0x10, RELATIVE)
IS_OP_CODE_MODE(BMI, 0x30, RELATIVE)
IS_OP_CODE_MODE(BVC, 0x50, RELATIVE)
IS_OP_CODE_MODE(BVS, 0x70, RELATIVE)
@@ -509,22 +960,22 @@ void process_op_code(int op) {
IS_OP_CODE_MODE(AXS, 0xcb, IMMEDIATE)
IS_OP_CODE_MODE(SBC, 0xeb, IMMEDIATE)
- IS_OP_CODE_MODE(SAX, 0x83, INDEXED_INDIRECT)
+ IS_OP_CODE_MODE(SAX, 0x83, INDIRECT_X)
IS_OP_CODE_MODE(SAX, 0x87, ZERO_PAGE)
IS_OP_CODE_MODE(XAA, 0x8b, IMMEDIATE)
IS_OP_CODE_MODE(SAX, 0x8f, ABSOLUTE)
- IS_OP_CODE_MODE(AHX, 0x93, INDIRECT_INDEXED)
+ IS_OP_CODE_MODE(AHX, 0x93, INDIRECT_Y)
IS_OP_CODE_MODE(SAX, 0x97, ZERO_PAGE_INDEXED_Y)
IS_OP_CODE_MODE(TAS, 0x9b, ABSOLUTE_INDEXED_Y)
IS_OP_CODE_MODE(AHX, 0x9f, ABSOLUTE_INDEXED_Y)
- IS_OP_CODE_MODE(LAX, 0xa3, INDEXED_INDIRECT)
+ IS_OP_CODE_MODE(LAX, 0xa3, INDIRECT_X)
IS_OP_CODE_MODE(LAX, 0xa7, ZERO_PAGE)
IS_OP_CODE_MODE(LAX, 0xab, IMMEDIATE)
IS_OP_CODE_MODE(LAX, 0xaf, ABSOLUTE)
- IS_OP_CODE_MODE(LAX, 0xb3, INDIRECT_INDEXED)
+ IS_OP_CODE_MODE(LAX, 0xb3, INDIRECT_Y)
IS_OP_CODE_MODE(LAX, 0xb7, ZERO_PAGE_INDEXED_Y)
IS_OP_CODE_MODE(LAX, 0xbb, ABSOLUTE_INDEXED_Y)
IS_OP_CODE_MODE(LAX, 0xbf, ABSOLUTE_INDEXED_Y)
}
-}
+}
\ No newline at end of file
diff --git a/include/cpu/op.h b/cpu/op.h
similarity index 90%
rename from include/cpu/op.h
rename to cpu/op.h
index 5a72747..9a8a8bc 100644
--- a/include/cpu/op.h
+++ b/cpu/op.h
@@ -22,13 +22,13 @@ typedef enum {
ADDR_MODE_ACCUMULATOR, // A
ADDR_MODE_IMMEDIATE, // #i
ADDR_MODE_IMPLICIT, // Imp
- ADDR_MODE_INDEXED_INDIRECT, // (d,x)
+ ADDR_MODE_INDIRECT_X, // (d,x)
ADDR_MODE_INDIRECT_JUMP, //
- ADDR_MODE_INDIRECT_INDEXED, // (d),y
+ ADDR_MODE_INDIRECT_Y, // (d),y
ADDR_MODE_RELATIVE, // label
ADDR_MODE_ZERO_PAGE, // d
ADDR_MODE_ZERO_PAGE_INDEXED_X, // d,x
ADDR_MODE_ZERO_PAGE_INDEXED_Y, // d,y
-} addr_mode_t;
+} AddressingMode;
#endif
diff --git a/cpu/ram.c b/cpu/ram.c
new file mode 100644
index 0000000..24b619d
--- /dev/null
+++ b/cpu/ram.c
@@ -0,0 +1,22 @@
+//
+// Created by william on 30/09/23.
+//
+
+#include "ram.h"
+#include "../include/cpu.h"
+
+byte ram[MEM_RAM_AMOUNT];
+
+void ram_set_byte(address addr, byte byte) {
+ ram[addr] = byte;
+}
+
+byte ram_get_byte(address addr) {
+ return ram[addr];
+}
+
+word ram_get_word(address addr) {
+ word word = ram_get_byte(addr);
+ word += ram_get_byte(addr + 1) << 8; // Little endian
+ return word;
+}
\ No newline at end of file
diff --git a/cpu/ram.h b/cpu/ram.h
new file mode 100644
index 0000000..2e9a31c
--- /dev/null
+++ b/cpu/ram.h
@@ -0,0 +1,20 @@
+//
+// Created by william on 30/09/23.
+//
+
+#ifndef NESEMULATOR_RAM_H
+#define NESEMULATOR_RAM_H
+
+// The 6502 CPU has 2 KiB of RAM
+#define MEM_RAM_AMOUNT 2048
+
+typedef unsigned short address;
+
+void init_ram();
+void clean_ram();
+
+void ram_set_byte(address addr, byte byte);
+byte ram_get_byte(address addr);
+word ram_get_word(address addr);
+
+#endif //NESEMULATOR_RAM_H
diff --git a/include/cpu.h b/include/cpu.h
new file mode 100644
index 0000000..92468cb
--- /dev/null
+++ b/include/cpu.h
@@ -0,0 +1,33 @@
+/*
+ * =====================================================================================
+ *
+ * Filename: cpu.h
+ *
+ * Description: 6502 CPU emulator headers
+ *
+ * Version: 1.0
+ * Created: 2023-09-21 10:12:33 PM
+ * Revision: none
+ * Compiler: gcc
+ *
+ * Author: William Nolin,
+ * Organization:
+ *
+ * =====================================================================================
+ */
+
+#ifndef NESEMULATOR_CPU_H
+#define NESEMULATOR_CPU_H
+
+typedef unsigned char byte;
+typedef unsigned short address;
+typedef unsigned short word;
+
+/**
+ * @brief Set clock
+ */
+void cpu_step_to(int cycle);
+
+void cpu_add_cycles(int count);
+
+#endif
diff --git a/include/cpu/cpu.h b/include/cpu/cpu.h
deleted file mode 100644
index abc161b..0000000
--- a/include/cpu/cpu.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * =====================================================================================
- *
- * Filename: cpu.h
- *
- * Description: 6502 CPU emulator headers
- *
- * Version: 1.0
- * Created: 2023-09-21 10:12:33 PM
- * Revision: none
- * Compiler: gcc
- *
- * Author: William Nolin,
- * Organization:
- *
- * =====================================================================================
- */
-
-#ifndef EMU_CPU_H
-#define EMU_CPU_H
-
-// Reference: https://www.nesdev.org/wiki/Status_flags
-#define CPU_STATUS_CARRY_MASK = 0x01;
-#define CPU_STATUS_ZERO_MASK = 0x02;
-#define CPU_STATUS_INTERRUPT_DISABLE_MASK = 0x04;
-#define CPU_STATUS_DECIMAL_MASK = 0x08;
-#define CPU_STATUS_B_MASK = 0x10;
-#define CPU_STATUS_I_MASK = 0x20;
-#define CPU_STATUS_OVERFLOW_MASK = 0x40;
-#define CPU_STATUS_NEGATIVE_MASK = 0x80;
-
-// Reference: https://www.nesdev.org/obelisk-6502-guide/registers.html
-typedef struct {
- unsigned short program_counter;
- unsigned char stack_pointer;
- unsigned char accumulator;
- unsigned char x;
- unsigned char y;
- unsigned char status;
-} cpu_registers_t;
-
-/**
- * @brief Set clock
- */
-void cpu_step_to(int cycle);
-
-void cpu_add_cycles(int count);
-
-cpu_registers_t* cpu_get_registers();
-
-#endif
diff --git a/include/cpu/mem.h b/include/cpu/mem.h
deleted file mode 100644
index b09141d..0000000
--- a/include/cpu/mem.h
+++ /dev/null
@@ -1,8 +0,0 @@
-//
-// Created by william on 30/09/23.
-//
-
-#ifndef NESEMULATOR_MEM_H
-#define NESEMULATOR_MEM_H
-
-#endif //NESEMULATOR_MEM_H
diff --git a/include/mapper.h b/include/mapper.h
new file mode 100644
index 0000000..67b48ff
--- /dev/null
+++ b/include/mapper.h
@@ -0,0 +1,20 @@
+//
+// Created by william on 10/15/23.
+//
+
+#ifndef NESEMULATOR_MAPPER_H
+#define NESEMULATOR_MAPPER_H
+
+#include "../include/cpu.h"
+
+typedef struct {
+ address (*redirect_addr)(unsigned short);
+} Mapper;
+
+enum MapperType {
+ MAPPER_TYPE_SIMPLE
+};
+
+Mapper get_mapper(enum MapperType type);
+
+#endif //NESEMULATOR_MAPPER_H
diff --git a/main.c b/main.c
index 0ad62ed..28c0284 100644
--- a/main.c
+++ b/main.c
@@ -18,12 +18,16 @@
#include
#include
-#include "config.h"
-#include "include/cpu/cpu.h"
+#include "include/cpu.h"
+#include "ram.h"
int main() {
- cpu_step_to(0);
+ init_ram();
+ ram_set_byte(0x10, 0xf);
+ ram_get_byte(0xffff);
+
+ clean_ram();
return -1;
}
diff --git a/mappers/CMakeLists.txt b/mappers/CMakeLists.txt
new file mode 100644
index 0000000..103800e
--- /dev/null
+++ b/mappers/CMakeLists.txt
@@ -0,0 +1,6 @@
+add_library(Mappers
+ simple_mapper.c
+ mappers.c)
+
+find_package(log.c)
+target_link_libraries(Mappers log.c::log.c)
\ No newline at end of file
diff --git a/mappers/mappers.c b/mappers/mappers.c
new file mode 100644
index 0000000..9b93955
--- /dev/null
+++ b/mappers/mappers.c
@@ -0,0 +1,19 @@
+//
+// Created by william on 10/15/23.
+//
+
+#include
+#include
+
+#include "../include/mapper.h"
+#include "simple_mapper.c"
+
+Mapper get_mapper(enum MapperType type) {
+ switch (type) {
+ case MAPPER_TYPE_SIMPLE:
+ return get_simple_mapper();
+ default:
+ log_error("Unsupported mapper %u", type);
+ exit(-1);
+ }
+}
\ No newline at end of file
diff --git a/mappers/simple_mapper.c b/mappers/simple_mapper.c
new file mode 100644
index 0000000..11538a5
--- /dev/null
+++ b/mappers/simple_mapper.c
@@ -0,0 +1,11 @@
+#include "../include/mapper.h"
+
+address redirect_addr(address addr) {
+ return addr;
+}
+
+Mapper get_simple_mapper() {
+ Mapper mapper;
+ mapper.redirect_addr = &redirect_addr;
+ return mapper;
+}
\ No newline at end of file