//#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.c * * Description: 6502 CPU emulator * * Version: 1.0 * Created: 2023-09-21 10:10:26 PM * Revision: none * Compiler: gcc * * Author: William Nolin, * Organization: * * ===================================================================================== */ void cpu_init(CPU *cpu) { cpu->program_counter = 0x8000; cpu->stack_pointer = 0xfd; cpu->accumulator = 0x00; cpu->x = 0x00; cpu->y = 0x00; cpu->status = 0x04; cpu->oam_dma_triggered = false; cpu->nmi_requested = false; } void print_registers(CPU cpu, byte op, unsigned long cycle_count) { log_debug("%#02x %#02x %s \t A:%#02x X:%#02x Y:%#02x F:%#02x SP:%#02x \t [%d]", cpu.program_counter, op, get_op_code_name(op), cpu.accumulator, cpu.x, cpu.y, cpu.status, cpu.stack_pointer, cycle_count); } void cpu_process_nmi(System *system) { cpu_stack_push_context(system); address handler_addr = mem_get_word(system, 0xfffa); log_debug("NMI %#04x", handler_addr); system->cpu.nmi_requested = false; system->cpu.program_counter = handler_addr; } void oam_dma_upload(System *system) { byte page_high_addr = *system->ppu.oam_dma_register; address page_addr = ((address) page_high_addr) << 8; byte n = 0xff; byte *ram_source = &system->ram[page_addr]; byte *oam_destination = system->ppu.oam; memcpy(oam_destination, ram_source, n); log_debug("OAM DMA %#04x", page_addr); cpu_add_cycles(system, 513); // TODO } void cpu_cycle(System *system) { if (system->cpu.nmi_requested) { cpu_process_nmi(system); } if (system->cpu.oam_dma_triggered) { oam_dma_upload(system); system->cpu.oam_dma_triggered = false; return; } CPU cpu = system->cpu; byte op = cpu_get_next_byte(system); print_registers(cpu, op, system->cycle_count); process_op_code(system, op); } void cpu_add_cycles(System *system, unsigned int cycle_count) { system->cycle_count += cycle_count; } // === Registers === bool system_get_flag(System *system, byte mask) { return cpu_get_flag(&system->cpu, mask); } void system_set_flag(System *system, byte mask, bool set) { if (set) { system->cpu.status |= mask; } else { system->cpu.status &= ~mask; } } byte cpu_get_next_byte(System *system) { byte next_byte = mem_get_byte(system, system->cpu.program_counter); system->cpu.program_counter++; return next_byte; } word cpu_get_next_word(System *system) { word next_word = mem_get_word(system, system->cpu.program_counter); system->cpu.program_counter += 2; return next_word; } void cpu_stack_push(System *system, byte value) { assert(system->cpu.stack_pointer > 0); address mem_addr = CPU_STACK_ADDR | system->cpu.stack_pointer; mem_set_byte(system, mem_addr, value); system->cpu.stack_pointer--; } byte cpu_stack_pop(System *system) { assert(system->cpu.stack_pointer < 0xff); system->cpu.stack_pointer++; address mem_addr = CPU_STACK_ADDR | system->cpu.stack_pointer; byte value = mem_get_byte(system, mem_addr); return value; } void cpu_stack_push_context(System *system) { cpu_stack_push(system, system->cpu.program_counter >> 8); cpu_stack_push(system, system->cpu.program_counter & 0xff); cpu_stack_push(system, system->cpu.status); } void cpu_stack_pop_context(System *system) { byte value = cpu_stack_pop(system); value &= 0xef; // The B mask cannot be set as it is a CPU signal value |= 0x20; // This value is always set system->cpu.status = value; byte lo = cpu_stack_pop(system); address pc = cpu_stack_pop(system) << 8; pc += lo; system->cpu.program_counter = pc; }