Skip to main content

nes_sim/
runtime.rs

1use crate::{
2    AudioBatch, CartridgeError, ControllerState, CoreCommand, DebugSnapshot, NES, SaveStateError,
3    VideoFrame,
4};
5
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
7pub struct FrontendInput {
8    pub controller1: ControllerState,
9    pub controller2: ControllerState,
10    pub reset: bool,
11    pub toggle_pause: bool,
12    pub step_frame: bool,
13    pub step_cpu_instruction: bool,
14    pub quit: bool,
15}
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum RunMode {
19    Running,
20    Paused,
21}
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub enum ExecutionTarget {
25    None,
26    Frame,
27    CpuInstruction,
28}
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub struct RuntimeStatus {
32    pub mode: RunMode,
33    pub executed: ExecutionTarget,
34    pub quit_requested: bool,
35}
36
37#[derive(Clone, Copy, Debug)]
38pub struct RuntimeSnapshot<'a> {
39    pub status: RuntimeStatus,
40    pub video: VideoFrame<'a>,
41    pub audio: AudioBatch<'a>,
42    pub debug: DebugSnapshot,
43}
44
45pub struct FrontendRuntime {
46    nes: NES,
47    mode: RunMode,
48}
49
50impl FrontendRuntime {
51    pub fn new(nes: NES) -> Self {
52        Self {
53            nes,
54            mode: RunMode::Running,
55        }
56    }
57
58    pub fn from_rom_bytes(rom: &[u8]) -> Result<Self, CartridgeError> {
59        let mut nes = NES::new();
60        nes.load_cartridge_ines(rom)?;
61        nes.reset();
62        Ok(Self::new(nes))
63    }
64
65    pub fn mode(&self) -> RunMode {
66        self.mode
67    }
68
69    pub fn nes(&self) -> &NES {
70        &self.nes
71    }
72
73    pub fn nes_mut(&mut self) -> &mut NES {
74        &mut self.nes
75    }
76
77    pub fn save_state(&self) -> Result<Vec<u8>, SaveStateError> {
78        self.nes.save_state()
79    }
80
81    pub fn load_state(&mut self, bytes: &[u8]) -> Result<(), SaveStateError> {
82        self.nes.load_state(bytes)
83    }
84
85    pub fn set_mode(&mut self, mode: RunMode) {
86        self.mode = mode;
87    }
88
89    pub fn snapshot(&self) -> RuntimeSnapshot<'_> {
90        RuntimeSnapshot {
91            status: RuntimeStatus {
92                mode: self.mode,
93                executed: ExecutionTarget::None,
94                quit_requested: false,
95            },
96            video: self.nes.video_frame(),
97            audio: self.nes.audio_batch(),
98            debug: self.nes.debug_snapshot(),
99        }
100    }
101
102    pub fn step(&mut self, input: FrontendInput) -> RuntimeSnapshot<'_> {
103        self.nes.clear_audio_samples();
104        self.nes.execute(CoreCommand::SetControllerState {
105            port: 0,
106            state: input.controller1,
107        });
108        self.nes.execute(CoreCommand::SetControllerState {
109            port: 1,
110            state: input.controller2,
111        });
112
113        if input.reset {
114            self.nes.execute(CoreCommand::Reset);
115        }
116
117        if input.toggle_pause {
118            self.mode = match self.mode {
119                RunMode::Running => RunMode::Paused,
120                RunMode::Paused => RunMode::Running,
121            };
122        }
123
124        let executed = if input.step_cpu_instruction {
125            self.nes.execute(CoreCommand::StepCpuInstruction);
126            ExecutionTarget::CpuInstruction
127        } else if input.step_frame || matches!(self.mode, RunMode::Running) {
128            self.nes.execute(CoreCommand::RunFrame);
129            ExecutionTarget::Frame
130        } else {
131            ExecutionTarget::None
132        };
133
134        RuntimeSnapshot {
135            status: RuntimeStatus {
136                mode: self.mode,
137                executed,
138                quit_requested: input.quit,
139            },
140            video: self.nes.video_frame(),
141            audio: self.nes.audio_batch(),
142            debug: self.nes.debug_snapshot(),
143        }
144    }
145}