From 36e572b78325e7b4ef2d74975d94f70a82fbfdcc Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Sat, 20 Mar 2021 21:11:45 -0500 Subject: [PATCH] feat: implement Joypad register --- src/bus.rs | 5 ++ src/joypad.rs | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 167 insertions(+) create mode 100644 src/joypad.rs diff --git a/src/bus.rs b/src/bus.rs index 015a6ff..765788d 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -2,6 +2,7 @@ use super::cartridge::Cartridge; use super::high_ram::HighRam; use super::instruction::Cycles; use super::interrupt::{Interrupt, InterruptFlag}; +use super::joypad::Joypad; use super::ppu::Ppu; use super::serial::Serial; use super::sound::Sound; @@ -23,6 +24,7 @@ pub struct Bus { sound: Sound, hram: HighRam, serial: Serial, + joypad: Joypad, } impl Default for Bus { @@ -38,6 +40,7 @@ impl Default for Bus { sound: Default::default(), hram: Default::default(), serial: Default::default(), + joypad: Default::default(), } } } @@ -117,6 +120,7 @@ impl Bus { 0xFF00..=0xFF7F => { // IO Registers match addr { + 0xFF00 => self.joypad.status.into(), 0xFF01 => self.serial.next, 0xFF02 => self.serial.control.into(), 0xFF07 => self.timer.control.into(), @@ -202,6 +206,7 @@ impl Bus { 0xFF00..=0xFF7F => { // IO Registers match addr { + 0xFF00 => self.joypad.status = byte.into(), 0xFF01 => self.serial.next = byte, 0xFF02 => self.serial.control = byte.into(), 0xFF07 => self.timer.control = byte.into(), diff --git a/src/joypad.rs b/src/joypad.rs new file mode 100644 index 0000000..d2e1bcf --- /dev/null +++ b/src/joypad.rs @@ -0,0 +1,161 @@ +use bitfield::bitfield; + +#[derive(Debug, Clone, Copy, Default)] +pub struct Joypad { + pub status: JoypadStatus, + pub interrupt: bool, +} + +bitfield! { + pub struct JoypadStatus(u8); + impl Debug; + pub from into ButtonSelection, action_buttons, select_action_buttons: 5, 5; + pub from into ButtonSelection, direction_buttons, select_direction_buttons: 4, 4; + _down, _set_down: 3; + _up, _set_up: 2; + _left, _set_left: 1; + _right, _set_right: 0; +} + +impl Copy for JoypadStatus {} +impl Clone for JoypadStatus { + fn clone(&self) -> Self { + *self + } +} + +impl Default for JoypadStatus { + fn default() -> Self { + // Selected Direction Buttons + // All Buttons are not pressed + Self(0b00011111) + } +} + +impl From for JoypadStatus { + fn from(byte: u8) -> Self { + Self(byte) + } +} + +impl From for u8 { + fn from(joypad: JoypadStatus) -> Self { + joypad.0 + } +} + +impl JoypadStatus { + pub fn start(&self) -> bool { + self.down() + } + + pub fn set_start(&mut self, pressed: bool) -> Option { + self.set_down(pressed) + } + + pub fn select(&self) -> bool { + self.up() + } + + pub fn set_select(&mut self, pressed: bool) -> Option { + self.set_up(pressed) + } + + pub fn b(&self) -> bool { + self.left() + } + + pub fn set_b(&mut self, pressed: bool) -> Option { + self.set_left(pressed) + } + + pub fn a(&self) -> bool { + self.right() + } + + pub fn set_a(&mut self, pressed: bool) -> Option { + self.set_right(pressed) + } + + pub fn down(&self) -> bool { + self._down() + } + + pub fn set_down(&mut self, pressed: bool) -> Option { + self._set_down(pressed); + + if !self._down() && pressed { + Some(JoypadAction::TriggerInterrupt) + } else { + None + } + } + + pub fn up(&self) -> bool { + self._up() + } + + pub fn set_up(&mut self, pressed: bool) -> Option { + self._set_up(pressed); + + if !self._up() && pressed { + Some(JoypadAction::TriggerInterrupt) + } else { + None + } + } + + pub fn left(&self) -> bool { + self._left() + } + + pub fn set_left(&mut self, pressed: bool) -> Option { + self._set_left(pressed); + + if !self._left() && pressed { + Some(JoypadAction::TriggerInterrupt) + } else { + None + } + } + + pub fn right(&self) -> bool { + self._right() + } + + pub fn set_right(&mut self, pressed: bool) -> Option { + self._set_right(pressed); + + if !self._right() && pressed { + Some(JoypadAction::TriggerInterrupt) + } else { + None + } + } +} + +pub enum JoypadAction { + TriggerInterrupt, +} + +#[derive(Debug, Clone, Copy)] +pub enum ButtonSelection { + Selected = 0, + NotSelected, +} + +impl From for ButtonSelection { + fn from(byte: u8) -> Self { + match byte { + 0b00 => Self::Selected, + 0b01 => Self::NotSelected, + _ => unreachable!("{:#04X} is not a valid value for ButtonSelection", byte), + } + } +} + +impl From for u8 { + fn from(selection: ButtonSelection) -> Self { + selection as Self + } +} diff --git a/src/lib.rs b/src/lib.rs index eb59231..863e773 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ mod cpu; mod high_ram; mod instruction; mod interrupt; +mod joypad; mod ppu; mod serial; mod sound;