nescore/
nes.rs

1//
2// nes.rs
3//
4// @author Natesh Narain <nnaraindev@gmail.com>
5// @date Sep 17 2020
6//
7use crate::cart::Cartridge;
8use crate::cpu::{Cpu, bus::CpuIoBus};
9use crate::ppu::{Ppu, bus::PpuIoBus};
10use crate::apu::{Apu, bus::ApuIoBus};
11use crate::joy::Joy;
12use crate::mapper::Mapper;
13use crate::common::Clockable;
14
15use crate::ppu::Pixel;
16use crate::apu::Sample;
17use crate::joy::{Controller, Button};
18
19// use crate::utils::sampler::DownSampler;
20
21use crate::ppu::{DISPLAY_WIDTH, DISPLAY_HEIGHT};
22
23/// Size of the display frame buffer: display size * RGB (3 bytes)
24const FRAME_BUFFER_SIZE: usize = DISPLAY_WIDTH * DISPLAY_HEIGHT * 3;
25
26/// Buffer for video data
27pub type FrameBuffer = [u8; FRAME_BUFFER_SIZE];
28/// Buffer for audio data
29pub type SampleBuffer = Vec<crate::apu::Sample>;
30
31
32use std::rc::Rc;
33use std::cell::RefCell;
34
35#[cfg(feature="events")]
36use std::sync::mpsc::{channel, Receiver};
37
38/// Sequencer event
39enum Event {
40    CPU, PPU, APU, None,
41}
42
43type SequencerEvents = [Event; 3];
44
45/// Component frame sequencer
46#[derive(Default)]
47struct FrameSequencer {
48    counter: u32,
49}
50
51impl Clockable<SequencerEvents> for FrameSequencer {
52    fn tick(&mut self) -> SequencerEvents {
53        let events = match self.counter {
54            0 => [Event::PPU, Event::CPU, Event::APU],
55            1 => [Event::PPU, Event::None, Event::None],
56            2 => [Event::PPU, Event::None, Event::None],
57            3 => [Event::PPU, Event::CPU, Event::None],
58            4 => [Event::PPU, Event::None, Event::None],
59            5 => [Event::PPU, Event::None, Event::None],
60            _ => panic!("Invalid clock for sequencer"),
61        };
62
63        self.counter = (self.counter + 1) % 6;
64
65        events
66    }
67}
68
69/// Representation of the NES system
70#[derive(Default)]
71pub struct Nes {
72    cpu: Rc<RefCell<Cpu<CpuIoBus>>>, // NES Central Processing Unit
73    ppu: Rc<RefCell<Ppu<PpuIoBus>>>, // NES Picture Processing Unit
74    apu: Rc<RefCell<Apu>>,           // NES Audio Processing Unit
75    joy: Rc<RefCell<Joy>>,           // NES Joystick
76    mapper: Option<Mapper>,          // Cartridge Mapper
77
78    sequencer: FrameSequencer,
79}
80
81impl Nes {
82    /// Instantiate a NES emulator instance
83    /// ```
84    /// # use nescore::Nes;
85    /// let nes = Nes::new();
86    /// ```
87    pub fn new() -> Self {
88        Nes::default()
89    }
90
91    /// Directly set the CPU entry point
92    /// ```
93    /// # use nescore::Nes;
94    /// let nes = Nes::default().entry(0xC000);
95    /// ```
96    pub fn entry(self, entry_addr: u16) -> Self {
97        self.cpu.borrow_mut().set_pc(entry_addr);
98        self
99    }
100
101    /// Builder function to allow inserting the cartridge
102    pub fn with_cart(mut self, cart: Cartridge) -> Self {
103        self.insert(cart);
104        self
105    }
106
107    /// Builder function to set debug mode
108    /// ```
109    /// # use nescore::Nes;
110    /// let nes = Nes::default().debug_mode(true);
111    /// ```
112    pub fn debug_mode(self, debug: bool) -> Self {
113        self.cpu.borrow_mut().set_debug(debug);
114        self
115    }
116
117    /// Run the emulator for a single frame
118    /// ```no_run
119    /// # use nescore::{Nes, Cartridge};
120    /// # let cart = Cartridge::from_path("/path/to/rom").unwrap();
121    /// let mut nes = Nes::from(cart);
122    /// let (videobuffer, audiobuffer) = nes.emulate_frame();
123    /// ```
124    ///
125    /// * `videobuffer` - A RGB8 frame buffer
126    /// * `audiobuffer` - Raw APU output (This must be down sampled to host playback rate)
127    pub fn emulate_frame(&mut self) -> (FrameBuffer, SampleBuffer) {
128        let mut framebuffer = [0x00u8; FRAME_BUFFER_SIZE];
129        let mut framebuffer_idx = 0usize;
130
131        let mut samplebuffer: Vec<Sample> = Vec::new();
132
133        if self.mapper.is_some() {
134            for _ in 0..crate::ppu::CYCLES_PER_FRAME {
135                // Clock the CPU, PPU and APU
136                let (pixel, sample) = self.clock_components();
137
138                if let Some((r, g, b)) = pixel {
139                    // Insert RGB data into the frame buffer
140                    framebuffer[framebuffer_idx] = r;
141                    framebuffer[framebuffer_idx + 1] = g;
142                    framebuffer[framebuffer_idx + 2] = b;
143                    framebuffer_idx = (framebuffer_idx + 3) % FRAME_BUFFER_SIZE;
144                }
145
146                if let Some(sample) = sample {
147                    samplebuffer.push(sample);
148                }
149            }
150        }
151
152        (framebuffer, samplebuffer)
153    }
154
155    /// Run the NES emulator until it fills an audio buffer to the specified size
156    /// ```no_run
157    /// # use nescore::Nes;
158    /// # let mut nes = Nes::default();
159    /// let samplebuffer = nes.run_audio(4096);
160    /// ```
161    pub fn run_audio(&mut self, buffer_size: usize) -> Vec<f32> {
162        let mut buffer = vec![0f32; 0];
163
164        while buffer.len() < buffer_size {
165            let sample = self.clock_components().1;
166            if let Some(sample) = sample {
167                buffer.push(sample);
168            }
169        }
170
171        buffer
172    }
173
174    /// Apply a button input into the emulator
175    /// ```
176    /// # use nescore::{Nes, Button};
177    /// # let mut nes = Nes::default();
178    /// nes.input(Button::A, true);
179    /// ```
180    pub fn input(&mut self, btn: Button, pressed: bool) {
181        self.joy.borrow_mut().input(btn, pressed);
182    }
183
184    /// Apply a button input to the emulator from the specified controller
185    /// ```
186    /// # use nescore::{Nes, Button, Controller};
187    /// # let mut nes = Nes::default();
188    /// // Send an `A` button press to input 1
189    /// nes.controller_input(Controller::Input1, Button::A, true);
190    /// // Send an `A` button press to input 2
191    /// nes.controller_input(Controller::Input2, Button::A, true);
192    /// ```
193    pub fn controller_input(&mut self, controller: Controller, btn: Button, pressed: bool) {
194        self.joy.borrow_mut().controller_input(controller, btn, pressed);
195    }
196
197    /// Run until the CPU's PC is at address **addr**
198    pub fn run_until(&mut self, addr: u16) {
199        // TODO: Time limit
200        if self.mapper.is_some() {
201            while self.cpu.borrow().get_pc() != addr {
202                self.clock_components();
203            }
204        }
205    }
206
207    /// Clock the NES components
208    fn clock_components(&mut self) -> (Option<Pixel>, Option<Sample>) {
209        let mut pixel: Option<Pixel> = None;
210        let mut sample: Option<Sample> = None;
211
212        for event in self.sequencer.tick().iter() {
213            match event {
214                Event::PPU => {
215                    pixel = self.ppu.borrow_mut().tick();
216                },
217                Event::CPU => {
218                    self.cpu.borrow_mut().tick();
219                },
220                Event::APU => {
221                    sample = Some(self.apu.borrow_mut().tick());
222                },
223                Event::None => {},
224            }
225        }
226
227        (pixel, sample)
228    }
229
230    /// Check if the CPU is in an infinite loop state
231    pub fn is_holding(&self) -> bool {
232        self.cpu.borrow().is_holding()
233    }
234
235    /// Load a cartridge
236    pub fn insert(&mut self, cart: Cartridge) {
237        // Consume provided cartridge and get the mapper
238        let mapper = crate::mapper::from_cartridge(cart);
239
240        // Complete initialization of components
241        let cpu_bus = CpuIoBus::new(self.ppu.clone(), self.apu.clone(), self.joy.clone(), mapper.clone());
242        self.cpu.borrow_mut().load_bus(cpu_bus);
243
244        let ppu_bus = PpuIoBus::new(self.cpu.clone(), mapper.clone());
245        self.ppu.borrow_mut().load_bus(ppu_bus);
246
247        let apu_bus = Rc::new(RefCell::new(ApuIoBus::new(self.cpu.clone(), mapper.clone())));
248        self.apu.borrow_mut().load_bus(apu_bus);
249
250        self.mapper = Some(mapper);
251    }
252
253    /// Eject the cartridge, returning the save state
254    /// ```
255    /// # use nescore::Nes;
256    /// let nes = Nes::default();
257    /// // This consumes the nes instance
258    /// let battery_ram = nes.eject();
259    /// ```
260    pub fn eject(self) -> Vec<u8> {
261        self.mapper.map_or(vec![], |mapper| mapper.borrow().get_battery_ram())
262    }
263
264    //------------------------------------------------------------------------------------------------------------------
265    // Event Logging
266    //------------------------------------------------------------------------------------------------------------------
267    #[cfg(feature="events")]
268    pub fn cpu_event_channel(&mut self) -> Receiver<crate::events::CpuEvent> {
269        let (tx, rx) = channel::<crate::events::CpuEvent>();
270        self.cpu.borrow_mut().set_event_sender(tx);
271
272        rx
273    }
274
275    #[cfg(feature="events")]
276    pub fn apu_event_channel(&mut self) -> Receiver<crate::events::ApuEvent> {
277        let (tx, rx) = channel::<crate::events::ApuEvent>();
278        self.apu.borrow_mut().set_event_sender(tx);
279
280        rx
281    }
282
283    //------------------------------------------------------------------------------------------------------------------
284    // Inspect the state of the NES system
285    //------------------------------------------------------------------------------------------------------------------
286
287    /// Get the CPU's program counter
288    pub fn get_program_counter(&self) -> u16 {
289        self.cpu.borrow().get_pc()
290    }
291
292    /// Read the byte, at the specified address, from CPU's internal RAM
293    pub fn read_cpu_ram(&self, addr: u16) -> u8 {
294        self.cpu.borrow().read_ram(addr)
295    }
296
297    /// Read directly from VRAM
298    pub fn read_ppu_memory(&self, addr: u16) -> u8 {
299        self.ppu.borrow().read_vram(addr)
300    }
301
302    /// Read a tile from the current nametable
303    pub fn read_tile(&self, nametable: u16, x: usize, y: usize) -> u8 {
304        self.ppu.borrow().read_tile(nametable, x, y)
305    }
306}
307
308impl From<Cartridge> for Nes {
309    fn from(cart: Cartridge) -> Self {
310        Nes::default().with_cart(cart)
311    }
312}
313
314#[cfg(test)]
315mod tests {
316
317}