Initial commit: NES emulator with GTK4 desktop frontend
Some checks failed
CI / rust (push) Has been cancelled
Some checks failed
CI / rust (push) Has been cancelled
Full NES emulation: CPU, PPU, APU, 47 mappers, iNES/NES 2.0 parsing. GTK4 desktop client with HeaderBar, pixel-perfect Cairo rendering, drag-and-drop ROM loading, and keyboard shortcuts. 187 tests covering core emulation, mappers, and runtime.
This commit is contained in:
93
src/native_core/bus.rs
Normal file
93
src/native_core/bus.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use crate::native_core::{apu::Apu, cpu::CpuBus, mapper::Mapper, ppu::Ppu};
|
||||
|
||||
const CPU_RAM_SIZE: usize = 0x0800;
|
||||
const PPU_DOTS_PER_SCANLINE: u32 = 341;
|
||||
const PPU_SCANLINES_PER_FRAME: u32 = 262;
|
||||
const PPU_DOTS_PER_FRAME: u32 = PPU_DOTS_PER_SCANLINE * PPU_SCANLINES_PER_FRAME;
|
||||
const PPU_VBLANK_START_SCANLINE: u32 = 241;
|
||||
const PPU_PRERENDER_SCANLINE: u32 = 261;
|
||||
|
||||
pub struct NativeBus {
|
||||
cpu_ram: [u8; CPU_RAM_SIZE],
|
||||
ppu: Ppu,
|
||||
apu: Apu,
|
||||
cpu_open_bus: u8,
|
||||
joypad_state: u8,
|
||||
joypad_shift: u8,
|
||||
joypad2_state: u8,
|
||||
joypad2_shift: u8,
|
||||
joypad_strobe: bool,
|
||||
nmi_pending: bool,
|
||||
suppress_vblank_this_frame: bool,
|
||||
ppu_dot: u32,
|
||||
odd_frame: bool,
|
||||
in_vblank: bool,
|
||||
frame_complete: bool,
|
||||
mmc3_a12_prev_high: bool,
|
||||
mmc3_a12_low_dots: u16,
|
||||
mmc3_last_irq_scanline: u32,
|
||||
mapper: Box<dyn Mapper + Send>,
|
||||
}
|
||||
|
||||
impl NativeBus {
|
||||
pub fn new(mapper: Box<dyn Mapper + Send>) -> Self {
|
||||
Self {
|
||||
cpu_ram: [0; CPU_RAM_SIZE],
|
||||
ppu: Ppu::new(),
|
||||
apu: Apu::new(),
|
||||
cpu_open_bus: 0,
|
||||
joypad_state: 0,
|
||||
joypad_shift: 0,
|
||||
joypad2_state: 0,
|
||||
joypad2_shift: 0,
|
||||
joypad_strobe: false,
|
||||
nmi_pending: false,
|
||||
suppress_vblank_this_frame: false,
|
||||
ppu_dot: 0,
|
||||
odd_frame: false,
|
||||
in_vblank: false,
|
||||
frame_complete: false,
|
||||
mmc3_a12_prev_high: false,
|
||||
mmc3_a12_low_dots: 8,
|
||||
mmc3_last_irq_scanline: u32::MAX,
|
||||
mapper,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apu_registers(&self) -> &[u8; 0x20] {
|
||||
self.apu.registers()
|
||||
}
|
||||
|
||||
pub fn render_frame(&self, out_rgba: &mut [u8], frame_number: u32, buttons: [bool; 8]) {
|
||||
let _ = (frame_number, buttons);
|
||||
let src = self.ppu.frame_buffer();
|
||||
if out_rgba.len() >= src.len() {
|
||||
out_rgba[..src.len()].copy_from_slice(src);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn begin_frame(&mut self) {
|
||||
self.frame_complete = false;
|
||||
self.ppu.begin_frame();
|
||||
}
|
||||
|
||||
pub fn take_frame_complete(&mut self) -> bool {
|
||||
let out = self.frame_complete;
|
||||
self.frame_complete = false;
|
||||
out
|
||||
}
|
||||
|
||||
pub fn clock_cpu(&mut self, cycles: u8) {
|
||||
self.clock_cpu_cycles(cycles as u32);
|
||||
}
|
||||
}
|
||||
|
||||
// CpuBus trait implementation (memory map + side effects).
|
||||
mod cpu_bus_impl;
|
||||
mod joypad;
|
||||
// Save-state serialization helpers.
|
||||
mod state;
|
||||
mod timing;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user