1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
pub mod register;
pub mod cpu;
pub mod ppu;
pub mod apu;
pub mod rom;
pub mod memory;
pub mod mapper;
pub mod button;
pub mod joypad;
pub mod input;
pub mod audio;
pub mod display;
pub mod default_input;
pub mod default_audio;
pub mod default_display;

use cpu::Cpu;
use rom::Rom;
use button::Button;
use input::Input;
use display::Display;
use audio::Audio;

/// NES emulator.
///
/// ```ignore
/// use std::fs::File;
/// use std::io::Read;
/// use std::time::Duration;
/// use nes_rust::Nes;
/// use nes_rust::rom::Rom;
/// use nes_rust::default_input::DefaultInput;
/// use nes_rust::default_audio::DefaultAudio;
/// use nes_rust::default_display::DefaultDisplay;
///
/// let input = Box::new(DefaultInput::new());
/// let display = Box::new(DefaultDisplay::new());
/// let audio = Box::new(DefaultAudio::new());
/// let mut nes = Nes::new(input, display, audio);
///
/// // Load and set Rom from rom image binary
/// let filename = &args[1];
/// let mut file = File::open(filename)?;
/// let mut contents = vec![];
/// file.read_to_end(&mut contents)?;
/// let rom = Rom::new(contents);
/// nes.set_rom(rom);
///
/// // Go!
/// nes.bootup();
/// let mut rgba_pixels = [256 * 240 * 4];
/// loop {
///   nes.step_frame();
///   nes.copy_pixels(rgba_pixels);
///   // Render rgba_pixels
///   // @TODO: Audio buffer sample code is T.B.D.
///   // Adjust sleep time for your platform
///   std::thread::sleep(Duration::from_millis(1));
/// }
/// ```
pub struct Nes {
	cpu: Cpu
}

impl Nes {
	/// Creates a new `Nes`.
    /// You need to pass [`input::Input`](./input/trait.Input.html),
    /// [`display::Display`](./display/trait.Display.html), and
    /// [`audio::Audio`](./audio/trait.Audio.html) traits for your platform
    /// specific Input/Output.
    ///
    /// # Arguments
    /// * `input` For pad input
    /// * `display` For screen output
    /// * `audio` For audio output
	pub fn new(input: Box<dyn Input>, display: Box<dyn Display>,
		audio: Box<dyn Audio>) -> Self {
		Nes {
			cpu: Cpu::new(
				input,
				display,
				audio
			)
		}
	}

	/// Sets up NES rom
	///
	/// # Arguments
	/// * `rom`
	pub fn set_rom(&mut self, rom: Rom) {
		self.cpu.set_rom(rom);
	}

	/// Boots up
	pub fn bootup(&mut self) {
		self.cpu.bootup();
	}

	/// Resets
	pub fn reset(&mut self) {
		self.cpu.reset();
	}

	/// Executes a CPU cycle
	pub fn step(&mut self) {
		self.cpu.step();
	}

	/// Executes a PPU (screen refresh) frame
	pub fn step_frame(&mut self) {
		self.cpu.step_frame();
	}

	/// Copies RGB pixels of screen to passed pixels.
	/// The length and result should be specific to `display` passed via the constructor.
	///
	/// # Arguments
	/// * `pixels`
	pub fn copy_pixels(&self, pixels: &mut [u8]) {
		self.cpu.get_ppu().get_display().copy_to_rgba_pixels(pixels);
	}

	/// Copies audio buffer to passed buffer.
	/// The length and result should be specific to `audio` passed via the constructor.
	///
	/// # Arguments
	/// * `buffer`
	pub fn copy_sample_buffer(&mut self, buffer: &mut [f32]) {
		self.cpu.get_mut_apu().get_mut_audio().copy_sample_buffer(buffer);
	}

	/// Presses a pad button
	///
	/// # Arguments
	/// * `button`
	pub fn press_button(&mut self, button: Button) {
		self.cpu.get_mut_input().press(button);
	}

	/// Releases a pad button
	///
	/// # Arguments
	/// * `buffer`
	pub fn release_button(&mut self, button: Button) {
		self.cpu.get_mut_input().release(button);
	}
}