feat: implement Joypad register
This commit is contained in:
		@@ -2,6 +2,7 @@ use super::cartridge::Cartridge;
 | 
				
			|||||||
use super::high_ram::HighRam;
 | 
					use super::high_ram::HighRam;
 | 
				
			||||||
use super::instruction::Cycles;
 | 
					use super::instruction::Cycles;
 | 
				
			||||||
use super::interrupt::{Interrupt, InterruptFlag};
 | 
					use super::interrupt::{Interrupt, InterruptFlag};
 | 
				
			||||||
 | 
					use super::joypad::Joypad;
 | 
				
			||||||
use super::ppu::Ppu;
 | 
					use super::ppu::Ppu;
 | 
				
			||||||
use super::serial::Serial;
 | 
					use super::serial::Serial;
 | 
				
			||||||
use super::sound::Sound;
 | 
					use super::sound::Sound;
 | 
				
			||||||
@@ -23,6 +24,7 @@ pub struct Bus {
 | 
				
			|||||||
    sound: Sound,
 | 
					    sound: Sound,
 | 
				
			||||||
    hram: HighRam,
 | 
					    hram: HighRam,
 | 
				
			||||||
    serial: Serial,
 | 
					    serial: Serial,
 | 
				
			||||||
 | 
					    joypad: Joypad,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for Bus {
 | 
					impl Default for Bus {
 | 
				
			||||||
@@ -38,6 +40,7 @@ impl Default for Bus {
 | 
				
			|||||||
            sound: Default::default(),
 | 
					            sound: Default::default(),
 | 
				
			||||||
            hram: Default::default(),
 | 
					            hram: Default::default(),
 | 
				
			||||||
            serial: Default::default(),
 | 
					            serial: Default::default(),
 | 
				
			||||||
 | 
					            joypad: Default::default(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -117,6 +120,7 @@ impl Bus {
 | 
				
			|||||||
            0xFF00..=0xFF7F => {
 | 
					            0xFF00..=0xFF7F => {
 | 
				
			||||||
                // IO Registers
 | 
					                // IO Registers
 | 
				
			||||||
                match addr {
 | 
					                match addr {
 | 
				
			||||||
 | 
					                    0xFF00 => self.joypad.status.into(),
 | 
				
			||||||
                    0xFF01 => self.serial.next,
 | 
					                    0xFF01 => self.serial.next,
 | 
				
			||||||
                    0xFF02 => self.serial.control.into(),
 | 
					                    0xFF02 => self.serial.control.into(),
 | 
				
			||||||
                    0xFF07 => self.timer.control.into(),
 | 
					                    0xFF07 => self.timer.control.into(),
 | 
				
			||||||
@@ -202,6 +206,7 @@ impl Bus {
 | 
				
			|||||||
            0xFF00..=0xFF7F => {
 | 
					            0xFF00..=0xFF7F => {
 | 
				
			||||||
                // IO Registers
 | 
					                // IO Registers
 | 
				
			||||||
                match addr {
 | 
					                match addr {
 | 
				
			||||||
 | 
					                    0xFF00 => self.joypad.status = byte.into(),
 | 
				
			||||||
                    0xFF01 => self.serial.next = byte,
 | 
					                    0xFF01 => self.serial.next = byte,
 | 
				
			||||||
                    0xFF02 => self.serial.control = byte.into(),
 | 
					                    0xFF02 => self.serial.control = byte.into(),
 | 
				
			||||||
                    0xFF07 => self.timer.control = byte.into(),
 | 
					                    0xFF07 => self.timer.control = byte.into(),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										161
									
								
								src/joypad.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								src/joypad.rs
									
									
									
									
									
										Normal file
									
								
							@@ -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<u8> for JoypadStatus {
 | 
				
			||||||
 | 
					    fn from(byte: u8) -> Self {
 | 
				
			||||||
 | 
					        Self(byte)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<JoypadStatus> 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<JoypadAction> {
 | 
				
			||||||
 | 
					        self.set_down(pressed)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn select(&self) -> bool {
 | 
				
			||||||
 | 
					        self.up()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn set_select(&mut self, pressed: bool) -> Option<JoypadAction> {
 | 
				
			||||||
 | 
					        self.set_up(pressed)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn b(&self) -> bool {
 | 
				
			||||||
 | 
					        self.left()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn set_b(&mut self, pressed: bool) -> Option<JoypadAction> {
 | 
				
			||||||
 | 
					        self.set_left(pressed)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn a(&self) -> bool {
 | 
				
			||||||
 | 
					        self.right()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn set_a(&mut self, pressed: bool) -> Option<JoypadAction> {
 | 
				
			||||||
 | 
					        self.set_right(pressed)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn down(&self) -> bool {
 | 
				
			||||||
 | 
					        self._down()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn set_down(&mut self, pressed: bool) -> Option<JoypadAction> {
 | 
				
			||||||
 | 
					        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<JoypadAction> {
 | 
				
			||||||
 | 
					        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<JoypadAction> {
 | 
				
			||||||
 | 
					        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<JoypadAction> {
 | 
				
			||||||
 | 
					        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<u8> 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<ButtonSelection> for u8 {
 | 
				
			||||||
 | 
					    fn from(selection: ButtonSelection) -> Self {
 | 
				
			||||||
 | 
					        selection as Self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -10,6 +10,7 @@ mod cpu;
 | 
				
			|||||||
mod high_ram;
 | 
					mod high_ram;
 | 
				
			||||||
mod instruction;
 | 
					mod instruction;
 | 
				
			||||||
mod interrupt;
 | 
					mod interrupt;
 | 
				
			||||||
 | 
					mod joypad;
 | 
				
			||||||
mod ppu;
 | 
					mod ppu;
 | 
				
			||||||
mod serial;
 | 
					mod serial;
 | 
				
			||||||
mod sound;
 | 
					mod sound;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user