@tmustier/pi-nes 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/AGENTS.md +89 -1
  2. package/README.md +78 -49
  3. package/extensions/nes/native/nes-core/Cargo.lock +0 -2
  4. package/extensions/nes/native/nes-core/Cargo.toml +1 -1
  5. package/extensions/nes/native/nes-core/index.d.ts +5 -0
  6. package/extensions/nes/native/nes-core/index.node +0 -0
  7. package/extensions/nes/native/nes-core/native.d.ts +5 -0
  8. package/extensions/nes/native/nes-core/src/lib.rs +25 -0
  9. package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo-ok +1 -0
  10. package/extensions/nes/native/nes-core/vendor/nes_rust/.cargo_vcs_info.json +5 -0
  11. package/extensions/nes/native/nes-core/vendor/nes_rust/.travis.yml +3 -0
  12. package/extensions/nes/native/nes-core/vendor/nes_rust/Cargo.toml +23 -0
  13. package/extensions/nes/native/nes-core/vendor/nes_rust/LICENSE +21 -0
  14. package/extensions/nes/native/nes-core/vendor/nes_rust/README.md +59 -0
  15. package/extensions/nes/native/nes-core/vendor/nes_rust/src/apu.rs +1114 -0
  16. package/extensions/nes/native/nes-core/vendor/nes_rust/src/audio.rs +6 -0
  17. package/extensions/nes/native/nes-core/vendor/nes_rust/src/button.rs +23 -0
  18. package/extensions/nes/native/nes-core/vendor/nes_rust/src/cpu.rs +2364 -0
  19. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_audio.rs +49 -0
  20. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_display.rs +47 -0
  21. package/extensions/nes/native/nes-core/vendor/nes_rust/src/default_input.rs +33 -0
  22. package/extensions/nes/native/nes-core/vendor/nes_rust/src/display.rs +10 -0
  23. package/extensions/nes/native/nes-core/vendor/nes_rust/src/input.rs +7 -0
  24. package/extensions/nes/native/nes-core/vendor/nes_rust/src/joypad.rs +86 -0
  25. package/extensions/nes/native/nes-core/vendor/nes_rust/src/lib.rs +168 -0
  26. package/extensions/nes/native/nes-core/vendor/nes_rust/src/mapper.rs +502 -0
  27. package/extensions/nes/native/nes-core/vendor/nes_rust/src/memory.rs +73 -0
  28. package/extensions/nes/native/nes-core/vendor/nes_rust/src/ppu.rs +1378 -0
  29. package/extensions/nes/native/nes-core/vendor/nes_rust/src/register.rs +560 -0
  30. package/extensions/nes/native/nes-core/vendor/nes_rust/src/rom.rs +231 -0
  31. package/extensions/nes/nes-core.ts +27 -4
  32. package/package.json +1 -1
@@ -0,0 +1,49 @@
1
+ use audio::{Audio, BUFFER_CAPACITY};
2
+
3
+ pub struct DefaultAudio {
4
+ buffer_index: usize,
5
+ buffer: [f32; BUFFER_CAPACITY],
6
+ previous_value: f32
7
+ }
8
+
9
+ impl DefaultAudio {
10
+ pub fn new() -> Self {
11
+ DefaultAudio {
12
+ buffer_index: 0,
13
+ buffer: [0.0; BUFFER_CAPACITY],
14
+ previous_value: 0.0
15
+ }
16
+ }
17
+ }
18
+
19
+ impl Audio for DefaultAudio {
20
+ fn push(&mut self, value: f32) {
21
+ if self.buffer_index >= BUFFER_CAPACITY {
22
+ return;
23
+ }
24
+ self.buffer[self.buffer_index] = value;
25
+ self.buffer_index += 1;
26
+ }
27
+
28
+ fn copy_sample_buffer(&mut self, sample_buffer: &mut [f32]) {
29
+ // @TODO: Remove side effect?
30
+
31
+ // @TODO: Remove magic number
32
+ let client_sample_buffer_length = 4096;
33
+
34
+ for i in 0..client_sample_buffer_length {
35
+ sample_buffer[i] = match i >= self.buffer_index {
36
+ true => self.previous_value,
37
+ false => self.buffer[i]
38
+ };
39
+ self.previous_value = sample_buffer[i];
40
+ }
41
+ for i in client_sample_buffer_length..self.buffer.len() {
42
+ self.buffer[i - client_sample_buffer_length] = self.buffer[i];
43
+ }
44
+ self.buffer_index = match self.buffer_index < client_sample_buffer_length {
45
+ true => 0,
46
+ false => self.buffer_index - client_sample_buffer_length
47
+ };
48
+ }
49
+ }
@@ -0,0 +1,47 @@
1
+ use display::{
2
+ Display,
3
+ PIXEL_BYTES,
4
+ PIXELS_CAPACITY,
5
+ SCREEN_HEIGHT,
6
+ SCREEN_WIDTH
7
+ };
8
+
9
+ pub struct DefaultDisplay {
10
+ pixels: Vec<u8>
11
+ }
12
+
13
+ impl DefaultDisplay {
14
+ pub fn new() -> Self {
15
+ DefaultDisplay {
16
+ pixels: vec![0; PIXELS_CAPACITY]
17
+ }
18
+ }
19
+ }
20
+
21
+ impl Display for DefaultDisplay {
22
+ fn render_pixel(&mut self, x: u16, y: u16, c: u32) {
23
+ let r = ((c >> 16) & 0xff) as u8;
24
+ let g = ((c >> 8) & 0xff) as u8;
25
+ let b = (c & 0xff) as u8;
26
+ let base_index = (y as u32 * SCREEN_WIDTH + x as u32) * PIXEL_BYTES;
27
+ // Is this memory layout, BGR, correct?
28
+ self.pixels[(base_index + 2) as usize] = r;
29
+ self.pixels[(base_index + 1) as usize] = g;
30
+ self.pixels[(base_index + 0) as usize] = b;
31
+ }
32
+
33
+ fn vblank(&mut self) {
34
+ }
35
+
36
+ fn copy_to_rgba_pixels(&self, pixels: &mut [u8]) {
37
+ for y in 0..SCREEN_HEIGHT {
38
+ for x in 0..SCREEN_WIDTH {
39
+ let base_index = (y * SCREEN_WIDTH + x) as usize;
40
+ pixels[base_index * 4 + 0] = self.pixels[base_index * 3 + 0];
41
+ pixels[base_index * 4 + 1] = self.pixels[base_index * 3 + 1];
42
+ pixels[base_index * 4 + 2] = self.pixels[base_index * 3 + 2];
43
+ pixels[base_index * 4 + 3] = 255;
44
+ }
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,33 @@
1
+ use std::collections::VecDeque;
2
+
3
+ use input::Input;
4
+ use button;
5
+
6
+ pub struct DefaultInput {
7
+ events: VecDeque<(button::Button, button::Event)>
8
+ }
9
+
10
+ impl DefaultInput {
11
+ pub fn new() -> Self {
12
+ DefaultInput {
13
+ events: VecDeque::<(button::Button, button::Event)>::new()
14
+ }
15
+ }
16
+ }
17
+
18
+ impl Input for DefaultInput {
19
+ fn get_input(&mut self) -> Option<(button::Button, button::Event)> {
20
+ match self.events.len() > 0 {
21
+ true => self.events.pop_front(),
22
+ false => None
23
+ }
24
+ }
25
+
26
+ fn press(&mut self, button: button::Button) {
27
+ self.events.push_back((button, button::Event::Press));
28
+ }
29
+
30
+ fn release(&mut self, button: button::Button) {
31
+ self.events.push_back((button, button::Event::Release));
32
+ }
33
+ }
@@ -0,0 +1,10 @@
1
+ pub const SCREEN_WIDTH: u32 = 256;
2
+ pub const SCREEN_HEIGHT: u32 = 240;
3
+ pub const PIXEL_BYTES: u32 = 3;
4
+ pub const PIXELS_CAPACITY: usize = SCREEN_WIDTH as usize * SCREEN_HEIGHT as usize * PIXEL_BYTES as usize;
5
+
6
+ pub trait Display {
7
+ fn render_pixel(&mut self, x: u16, y: u16, c: u32);
8
+ fn vblank(&mut self);
9
+ fn copy_to_rgba_pixels(&self, pixels: &mut [u8]);
10
+ }
@@ -0,0 +1,7 @@
1
+ use button::{Button, Event};
2
+
3
+ pub trait Input {
4
+ fn get_input(&mut self) -> Option<(Button, Event)>;
5
+ fn press(&mut self, button: Button);
6
+ fn release(&mut self, button: Button);
7
+ }
@@ -0,0 +1,86 @@
1
+ use button;
2
+ use register::Register;
3
+
4
+ const BUTTON_NUM: u8 = 8;
5
+
6
+ pub enum Button {
7
+ A,
8
+ B,
9
+ Select,
10
+ Start,
11
+ Up,
12
+ Down,
13
+ Left,
14
+ Right
15
+ }
16
+
17
+ fn button_index(button: Button) -> usize {
18
+ match button {
19
+ Button::A => 0,
20
+ Button::B => 1,
21
+ Button::Select => 2,
22
+ Button::Start => 3,
23
+ Button::Up => 4,
24
+ Button::Down => 5,
25
+ Button::Left => 6,
26
+ Button::Right => 7
27
+ }
28
+ }
29
+
30
+ pub struct Joypad {
31
+ register: Register<u8>,
32
+ latch: u8,
33
+ current_button: u8,
34
+ buttons: [bool; BUTTON_NUM as usize]
35
+ }
36
+
37
+ impl Joypad {
38
+ pub fn new() -> Self {
39
+ Joypad {
40
+ register: Register::<u8>::new(),
41
+ latch: 0,
42
+ current_button: 0,
43
+ buttons: [false; BUTTON_NUM as usize]
44
+ }
45
+ }
46
+
47
+ pub fn handle_input(&mut self, button: Button, event: button::Event) {
48
+ match event {
49
+ button::Event::Press => self.press_button(button),
50
+ button::Event::Release => self.release_button(button)
51
+ };
52
+ }
53
+
54
+ pub fn load_register(&mut self) -> u8 {
55
+ let button = match self.latch == 1 {
56
+ true => 1,
57
+ _ => {
58
+ let value = self.current_button;
59
+ self.current_button += 1;
60
+ value
61
+ }
62
+ };
63
+
64
+ match button >= BUTTON_NUM || self.buttons[button as usize] {
65
+ true => 1,
66
+ false => 0
67
+ }
68
+ }
69
+
70
+ pub fn store_register(&mut self, mut value: u8) {
71
+ self.register.store(value);
72
+ value = value & 1;
73
+ if value == 1 {
74
+ self.current_button = 0;
75
+ }
76
+ self.latch = value;
77
+ }
78
+
79
+ pub fn press_button(&mut self, button: Button) {
80
+ self.buttons[button_index(button)] = true;
81
+ }
82
+
83
+ pub fn release_button(&mut self, button: Button) {
84
+ self.buttons[button_index(button)] = false;
85
+ }
86
+ }
@@ -0,0 +1,168 @@
1
+ pub mod register;
2
+ pub mod cpu;
3
+ pub mod ppu;
4
+ pub mod apu;
5
+ pub mod rom;
6
+ pub mod memory;
7
+ pub mod mapper;
8
+ pub mod button;
9
+ pub mod joypad;
10
+ pub mod input;
11
+ pub mod audio;
12
+ pub mod display;
13
+ pub mod default_input;
14
+ pub mod default_audio;
15
+ pub mod default_display;
16
+
17
+ use cpu::Cpu;
18
+ use rom::Rom;
19
+ use button::Button;
20
+ use input::Input;
21
+ use display::Display;
22
+ use audio::Audio;
23
+
24
+ /// NES emulator.
25
+ ///
26
+ /// ```ignore
27
+ /// use std::fs::File;
28
+ /// use std::io::Read;
29
+ /// use std::time::Duration;
30
+ /// use nes_rust::Nes;
31
+ /// use nes_rust::rom::Rom;
32
+ /// use nes_rust::default_input::DefaultInput;
33
+ /// use nes_rust::default_audio::DefaultAudio;
34
+ /// use nes_rust::default_display::DefaultDisplay;
35
+ ///
36
+ /// let input = Box::new(DefaultInput::new());
37
+ /// let display = Box::new(DefaultDisplay::new());
38
+ /// let audio = Box::new(DefaultAudio::new());
39
+ /// let mut nes = Nes::new(input, display, audio);
40
+ ///
41
+ /// // Load and set Rom from rom image binary
42
+ /// let filename = &args[1];
43
+ /// let mut file = File::open(filename)?;
44
+ /// let mut contents = vec![];
45
+ /// file.read_to_end(&mut contents)?;
46
+ /// let rom = Rom::new(contents);
47
+ /// nes.set_rom(rom);
48
+ ///
49
+ /// // Go!
50
+ /// nes.bootup();
51
+ /// let mut rgba_pixels = [256 * 240 * 4];
52
+ /// loop {
53
+ /// nes.step_frame();
54
+ /// nes.copy_pixels(rgba_pixels);
55
+ /// // Render rgba_pixels
56
+ /// // @TODO: Audio buffer sample code is T.B.D.
57
+ /// // Adjust sleep time for your platform
58
+ /// std::thread::sleep(Duration::from_millis(1));
59
+ /// }
60
+ /// ```
61
+ pub struct Nes {
62
+ cpu: Cpu
63
+ }
64
+
65
+ impl Nes {
66
+ /// Creates a new `Nes`.
67
+ /// You need to pass [`input::Input`](./input/trait.Input.html),
68
+ /// [`display::Display`](./display/trait.Display.html), and
69
+ /// [`audio::Audio`](./audio/trait.Audio.html) traits for your platform
70
+ /// specific Input/Output.
71
+ ///
72
+ /// # Arguments
73
+ /// * `input` For pad input
74
+ /// * `display` For screen output
75
+ /// * `audio` For audio output
76
+ pub fn new(input: Box<dyn Input>, display: Box<dyn Display>,
77
+ audio: Box<dyn Audio>) -> Self {
78
+ Nes {
79
+ cpu: Cpu::new(
80
+ input,
81
+ display,
82
+ audio
83
+ )
84
+ }
85
+ }
86
+
87
+ /// Sets up NES rom
88
+ ///
89
+ /// # Arguments
90
+ /// * `rom`
91
+ pub fn set_rom(&mut self, rom: Rom) {
92
+ self.cpu.set_rom(rom);
93
+ }
94
+
95
+ /// Boots up
96
+ pub fn bootup(&mut self) {
97
+ self.cpu.bootup();
98
+ }
99
+
100
+ /// Resets
101
+ pub fn reset(&mut self) {
102
+ self.cpu.reset();
103
+ }
104
+
105
+ /// Executes a CPU cycle
106
+ pub fn step(&mut self) {
107
+ self.cpu.step();
108
+ }
109
+
110
+ /// Executes a PPU (screen refresh) frame
111
+ pub fn step_frame(&mut self) {
112
+ self.cpu.step_frame();
113
+ }
114
+
115
+ /// Copies RGB pixels of screen to passed pixels.
116
+ /// The length and result should be specific to `display` passed via the constructor.
117
+ ///
118
+ /// # Arguments
119
+ /// * `pixels`
120
+ pub fn copy_pixels(&self, pixels: &mut [u8]) {
121
+ self.cpu.get_ppu().get_display().copy_to_rgba_pixels(pixels);
122
+ }
123
+
124
+ /// Copies audio buffer to passed buffer.
125
+ /// The length and result should be specific to `audio` passed via the constructor.
126
+ ///
127
+ /// # Arguments
128
+ /// * `buffer`
129
+ pub fn copy_sample_buffer(&mut self, buffer: &mut [f32]) {
130
+ self.cpu.get_mut_apu().get_mut_audio().copy_sample_buffer(buffer);
131
+ }
132
+
133
+ /// Presses a pad button
134
+ ///
135
+ /// # Arguments
136
+ /// * `button`
137
+ pub fn press_button(&mut self, button: Button) {
138
+ self.cpu.get_mut_input().press(button);
139
+ }
140
+
141
+ /// Releases a pad button
142
+ ///
143
+ /// # Arguments
144
+ /// * `buffer`
145
+ pub fn release_button(&mut self, button: Button) {
146
+ self.cpu.get_mut_input().release(button);
147
+ }
148
+
149
+ pub fn has_battery_backed_ram(&self) -> bool {
150
+ self.cpu.has_battery_backed_ram()
151
+ }
152
+
153
+ pub fn get_sram(&self) -> Vec<u8> {
154
+ self.cpu.get_sram()
155
+ }
156
+
157
+ pub fn set_sram(&mut self, data: Vec<u8>) {
158
+ self.cpu.set_sram(&data);
159
+ }
160
+
161
+ pub fn is_sram_dirty(&self) -> bool {
162
+ self.cpu.is_sram_dirty()
163
+ }
164
+
165
+ pub fn mark_sram_saved(&mut self) {
166
+ self.cpu.mark_sram_saved();
167
+ }
168
+ }