pub struct NES { /* private fields */ }Implementations§
Source§impl NES
impl NES
Sourcepub fn new() -> Self
pub fn new() -> Self
Examples found in repository?
examples/export_frame.rs (line 43)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "export_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let Some(output_path) = args.next() else {
21 usage(&program);
22 return ExitCode::from(2);
23 };
24 let frames = match args.next() {
25 Some(value) => match value.parse::<usize>() {
26 Ok(frames) => frames,
27 Err(error) => {
28 eprintln!("invalid frame count {value:?}: {error}");
29 return ExitCode::from(2);
30 }
31 },
32 None => 120,
33 };
34
35 let rom = match std::fs::read(&rom_path) {
36 Ok(rom) => rom,
37 Err(error) => {
38 eprintln!("failed to read ROM {rom_path:?}: {error}");
39 return ExitCode::from(1);
40 }
41 };
42
43 let mut nes = NES::new();
44 if let Err(error) = nes.load_cartridge_ines(&rom) {
45 eprintln!("failed to load ROM {rom_path:?}: {error}");
46 return ExitCode::from(1);
47 }
48 nes.reset();
49
50 for _ in 0..frames {
51 nes.run_frame();
52 }
53
54 if let Some(parent) = Path::new(&output_path).parent()
55 && !parent.as_os_str().is_empty()
56 {
57 if let Err(error) = std::fs::create_dir_all(parent) {
58 eprintln!("failed to create output directory {:?}: {}", parent, error);
59 return ExitCode::from(1);
60 }
61 }
62
63 if let Err(error) = write_frame_ppm(&output_path, nes.video_frame()) {
64 eprintln!("failed to write PPM {output_path:?}: {error}");
65 return ExitCode::from(1);
66 }
67
68 println!(
69 "wrote frame {} from {} to {}",
70 nes.frame_number(),
71 rom_path,
72 output_path
73 );
74 ExitCode::SUCCESS
75}More examples
examples/hash_frame.rs (line 40)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "hash_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let frames = match args.next() {
21 Some(value) => match value.parse::<usize>() {
22 Ok(frames) => frames,
23 Err(error) => {
24 eprintln!("invalid frame count {value:?}: {error}");
25 return ExitCode::from(2);
26 }
27 },
28 None => 180,
29 };
30 let output_path = args.next();
31
32 let rom = match std::fs::read(&rom_path) {
33 Ok(rom) => rom,
34 Err(error) => {
35 eprintln!("failed to read ROM {rom_path:?}: {error}");
36 return ExitCode::from(1);
37 }
38 };
39
40 let mut nes = NES::new();
41 if let Err(error) = nes.load_cartridge_ines(&rom) {
42 eprintln!("failed to load ROM {rom_path:?}: {error}");
43 return ExitCode::from(1);
44 }
45 nes.reset();
46
47 for _ in 0..frames {
48 nes.run_frame();
49 }
50
51 let ppm = frame_to_ppm(nes.video_frame());
52 let hash = stable_byte_hash(&ppm);
53 println!(
54 "{} frame={} hash=0x{:016X}",
55 rom_path,
56 nes.frame_number(),
57 hash
58 );
59
60 if let Some(output_path) = output_path {
61 if let Some(parent) = Path::new(&output_path).parent()
62 && !parent.as_os_str().is_empty()
63 {
64 if let Err(error) = std::fs::create_dir_all(parent) {
65 eprintln!("failed to create output directory {:?}: {}", parent, error);
66 return ExitCode::from(1);
67 }
68 }
69
70 if let Err(error) = std::fs::write(&output_path, &ppm) {
71 eprintln!("failed to write PPM {output_path:?}: {error}");
72 return ExitCode::from(1);
73 }
74 println!("wrote {}", output_path);
75 }
76
77 ExitCode::SUCCESS
78}examples/analyze_state.rs (line 108)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Examples found in repository?
examples/export_frame.rs (line 48)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "export_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let Some(output_path) = args.next() else {
21 usage(&program);
22 return ExitCode::from(2);
23 };
24 let frames = match args.next() {
25 Some(value) => match value.parse::<usize>() {
26 Ok(frames) => frames,
27 Err(error) => {
28 eprintln!("invalid frame count {value:?}: {error}");
29 return ExitCode::from(2);
30 }
31 },
32 None => 120,
33 };
34
35 let rom = match std::fs::read(&rom_path) {
36 Ok(rom) => rom,
37 Err(error) => {
38 eprintln!("failed to read ROM {rom_path:?}: {error}");
39 return ExitCode::from(1);
40 }
41 };
42
43 let mut nes = NES::new();
44 if let Err(error) = nes.load_cartridge_ines(&rom) {
45 eprintln!("failed to load ROM {rom_path:?}: {error}");
46 return ExitCode::from(1);
47 }
48 nes.reset();
49
50 for _ in 0..frames {
51 nes.run_frame();
52 }
53
54 if let Some(parent) = Path::new(&output_path).parent()
55 && !parent.as_os_str().is_empty()
56 {
57 if let Err(error) = std::fs::create_dir_all(parent) {
58 eprintln!("failed to create output directory {:?}: {}", parent, error);
59 return ExitCode::from(1);
60 }
61 }
62
63 if let Err(error) = write_frame_ppm(&output_path, nes.video_frame()) {
64 eprintln!("failed to write PPM {output_path:?}: {error}");
65 return ExitCode::from(1);
66 }
67
68 println!(
69 "wrote frame {} from {} to {}",
70 nes.frame_number(),
71 rom_path,
72 output_path
73 );
74 ExitCode::SUCCESS
75}More examples
examples/hash_frame.rs (line 45)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "hash_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let frames = match args.next() {
21 Some(value) => match value.parse::<usize>() {
22 Ok(frames) => frames,
23 Err(error) => {
24 eprintln!("invalid frame count {value:?}: {error}");
25 return ExitCode::from(2);
26 }
27 },
28 None => 180,
29 };
30 let output_path = args.next();
31
32 let rom = match std::fs::read(&rom_path) {
33 Ok(rom) => rom,
34 Err(error) => {
35 eprintln!("failed to read ROM {rom_path:?}: {error}");
36 return ExitCode::from(1);
37 }
38 };
39
40 let mut nes = NES::new();
41 if let Err(error) = nes.load_cartridge_ines(&rom) {
42 eprintln!("failed to load ROM {rom_path:?}: {error}");
43 return ExitCode::from(1);
44 }
45 nes.reset();
46
47 for _ in 0..frames {
48 nes.run_frame();
49 }
50
51 let ppm = frame_to_ppm(nes.video_frame());
52 let hash = stable_byte_hash(&ppm);
53 println!(
54 "{} frame={} hash=0x{:016X}",
55 rom_path,
56 nes.frame_number(),
57 hash
58 );
59
60 if let Some(output_path) = output_path {
61 if let Some(parent) = Path::new(&output_path).parent()
62 && !parent.as_os_str().is_empty()
63 {
64 if let Err(error) = std::fs::create_dir_all(parent) {
65 eprintln!("failed to create output directory {:?}: {}", parent, error);
66 return ExitCode::from(1);
67 }
68 }
69
70 if let Err(error) = std::fs::write(&output_path, &ppm) {
71 eprintln!("failed to write PPM {output_path:?}: {error}");
72 return ExitCode::from(1);
73 }
74 println!("wrote {}", output_path);
75 }
76
77 ExitCode::SUCCESS
78}pub fn insert_cartridge(&mut self, cartridge: Cartridge)
Sourcepub fn load_cartridge_ines(&mut self, rom: &[u8]) -> Result<(), CartridgeError>
pub fn load_cartridge_ines(&mut self, rom: &[u8]) -> Result<(), CartridgeError>
Examples found in repository?
examples/export_frame.rs (line 44)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "export_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let Some(output_path) = args.next() else {
21 usage(&program);
22 return ExitCode::from(2);
23 };
24 let frames = match args.next() {
25 Some(value) => match value.parse::<usize>() {
26 Ok(frames) => frames,
27 Err(error) => {
28 eprintln!("invalid frame count {value:?}: {error}");
29 return ExitCode::from(2);
30 }
31 },
32 None => 120,
33 };
34
35 let rom = match std::fs::read(&rom_path) {
36 Ok(rom) => rom,
37 Err(error) => {
38 eprintln!("failed to read ROM {rom_path:?}: {error}");
39 return ExitCode::from(1);
40 }
41 };
42
43 let mut nes = NES::new();
44 if let Err(error) = nes.load_cartridge_ines(&rom) {
45 eprintln!("failed to load ROM {rom_path:?}: {error}");
46 return ExitCode::from(1);
47 }
48 nes.reset();
49
50 for _ in 0..frames {
51 nes.run_frame();
52 }
53
54 if let Some(parent) = Path::new(&output_path).parent()
55 && !parent.as_os_str().is_empty()
56 {
57 if let Err(error) = std::fs::create_dir_all(parent) {
58 eprintln!("failed to create output directory {:?}: {}", parent, error);
59 return ExitCode::from(1);
60 }
61 }
62
63 if let Err(error) = write_frame_ppm(&output_path, nes.video_frame()) {
64 eprintln!("failed to write PPM {output_path:?}: {error}");
65 return ExitCode::from(1);
66 }
67
68 println!(
69 "wrote frame {} from {} to {}",
70 nes.frame_number(),
71 rom_path,
72 output_path
73 );
74 ExitCode::SUCCESS
75}More examples
examples/hash_frame.rs (line 41)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "hash_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let frames = match args.next() {
21 Some(value) => match value.parse::<usize>() {
22 Ok(frames) => frames,
23 Err(error) => {
24 eprintln!("invalid frame count {value:?}: {error}");
25 return ExitCode::from(2);
26 }
27 },
28 None => 180,
29 };
30 let output_path = args.next();
31
32 let rom = match std::fs::read(&rom_path) {
33 Ok(rom) => rom,
34 Err(error) => {
35 eprintln!("failed to read ROM {rom_path:?}: {error}");
36 return ExitCode::from(1);
37 }
38 };
39
40 let mut nes = NES::new();
41 if let Err(error) = nes.load_cartridge_ines(&rom) {
42 eprintln!("failed to load ROM {rom_path:?}: {error}");
43 return ExitCode::from(1);
44 }
45 nes.reset();
46
47 for _ in 0..frames {
48 nes.run_frame();
49 }
50
51 let ppm = frame_to_ppm(nes.video_frame());
52 let hash = stable_byte_hash(&ppm);
53 println!(
54 "{} frame={} hash=0x{:016X}",
55 rom_path,
56 nes.frame_number(),
57 hash
58 );
59
60 if let Some(output_path) = output_path {
61 if let Some(parent) = Path::new(&output_path).parent()
62 && !parent.as_os_str().is_empty()
63 {
64 if let Err(error) = std::fs::create_dir_all(parent) {
65 eprintln!("failed to create output directory {:?}: {}", parent, error);
66 return ExitCode::from(1);
67 }
68 }
69
70 if let Err(error) = std::fs::write(&output_path, &ppm) {
71 eprintln!("failed to write PPM {output_path:?}: {error}");
72 return ExitCode::from(1);
73 }
74 println!("wrote {}", output_path);
75 }
76
77 ExitCode::SUCCESS
78}examples/analyze_state.rs (line 109)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}Sourcepub fn set_controller_state(&mut self, port: usize, state: ControllerState)
pub fn set_controller_state(&mut self, port: usize, state: ControllerState)
Examples found in repository?
examples/analyze_state.rs (line 145)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}pub fn clock(&mut self)
Sourcepub fn run_frame(&mut self)
pub fn run_frame(&mut self)
Examples found in repository?
examples/export_frame.rs (line 51)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "export_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let Some(output_path) = args.next() else {
21 usage(&program);
22 return ExitCode::from(2);
23 };
24 let frames = match args.next() {
25 Some(value) => match value.parse::<usize>() {
26 Ok(frames) => frames,
27 Err(error) => {
28 eprintln!("invalid frame count {value:?}: {error}");
29 return ExitCode::from(2);
30 }
31 },
32 None => 120,
33 };
34
35 let rom = match std::fs::read(&rom_path) {
36 Ok(rom) => rom,
37 Err(error) => {
38 eprintln!("failed to read ROM {rom_path:?}: {error}");
39 return ExitCode::from(1);
40 }
41 };
42
43 let mut nes = NES::new();
44 if let Err(error) = nes.load_cartridge_ines(&rom) {
45 eprintln!("failed to load ROM {rom_path:?}: {error}");
46 return ExitCode::from(1);
47 }
48 nes.reset();
49
50 for _ in 0..frames {
51 nes.run_frame();
52 }
53
54 if let Some(parent) = Path::new(&output_path).parent()
55 && !parent.as_os_str().is_empty()
56 {
57 if let Err(error) = std::fs::create_dir_all(parent) {
58 eprintln!("failed to create output directory {:?}: {}", parent, error);
59 return ExitCode::from(1);
60 }
61 }
62
63 if let Err(error) = write_frame_ppm(&output_path, nes.video_frame()) {
64 eprintln!("failed to write PPM {output_path:?}: {error}");
65 return ExitCode::from(1);
66 }
67
68 println!(
69 "wrote frame {} from {} to {}",
70 nes.frame_number(),
71 rom_path,
72 output_path
73 );
74 ExitCode::SUCCESS
75}More examples
examples/hash_frame.rs (line 48)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "hash_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let frames = match args.next() {
21 Some(value) => match value.parse::<usize>() {
22 Ok(frames) => frames,
23 Err(error) => {
24 eprintln!("invalid frame count {value:?}: {error}");
25 return ExitCode::from(2);
26 }
27 },
28 None => 180,
29 };
30 let output_path = args.next();
31
32 let rom = match std::fs::read(&rom_path) {
33 Ok(rom) => rom,
34 Err(error) => {
35 eprintln!("failed to read ROM {rom_path:?}: {error}");
36 return ExitCode::from(1);
37 }
38 };
39
40 let mut nes = NES::new();
41 if let Err(error) = nes.load_cartridge_ines(&rom) {
42 eprintln!("failed to load ROM {rom_path:?}: {error}");
43 return ExitCode::from(1);
44 }
45 nes.reset();
46
47 for _ in 0..frames {
48 nes.run_frame();
49 }
50
51 let ppm = frame_to_ppm(nes.video_frame());
52 let hash = stable_byte_hash(&ppm);
53 println!(
54 "{} frame={} hash=0x{:016X}",
55 rom_path,
56 nes.frame_number(),
57 hash
58 );
59
60 if let Some(output_path) = output_path {
61 if let Some(parent) = Path::new(&output_path).parent()
62 && !parent.as_os_str().is_empty()
63 {
64 if let Err(error) = std::fs::create_dir_all(parent) {
65 eprintln!("failed to create output directory {:?}: {}", parent, error);
66 return ExitCode::from(1);
67 }
68 }
69
70 if let Err(error) = std::fs::write(&output_path, &ppm) {
71 eprintln!("failed to write PPM {output_path:?}: {error}");
72 return ExitCode::from(1);
73 }
74 println!("wrote {}", output_path);
75 }
76
77 ExitCode::SUCCESS
78}examples/analyze_state.rs (line 146)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}pub fn step_cpu_instruction(&mut self)
pub fn execute(&mut self, command: CoreCommand) -> CoreResponse
pub fn master_clock(&self) -> u64
Sourcepub fn frame_number(&self) -> u64
pub fn frame_number(&self) -> u64
Examples found in repository?
examples/export_frame.rs (line 70)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "export_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let Some(output_path) = args.next() else {
21 usage(&program);
22 return ExitCode::from(2);
23 };
24 let frames = match args.next() {
25 Some(value) => match value.parse::<usize>() {
26 Ok(frames) => frames,
27 Err(error) => {
28 eprintln!("invalid frame count {value:?}: {error}");
29 return ExitCode::from(2);
30 }
31 },
32 None => 120,
33 };
34
35 let rom = match std::fs::read(&rom_path) {
36 Ok(rom) => rom,
37 Err(error) => {
38 eprintln!("failed to read ROM {rom_path:?}: {error}");
39 return ExitCode::from(1);
40 }
41 };
42
43 let mut nes = NES::new();
44 if let Err(error) = nes.load_cartridge_ines(&rom) {
45 eprintln!("failed to load ROM {rom_path:?}: {error}");
46 return ExitCode::from(1);
47 }
48 nes.reset();
49
50 for _ in 0..frames {
51 nes.run_frame();
52 }
53
54 if let Some(parent) = Path::new(&output_path).parent()
55 && !parent.as_os_str().is_empty()
56 {
57 if let Err(error) = std::fs::create_dir_all(parent) {
58 eprintln!("failed to create output directory {:?}: {}", parent, error);
59 return ExitCode::from(1);
60 }
61 }
62
63 if let Err(error) = write_frame_ppm(&output_path, nes.video_frame()) {
64 eprintln!("failed to write PPM {output_path:?}: {error}");
65 return ExitCode::from(1);
66 }
67
68 println!(
69 "wrote frame {} from {} to {}",
70 nes.frame_number(),
71 rom_path,
72 output_path
73 );
74 ExitCode::SUCCESS
75}More examples
examples/hash_frame.rs (line 56)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "hash_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let frames = match args.next() {
21 Some(value) => match value.parse::<usize>() {
22 Ok(frames) => frames,
23 Err(error) => {
24 eprintln!("invalid frame count {value:?}: {error}");
25 return ExitCode::from(2);
26 }
27 },
28 None => 180,
29 };
30 let output_path = args.next();
31
32 let rom = match std::fs::read(&rom_path) {
33 Ok(rom) => rom,
34 Err(error) => {
35 eprintln!("failed to read ROM {rom_path:?}: {error}");
36 return ExitCode::from(1);
37 }
38 };
39
40 let mut nes = NES::new();
41 if let Err(error) = nes.load_cartridge_ines(&rom) {
42 eprintln!("failed to load ROM {rom_path:?}: {error}");
43 return ExitCode::from(1);
44 }
45 nes.reset();
46
47 for _ in 0..frames {
48 nes.run_frame();
49 }
50
51 let ppm = frame_to_ppm(nes.video_frame());
52 let hash = stable_byte_hash(&ppm);
53 println!(
54 "{} frame={} hash=0x{:016X}",
55 rom_path,
56 nes.frame_number(),
57 hash
58 );
59
60 if let Some(output_path) = output_path {
61 if let Some(parent) = Path::new(&output_path).parent()
62 && !parent.as_os_str().is_empty()
63 {
64 if let Err(error) = std::fs::create_dir_all(parent) {
65 eprintln!("failed to create output directory {:?}: {}", parent, error);
66 return ExitCode::from(1);
67 }
68 }
69
70 if let Err(error) = std::fs::write(&output_path, &ppm) {
71 eprintln!("failed to write PPM {output_path:?}: {error}");
72 return ExitCode::from(1);
73 }
74 println!("wrote {}", output_path);
75 }
76
77 ExitCode::SUCCESS
78}examples/analyze_state.rs (line 123)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}Sourcepub fn frame_pixels(&self) -> &[u8] ⓘ
pub fn frame_pixels(&self) -> &[u8] ⓘ
Examples found in repository?
examples/analyze_state.rs (line 118)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}Sourcepub fn video_frame(&self) -> VideoFrame<'_>
pub fn video_frame(&self) -> VideoFrame<'_>
Examples found in repository?
examples/export_frame.rs (line 63)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "export_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let Some(output_path) = args.next() else {
21 usage(&program);
22 return ExitCode::from(2);
23 };
24 let frames = match args.next() {
25 Some(value) => match value.parse::<usize>() {
26 Ok(frames) => frames,
27 Err(error) => {
28 eprintln!("invalid frame count {value:?}: {error}");
29 return ExitCode::from(2);
30 }
31 },
32 None => 120,
33 };
34
35 let rom = match std::fs::read(&rom_path) {
36 Ok(rom) => rom,
37 Err(error) => {
38 eprintln!("failed to read ROM {rom_path:?}: {error}");
39 return ExitCode::from(1);
40 }
41 };
42
43 let mut nes = NES::new();
44 if let Err(error) = nes.load_cartridge_ines(&rom) {
45 eprintln!("failed to load ROM {rom_path:?}: {error}");
46 return ExitCode::from(1);
47 }
48 nes.reset();
49
50 for _ in 0..frames {
51 nes.run_frame();
52 }
53
54 if let Some(parent) = Path::new(&output_path).parent()
55 && !parent.as_os_str().is_empty()
56 {
57 if let Err(error) = std::fs::create_dir_all(parent) {
58 eprintln!("failed to create output directory {:?}: {}", parent, error);
59 return ExitCode::from(1);
60 }
61 }
62
63 if let Err(error) = write_frame_ppm(&output_path, nes.video_frame()) {
64 eprintln!("failed to write PPM {output_path:?}: {error}");
65 return ExitCode::from(1);
66 }
67
68 println!(
69 "wrote frame {} from {} to {}",
70 nes.frame_number(),
71 rom_path,
72 output_path
73 );
74 ExitCode::SUCCESS
75}More examples
examples/hash_frame.rs (line 51)
12fn main() -> ExitCode {
13 let mut args = env::args();
14 let program = args.next().unwrap_or_else(|| "hash_frame".to_string());
15
16 let Some(rom_path) = args.next() else {
17 usage(&program);
18 return ExitCode::from(2);
19 };
20 let frames = match args.next() {
21 Some(value) => match value.parse::<usize>() {
22 Ok(frames) => frames,
23 Err(error) => {
24 eprintln!("invalid frame count {value:?}: {error}");
25 return ExitCode::from(2);
26 }
27 },
28 None => 180,
29 };
30 let output_path = args.next();
31
32 let rom = match std::fs::read(&rom_path) {
33 Ok(rom) => rom,
34 Err(error) => {
35 eprintln!("failed to read ROM {rom_path:?}: {error}");
36 return ExitCode::from(1);
37 }
38 };
39
40 let mut nes = NES::new();
41 if let Err(error) = nes.load_cartridge_ines(&rom) {
42 eprintln!("failed to load ROM {rom_path:?}: {error}");
43 return ExitCode::from(1);
44 }
45 nes.reset();
46
47 for _ in 0..frames {
48 nes.run_frame();
49 }
50
51 let ppm = frame_to_ppm(nes.video_frame());
52 let hash = stable_byte_hash(&ppm);
53 println!(
54 "{} frame={} hash=0x{:016X}",
55 rom_path,
56 nes.frame_number(),
57 hash
58 );
59
60 if let Some(output_path) = output_path {
61 if let Some(parent) = Path::new(&output_path).parent()
62 && !parent.as_os_str().is_empty()
63 {
64 if let Err(error) = std::fs::create_dir_all(parent) {
65 eprintln!("failed to create output directory {:?}: {}", parent, error);
66 return ExitCode::from(1);
67 }
68 }
69
70 if let Err(error) = std::fs::write(&output_path, &ppm) {
71 eprintln!("failed to write PPM {output_path:?}: {error}");
72 return ExitCode::from(1);
73 }
74 println!("wrote {}", output_path);
75 }
76
77 ExitCode::SUCCESS
78}examples/analyze_state.rs (line 119)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}pub fn audio_batch(&self) -> AudioBatch<'_>
pub fn add_expansion_audio_chip(&mut self, chip: Box<dyn ExpansionAudioChip>)
Sourcepub fn debug_snapshot(&self) -> DebugSnapshot
pub fn debug_snapshot(&self) -> DebugSnapshot
Examples found in repository?
examples/analyze_state.rs (line 153)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}pub fn save_state(&self) -> Result<Vec<u8>, SaveStateError>
Sourcepub fn load_state(&mut self, bytes: &[u8]) -> Result<(), SaveStateError>
pub fn load_state(&mut self, bytes: &[u8]) -> Result<(), SaveStateError>
Examples found in repository?
examples/analyze_state.rs (line 113)
68fn main() -> ExitCode {
69 let mut args = env::args();
70 let program = args.next().unwrap_or_else(|| "analyze_state".to_string());
71
72 let Some(rom_path) = args.next() else {
73 usage(&program);
74 return ExitCode::from(2);
75 };
76 let Some(state_path) = args.next() else {
77 usage(&program);
78 return ExitCode::from(2);
79 };
80 let frames = match args.next() {
81 Some(value) => match value.parse::<usize>() {
82 Ok(frames) => frames,
83 Err(error) => {
84 eprintln!("invalid frame count {value:?}: {error}");
85 return ExitCode::from(2);
86 }
87 },
88 None => 240,
89 };
90 let input_mode = args.next().unwrap_or_else(|| "none".to_string());
91 let out_dir = args.next();
92
93 let rom = match std::fs::read(&rom_path) {
94 Ok(rom) => rom,
95 Err(error) => {
96 eprintln!("failed to read ROM {rom_path:?}: {error}");
97 return ExitCode::from(1);
98 }
99 };
100 let state = match std::fs::read(&state_path) {
101 Ok(state) => state,
102 Err(error) => {
103 eprintln!("failed to read state {state_path:?}: {error}");
104 return ExitCode::from(1);
105 }
106 };
107
108 let mut nes = NES::new();
109 if let Err(error) = nes.load_cartridge_ines(&rom) {
110 eprintln!("failed to load ROM {rom_path:?}: {error}");
111 return ExitCode::from(1);
112 }
113 if let Err(error) = nes.load_state(&state) {
114 eprintln!("failed to load state {state_path:?}: {error}");
115 return ExitCode::from(1);
116 }
117
118 let mut prev = nes.frame_pixels().to_vec();
119 let mut prev_hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
120 let mut same_hash_run = 0usize;
121 println!(
122 "start frame={} hash=0x{:016X}",
123 nes.frame_number(),
124 prev_hash
125 );
126
127 if let Some(ref out_dir) = out_dir {
128 if !out_dir.is_empty() {
129 let path = Path::new(out_dir);
130 if let Err(error) = std::fs::create_dir_all(path) {
131 eprintln!("failed to create output directory {:?}: {}", path, error);
132 return ExitCode::from(1);
133 }
134 }
135 }
136
137 for i in 1..=frames {
138 let mut controller = ControllerState::new();
139 if input_mode == "right" || input_mode == "right_a" {
140 controller.set_pressed(ControllerButton::Right, true);
141 }
142 if input_mode == "right_a" {
143 controller.set_pressed(ControllerButton::A, true);
144 }
145 nes.set_controller_state(0, controller);
146 nes.run_frame();
147 let frame = nes.frame_pixels().to_vec();
148 let hash = stable_byte_hash(&frame_to_ppm(nes.video_frame()));
149 let changed_all = changed_pixels(&prev, &frame);
150 let changed_top_hud = changed_pixels_region(&prev, &frame, 0, 48);
151 let changed_bottom_hud = changed_pixels_region(&prev, &frame, 208, 240);
152 let changed_gameplay = changed_pixels_region(&prev, &frame, 48, 208);
153 let debug = nes.debug_snapshot();
154
155 if hash == prev_hash {
156 same_hash_run += 1;
157 } else {
158 same_hash_run = 0;
159 }
160
161 if let Some((min_x, min_y, max_x, max_y)) = changed_bbox(&prev, &frame) {
162 println!(
163 "i={} frame={} hash=0x{:016X} changed_all={} changed_top_hud={} changed_bottom_hud={} changed_gameplay={} bbox=({},{})->({},{}) same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
164 i,
165 nes.frame_number(),
166 hash,
167 changed_all,
168 changed_top_hud,
169 changed_bottom_hud,
170 changed_gameplay,
171 min_x,
172 min_y,
173 max_x,
174 max_y,
175 same_hash_run,
176 debug.cpu.pc,
177 debug.ppu.scanline,
178 debug.ppu.in_vblank
179 );
180 } else {
181 println!(
182 "i={} frame={} hash=0x{:016X} changed_all=0 changed_top_hud=0 changed_bottom_hud=0 changed_gameplay=0 bbox=none same_hash_run={} pc={:04X} ppu_scanline={} in_vblank={}",
183 i,
184 nes.frame_number(),
185 hash,
186 same_hash_run,
187 debug.cpu.pc,
188 debug.ppu.scanline,
189 debug.ppu.in_vblank
190 );
191 }
192
193 if let Some(ref out_dir) = out_dir
194 && !out_dir.is_empty()
195 && (i <= 8 || same_hash_run >= 30 || i % 60 == 0)
196 {
197 let ppm = frame_to_ppm(nes.video_frame());
198 let output = Path::new(out_dir).join(format!("frame_{:04}.ppm", i));
199 if let Err(error) = std::fs::write(&output, ppm) {
200 eprintln!("failed to write {:?}: {}", output, error);
201 return ExitCode::from(1);
202 }
203 }
204
205 prev = frame;
206 prev_hash = hash;
207 }
208
209 ExitCode::SUCCESS
210}pub fn clear_audio_samples(&mut self)
pub fn set_apu_sample_rate(&mut self, sample_rate: u32)
pub fn set_apu_debug_mute_mask(&mut self, mask: u8)
pub fn apu_debug_mute_mask(&self) -> u8
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for NES
impl !Send for NES
impl !Sync for NES
impl !UnwindSafe for NES
impl Freeze for NES
impl Unpin for NES
impl UnsafeUnpin for NES
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more