diff options
author | Astatin <[email protected]> | 2024-09-14 23:49:32 +0900 |
---|---|---|
committer | Astatin <astatin@redacted> | 2024-09-14 23:49:32 +0900 |
commit | 7101d14f3bcc0af29b8d51b1f5d58689fee1a571 (patch) | |
tree | f0d24574e6ec3153a3f4a5969233946be43719a6 | |
parent | 249921a2094d172e94543446e2af11dcba5075e8 (diff) |
Add keyboard support & start supporting serial communication (but tetris doesn't work in 2p)
-rw-r--r-- | src/audio.rs | 35 | ||||
-rw-r--r-- | src/display.rs | 5 | ||||
-rw-r--r-- | src/gamepad.rs | 77 | ||||
-rw-r--r-- | src/interrupts_timers.rs | 4 | ||||
-rw-r--r-- | src/io.rs | 20 | ||||
-rw-r--r-- | src/main.rs | 83 | ||||
-rw-r--r-- | src/opcodes.rs | 1276 | ||||
-rw-r--r-- | src/serial.rs | 136 | ||||
-rw-r--r-- | src/state.rs | 44 |
9 files changed, 993 insertions, 687 deletions
diff --git a/src/audio.rs b/src/audio.rs index 07f7c85..0a152a6 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -40,7 +40,38 @@ const SQUARE_WAVE_PATTERN_DUTY_3: [u8; 32] = [ */ const NOISE_WAVE: [u16; 1023] = [ - 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1 + 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, + 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, + 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, + 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, + 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, + 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, + 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, + 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, + 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, + 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, + 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, + 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, + 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, + 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, + 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, + 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, + 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, ]; const SQUARE_WAVE_PATTERNS: [[u8; 32]; 4] = [ @@ -256,7 +287,7 @@ impl Iterator for NoiseWave { for n in 0..SAMPLE_AVERAGING { if self.num_sample as i32 + n as i32 - SAMPLE_AVERAGING as i32 >= 0 { let ns = ((262144. / ((clock_divider) * (2 << self.clock_shift) as f32)) / 32768.) - * (self.num_sample + n - (SAMPLE_AVERAGING / 2)) as f32; + * (self.num_sample + n - (SAMPLE_AVERAGING / 2)) as f32; let i = (ns as f32 * (32768 as f32 / SAMPLE_RATE as f32)) as usize; diff --git a/src/display.rs b/src/display.rs index 8db432f..7abf5b3 100644 --- a/src/display.rs +++ b/src/display.rs @@ -29,7 +29,7 @@ pub enum DisplayInterrupt { #[derive(Debug)] pub struct Display { - window: Window, + pub window: Window, framebuffer: [u32; 160 * 144], bg_buffer: [u8; 160 * 144], @@ -64,7 +64,8 @@ impl Display { Self { window: Window::new( "Gameboy Emulator", - 512, 461, + 512, + 461, /* 1200, 1080, */ WindowOptions::default(), ) diff --git a/src/gamepad.rs b/src/gamepad.rs index 8f05333..4ea82f7 100644 --- a/src/gamepad.rs +++ b/src/gamepad.rs @@ -1,11 +1,18 @@ -use crate::state::GBState; -use gilrs::{Button, GamepadId, Gilrs, Event}; +use crate::display::Display; +use gilrs::{Button, GamepadId, Gilrs}; +use minifb::Key; pub struct Gamepad { gilrs: Gilrs, gamepad_id: Option<GamepadId>, } +pub trait Input { + fn update_events(&mut self); + fn get_action_gamepad_reg(&self) -> u8; + fn get_direction_gamepad_reg(&self) -> u8; +} + impl Gamepad { pub fn new() -> Self { let mut gilrs = Gilrs::new().unwrap(); @@ -18,24 +25,24 @@ impl Gamepad { None }; - Self { gilrs, gamepad_id } } - pub fn update_events(&mut self) { - while let Some(_) = self.gilrs.next_event() {} - } - - pub fn check_special_actions(&self, state: &mut GBState) { + pub fn check_special_actions(&self, is_debug: &mut bool) { if let Some(gamepad_id) = self.gamepad_id { if let Some(gamepad) = self.gilrs.connected_gamepad(gamepad_id) { - state.is_debug = gamepad.is_pressed(Button::West); + *is_debug = gamepad.is_pressed(Button::West); } } } +} - pub fn get_action_gamepad_reg(&self) -> u8 { +impl Input for Gamepad { + fn update_events(&mut self) { + while let Some(_) = self.gilrs.next_event() {} + } + fn get_action_gamepad_reg(&self) -> u8 { let mut res = 0xf; if let Some(gamepad_id) = self.gamepad_id { @@ -61,7 +68,7 @@ impl Gamepad { res } - pub fn get_direction_gamepad_reg(&self) -> u8 { + fn get_direction_gamepad_reg(&self) -> u8 { let mut res = 0xf; if let Some(gamepad_id) = self.gamepad_id { @@ -87,3 +94,51 @@ impl Gamepad { res } } + +impl Input for Display { + fn update_events(&mut self) {} + + fn get_action_gamepad_reg(&self) -> u8 { + let mut res = 0xf; + + if self.window.is_key_down(Key::A) { + res &= 0b1110; + } + + if self.window.is_key_down(Key::B) { + res &= 0b1101; + } + + if self.window.is_key_down(Key::Backspace) { + res &= 0b1011; + } + + if self.window.is_key_down(Key::Enter) { + res &= 0b0111; + } + + res + } + + fn get_direction_gamepad_reg(&self) -> u8 { + let mut res = 0xf; + + if self.window.is_key_down(Key::Right) { + res &= 0b1110; + } + + if self.window.is_key_down(Key::Left) { + res &= 0b1101; + } + + if self.window.is_key_down(Key::Up) { + res &= 0b1011; + } + + if self.window.is_key_down(Key::Down) { + res &= 0b0111; + } + + res + } +} diff --git a/src/interrupts_timers.rs b/src/interrupts_timers.rs index c339ce8..4ba07be 100644 --- a/src/interrupts_timers.rs +++ b/src/interrupts_timers.rs @@ -1,5 +1,5 @@ use crate::display::DisplayInterrupt; -use crate::opcodes; +use crate::serial::Serial; use crate::state::{GBState, MemError}; const TIMA_TIMER_SPEEDS: [u64; 4] = [1024, 16, 64, 256]; @@ -10,7 +10,7 @@ impl GBState { let interrupts = self.mem.io[0x0f] & self.mem.interrupts_register & 0b11111; for i in 0..5 { if interrupts & (1 << i) != 0 { - opcodes::push(self, self.cpu.pc)?; + self.push(self.cpu.pc)?; self.mem.ime = false; self.cpu.pc = 0x40 + (i << 3); @@ -1,3 +1,4 @@ +use crate::serial::Serial; use crate::state::{MemError, Memory}; impl Memory { @@ -13,6 +14,8 @@ impl Memory { (self.joypad_reg & 0xf) | 0b11100000 } } + 0x01 => self.serial_data, + 0x02 => self.serial_control, 0x04 => self.div, 0x40 => self.display.lcdc, 0x42 => self.display.viewport_y, @@ -57,7 +60,7 @@ impl Memory { } } _ => { - // println!("Reading from 0xff{:02x} not implemented yet", addr); + println!("Reading from 0xff{:02x} not implemented yet", addr); self.io[addr as usize] } } @@ -68,6 +71,19 @@ impl Memory { 0x00 => { self.joypad_is_action = !value & 0b00100000 != 0; } + 0x01 => { + self.serial_data = value; + } + 0x02 => { + if value & 0x01 != 0 { + self.serial.set_clock_master(true); + println!("Set as master"); + } else if value & 0x01 != 0 { + self.serial.set_clock_master(false); + println!("Set as slave"); + } + self.serial_control = value; + } 0x04 => { self.div = 0; } @@ -236,7 +252,7 @@ impl Memory { } } _ => { - if addr >= 0x4d { + if addr != 0x25 && addr != 0x24 && addr != 0x26 && addr < 0x30 && addr > 0x3f { println!( "Writing to 0xff{:02x} not implemented yet ({:02x})", addr, value diff --git a/src/main.rs b/src/main.rs index f0a7361..b057486 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,38 +5,15 @@ pub mod gamepad; pub mod interrupts_timers; pub mod io; pub mod opcodes; +pub mod serial; pub mod state; -use crate::gamepad::Gamepad; -use crate::state::{GBState, MemError}; +use crate::gamepad::{Gamepad, Input}; +use crate::state::GBState; use clap::Parser; use std::time::SystemTime; use std::{thread, time}; -pub fn exec_opcode(state: &mut GBState) -> Result<u64, MemError> { - let opcode = state.mem.r(state.cpu.pc)?; - - if state.is_debug { - println!( - "{:02x}:{:04x} = {:02x} (IME: {})", - state.mem.rom_bank, state.cpu.pc, opcode, state.mem.ime - ); - } - - state.cpu.pc += 1; - - let n1 = (opcode >> 3) & 0b111; - let n2 = opcode & 0b111; - - match opcode >> 6 { - 0b00 => opcodes::op00(state, n1, n2), - 0b01 => opcodes::op01(state, n1, n2), - 0b10 => opcodes::op10(state, n1, n2), - 0b11 => opcodes::op11(state, n1, n2), - _ => panic!(), - } -} - #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Cli { @@ -45,7 +22,16 @@ struct Cli { /// Setting this saves battery by using thread::sleep instead of spin_sleeping. It can result in lag and inconsistent timing. #[arg(long)] - thread_sleep: bool, + loop_lock_timing: bool, + + #[arg(long)] + fifo_input: Option<String>, + + #[arg(long)] + fifo_output: Option<String>, + + #[arg(short, long, default_value_t = false)] + keyboard: bool, #[arg(short, long, default_value_t = 1.0)] speed: f32, @@ -56,11 +42,17 @@ fn main() { println!("Initializing Gamepad..."); - let mut gamepad = Gamepad::new(); - println!("Starting {:?}...", &cli.rom); - let mut state = GBState::new(); + let mut state = match (cli.fifo_input, cli.fifo_output) { + (Some(fifo_input), Some(fifo_output)) => { + GBState::new(Box::new(serial::FIFOSerial::new(fifo_input, fifo_output))) + } + (None, None) => GBState::new(Box::new(serial::UnconnectedSerial {})), + _ => panic!("If using fifo serial, both input and output should be set"), + }; + + let mut gamepad = Gamepad::new(); let save_file = format!("{}.sav", &cli.rom); @@ -87,7 +79,7 @@ fn main() { } was_previously_halted = state.mem.halt; let c = if !state.mem.halt { - exec_opcode(&mut state).unwrap() + state.exec_opcode().unwrap() } else { halt_time += 4; 4 @@ -97,18 +89,27 @@ fn main() { state.tima_timer(c); state.update_display_interrupts(c); state.check_interrupts().unwrap(); + state.mem.update_serial(); nanos_sleep += c as i128 * (consts::CPU_CYCLE_LENGTH_NANOS as f32 / cli.speed) as i128; if nanos_sleep > 0 { - gamepad.update_events(); + let (action_button_reg, direction_button_reg) = if cli.keyboard { + ( + state.mem.display.get_action_gamepad_reg(), + state.mem.display.get_direction_gamepad_reg(), + ) + } else { + gamepad.update_events(); - let action_button_reg = gamepad.get_action_gamepad_reg(); - let direction_button_reg = gamepad.get_direction_gamepad_reg(); - gamepad.check_special_actions(&mut state); + ( + gamepad.get_action_gamepad_reg(), + gamepad.get_direction_gamepad_reg(), + ) + }; + // gamepad.check_special_actions(&mut state.is_debug); if state.mem.joypad_is_action - && (action_button_reg & (state.mem.joypad_reg >> 4)) - != (state.mem.joypad_reg >> 4) + && (action_button_reg & (state.mem.joypad_reg >> 4)) != (state.mem.joypad_reg >> 4) || (!state.mem.joypad_is_action && (direction_button_reg & state.mem.joypad_reg & 0b1111) != (state.mem.joypad_reg & 0b1111)) @@ -118,16 +119,18 @@ fn main() { state.mem.joypad_reg = direction_button_reg | (action_button_reg << 4); - if cli.thread_sleep { + if !cli.loop_lock_timing { thread::sleep(time::Duration::from_nanos(nanos_sleep as u64 / 10)); } else { while SystemTime::now().duration_since(now).unwrap().as_nanos() < nanos_sleep as u128 - {} + { + for _ in 0..100_000_000 {} + } } nanos_sleep = - nanos_sleep - SystemTime::now().duration_since(now).unwrap().as_nanos() as i128; + nanos_sleep - SystemTime::now().duration_since(now).unwrap().as_nanos() as i128; now = SystemTime::now(); if last_ram_bank_enabled && !state.mem.ram_bank_enabled { diff --git a/src/opcodes.rs b/src/opcodes.rs index f238239..2502782 100644 --- a/src/opcodes.rs +++ b/src/opcodes.rs @@ -1,825 +1,851 @@ +use crate::serial::Serial; use crate::state::{flag, reg, GBState, MemError}; // The opcodes functions are returning the number of cycles used. -pub fn r_16b_from_pc(state: &mut GBState) -> Result<u16, MemError> { - let p: u16 = state.mem.r(state.cpu.pc)? as u16 | ((state.mem.r(state.cpu.pc + 1)? as u16) << 8); - state.cpu.pc += 2; +impl GBState { + fn r_16b_from_pc(&mut self) -> Result<u16, MemError> { + let p: u16 = self.mem.r(self.cpu.pc)? as u16 | ((self.mem.r(self.cpu.pc + 1)? as u16) << 8); + self.cpu.pc += 2; - Ok(p) -} + Ok(p) + } -pub fn r_8b_from_pc(state: &mut GBState) -> Result<u8, MemError> { - let p = state.mem.r(state.cpu.pc)?; - state.cpu.pc += 1; + fn r_8b_from_pc(&mut self) -> Result<u8, MemError> { + let p = self.mem.r(self.cpu.pc)?; + self.cpu.pc += 1; - Ok(p) -} + Ok(p) + } -pub fn ldrr(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> { - // Load a register into another register - // LD r, r - state.w_reg(n1, state.r_reg(n2)?) -} + fn ldrr(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { + // Load a register into another register + // LD r, r + self.w_reg(n1, self.r_reg(n2)?) + } -pub fn ldr8(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - // Load an raw 8b value into a register - let p = r_8b_from_pc(state)?; + fn ldr8(&mut self, n1: u8) -> Result<u64, MemError> { + // Load an raw 8b value into a register + let p = self.r_8b_from_pc()?; - state.w_reg(n1, p)?; - Ok(8) -} + self.w_reg(n1, p)?; + Ok(8) + } -pub fn ldrr16(state: &mut GBState, rr: u8, x: u16) { - // Load a raw 16b value into a register - state.cpu.w16(rr, x); -} + fn ldrr16(&mut self, rr: u8, x: u16) { + // Load a raw 16b value into a register + self.cpu.w16(rr, x); + } -pub fn ldnnsp(state: &mut GBState) -> Result<u64, MemError> { - // Load SP into an arbitrary position in memory - let p = r_16b_from_pc(state)?; + fn ldnnsp(&mut self) -> Result<u64, MemError> { + // Load SP into an arbitrary position in memory + let p = self.r_16b_from_pc()?; - state.mem.w(p, (state.cpu.sp & 0xff) as u8)?; - state.mem.w(p + 1, (state.cpu.sp >> 8) as u8)?; - Ok(20) -} + self.mem.w(p, (self.cpu.sp & 0xff) as u8)?; + self.mem.w(p + 1, (self.cpu.sp >> 8) as u8)?; + Ok(20) + } -pub fn ldsphl(state: &mut GBState) -> u64 { - state.cpu.sp = state.cpu.r16(reg::HL); - 8 -} + fn ldsphl(&mut self) -> u64 { + self.cpu.sp = self.cpu.r16(reg::HL); + 8 + } -pub fn ldnna(state: &mut GBState, nn: u16) -> Result<(), MemError> { - // Load A into an arbitrary position in memory - state.mem.w(nn, state.cpu.r[reg::A as usize])?; - Ok(()) -} + fn ldnna(&mut self, nn: u16) -> Result<(), MemError> { + // Load A into an arbitrary position in memory + self.mem.w(nn, self.cpu.r[reg::A as usize])?; + Ok(()) + } -pub fn ldann(state: &mut GBState, nn: u16) -> Result<(), MemError> { - // Load A from an arbitrary position in memory - state.cpu.r[reg::A as usize] = state.mem.r(nn)?; - Ok(()) -} + fn ldann(&mut self, nn: u16) -> Result<(), MemError> { + // Load A from an arbitrary position in memory + self.cpu.r[reg::A as usize] = self.mem.r(nn)?; + Ok(()) + } -pub fn push(state: &mut GBState, x: u16) -> Result<(), MemError> { - state.cpu.sp -= 2; + pub fn push(&mut self, x: u16) -> Result<(), MemError> { + self.cpu.sp -= 2; - state.mem.w(state.cpu.sp, (x & 0xff) as u8)?; + self.mem.w(self.cpu.sp, (x & 0xff) as u8)?; - state.mem.w(state.cpu.sp + 1, (x >> 8) as u8)?; + self.mem.w(self.cpu.sp + 1, (x >> 8) as u8)?; - Ok(()) -} + Ok(()) + } -pub fn pop(state: &mut GBState) -> Result<u16, MemError> { - let res = state.mem.r(state.cpu.sp)? as u16 | ((state.mem.r(state.cpu.sp + 1)? as u16) << 8); + fn pop(&mut self) -> Result<u16, MemError> { + let res = self.mem.r(self.cpu.sp)? as u16 | ((self.mem.r(self.cpu.sp + 1)? as u16) << 8); - state.cpu.sp += 2; + self.cpu.sp += 2; - Ok(res) -} + Ok(res) + } -pub fn jr8(state: &mut GBState) -> Result<u64, MemError> { - // Unconditional relative jump - let p = r_8b_from_pc(state)?; + fn jr8(&mut self) -> Result<u64, MemError> { + // Unconditional relative jump + let p = self.r_8b_from_pc()?; - state.cpu.pc = (state.cpu.pc as i16 + p as i8 as i16) as u16; + self.cpu.pc = (self.cpu.pc as i16 + p as i8 as i16) as u16; - Ok(12) -} + Ok(12) + } + + fn jrcc8(&mut self, n1: u8) -> Result<u64, MemError> { + // Conditional relative jump + let p = self.r_8b_from_pc()?; + let mut cycles = 8; -pub fn jrcc8(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - // Conditional relative jump - let p = r_8b_from_pc(state)?; - let mut cycles = 8; + if self.cpu.check_flag(n1 & 0b11) { + cycles += 4; + self.cpu.pc = (self.cpu.pc as i16 + p as i8 as i16) as u16; + } - if state.cpu.check_flag(n1 & 0b11) { - cycles += 4; - state.cpu.pc = (state.cpu.pc as i16 + p as i8 as i16) as u16; + Ok(cycles) } - Ok(cycles) -} + fn jp16(&mut self) -> Result<u64, MemError> { + // Unconditional absolute jump + let p = self.r_16b_from_pc()?; -pub fn jp16(state: &mut GBState) -> Result<u64, MemError> { - // Unconditional absolute jump - let p = r_16b_from_pc(state)?; + self.cpu.pc = p; - state.cpu.pc = p; + Ok(16) + } - Ok(16) -} + fn jphl(&mut self) -> u64 { + // Unconditional absolute jump to HL + self.cpu.pc = self.cpu.r16(reg::HL); -pub fn jphl(state: &mut GBState) -> u64 { - // Unconditional absolute jump to HL - state.cpu.pc = state.cpu.r16(reg::HL); + 4 + } - 4 -} + fn jpcc16(&mut self, n1: u8) -> Result<u64, MemError> { + // Conditional absolute jump + let p = self.r_16b_from_pc()?; + let mut cycles = 8; -pub fn jpcc16(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - // Conditional absolute jump - let p = r_16b_from_pc(state)?; - let mut cycles = 8; + if self.cpu.check_flag(n1 & 0b11) { + cycles += 4; + self.cpu.pc = p; + } - if state.cpu.check_flag(n1 & 0b11) { - cycles += 4; - state.cpu.pc = p; + Ok(cycles) } - Ok(cycles) -} + fn call(&mut self) -> Result<u64, MemError> { + // Unconditional function call + let p = self.r_16b_from_pc()?; -pub fn call(state: &mut GBState) -> Result<u64, MemError> { - // Unconditional function call - let p = r_16b_from_pc(state)?; + self.push(self.cpu.pc)?; + self.cpu.pc = p; - push(state, state.cpu.pc)?; - state.cpu.pc = p; + Ok(24) + } - Ok(24) -} + fn callcc(&mut self, n1: u8) -> Result<u64, MemError> { + // Conditional function call + let p = self.r_16b_from_pc()?; + let mut cycles = 12; -pub fn callcc(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - // Conditional function call - let p = r_16b_from_pc(state)?; - let mut cycles = 12; + if self.cpu.check_flag(n1 & 0b11) { + cycles += 12; + self.push(self.cpu.pc)?; + self.cpu.pc = p; + } - if state.cpu.check_flag(n1 & 0b11) { - cycles += 12; - push(state, state.cpu.pc)?; - state.cpu.pc = p; + Ok(cycles) } - Ok(cycles) -} + fn ret(&mut self) -> Result<u64, MemError> { + let res = self.pop()?; + + if res == 0 { + println!("DEBUG: {:?}", self.cpu); + panic!("RET to start"); + } -pub fn ret(state: &mut GBState) -> Result<u64, MemError> { - let res = pop(state)?; + self.cpu.pc = res; - if res == 0 { - println!("DEBUG: {:?}", state.cpu); - panic!("RET to start"); + Ok(16) } - state.cpu.pc = res; - - Ok(16) -} + fn retcc(&mut self, n1: u8) -> Result<u64, MemError> { + let mut cycles = 8; + if self.cpu.check_flag(n1 & 0b11) { + cycles += 12; + self.cpu.pc = self.pop()?; + } -pub fn retcc(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - let mut cycles = 8; - if state.cpu.check_flag(n1 & 0b11) { - cycles += 12; - state.cpu.pc = pop(state)?; + Ok(cycles) } - Ok(cycles) -} + fn ld00a(&mut self, n1: u8) -> Result<u64, MemError> { + // Load register A into or from memory pointed by rr (BC, DE or HL(+/-)) + // LD (rr), A + // LD A, (rr) + let ptr_reg = match n1 & 0b110 { + 0b000 => reg::B, + 0b010 => reg::C, + _ => reg::HL, + }; -pub fn ld00a(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - // Load register A into or from memory pointed by rr (BC, DE or HL(+/-)) - // LD (rr), A - // LD A, (rr) - let ptr_reg = match n1 & 0b110 { - 0b000 => reg::B, - 0b010 => reg::C, - _ => reg::HL, - }; + if n1 & 0b001 == 1 { + self.cpu.r[reg::A as usize] = self.mem.r(self.cpu.r16(ptr_reg))?; + } else { + self.mem + .w(self.cpu.r16(ptr_reg), self.cpu.r[reg::A as usize])?; + } - if n1 & 0b001 == 1 { - state.cpu.r[reg::A as usize] = state.mem.r(state.cpu.r16(ptr_reg))?; - } else { - state - .mem - .w(state.cpu.r16(ptr_reg), state.cpu.r[reg::A as usize])?; - } + if n1 & 0b110 == 0b100 { + self.cpu.w16(reg::HL, self.cpu.r16(reg::HL) + 1); // (HL+) + } - if n1 & 0b110 == 0b100 { - state.cpu.w16(reg::HL, state.cpu.r16(reg::HL) + 1); // (HL+) - } + if n1 & 0b110 == 0b110 { + self.cpu.w16(reg::HL, self.cpu.r16(reg::HL) - 1); // (HL-) + } - if n1 & 0b110 == 0b110 { - state.cpu.w16(reg::HL, state.cpu.r16(reg::HL) - 1); // (HL-) + Ok(8) } - Ok(8) -} + fn inc8(&mut self, n1: u8) -> Result<u64, MemError> { + // Increment 8 bit register + self.w_reg(n1, self.r_reg(n1)? + 1)?; + self.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF | flag::H); + if self.r_reg(n1)? == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } -pub fn inc8(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - // Increment 8 bit register - state.w_reg(n1, state.r_reg(n1)? + 1)?; - state.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF | flag::H); - if state.r_reg(n1)? == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; - } + if self.r_reg(n1)? & 0xf == 0x0 { + self.cpu.r[reg::F as usize] |= flag::H; + } - if state.r_reg(n1)? & 0xf == 0x0 { - state.cpu.r[reg::F as usize] |= flag::H; + Ok(4) } - Ok(4) -} + fn dec8(&mut self, n1: u8) -> Result<u64, MemError> { + // Decrement 8 bit register + self.w_reg(n1, self.r_reg(n1)? - 1)?; + self.cpu.r[reg::F as usize] |= flag::N; + + self.cpu.r[reg::F as usize] &= !(flag::ZF | flag::H); + if self.r_reg(n1)? == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } -pub fn dec8(state: &mut GBState, n1: u8) -> Result<u64, MemError> { - // Decrement 8 bit register - state.w_reg(n1, state.r_reg(n1)? - 1)?; - state.cpu.r[reg::F as usize] |= flag::N; + if self.r_reg(n1)? & 0xf == 0xf { + self.cpu.r[reg::F as usize] |= flag::H; + } - state.cpu.r[reg::F as usize] &= !(flag::ZF | flag::H); - if state.r_reg(n1)? == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + Ok(4) } - if state.r_reg(n1)? & 0xf == 0xf { - state.cpu.r[reg::F as usize] |= flag::H; + fn inc16(&mut self, rr: u8) -> u64 { + // Increment 16 bit register + self.cpu.w16(rr, self.cpu.r16(rr) + 1); + 8 } - Ok(4) -} + fn dec16(&mut self, rr: u8) -> u64 { + // Decrement 16 bit register + self.cpu.w16(rr, self.cpu.r16(rr) - 1); + 8 + } -pub fn inc16(state: &mut GBState, rr: u8) -> u64 { - // Increment 16 bit register - state.cpu.w16(rr, state.cpu.r16(rr) + 1); - 8 -} + fn ccf(&mut self) { + // Flip carry flag + self.cpu.r[reg::F as usize] = (self.cpu.r[reg::F as usize] & 0b10011111) ^ 0b00010000 + } -pub fn dec16(state: &mut GBState, rr: u8) -> u64 { - // Decrement 16 bit register - state.cpu.w16(rr, state.cpu.r16(rr) - 1); - 8 -} + fn scf(&mut self) { + // Set carry flag + self.cpu.r[reg::F as usize] = (self.cpu.r[reg::F as usize] & 0b10011111) | 0b00010000 + } -pub fn ccf(state: &mut GBState) { - // Flip carry flag - state.cpu.r[reg::F as usize] = (state.cpu.r[reg::F as usize] & 0b10011111) ^ 0b00010000 -} + fn daa(&mut self) { + // Decimal Adjust Accumulator + // Adjust the A register after a addition or substraction to keep valid BCD representation + let nibble_low = self.cpu.r[reg::A as usize] & 0b1111; + let sub_flag = (self.cpu.r[reg::F as usize] & flag::N) != 0; + let half_carry_flag = (self.cpu.r[reg::F as usize] & flag::H) != 0; -pub fn scf(state: &mut GBState) { - // Set carry flag - state.cpu.r[reg::F as usize] = (state.cpu.r[reg::F as usize] & 0b10011111) | 0b00010000 -} + if (half_carry_flag || nibble_low > 9) && !sub_flag { + self.cpu.r[reg::A as usize] += 0x06; + } + if (half_carry_flag || nibble_low > 9) && sub_flag { + self.cpu.r[reg::A as usize] -= 0x06; + } -pub fn daa(state: &mut GBState) { - // Decimal Adjust Accumulator - // Adjust the A register after a addition or substraction to keep valid BCD representation - let nibble_low = state.cpu.r[reg::A as usize] & 0b1111; - let sub_flag = (state.cpu.r[reg::F as usize] & flag::N) != 0; - let half_carry_flag = (state.cpu.r[reg::F as usize] & flag::H) != 0; + let nibble_high = self.cpu.r[reg::A as usize] >> 4; - if (half_carry_flag || nibble_low > 9) && !sub_flag { - state.cpu.r[reg::A as usize] += 0x06; - } - if (half_carry_flag || nibble_low > 9) && sub_flag { - state.cpu.r[reg::A as usize] -= 0x06; - } + self.cpu.r[reg::F as usize] &= !(flag::CY | flag::ZF); - let nibble_high = state.cpu.r[reg::A as usize] >> 4; + if nibble_high > 9 && !sub_flag { + self.cpu.r[reg::A as usize] += 0x60; + self.cpu.r[reg::F as usize] |= flag::CY; + } + if nibble_high > 9 && sub_flag { + self.cpu.r[reg::A as usize] -= 0x60; + self.cpu.r[reg::F as usize] |= flag::CY; + } - state.cpu.r[reg::F as usize] &= !(flag::CY | flag::ZF); + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } - if nibble_high > 9 && !sub_flag { - state.cpu.r[reg::A as usize] += 0x60; - state.cpu.r[reg::F as usize] |= flag::CY; - } - if nibble_high > 9 && sub_flag { - state.cpu.r[reg::A as usize] -= 0x60; - state.cpu.r[reg::F as usize] |= flag::CY; + self.cpu.r[reg::F as usize] &= !flag::H; } - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + fn cpl(&mut self) { + // Flip all bits in register A + self.cpu.r[reg::F as usize] = self.cpu.r[reg::F as usize] | flag::N | flag::H; + self.cpu.r[reg::A as usize] ^= 0xff; } - state.cpu.r[reg::F as usize] &= !flag::H; -} + fn addsp8(&mut self) -> Result<u64, MemError> { + let n = self.r_8b_from_pc()? as i8; -pub fn cpl(state: &mut GBState) { - // Flip all bits in register A - state.cpu.r[reg::F as usize] = state.cpu.r[reg::F as usize] | flag::N | flag::H; - state.cpu.r[reg::A as usize] ^= 0xff; -} - -pub fn addsp8(state: &mut GBState) -> Result<u64, MemError> { - let n = r_8b_from_pc(state)? as i8; + self.cpu.sp = (self.cpu.sp as i32 + n as i32) as u16; - state.cpu.sp = (state.cpu.sp as i32 + n as i32) as u16; + self.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY); - state.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY); + if (self.cpu.sp & 0xff) as i32 + n as i32 & !0xff != 0 { + self.cpu.r[reg::F as usize] |= flag::H; + } - if (state.cpu.sp & 0xff) as i32 + n as i32 & !0xff != 0 { - state.cpu.r[reg::F as usize] |= flag::H; + if (self.cpu.sp as i32 + n as i32) & !0xffff != 0 { + self.cpu.r[reg::F as usize] |= flag::CY; + } + Ok(16) } - if (state.cpu.sp as i32 + n as i32) & !0xffff != 0 { - state.cpu.r[reg::F as usize] |= flag::CY; - } - Ok(16) -} + fn add(&mut self, x: u8) { + // ADD a number to A and store the result in A + let res = x as u16 + self.cpu.r[reg::A as usize] as u16; -pub fn add(state: &mut GBState, x: u8) { - // ADD a number to A and store the result in A - let res = x as u16 + state.cpu.r[reg::A as usize] as u16; + self.cpu.r[reg::F as usize] = 0; - state.cpu.r[reg::F as usize] = 0; + if (x & 0xf) + (self.cpu.r[reg::A as usize] & 0xf) > 0xf { + self.cpu.r[reg::F as usize] |= flag::H; + } - if (x & 0xf) + (state.cpu.r[reg::A as usize] & 0xf) > 0xf { - state.cpu.r[reg::F as usize] |= flag::H; - } + if res > 0xff { + self.cpu.r[reg::F as usize] |= flag::CY; + } - if res > 0xff { - state.cpu.r[reg::F as usize] |= flag::CY; + self.cpu.r[reg::A as usize] = res as u8; + + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } - state.cpu.r[reg::A as usize] = res as u8; + fn addhlrr(&mut self, rr: u8) -> u64 { + let n = self.cpu.r16(rr); + let hl = self.cpu.r16(reg::HL); - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; - } -} + self.cpu.w16(reg::HL, (hl as i32 + n as i32) as u16); -pub fn addhlrr(state: &mut GBState, rr: u8) -> u64 { - let n = state.cpu.r16(rr); - let hl = state.cpu.r16(reg::HL); + self.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY); - state.cpu.w16(reg::HL, (hl as i32 + n as i32) as u16); + if (hl & 0xff) as i32 + n as i32 & !0xff != 0 { + self.cpu.r[reg::F as usize] |= flag::H; + } - state.cpu.r[reg::F as usize] &= !(flag::N | flag::H | flag::CY); + if (hl as i32 + n as i32) & !0xffff != 0 { + self.cpu.r[reg::F as usize] |= flag::CY; + } - if (hl & 0xff) as i32 + n as i32 & !0xff != 0 { - state.cpu.r[reg::F as usize] |= flag::H; + 8 } - if (hl as i32 + n as i32) & !0xffff != 0 { - state.cpu.r[reg::F as usize] |= flag::CY; - } + fn adc(&mut self, x: u8) { + // ADD a number and the carry flag to A and store the result in A + let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4; + let res = x as u16 + self.cpu.r[reg::A as usize] as u16 + carry as u16; - 8 -} + self.cpu.r[reg::F as usize] = 0; -pub fn adc(state: &mut GBState, x: u8) { - // ADD a number and the carry flag to A and store the result in A - let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4; - let res = x as u16 + state.cpu.r[reg::A as usize] as u16 + carry as u16; + if (x & 0xf) + ((self.cpu.r[reg::A as usize] & 0xf) + carry) > 0xf { + self.cpu.r[reg::F as usize] |= flag::H; + } - state.cpu.r[reg::F as usize] = 0; + if res > 0xff { + self.cpu.r[reg::F as usize] |= flag::CY; + } - if (x & 0xf) + ((state.cpu.r[reg::A as usize] & 0xf) + carry) > 0xf { - state.cpu.r[reg::F as usize] |= flag::H; - } + self.cpu.r[reg::A as usize] = res as u8; - if res > 0xff { - state.cpu.r[reg::F as usize] |= flag::CY; + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } - state.cpu.r[reg::A as usize] = res as u8; + fn sub(&mut self, x: u8) { + // SUB a number to A and store the result in A + self.cpu.r[reg::F as usize] = flag::N; - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; - } -} + if (x & 0xf) > (self.cpu.r[reg::A as usize] & 0xf) { + self.cpu.r[reg::F as usize] |= flag::H; + } + + if x > self.cpu.r[reg::A as usize] { + self.cpu.r[reg::F as usize] |= flag::CY; + } -pub fn sub(state: &mut GBState, x: u8) { - // SUB a number to A and store the result in A - state.cpu.r[reg::F as usize] = flag::N; + self.cpu.r[reg::A as usize] = self.cpu.r[reg::A as usize] - x; - if (x & 0xf) > (state.cpu.r[reg::A as usize] & 0xf) { - state.cpu.r[reg::F as usize] |= flag::H; + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } - if x > state.cpu.r[reg::A as usize] { - state.cpu.r[reg::F as usize] |= flag::CY; - } + fn sbc(&mut self, x: u8) { + // SUB a number and the carry flag to A and store the result in A + let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4; + self.cpu.r[reg::F as usize] = flag::N; - state.cpu.r[reg::A as usize] = state.cpu.r[reg::A as usize] - x; + if (x & 0xf) > (self.cpu.r[reg::A as usize] & 0xf) - carry { + self.cpu.r[reg::F as usize] |= flag::H; + } - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; - } -} + if x as i32 > self.cpu.r[reg::A as usize] as i32 - carry as i32 { + self.cpu.r[reg::F as usize] |= flag::CY; + } -pub fn sbc(state: &mut GBState, x: u8) { - // SUB a number and the carry flag to A and store the result in A - let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4; - state.cpu.r[reg::F as usize] = flag::N; + self.cpu.r[reg::A as usize] = self.cpu.r[reg::A as usize] - x - carry; - if (x & 0xf) > (state.cpu.r[reg::A as usize] & 0xf) - carry { - state.cpu.r[reg::F as usize] |= flag::H; + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } - if x as i32 > state.cpu.r[reg::A as usize] as i32 - carry as i32 { - state.cpu.r[reg::F as usize] |= flag::CY; - } + fn and(&mut self, x: u8) { + // AND a number to A and store the result in A + self.cpu.r[reg::A as usize] &= x; - state.cpu.r[reg::A as usize] = state.cpu.r[reg::A as usize] - x - carry; + self.cpu.r[reg::F as usize] = flag::H; - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } -} -pub fn and(state: &mut GBState, x: u8) { - // AND a number to A and store the result in A - state.cpu.r[reg::A as usize] &= x; + fn xor(&mut self, x: u8) { + // XOR a number to A and store the result in A + self.cpu.r[reg::A as usize] ^= x; - state.cpu.r[reg::F as usize] = flag::H; + self.cpu.r[reg::F as usize] = 0; - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } -} -pub fn xor(state: &mut GBState, x: u8) { - // XOR a number to A and store the result in A - state.cpu.r[reg::A as usize] ^= x; + fn or(&mut self, x: u8) { + // OR a number to A and store the result in A + self.cpu.r[reg::A as usize] |= x; - state.cpu.r[reg::F as usize] = 0; + self.cpu.r[reg::F as usize] = 0; - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + if self.cpu.r[reg::A as usize] == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } -} -pub fn or(state: &mut GBState, x: u8) { - // OR a number to A and store the result in A - state.cpu.r[reg::A as usize] |= x; + fn cp(&mut self, x: u8) { + // SUB a number to A and update the flags accordingly without updating A + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] = 0; + self.cpu.r[reg::F as usize] |= flag::N; - if state.cpu.r[reg::A as usize] == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; - } -} + if x & 0xf > self.cpu.r[reg::A as usize] & 0xf { + self.cpu.r[reg::F as usize] |= flag::H; + } -pub fn cp(state: &mut GBState, x: u8) { - // SUB a number to A and update the flags accordingly without updating A - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + if x > self.cpu.r[reg::A as usize] { + self.cpu.r[reg::F as usize] |= flag::CY; + } - state.cpu.r[reg::F as usize] |= flag::N; + let res = self.cpu.r[reg::A as usize] - x; - if x & 0xf > state.cpu.r[reg::A as usize] & 0xf { - state.cpu.r[reg::F as usize] |= flag::H; + if res == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } } - if x > state.cpu.r[reg::A as usize] { - state.cpu.r[reg::F as usize] |= flag::CY; + fn rlc(&mut self, r_i: u8) -> Result<(), MemError> { + // ROTATE LEFT the input register + let mut n = self.r_reg(r_i)?; + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + self.cpu.r[reg::F as usize] |= (n >> 7) << 4; + n <<= 1; + n |= (self.cpu.r[reg::F as usize] & flag::CY) >> 4; + self.w_reg(r_i, n) } - let res = state.cpu.r[reg::A as usize] - x; - - if res == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + fn rrc(&mut self, r_i: u8) -> Result<(), MemError> { + // ROTATE RIGHT the input register + let mut n = self.r_reg(r_i)?; + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + self.cpu.r[reg::F as usize] |= (n & 1) << 4; + n >>= 1; + n |= ((self.cpu.r[reg::F as usize] & flag::CY) >> 4) << 7; + self.w_reg(r_i, n) } -} -pub fn rlc(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // ROTATE LEFT the input register - let mut n = state.r_reg(r_i)?; - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] |= (n >> 7) << 4; - n <<= 1; - n |= (state.cpu.r[reg::F as usize] & flag::CY) >> 4; - state.w_reg(r_i, n) -} + fn rl(&mut self, r_i: u8) -> Result<(), MemError> { + // ROTATE LEFT THROUGH CARRY the input register + // (RLC IS ROTATE AND RL IS ROTATE THROUGH CARRY ! IT DOESN'T MAKE ANY SENSE !!) + let mut n = self.r_reg(r_i)?; + let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4; -pub fn rrc(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // ROTATE RIGHT the input register - let mut n = state.r_reg(r_i)?; - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] |= (n & 1) << 4; - n >>= 1; - n |= ((state.cpu.r[reg::F as usize] & flag::CY) >> 4) << 7; - state.w_reg(r_i, n) -} + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + self.cpu.r[reg::F as usize] |= (n >> 7) << 4; + n <<= 1; + n |= carry; + self.w_reg(r_i, n) + } -pub fn rl(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // ROTATE LEFT THROUGH CARRY the input register - // (RLC IS ROTATE AND RL IS ROTATE THROUGH CARRY ! IT DOESN'T MAKE ANY SENSE !!) - let mut n = state.r_reg(r_i)?; - let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4; - - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] |= (n >> 7) << 4; - n <<= 1; - n |= carry; - state.w_reg(r_i, n) -} + fn rr(&mut self, r_i: u8) -> Result<(), MemError> { + // ROTATE RIGHT THROUGH CARRY the input register + let mut n = self.r_reg(r_i)?; + let carry = (self.cpu.r[reg::F as usize] & flag::CY) >> 4; -pub fn rr(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // ROTATE RIGHT THROUGH CARRY the input register - let mut n = state.r_reg(r_i)?; - let carry = (state.cpu.r[reg::F as usize] & flag::CY) >> 4; + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + self.cpu.r[reg::F as usize] |= (n & 1) << 4; + n >>= 1; + n |= carry << 7; + self.w_reg(r_i, n) + } - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] |= (n & 1) << 4; - n >>= 1; - n |= carry << 7; - state.w_reg(r_i, n) -} + fn sla(&mut self, r_i: u8) -> Result<(), MemError> { + // Shift left Arithmetic (b0=0) the input register + let mut n = self.r_reg(r_i)?; -pub fn sla(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // Shift left Arithmetic (b0=0) the input register - let mut n = state.r_reg(r_i)?; + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + self.cpu.r[reg::F as usize] |= (n >> 7) << 4; + n <<= 1; - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] |= (n >> 7) << 4; - n <<= 1; + if n == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } - if n == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + self.w_reg(r_i, n) } - state.w_reg(r_i, n) -} + fn sra(&mut self, r_i: u8) -> Result<(), MemError> { + // Shift right Arithmetic (b7=b7) the input register + let mut n = self.r_reg(r_i)?; -pub fn sra(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // Shift right Arithmetic (b7=b7) the input register - let mut n = state.r_reg(r_i)?; + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + self.cpu.r[reg::F as usize] |= (n & 0b1) << 4; + let b7 = n & 0b10000000; + n >>= 1; + n |= b7; - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] |= (n & 0b1) << 4; - let b7 = n & 0b10000000; - n >>= 1; - n |= b7; + if n == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } - if n == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + self.w_reg(r_i, n) } - state.w_reg(r_i, n) -} + fn swap(&mut self, r_i: u8) -> Result<(), MemError> { + // Swap the high nibble and low nibble + let mut n = self.r_reg(r_i)?; -pub fn swap(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // Swap the high nibble and low nibble - let mut n = state.r_reg(r_i)?; + let nibble_low = n & 0b1111; + let nibble_high = n >> 4; - let nibble_low = n & 0b1111; - let nibble_high = n >> 4; + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + n = nibble_high | (nibble_low << 4); - n = nibble_high | (nibble_low << 4); + if n == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } - if n == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + self.w_reg(r_i, n) } - state.w_reg(r_i, n) -} + fn srl(&mut self, r_i: u8) -> Result<(), MemError> { + // Shift right Logical (b7=0) the input register + let mut n = self.r_reg(r_i)?; -pub fn srl(state: &mut GBState, r_i: u8) -> Result<(), MemError> { - // Shift right Logical (b7=0) the input register - let mut n = state.r_reg(r_i)?; + self.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); + self.cpu.r[reg::F as usize] |= (n & 0b1) << 4; + n >>= 1; - state.cpu.r[reg::F as usize] &= !(flag::H | flag::N | flag::ZF | flag::CY); - state.cpu.r[reg::F as usize] |= (n & 0b1) << 4; - n >>= 1; + if n == 0 { + self.cpu.r[reg::F as usize] |= flag::ZF; + } - if n == 0 { - state.cpu.r[reg::F as usize] |= flag::ZF; + self.w_reg(r_i, n) } - state.w_reg(r_i, n) -} + fn bit(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { + let z = (((self.r_reg(n2)? >> n1) & 1) ^ 1) << 7; -pub fn bit(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> { - let z = (((state.r_reg(n2)? >> n1) & 1) ^ 1) << 7; + self.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF); + self.cpu.r[reg::F as usize] |= flag::H | z; + Ok(()) + } - state.cpu.r[reg::F as usize] &= !(flag::N | flag::ZF); - state.cpu.r[reg::F as usize] |= flag::H | z; - Ok(()) -} + fn set(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { + self.w_reg(n2, self.r_reg(n2)? | (1 << n1)) + } -pub fn set(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> { - state.w_reg(n2, state.r_reg(n2)? | (1 << n1)) -} + fn res(&mut self, n1: u8, n2: u8) -> Result<(), MemError> { + self.w_reg(n2, self.r_reg(n2)? & !(1 << n1)) + } -pub fn res(state: &mut GBState, n1: u8, n2: u8) -> Result<(), MemError> { - state.w_reg(n2, state.r_reg(n2)? & !(1 << n1)) -} + // I don't remember why I separated op00, op01, op10 and op11 AND I'M NOT GOING TO CHANGE IT + // BECAUSE I LOVE CHAOS -// I don't remember why I separated op00, op01, op10 and op11 AND I'M NOT GOING TO CHANGE IT -// BECAUSE I LOVE CHAOS - -pub fn op00(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> { - // Dispatcher for the instructions starting with 0b00 based on their 3 LSB - match n2 { - 0b000 => match n1 { - 0b000 => Ok(4), - 0b001 => ldnnsp(state), - 0b010 => todo!("STOP"), - 0b011 => jr8(state), - _ => jrcc8(state, n1), - }, - 0b001 => match n1 { - 0b001 | 0b011 | 0b101 | 0b111 => Ok(addhlrr(state, n1 >> 1)), - 0b000 | 0b010 | 0b100 | 0b110 => { - let p = r_16b_from_pc(state)?; - ldrr16(state, n1 >> 1, p); - Ok(12) + fn op00(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + // Dispatcher for the instructions starting with 0b00 based on their 3 LSB + match n2 { + 0b000 => match n1 { + 0b000 => Ok(4), + 0b001 => self.ldnnsp(), + 0b010 => todo!("STOP"), + 0b011 => self.jr8(), + _ => self.jrcc8(n1), + }, + 0b001 => match n1 { + 0b001 | 0b011 | 0b101 | 0b111 => Ok(self.addhlrr(n1 >> 1)), + 0b000 | 0b010 | 0b100 | 0b110 => { + let p = self.r_16b_from_pc()?; + self.ldrr16(n1 >> 1, p); + Ok(12) + } + _ => panic!(), + }, + 0b010 => self.ld00a(n1), + 0b011 => match n1 { + 0b001 | 0b011 | 0b101 | 0b111 => Ok(self.dec16(n1 >> 1)), + 0b000 | 0b010 | 0b100 | 0b110 => Ok(self.inc16(n1 >> 1)), + _ => panic!(), + }, + 0b100 => self.inc8(n1), + 0b101 => self.dec8(n1), + 0b110 => self.ldr8(n1), + 0b111 => { + match n1 { + 0b000 => self.rlc(7)?, + 0b001 => self.rrc(7)?, + 0b010 => self.rl(7)?, + 0b011 => self.rr(7)?, + 0b100 => self.daa(), + 0b101 => self.cpl(), + 0b110 => self.scf(), + 0b111 => self.ccf(), + _ => panic!(), + }; + Ok(4) } _ => panic!(), - }, - 0b010 => ld00a(state, n1), - 0b011 => match n1 { - 0b001 | 0b011 | 0b101 | 0b111 => Ok(dec16(state, n1 >> 1)), - 0b000 | 0b010 | 0b100 | 0b110 => Ok(inc16(state, n1 >> 1)), - _ => panic!(), - }, - 0b100 => inc8(state, n1), - 0b101 => dec8(state, n1), - 0b110 => ldr8(state, n1), - 0b111 => { - match n1 { - 0b000 => rlc(state, 7)?, - 0b001 => rrc(state, 7)?, - 0b010 => rl(state, 7)?, - 0b011 => rr(state, 7)?, - 0b100 => daa(state), - 0b101 => cpl(state), - 0b110 => scf(state), - 0b111 => ccf(state), - _ => panic!(), - }; + } + } + + fn op01(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + // Dispatcher for the instructions starting with 0b01 (LD r,r and HALT) + if n1 == 0b110 && n2 == 0b110 { + self.mem.halt = true; Ok(4) + } else { + self.ldrr(n1, n2)?; + + if n1 == 0b110 || n2 == 0b110 { + Ok(8) + } else { + Ok(4) + } } - _ => panic!(), } -} -pub fn op01(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> { - // Dispatcher for the instructions starting with 0b01 (LD r,r and HALT) - if n1 == 0b110 && n2 == 0b110 { - state.mem.halt = true; - Ok(4) - } else { - ldrr(state, n1, n2)?; + fn op10(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + // Dispatcher for the instructions starting with 0b10 (Arithmetic) + match n1 { + 0b000 => self.add(self.r_reg(n2)?), + 0b001 => self.adc(self.r_reg(n2)?), + 0b010 => self.sub(self.r_reg(n2)?), + 0b011 => self.sbc(self.r_reg(n2)?), + 0b100 => self.and(self.r_reg(n2)?), + 0b101 => self.xor(self.r_reg(n2)?), + 0b110 => self.or(self.r_reg(n2)?), + 0b111 => self.cp(self.r_reg(n2)?), + _ => panic!(), + } - if n1 == 0b110 || n2 == 0b110 { + if n2 == 0b110 { Ok(8) } else { Ok(4) } } -} -pub fn op10(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> { - // Dispatcher for the instructions starting with 0b10 (Arithmetic) - match n1 { - 0b000 => add(state, state.r_reg(n2)?), - 0b001 => adc(state, state.r_reg(n2)?), - 0b010 => sub(state, state.r_reg(n2)?), - 0b011 => sbc(state, state.r_reg(n2)?), - 0b100 => and(state, state.r_reg(n2)?), - 0b101 => xor(state, state.r_reg(n2)?), - 0b110 => or(state, state.r_reg(n2)?), - 0b111 => cp(state, state.r_reg(n2)?), - _ => panic!(), - } - - if n2 == 0b110 { - Ok(8) - } else { - Ok(4) - } -} - -pub fn op11(state: &mut GBState, n1: u8, n2: u8) -> Result<u64, MemError> { - match n2 { - 0b000 => match n1 { - 0b100 => { - let n = r_8b_from_pc(state)?; - ldnna(state, n as u16 | 0xff00)?; - Ok(12) - } - 0b101 => addsp8(state), - 0b110 => { - let n = r_8b_from_pc(state)?; - ldann(state, n as u16 | 0xff00)?; - Ok(12) - } - 0b111 => { - let n = r_8b_from_pc(state)?; - ldrr16(state, reg::HL, n as u16 + state.cpu.sp); - Ok(12) - } - _ => retcc(state, n1 & 0b11), - }, - 0b001 => match n1 { - 0b001 => ret(state), - 0b011 => { - state.mem.ime = true; - - ret(state) - } - 0b101 => Ok(jphl(state)), - 0b111 => Ok(ldsphl(state)), - _ => { - let p = pop(state)?; - state.cpu.r[(n1 >> 1) as usize * 2 + 1] = (p & 0xff) as u8; - state.cpu.r[(n1 >> 1) as usize * 2] = (p >> 8) as u8; - Ok(12) - } - }, - 0b010 => match n1 { - 0b100 => { - ldnna(state, state.cpu.r[reg::C as usize] as u16 | 0xff00)?; - Ok(8) - } - 0b101 => { - let nn = r_16b_from_pc(state)?; - ldnna(state, nn)?; - Ok(16) - } + fn op11(&mut self, n1: u8, n2: u8) -> Result<u64, MemError> { + match n2 { + 0b000 => match n1 { + 0b100 => { + let n = self.r_8b_from_pc()?; + self.ldnna(n as u16 | 0xff00)?; + Ok(12) + } + 0b101 => self.addsp8(), + 0b110 => { + let n = self.r_8b_from_pc()?; + self.ldann(n as u16 | 0xff00)?; + Ok(12) + } + 0b111 => { + let n = self.r_8b_from_pc()?; + self.ldrr16(reg::HL, n as u16 + self.cpu.sp); + Ok(12) + } + _ => self.retcc(n1 & 0b11), + }, + 0b001 => match n1 { + 0b001 => self.ret(), + 0b011 => { + self.mem.ime = true; + + self.ret() + } + 0b101 => Ok(self.jphl()), + 0b111 => Ok(self.ldsphl()), + _ => { + let p = self.pop()?; + self.cpu.r[(n1 >> 1) as usize * 2 + 1] = (p & 0xff) as u8; + self.cpu.r[(n1 >> 1) as usize * 2] = (p >> 8) as u8; + Ok(12) + } + }, + 0b010 => match n1 { + 0b100 => { + self.ldnna(self.cpu.r[reg::C as usize] as u16 | 0xff00)?; + Ok(8) + } + 0b101 => { + let nn = self.r_16b_from_pc()?; + self.ldnna(nn)?; + Ok(16) + } + 0b110 => { + self.ldann(self.cpu.r[reg::C as usize] as u16 | 0xff00)?; + Ok(8) + } + 0b111 => { + let nn = self.r_16b_from_pc()?; + self.ldann(nn)?; + Ok(16) + } + _ => self.jpcc16(n1 & 0b11), + }, + 0b011 => match n1 { + 0b000 => self.jp16(), + 0b001 => self.op_bitwise(), // Bitwise operations + 0b010 | 0b011 | 0b100 | 0b101 => unimplemented!(), + 0b110 => { + self.mem.ime = false; + Ok(4) + } + 0b111 => { + self.mem.ime = true; + Ok(4) + } + _ => panic!(), + }, + 0b100 => self.callcc(n1 & 0b11), + 0b101 => match n1 { + 0b001 => self.call(), + 0b011 | 0b101 | 0b111 => unimplemented!(), + _ => { + let value = self.cpu.r[(n1 >> 1) as usize * 2 + 1] as u16 + | ((self.cpu.r[(n1 >> 1) as usize * 2] as u16) << 8); + self.push(value)?; + Ok(16) + } + }, 0b110 => { - ldann(state, state.cpu.r[reg::C as usize] as u16 | 0xff00)?; + let p = self.r_8b_from_pc()?; + + match n1 { + 0b000 => self.add(p), + 0b001 => self.adc(p), + 0b010 => self.sub(p), + 0b011 => self.sbc(p), + 0b100 => self.and(p), + 0b101 => self.xor(p), + 0b110 => self.or(p), + 0b111 => self.cp(p), + _ => panic!(), + } Ok(8) } 0b111 => { - let nn = r_16b_from_pc(state)?; - ldann(state, nn)?; + let p = n1 << 3; + + self.push(self.cpu.pc)?; + self.cpu.pc = p as u16; Ok(16) - } - _ => jpcc16(state, n1 & 0b11), - }, - 0b011 => match n1 { - 0b000 => jp16(state), - 0b001 => op_bitwise(state), // Bitwise operations - 0b010 | 0b011 | 0b100 | 0b101 => unimplemented!(), - 0b110 => { - state.mem.ime = false; - Ok(4) - } - 0b111 => { - state.mem.ime = true; - Ok(4) - } + } // RST _ => panic!(), - }, - 0b100 => callcc(state, n1 & 0b11), - 0b101 => match n1 { - 0b001 => call(state), - 0b011 | 0b101 | 0b111 => unimplemented!(), - _ => { - let value = state.cpu.r[(n1 >> 1) as usize * 2 + 1] as u16 - | ((state.cpu.r[(n1 >> 1) as usize * 2] as u16) << 8); - push(state, value)?; - Ok(16) - } - }, - 0b110 => { - let p = r_8b_from_pc(state)?; - - match n1 { - 0b000 => add(state, p), - 0b001 => adc(state, p), - 0b010 => sub(state, p), - 0b011 => sbc(state, p), - 0b100 => and(state, p), - 0b101 => xor(state, p), - 0b110 => or(state, p), - 0b111 => cp(state, p), - _ => panic!(), - } - Ok(8) } - 0b111 => { - let p = n1 << 3; + } - push(state, state.cpu.pc)?; - state.cpu.pc = p as u16; + fn op_bitwise(&mut self) -> Result<u64, MemError> { + let p = self.r_8b_from_pc()?; + let opcode = p >> 6; + let n1 = p >> 3 & 0b111; + let n2 = p & 0b111; + + match opcode { + 0b00 => match n1 { + 0b000 => self.rlc(n2), + 0b001 => self.rrc(n2), + 0b010 => self.rl(n2), + 0b011 => self.rr(n2), + 0b100 => self.sla(n2), + 0b101 => self.sra(n2), + 0b110 => self.swap(n2), + 0b111 => self.srl(n2), + _ => panic!(), + }, + 0b01 => self.bit(n1, n2), + 0b10 => self.res(n1, n2), + 0b11 => self.set(n1, n2), + _ => panic!(), + }?; + if n2 == 0b110 { Ok(16) - } // RST - _ => panic!(), + } else { + Ok(8) + } } -} -pub fn op_bitwise(state: &mut GBState) -> Result<u64, MemError> { - let p = r_8b_from_pc(state)?; - let opcode = p >> 6; - let n1 = p >> 3 & 0b111; - let n2 = p & 0b111; - - match opcode { - 0b00 => match n1 { - 0b000 => rlc(state, n2), - 0b001 => rrc(state, n2), - 0b010 => rl(state, n2), - 0b011 => rr(state, n2), - 0b100 => sla(state, n2), - 0b101 => sra(state, n2), - 0b110 => swap(state, n2), - 0b111 => srl(state, n2), + pub fn exec_opcode(&mut self) -> Result<u64, MemError> { + let opcode = self.mem.r(self.cpu.pc)?; + + if self.is_debug { + println!( + "{:02x}:{:04x} = {:02x} (IME: {})", + self.mem.rom_bank, self.cpu.pc, opcode, self.mem.ime + ); + } + + self.cpu.pc += 1; + + let n1 = (opcode >> 3) & 0b111; + let n2 = opcode & 0b111; + + match opcode >> 6 { + 0b00 => self.op00(n1, n2), + 0b01 => self.op01(n1, n2), + 0b10 => self.op10(n1, n2), + 0b11 => self.op11(n1, n2), _ => panic!(), - }, - 0b01 => bit(state, n1, n2), - 0b10 => res(state, n1, n2), - 0b11 => set(state, n1, n2), - _ => panic!(), - }?; - if n2 == 0b110 { - Ok(16) - } else { - Ok(8) + } } } diff --git a/src/serial.rs b/src/serial.rs new file mode 100644 index 0000000..577723d --- /dev/null +++ b/src/serial.rs @@ -0,0 +1,136 @@ +use std::fs::File; +use std::io::{Read, Write}; +use std::sync::mpsc::{self, Receiver, Sender}; +use std::sync::{Arc, Mutex}; +use std::thread; + +pub trait Serial { + // Should not be blocking + fn write(&mut self, byte: u8); + fn read(&mut self) -> u8; + + fn new_transfer(&mut self) -> bool; // since last read + fn clock_master(&mut self) -> bool; + + fn set_clock_master(&mut self, clock_master: bool); +} + +pub struct UnconnectedSerial {} + +impl Serial for UnconnectedSerial { + fn write(&mut self, byte: u8) { + println!("Writing {} to unconnected serial", byte); + } + + fn read(&mut self) -> u8 { + println!("Reading 0 from unconnected serial"); + 0 + } + + fn new_transfer(&mut self) -> bool { + false + } + + fn clock_master(&mut self) -> bool { + false + } + + fn set_clock_master(&mut self, clock_master: bool) {} +} + +pub struct FIFOPackage { + t: bool, + value: u8, +} + +pub struct FIFOSerial { + input: Receiver<u8>, + output: Sender<FIFOPackage>, + clock_change: Receiver<bool>, + last_read_byte: u8, + clock_master: bool, +} + +impl FIFOSerial { + pub fn new(input_path: String, output_path: String) -> FIFOSerial { + let (tx, input) = mpsc::channel::<u8>(); + let (clock_tx, clock_change) = mpsc::channel::<bool>(); + thread::spawn(move || { + let mut input_f = File::open(input_path).unwrap(); + loop { + let mut byte = [0, 0]; + + input_f.read(&mut byte).unwrap(); + if byte[0] == 1 { + tx.send(byte[1]).unwrap(); + } else { + clock_tx.send(byte[1] == 0).unwrap(); + } + } + }); + + let (output, rx) = mpsc::channel::<FIFOPackage>(); + thread::spawn(move || { + let mut output_f = File::create(output_path).unwrap(); + for b in rx.iter() { + if b.t { + output_f.write(&[1, b.value]).unwrap(); + } else { + output_f.write(&[0, b.value]).unwrap(); + } + } + }); + + FIFOSerial { + input, + output, + clock_change, + last_read_byte: 0xff, + clock_master: false, + } + } +} + +impl Serial for FIFOSerial { + fn write(&mut self, byte: u8) { + println!("Writing {} to fifo serial", byte); + self.output.send(FIFOPackage { + t: true, + value: byte, + }); + } + + fn read(&mut self) -> u8 { + println!("Reading {} from fifo serial", self.last_read_byte); + self.last_read_byte + } + + fn new_transfer(&mut self) -> bool { + match self.input.try_recv() { + Ok(byte) => { + println!("Received: {}", byte); + self.last_read_byte = byte; + true + } + _ => false, + } + } + fn clock_master(&mut self) -> bool { + match self.clock_change.try_recv() { + Ok(byte) => { + println!("Received clock change, master: {}", byte); + self.clock_master = byte; + } + _ => {} + }; + self.clock_master + } + + fn set_clock_master(&mut self, clock_master: bool) { + self.clock_master = clock_master; + self.output.send(FIFOPackage { + t: false, + value: (if clock_master { 1 } else { 0 }), + }); + } +} diff --git a/src/state.rs b/src/state.rs index d2f93d9..49bea41 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,7 @@ use crate::audio::Audio; use crate::consts::{PROGRAM_START_ADDRESS, STACK_START_ADDRESS}; use crate::display::Display; +use crate::serial::Serial; use std::fs::File; use std::io::{Read, Write}; @@ -127,6 +128,8 @@ pub struct Memory { pub audio: Audio, + pub serial: Box<dyn Serial>, + pub ime: bool, pub div: u8, @@ -146,6 +149,10 @@ pub struct Memory { pub timer_enabled: bool, pub timer_speed: u8, + + pub serial_data: u8, + + pub serial_control: u8, } #[derive(Debug)] @@ -155,8 +162,13 @@ pub enum MemError { NotUsable, } +mod serial_control_flags { + pub const CLOCK_SELECT: u8 = 0b1; + pub const TRANSFER_ENABLE: u8 = 0b10000000; +} + impl Memory { - pub fn new() -> Self { + pub fn new(serial: Box<dyn Serial>) -> Self { let mut display = Display::new(); display.cls(); @@ -190,6 +202,32 @@ impl Memory { tma: 0, timer_enabled: false, timer_speed: 0, + serial, + serial_control: 0, + serial_data: 0, + } + } + + pub fn update_serial(&mut self) { + if self.serial.new_transfer() { + println!("TRANSFER ENABLED"); + self.serial_control |= serial_control_flags::TRANSFER_ENABLE; + } + + if self.serial.clock_master() { + self.serial_control |= serial_control_flags::CLOCK_SELECT; + } else { + self.serial_control &= !serial_control_flags::CLOCK_SELECT; + } + + if (self.serial_control & serial_control_flags::CLOCK_SELECT != 0 + || self.serial.new_transfer()) + && self.serial_control & serial_control_flags::TRANSFER_ENABLE != 0 + { + self.serial.write(self.serial_data); + self.serial_data = self.serial.read(); + self.serial_control &= !serial_control_flags::TRANSFER_ENABLE; + self.io[0x0f] |= 0b1000; } } @@ -331,8 +369,8 @@ pub struct GBState { } impl GBState { - pub fn new() -> Self { - let mem = Memory::new(); + pub fn new(serial: Box<dyn Serial>) -> Self { + let mem = Memory::new(serial); Self { cpu: CPU::new(), |