CPU NMI implementation
This commit is contained in:
parent
4ac584f633
commit
7caf88171f
19
cpu/cpu.c
19
cpu/cpu.c
|
@ -34,6 +34,7 @@ void cpu_init(CPU *cpu) {
|
||||||
cpu->y = 0x00;
|
cpu->y = 0x00;
|
||||||
cpu->status = 0x04;
|
cpu->status = 0x04;
|
||||||
cpu->oam_dma_triggered = false;
|
cpu->oam_dma_triggered = false;
|
||||||
|
cpu->nmi_requested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_registers(CPU cpu, byte op, unsigned long cycle_count) {
|
void print_registers(CPU cpu, byte op, unsigned long cycle_count) {
|
||||||
|
@ -49,6 +50,16 @@ void print_registers(CPU cpu, byte op, unsigned long cycle_count) {
|
||||||
cycle_count);
|
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) {
|
void oam_dma_upload(System *system) {
|
||||||
byte page_high_addr = *system->ppu.oam_dma_register;
|
byte page_high_addr = *system->ppu.oam_dma_register;
|
||||||
address page_addr = ((address) page_high_addr) << 8;
|
address page_addr = ((address) page_high_addr) << 8;
|
||||||
|
@ -64,16 +75,20 @@ void oam_dma_upload(System *system) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_cycle(System *system) {
|
void cpu_cycle(System *system) {
|
||||||
|
if (system->cpu.nmi_requested) {
|
||||||
|
cpu_process_nmi(system);
|
||||||
|
}
|
||||||
|
|
||||||
if (system->cpu.oam_dma_triggered) {
|
if (system->cpu.oam_dma_triggered) {
|
||||||
oam_dma_upload(system);
|
oam_dma_upload(system);
|
||||||
system->cpu.oam_dma_triggered = false;
|
system->cpu.oam_dma_triggered = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPU registers = system->cpu;
|
CPU cpu = system->cpu;
|
||||||
byte op = cpu_get_next_byte(system);
|
byte op = cpu_get_next_byte(system);
|
||||||
|
|
||||||
print_registers(registers, op, system->cycle_count);
|
print_registers(cpu, op, system->cycle_count);
|
||||||
|
|
||||||
process_op_code(system, op);
|
process_op_code(system, op);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ typedef struct cpu {
|
||||||
byte y;
|
byte y;
|
||||||
byte status;
|
byte status;
|
||||||
bool oam_dma_triggered;
|
bool oam_dma_triggered;
|
||||||
|
bool nmi_requested;
|
||||||
} CPU;
|
} CPU;
|
||||||
|
|
||||||
typedef struct system {
|
typedef struct system {
|
||||||
|
|
9
main.c
9
main.c
|
@ -36,14 +36,9 @@ int main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
system_start(&system);
|
system_start(&system);
|
||||||
start_debugger(&system);
|
// start_debugger(&system);
|
||||||
// system_loop(&system);
|
system_loop(&system);
|
||||||
|
|
||||||
system_uninit(&system);
|
system_uninit(&system);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
// system_uninit(&system);
|
|
||||||
|
|
||||||
|
|
||||||
// return win();
|
|
||||||
}
|
}
|
12
ppu/ppu.c
12
ppu/ppu.c
|
@ -1,5 +1,17 @@
|
||||||
//
|
//
|
||||||
// Created by william on 12/30/23.
|
// Created by william on 12/30/23.
|
||||||
|
// https://www.reddit.com/r/EmuDev/comments/evu3u2/comment/fgr03ms/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button
|
||||||
|
//
|
||||||
|
// 1. Make sure you have NMI implemented on CPU (pretty straightforward)
|
||||||
|
// 2. Implement PPUSTATUS vblank flag (simple) and PPUCTRL NMI flag + background address flag (simple)
|
||||||
|
// 3. Implement PPUADDR/PPUDATA so that the nametables are filled out
|
||||||
|
// 4. Now you have some data your PPU can actually read for rendering background. Render it scanline by scanline - just follow the wiki on this. Maybe the timing will be bad, it doesn't matter for this game. Start off with rendering tiles based on the pattern table ID, don't try and fetch patterns.
|
||||||
|
// 5. Fix the inevitable bugs with your PPUDATA implementation until you see a blocky version of the Donkey Kong screen.
|
||||||
|
// 6. Now fetch pattern table data using the nametable data. If it looks "wrong" make sure you are consuming the background address flag. Start off with black and white, then pick two colors to mix for the two bits. Now you should have something like https://i.imgur.com/7OIpHgd.png
|
||||||
|
// 7. (Optional) implement palette reads (I'm skipping this for now).
|
||||||
|
// 8. Implement OAMDMA (and OAMDATA I guess, I implemented one on top of the other)
|
||||||
|
// 9. Now you should have sprite data to render. Implement the logic for copying from primary OAM to scanline OAM. I'm doing it all as one step (not smearing it over up to 256 cycles like the actual hardware). Skip the confusing sprite overflow junk.
|
||||||
|
// 10. This is where I'm stuck. I think I need to read the "sprites" section of https://wiki.nesdev.com/w/index.php/PPU_rendering very carefully.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
2
system.c
2
system.c
|
@ -35,7 +35,7 @@ void system_loop(System *system) {
|
||||||
long frame = 1;
|
long frame = 1;
|
||||||
long cpu_cycle_count = 0;
|
long cpu_cycle_count = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
log_info("Frame %d", frame);
|
// log_info("Frame %d", frame);
|
||||||
|
|
||||||
while (system->cycle_count < cpu_cycle_per_frame * frame) {
|
while (system->cycle_count < cpu_cycle_per_frame * frame) {
|
||||||
if (cpu_cycle_count == system->cycle_count) {
|
if (cpu_cycle_count == system->cycle_count) {
|
||||||
|
|
Loading…
Reference in New Issue