Newer
Older
//! Main GameBoy emulation entrypoint functions and structures.
use std::{
cell::RefCell,
collections::VecDeque,
fmt::{self, Display, Formatter},
rc::Rc,
};
cheats::{
genie::{GameGenie, GameGenieCode},
shark::{GameShark, GameSharkCode},
},
data::{BootRom, CGB_BOOT, DMG_BOOT, DMG_BOOTIX, MGB_BOOTIX, SGB_BOOT},
devices::{printer::PrinterDevice, stdout::StdoutDevice},
Ppu, PpuMode, Tile, DISPLAY_HEIGHT, DISPLAY_WIDTH, FRAME_BUFFER_RGB1555_SIZE,
FRAME_BUFFER_RGB565_SIZE, FRAME_BUFFER_SIZE, FRAME_BUFFER_XRGB8888_SIZE,
serial::{NullDevice, Serial, SerialDevice},
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;
#[cfg(feature = "wasm")]
use crate::{
gen::dependencies_map,
ppu::{Palette, Pixel},
};
#[cfg(feature = "wasm")]
use std::{
convert::TryInto,
panic::{set_hook, take_hook, PanicInfo},
};
/// Enumeration that describes the multiple running
// modes of the Game Boy emulator.
// DMG = Original Game Boy
// CGB = Game Boy Color
// SGB = Super Game Boy
#[cfg_attr(feature = "wasm", wasm_bindgen)]
#[derive(Clone, Copy, PartialEq, Eq)]
Dmg = 1,
Cgb = 2,
Sgb = 3,
}
impl GameBoyMode {
pub fn description(&self) -> &'static str {
match self {
GameBoyMode::Dmg => "Game Boy (DMG)",
GameBoyMode::Cgb => "Game Boy Color (CGB)",
GameBoyMode::Sgb => "Super Game Boy (SGB)",
}
}
match value {
1 => GameBoyMode::Dmg,
2 => GameBoyMode::Cgb,
3 => GameBoyMode::Sgb,
_ => panic!("Invalid mode value: {}", value),
}
}
pub fn from_string(value: &str) -> Self {
"dmg" | "DMG" => GameBoyMode::Dmg,
"cgb" | "CGB" => GameBoyMode::Cgb,
"sgb" | "SGB" => GameBoyMode::Sgb,
_ => panic!("Invalid mode value: {}", value),
}
}
pub fn to_string(&self, uppercase: Option<bool>) -> String {
let uppercase = uppercase.unwrap_or(false);
match self {
GameBoyMode::Dmg => (if uppercase { "DMG" } else { "dmg" }).to_string(),
GameBoyMode::Cgb => (if uppercase { "CGB" } else { "cgb" }).to_string(),
GameBoyMode::Sgb => (if uppercase { "SGB" } else { "sgb" }).to_string(),
}
}
pub fn is_dmg(&self) -> bool {
*self == GameBoyMode::Dmg
}
pub fn is_cgb(&self) -> bool {
*self == GameBoyMode::Cgb
}
pub fn is_sgb(&self) -> bool {
*self == GameBoyMode::Sgb
}
}
impl Display for GameBoyMode {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.description())
}
}
#[cfg_attr(feature = "wasm", wasm_bindgen)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum GameBoySpeed {
Normal = 0,
Double = 1,
}
impl GameBoySpeed {
pub fn description(&self) -> &'static str {
match self {
GameBoySpeed::Normal => "Normal Speed",
GameBoySpeed::Double => "Double Speed",
}
}
match self {
GameBoySpeed::Normal => GameBoySpeed::Double,
GameBoySpeed::Double => GameBoySpeed::Normal,
}
}
pub fn multiplier(&self) -> u8 {
match self {
GameBoySpeed::Normal => 1,
GameBoySpeed::Double => 2,
}
}
pub fn from_u8(value: u8) -> Self {
match value {
0 => GameBoySpeed::Normal,
1 => GameBoySpeed::Double,
_ => panic!("Invalid speed value: {}", value),
}
}
}
impl Display for GameBoySpeed {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.description())
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct GameBoyConfig {
/// The current running mode of the emulator, this
/// may affect many aspects of the emulation, like
/// CPU frequency, PPU frequency, Boot rome size, etc.
/// If the PPU is enabled, it will be clocked.
/// If the APU is enabled, it will be clocked.
/// if the DMA is enabled, it will be clocked.
dma_enabled: bool,
/// If the timer is enabled, it will be clocked.
/// If the serial is enabled, it will be clocked.
serial_enabled: bool,
/// The current frequency at which the Game Boy
/// emulator is being handled. This is a "hint" that
/// may help components to adjust their internal
/// logic to match the current frequency. For example
/// the APU will adjust its internal clock to match
/// this hint.
clock_freq: u32,
#[cfg_attr(feature = "wasm", wasm_bindgen)]
impl GameBoyConfig {
pub fn is_dmg(&self) -> bool {
}
pub fn is_cgb(&self) -> bool {
Loading
Loading full blame...