1use alloc::boxed::Box;
2use alloc::vec;
3use alloc::vec::Vec;
4use gte_w65c02s::{System, W65C02S};
5use log::{debug, error, info, warn};
6use gte_w65c02s::State::AwaitingInterrupt;
7use core::fmt::{Debug, Formatter};
8use bytemuck::bytes_of;
9use heapless::{FnvIndexMap};
10use rtrb::PushError;
11use gte_acp::audio_output::GameTankAudio;
12use crate::blitter::Blitter;
13use crate::cartridges::CartridgeType;
14use crate::emulator::PlayState::{Paused, Playing, WasmInit};
15use crate::gametank_bus::{CpuBus};
16use gte_acp::AcpBus;
17use crate::inputs::{ControllerButton, InputCommand, KeyState};
18use crate::inputs::ControllerButton::{Down, Left, Right, Start, Up, A, B, C};
19use crate::inputs::InputCommand::{Controller1, Controller2, HardReset, PlayPause, SoftReset};
20use crate::inputs::KeyState::JustReleased;
21
22pub const WIDTH: u32 = 128;
23pub const HEIGHT: u32 = 128;
24
25#[derive(Copy, Clone, Debug, PartialEq)]
26pub enum PlayState {
27 WasmInit,
28 Paused,
29 Playing,
30}
31
32pub trait TimeDaemon {
33 fn get_now_ms(&self) -> f64;
34}
35
36pub struct Emulator<Clock: TimeDaemon> {
37 pub cpu_bus: CpuBus,
38 pub acp_bus: AcpBus,
39 pub cpu: W65C02S,
40 pub acp: W65C02S,
41
42 pub blitter: Blitter,
43
44 pub clock_cycles_to_vblank: i32,
45
46 pub last_emu_tick: f64,
47 pub cpu_ns_per_cycle: f64,
48 pub cpu_frequency_hz: f64,
49 pub last_render_time: f64,
50 pub audio_out: Option<GameTankAudio>,
51 pub target_sample_rate: f64,
52 pub play_state: PlayState,
53 pub wait_counter: u64,
54
55 pub input_state: FnvIndexMap<InputCommand, KeyState, 32>, pub clock: Clock,
58}
59
60impl <Clock: TimeDaemon> Emulator<Clock> {
61 pub fn load_rom(&mut self, bytes: &[u8]) {
62 warn!("loading new rom from memory, size: {}", bytes.len());
63 self.cpu_bus.cartridge = CartridgeType::from_slice(bytes);
64 warn!(" - cartridge loaded from memory");
65 self.cpu.reset();
66 warn!(" - cpu reset");
67 self.acp.reset();
68 warn!(" - acp reset");
69 self.blitter.clear_irq_trigger();
70 warn!(" - blitter irq cleared");
71 }
72}
73
74impl <Clock: TimeDaemon> Debug for Emulator<Clock> {
75 fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
76 f.debug_struct("Emulator")
77 .field("cpu_bus", &self.cpu_bus)
78 .field("acp_bus", &self.acp_bus)
79 .field("cpu", &self.cpu)
80 .field("acp", &self.acp)
81 .field("blitter", &self.blitter)
82 .field("clock_cycles_to_vblank", &self.clock_cycles_to_vblank)
83 .field("last_emu_tick", &self.last_emu_tick);
84
85 Ok(())
86 }}
87
88
89impl <Clock: TimeDaemon> Emulator<Clock> {
90 pub fn wasm_init(&mut self) {
91 if self.play_state == WasmInit {
92 self.play_state = Playing;
93 self.last_emu_tick = self.clock.get_now_ms();
94 self.last_render_time = self.clock.get_now_ms();
95 }
96 }
97
98 pub fn init(clock: Clock, target_sample_rate: f64) -> Self {
99 let play_state = WasmInit;
100
101 let mut bus = CpuBus::default();
102 let mut cpu = W65C02S::new();
103 cpu.step(&mut bus); let acp = W65C02S::new();
105
106 let blitter = Blitter::default();
107
108 let last_cpu_tick_ms = clock.get_now_ms();
109 let cpu_frequency_hz = 3_579_545.0; let cpu_ns_per_cycle = 1_000_000_000.0 / cpu_frequency_hz; let last_render_time = last_cpu_tick_ms;
113
114 Emulator {
115 play_state,
116 cpu_bus: bus,
117 acp_bus: AcpBus::default(),
118 cpu,
119 acp,
120 blitter,
121
122 clock_cycles_to_vblank: 59659,
123 last_emu_tick: last_cpu_tick_ms,
124 cpu_frequency_hz,
125 cpu_ns_per_cycle,
126 last_render_time,
127 audio_out: None,
128 target_sample_rate,
129 wait_counter: 0,
130 input_state: Default::default(),
131 clock,
132 }
133 }
134
135 pub fn process_cycles(&mut self, is_web: bool) {
136 self.process_inputs();
137
138 if self.play_state != Playing {
139 return
140 }
141
142 let now_ms = self.clock.get_now_ms();
143 let mut elapsed_ms = now_ms - self.last_emu_tick;
144
145 if elapsed_ms > 33.0 {
146 warn!("emulator took more than 33ms to process cycles");
147 elapsed_ms = 16.667;
148 }
149
150 let elapsed_ns = elapsed_ms * 1000000.0;
151 let mut remaining_cycles: i32 = (elapsed_ns / self.cpu_ns_per_cycle) as i32;
152
153 let mut acp_cycle_accumulator = 0;
154
155 while remaining_cycles > 0 {
156 if self.cpu.get_state() == AwaitingInterrupt {
157 self.wait_counter += 1;
158 } else if self.wait_counter > 0 {
160 debug!("waited {} cycles", self.wait_counter);
161 self.wait_counter = 0;
162 }
163
164 let cpu_cycles = self.cpu.step(&mut self.cpu_bus);
165
166 remaining_cycles -= cpu_cycles;
167
168 acp_cycle_accumulator += cpu_cycles * 4;
169
170 if self.cpu_bus.system_control.acp_enabled() {
172 self.run_acp(&mut acp_cycle_accumulator);
173 }
174
175 for _ in 0..cpu_cycles {
177 self.blitter.cycle(&mut self.cpu_bus);
178 }
179 let blit_irq = self.blitter.irq_trigger;
182 if blit_irq {
183 debug!("blit irq");
184 }
185 self.cpu.set_irq(blit_irq);
186
187 self.clock_cycles_to_vblank -= cpu_cycles;
188 if self.clock_cycles_to_vblank <= 0 {
189 self.vblank();
190 }
191 }
192
193 self.last_emu_tick = now_ms;
194
195 if !is_web && (now_ms - self.last_render_time) >= 16.67 {
196 debug!("time since last render: {}", now_ms - self.last_render_time);
197 self.last_render_time = now_ms;
198 }
199 }
200
201 fn run_acp(&mut self, acp_cycle_accumulator: &mut i32) {
202 if self.cpu_bus.system_control.clear_acp_reset() {
203 self.acp.reset();
204 }
205
206 if self.cpu_bus.system_control.clear_acp_nmi() {
207 self.acp.set_nmi(true);
208 }
209
210 while *acp_cycle_accumulator > 0 {
211 let acp_cycles = self.acp.step(&mut self.acp_bus);
212 *acp_cycle_accumulator -= acp_cycles;
213 self.acp_bus.irq_counter -= acp_cycles;
214
215 self.acp.set_irq(false);
217 self.acp.set_nmi(false);
218
219 if self.acp_bus.irq_counter <= 0 {
220 self.acp_bus.irq_counter = self.cpu_bus.system_control.sample_rate() as i32 * 4;
221 self.acp.set_irq(true);
222
223 let sample_rate = self.cpu_frequency_hz / self.cpu_bus.system_control.sample_rate() as f64;
224 if self.audio_out.as_ref().map_or(true, |gta| gta.sample_rate != sample_rate) {
226 warn!("recreated audio stream with new sample rate: {:.3}Hz ({})", sample_rate, self.cpu_bus.system_control.sample_rate());
227 self.audio_out = Some(GameTankAudio::new(sample_rate, self.target_sample_rate));
228 }
229
230 if let Some(audio) = &mut self.audio_out {
231 let next_sample_u8 = self.acp_bus.sample;
232 if let Err(e) = audio.producer.push(next_sample_u8) {
233 error!("not enough slots in audio producer: {e}");
234 }
235 }
236
237 if let Some(audio) = &mut self.audio_out {
238 audio.convert_to_output_buffers();
239 }
241 }
242 }
243 }
244
245 fn vblank(&mut self) {
246 self.clock_cycles_to_vblank += 59659;
247
248 if self.cpu_bus.vblank_nmi_enabled() {
249 self.cpu.set_nmi(true);
250 debug!("vblanked");
251 }
252 }
253
254 pub fn set_input_state(&mut self, input_command: InputCommand, state: KeyState) {
255 self.input_state.insert(input_command, state).expect("shit's full dog ://");
256 }
257
258 fn process_inputs(&mut self) {
259 let keys: Vec<_> = self.input_state.keys().cloned().collect(); if keys.len() > 0 && self.play_state == WasmInit {
262 self.play_state = Playing;
263 }
264
265 for key in &keys {
266 match key {
267 Controller1(button) => { self.set_gamepad_input(0, &key, &button); }
268 Controller2(button) => { self.set_gamepad_input(1, &key, &button); }
269 PlayPause => {
270 if self.input_state[key] == JustReleased {
271 match self.play_state {
272 Paused => { self.play_state = Playing; }
273 Playing => { self.play_state = Paused; }
274 WasmInit => { self.play_state = Playing; }
275 }
276 }
277 }
278 SoftReset => {
279 self.cpu.reset();
280 }
281 HardReset => {
282 let cart = self.cpu_bus.cartridge.clone();
284 self.cpu_bus = CpuBus::default();
285 self.cpu_bus.cartridge = cart;
286 self.cpu = W65C02S::new();
287 self.cpu.step(&mut self.cpu_bus); self.acp = W65C02S::new();
289 self.blitter = Blitter::default();
290 }
291 }
292 self.input_state.insert(*key, self.input_state[key].update()).expect("shit's full dog ://");
293 }
294 }
295 fn set_gamepad_input(&mut self, gamepad: usize, key: &InputCommand, button: &ControllerButton) {
296 let gamepad = &mut self.cpu_bus.system_control.gamepads[gamepad];
297 match button {
298 Up => { gamepad.up = self.input_state[&key].is_pressed(); }
299 Down => { gamepad.down = self.input_state[&key].is_pressed(); }
300 Left => { gamepad.left = self.input_state[&key].is_pressed(); }
301 Right => { gamepad.right = self.input_state[&key].is_pressed(); }
302 B => { gamepad.b = self.input_state[&key].is_pressed(); }
303 A => { gamepad.a = self.input_state[&key].is_pressed(); }
304 Start => { gamepad.start = self.input_state[&key].is_pressed(); }
305 C => { gamepad.c = self.input_state[&key].is_pressed(); }
306 }
307 }
308}