1pub mod api;
2mod apu;
3mod bus;
4pub mod cartridge;
5mod cpu;
6mod dma;
7pub mod headless;
8mod input;
9mod ppu;
10mod ppu_memory;
11pub mod runtime;
12pub mod savestate;
13pub mod video;
14
15pub use api::{
16 AudioBatch, CoreCommand, CoreEvent, CoreResponse, CpuDebugSnapshot, DebugSnapshot, PixelFormat,
17 PpuDebugSnapshot, VIDEO_FRAME_PITCH, VideoFrame,
18};
19pub use apu::ExpansionAudioChip;
20pub use cartridge::{Cartridge, CartridgeError, Mirroring, TVSystem};
21pub use input::{ControllerButton, ControllerState};
22pub use ppu::{FRAME_HEIGHT, FRAME_WIDTH};
23pub use runtime::{
24 ExecutionTarget, FrontendInput, FrontendRuntime, RunMode, RuntimeSnapshot, RuntimeStatus,
25};
26pub use savestate::SaveStateError;
27use savestate::{StateReader, StateWriter};
28
29const NTSC_CPU_SCHEDULE: [u8; 1] = [3];
30const PAL_CPU_SCHEDULE: [u8; 5] = [3, 3, 3, 3, 4];
31const DENDY_CPU_SCHEDULE: [u8; 1] = [3];
32
33fn cpu_schedule(tv: TVSystem) -> &'static [u8] {
34 match tv {
35 TVSystem::NTSC => &NTSC_CPU_SCHEDULE,
36 TVSystem::PAL => &PAL_CPU_SCHEDULE,
37 TVSystem::DENDY => &DENDY_CPU_SCHEDULE,
38 }
39}
40
41pub struct NES {
42 cpu: cpu::CPU,
43 bus: bus::NESBus,
44 master_clock: u64,
45 cpu_ppu_counter: u8,
46 cpu_schedule_index: usize,
47 cached_tv_system: TVSystem,
48}
49
50impl NES {
51 pub fn new() -> Self {
52 Self {
53 cpu: cpu::CPU::new(),
54 bus: bus::NESBus::new(),
55 master_clock: 0,
56 cpu_ppu_counter: 0,
57 cpu_schedule_index: 0,
58 cached_tv_system: TVSystem::NTSC,
59 }
60 }
61
62 pub fn reset(&mut self) {
63 self.bus.reset();
64 self.reset_cpu_schedule();
65 self.cpu.reset(&mut self.bus);
66 self.cpu.set_nmi(self.bus.ppu_nmi_line());
67 }
68
69 pub fn insert_cartridge(&mut self, cartridge: Cartridge) {
70 self.bus.insert_cartridge(cartridge);
71 self.reset_cpu_schedule();
72 self.reset();
73 }
74
75 pub fn load_cartridge_ines(&mut self, rom: &[u8]) -> Result<(), CartridgeError> {
76 self.bus.load_cartridge_ines(rom)?;
77 self.reset_cpu_schedule();
78 Ok(())
79 }
80
81 pub fn set_controller_state(&mut self, port: usize, state: ControllerState) {
82 self.bus.set_controller_state(port, state);
83 }
84
85 pub fn clock(&mut self) {
86 self.master_clock += 1;
87 self.bus.tick_ppu();
88
89 let schedule = cpu_schedule(self.cached_tv_system);
90 self.cpu_ppu_counter += 1;
91 if self.cpu_ppu_counter >= schedule[self.cpu_schedule_index] {
92 self.cpu_ppu_counter = 0;
93 self.cpu_schedule_index = (self.cpu_schedule_index + 1) % schedule.len();
94 self.cpu.set_nmi(self.bus.ppu_nmi_line());
96 self.bus.advance_dma_cpu_phase();
97 self.bus.tick_apu_cpu_cycle();
98 self.cpu.clock(&mut self.bus);
99 self.cpu.irq_set_level(0x01, self.bus.apu_irq_line());
100 self.cpu.irq_set_level(0x02, self.bus.cartridge_irq_line());
101 self.cpu.set_nmi(self.bus.ppu_nmi_line());
102 }
103 }
104
105 pub fn run_frame(&mut self) {
106 let start_frame = self.frame_number();
107 while self.frame_number() == start_frame {
108 self.clock();
109 }
110 }
111
112 pub fn step_cpu_instruction(&mut self) {
113 let start_instruction = self.cpu.instruction_counter();
114 while self.cpu.instruction_counter() == start_instruction {
115 self.clock();
116 }
117 }
118
119 pub fn execute(&mut self, command: CoreCommand) -> CoreResponse {
120 let event = match command {
121 CoreCommand::Reset => {
122 self.reset();
123 CoreEvent::ResetComplete
124 }
125 CoreCommand::SetControllerState { port, state } => {
126 self.set_controller_state(port, state);
127 CoreEvent::ControllerStateUpdated { port }
128 }
129 CoreCommand::RunFrame => {
130 self.run_frame();
131 CoreEvent::FrameReady {
132 frame_number: self.frame_number(),
133 }
134 }
135 CoreCommand::StepCpuInstruction => {
136 self.step_cpu_instruction();
137 CoreEvent::CpuInstructionComplete {
138 instruction_counter: self.cpu.instruction_counter(),
139 }
140 }
141 };
142
143 CoreResponse {
144 event,
145 master_clock: self.master_clock,
146 }
147 }
148
149 pub fn master_clock(&self) -> u64 {
150 self.master_clock
151 }
152
153 pub fn frame_number(&self) -> u64 {
154 self.bus.ppu_frame()
155 }
156
157 pub fn frame_pixels(&self) -> &[u8] {
158 self.bus.ppu().frame_pixels()
159 }
160
161 pub fn video_frame(&self) -> VideoFrame<'_> {
162 VideoFrame {
163 width: FRAME_WIDTH,
164 height: FRAME_HEIGHT,
165 pitch: VIDEO_FRAME_PITCH,
166 format: PixelFormat::Indexed8,
167 frame_number: self.frame_number(),
168 pixels: self.frame_pixels(),
169 }
170 }
171
172 pub fn audio_batch(&self) -> AudioBatch<'_> {
173 AudioBatch {
174 channels: 1,
175 sample_rate: self.bus.apu_sample_rate(),
176 samples: self.bus.apu_audio_samples(),
177 }
178 }
179
180 pub fn add_expansion_audio_chip(&mut self, chip: Box<dyn ExpansionAudioChip>) {
181 self.bus.add_expansion_audio_chip(chip);
182 }
183
184 pub fn debug_snapshot(&self) -> DebugSnapshot {
185 let ppu = self.bus.ppu();
186 DebugSnapshot {
187 master_clock: self.master_clock,
188 cpu: self.cpu.debug_snapshot(),
189 ppu: PpuDebugSnapshot {
190 frame: ppu.frame(),
191 scanline: ppu.scanline(),
192 in_vblank: ppu.in_vblank(),
193 nmi_line: ppu.nmi_line(),
194 oam_addr: ppu.oam_addr(),
195 },
196 }
197 }
198
199 pub fn save_state(&self) -> Result<Vec<u8>, SaveStateError> {
200 let mut writer = StateWriter::new();
201 writer.write_u64(self.master_clock);
202 writer.write_u8(self.cpu_ppu_counter);
203 writer.write_u64(self.cpu_schedule_index as u64);
204 self.cpu.save_state(&mut writer);
205 self.bus.save_state(&mut writer)?;
206 Ok(writer.finish())
207 }
208
209 pub fn load_state(&mut self, bytes: &[u8]) -> Result<(), SaveStateError> {
210 let mut reader = StateReader::new(bytes)?;
211 self.master_clock = reader.read_u64()?;
212 self.cpu_ppu_counter = reader.read_u8()?;
213 self.cpu_schedule_index = reader.read_u64()? as usize;
214 self.cpu.load_state(&mut reader)?;
215 self.bus.load_state(&mut reader)?;
216 self.cached_tv_system = self.bus.ppu().tv_system();
217 self.cpu.set_nmi(self.bus.ppu_nmi_line());
218 reader.finish()
219 }
220
221 pub fn clear_audio_samples(&mut self) {
222 self.bus.clear_apu_audio_samples();
223 }
224
225 pub fn set_apu_sample_rate(&mut self, sample_rate: u32) {
226 self.bus.set_apu_sample_rate(sample_rate);
227 }
228
229 pub fn set_apu_debug_mute_mask(&mut self, mask: u8) {
230 self.bus.set_apu_debug_mute_mask(mask);
231 }
232
233 pub fn apu_debug_mute_mask(&self) -> u8 {
234 self.bus.apu_debug_mute_mask()
235 }
236
237 fn reset_cpu_schedule(&mut self) {
238 self.cached_tv_system = self.bus.ppu().tv_system();
239 self.cpu_ppu_counter = 0;
240 self.cpu_schedule_index = 0;
241 }
242}
243
244impl Default for NES {
245 fn default() -> Self {
246 Self::new()
247 }
248}
249
250#[cfg(test)]
251mod tests;