106 lines
2.8 KiB
Rust
106 lines
2.8 KiB
Rust
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,
|
|
cpu_cycles_since_poll: u32,
|
|
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,
|
|
cpu_cycles_since_poll: 0,
|
|
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 apu_channel_outputs(&self) -> crate::native_core::apu::ChannelOutputs {
|
|
self.apu.channel_outputs()
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
pub fn take_cpu_cycles_since_poll(&mut self) -> u32 {
|
|
let cycles = self.cpu_cycles_since_poll;
|
|
self.cpu_cycles_since_poll = 0;
|
|
cycles
|
|
}
|
|
}
|
|
|
|
// 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;
|