//#include "log.h" #include #include #include "../include/cpu.h" #include "cpu.h" #include "memory.h" #include "op.h" #include "decoding.h" #include "log.h" /* * ===================================================================================== * * Filename: cpu_state.c * * Description: 6502 CPU emulator * * Version: 1.0 * Created: 2023-09-21 10:10:26 PM * Revision: none * Compiler: gcc * * Author: William Nolin, * Organization: * * ===================================================================================== */ CPU cpu_state; void cpu_init() { cpu_state.program_counter = 0x8000; cpu_state.stack_pointer = 0xfd; cpu_state.accumulator = 0x00; cpu_state.x = 0x00; cpu_state.y = 0x00; cpu_state.status = 0x04; cpu_state.oam_dma_triggered = false; cpu_state.nmi_requested = false; cpu_state.busy_cycle_count = 0; } void print_registers(byte op, unsigned long cycle_count) { log_trace("%#02x %#02x %s \t A:%#02x X:%#02x Y:%#02x F:%#02x SP:%#02x \t [%d]", cpu_state.program_counter - 1, // The PC as been incremented when printing op, get_op_code_name(op), cpu_state.accumulator, cpu_state.x, cpu_state.y, cpu_state.status, cpu_state.stack_pointer, cycle_count); } void cpu_process_nmi() { cpu_stack_push_context(); address handler_addr = mem_get_word(0xfffa); log_debug("NMI %#04x", handler_addr); cpu_state.nmi_requested = false; cpu_state.program_counter = handler_addr; } void oam_dma_upload() { byte page_high_addr = ppu_get_state()->oam_dma_register; // TODO address page_addr = ((address) page_high_addr) << 8; byte n = 0xff; byte *ram_source = mem_get_ptr(page_addr); byte *oam_destination = ppu_get_state()->oam; memcpy(oam_destination, ram_source, n); log_debug("OAM DMA %#04x", page_addr); cpu_add_cycles(513); // TODO } void cpu_cycle() { if (cpu_state.busy_cycle_count > 0) { // The last operation is not done yet cpu_state.busy_cycle_count--; return; } if (cpu_state.nmi_requested) { cpu_process_nmi(); } if (cpu_state.oam_dma_triggered) { oam_dma_upload(); cpu_state.oam_dma_triggered = false; return; } byte op = cpu_get_next_byte(); print_registers(op, system_get_cycles()); process_op_code(op); } void cpu_add_cycles(unsigned int cycle_count) { cpu_state.busy_cycle_count += cycle_count; } // === Registers === bool cpu_get_flag(byte mask) { return cpu_state.status & mask; } void cpu_set_flag(byte mask, bool set) { if (set) { cpu_state.status |= mask; } else { cpu_state.status &= ~mask; } } byte cpu_get_next_byte() { byte next_byte = mem_get_byte(cpu_state.program_counter); cpu_state.program_counter++; return next_byte; } word cpu_get_next_word() { word next_word = mem_get_word(cpu_state.program_counter); cpu_state.program_counter += 2; return next_word; } void cpu_stack_push(byte value) { assert(cpu_state.stack_pointer > 0); address mem_addr = CPU_STACK_ADDR | cpu_state.stack_pointer; mem_set_byte(mem_addr, value); cpu_state.stack_pointer--; } byte cpu_stack_pop() { assert(cpu_state.stack_pointer < 0xff); cpu_state.stack_pointer++; address mem_addr = CPU_STACK_ADDR | cpu_state.stack_pointer; byte value = mem_get_byte(mem_addr); return value; } void cpu_stack_push_context() { cpu_stack_push(cpu_state.program_counter >> 8); cpu_stack_push(cpu_state.program_counter & 0xff); cpu_stack_push(cpu_state.status); } void cpu_stack_pop_context() { byte value = cpu_stack_pop(); value &= 0xef; // The B mask cannot be set as it is a CPU signal value |= 0x20; // This value is always set cpu_state.status = value; byte lo = cpu_stack_pop(); address pc = cpu_stack_pop() << 8; pc += lo; cpu_state.program_counter = pc; } void cpu_trigger_oam_dma() { cpu_state.oam_dma_triggered = true; } void cpu_trigger_nmi() { cpu_state.nmi_requested = true; } CPU *cpu_get_state() { return &cpu_state; }