This commit is contained in:
Alex Janka 2023-04-20 12:16:04 +10:00
parent 02812aa458
commit 1d09a2500a
9 changed files with 76 additions and 93 deletions

View file

@ -39,10 +39,6 @@ struct Args {
#[arg(short, long)] #[arg(short, long)]
bootrom: Option<String>, bootrom: Option<String>,
/// Verbose print
#[arg(short, long)]
verbose: bool,
/// Connect the serial port output to stdout /// Connect the serial port output to stdout
#[arg(short, long)] #[arg(short, long)]
connect_serial: bool, connect_serial: bool,
@ -113,7 +109,6 @@ fn main() {
}) })
.with_bootrom(args.bootrom.map(RomFile::Path)) .with_bootrom(args.bootrom.map(RomFile::Path))
.with_no_save(args.no_save) .with_no_save(args.no_save)
.with_verbose(args.verbose)
.with_tile_window(tile_window); .with_tile_window(tile_window);
let mut core = EmulatorCore::init(receiver, options); let mut core = EmulatorCore::init(receiver, options);

View file

@ -166,7 +166,6 @@ where
pub(crate) no_save: bool, pub(crate) no_save: bool,
pub(crate) bootrom: Option<RomFile>, pub(crate) bootrom: Option<RomFile>,
pub(crate) serial_target: SerialTarget, pub(crate) serial_target: SerialTarget,
pub(crate) verbose: bool,
spooky: PhantomData<ColourFormat>, spooky: PhantomData<ColourFormat>,
} }
@ -186,7 +185,6 @@ where
no_save: false, no_save: false,
bootrom: None, bootrom: None,
serial_target: SerialTarget::None, serial_target: SerialTarget::None,
verbose: false,
spooky: PhantomData, spooky: PhantomData,
} }
} }
@ -209,7 +207,6 @@ where
no_save: false, no_save: false,
bootrom: None, bootrom: None,
serial_target: SerialTarget::None, serial_target: SerialTarget::None,
verbose: false,
spooky: PhantomData, spooky: PhantomData,
} }
} }
@ -229,11 +226,6 @@ where
self self
} }
pub fn with_verbose(mut self, verbose: bool) -> Self {
self.verbose = verbose;
self
}
pub fn with_bootrom(mut self, bootrom: Option<RomFile>) -> Self { pub fn with_bootrom(mut self, bootrom: Option<RomFile>) -> Self {
self.bootrom = bootrom; self.bootrom = bootrom;
self self
@ -253,9 +245,4 @@ where
self.tile_window = window; self.tile_window = window;
self self
} }
pub fn verbose(mut self) -> Self {
self.verbose = true;
self
}
} }

View file

@ -1,2 +1,7 @@
use crate::processor::memory::rom::CgbRomType;
use once_cell::sync::OnceCell;
// Hz // Hz
pub const CLOCK_SPEED: usize = 4194304; pub const CLOCK_SPEED: usize = 4194304;
pub(crate) static IS_CGB: OnceCell<CgbRomType> = OnceCell::new();

View file

@ -8,7 +8,6 @@ use connect::{
AudioOutput, CameraWrapper, CameraWrapperRef, EmulatorMessage, EmulatorOptions, NoCamera, AudioOutput, CameraWrapper, CameraWrapperRef, EmulatorMessage, EmulatorOptions, NoCamera,
PocketCamera, Renderer, RomFile, SerialTarget, PocketCamera, Renderer, RomFile, SerialTarget,
}; };
use once_cell::sync::OnceCell;
use processor::{ use processor::{
memory::{mmio::gpu::Colour, Rom}, memory::{mmio::gpu::Colour, Rom},
Cpu, CpuSaveState, Cpu, CpuSaveState,
@ -28,8 +27,6 @@ mod constants;
mod processor; mod processor;
pub mod util; pub mod util;
static VERBOSE: OnceCell<bool> = OnceCell::new();
pub const WIDTH: usize = 160; pub const WIDTH: usize = 160;
pub const HEIGHT: usize = 144; pub const HEIGHT: usize = 144;
@ -54,10 +51,6 @@ where
receiver: Receiver<EmulatorMessage>, receiver: Receiver<EmulatorMessage>,
mut options: EmulatorOptions<ColourFormat, R, C>, mut options: EmulatorOptions<ColourFormat, R, C>,
) -> Self { ) -> Self {
if options.verbose {
VERBOSE.set(true).unwrap();
}
let camera: CameraWrapperRef<C> = Arc::new(Mutex::new(CameraWrapper::new(options.camera))); let camera: CameraWrapperRef<C> = Arc::new(Mutex::new(CameraWrapper::new(options.camera)));
let rom = match options.rom { let rom = match options.rom {

View file

@ -243,6 +243,7 @@ where
0xFF4B => self.gpu.get_wx(), 0xFF4B => self.gpu.get_wx(),
0x0..0xFF40 | 0xFF4C..=0xFFFF => unreachable!(), 0x0..0xFF40 | 0xFF4C..=0xFFFF => unreachable!(),
}, },
IoAddress::Cgb(_) => todo!(),
IoAddress::Unused(_) => 0xFF, IoAddress::Unused(_) => 0xFF,
} }
} }
@ -282,6 +283,7 @@ where
0xFF4B => self.gpu.update_wx(data), 0xFF4B => self.gpu.update_wx(data),
0x0..0xFF40 | 0xFF4C..=0xFFFF => unreachable!(), 0x0..0xFF40 | 0xFF4C..=0xFFFF => unreachable!(),
}, },
IoAddress::Cgb(_) => todo!(),
IoAddress::Unused(_) => {} IoAddress::Unused(_) => {}
} }
} }

View file

@ -36,9 +36,12 @@ pub(crate) enum IoAddress {
Audio(AudioAddress), Audio(AudioAddress),
WaveRam(WaveRamAddress), WaveRam(WaveRamAddress),
Video(VideoAddress), Video(VideoAddress),
Cgb(CgbIoAddress),
Unused(u16), Unused(u16),
} }
pub(crate) enum CgbIoAddress {}
pub(crate) enum Address { pub(crate) enum Address {
Rom(RomAddress), Rom(RomAddress),
Vram(VramAddress), Vram(VramAddress),
@ -53,27 +56,6 @@ pub(crate) enum Address {
InterruptEnable(InterruptEnable), InterruptEnable(InterruptEnable),
} }
impl TryInto<RomAddress> for u16 {
type Error = AddressError;
fn try_into(self) -> Result<RomAddress, Self::Error> {
match self {
0x0..0x4000 => Ok(RomAddress::Bank0(self.try_into().unwrap())),
0x4000..0x8000 => Ok(RomAddress::MappedBank(self.try_into().unwrap())),
_ => Err(AddressError::OutOfBounds),
}
}
}
impl AddressMarker for RomAddress {
fn inner(&self) -> u16 {
match self {
RomAddress::Bank0(v) => v.inner(),
RomAddress::MappedBank(v) => v.inner(),
}
}
}
impl From<u16> for Address { impl From<u16> for Address {
fn from(value: u16) -> Self { fn from(value: u16) -> Self {
match value { match value {
@ -92,6 +74,24 @@ impl From<u16> for Address {
} }
} }
impl From<Address> for u16 {
fn from(value: Address) -> Self {
value.inner()
}
}
impl TryInto<RomAddress> for u16 {
type Error = AddressError;
fn try_into(self) -> Result<RomAddress, Self::Error> {
match self {
0x0..0x4000 => Ok(RomAddress::Bank0(self.try_into().unwrap())),
0x4000..0x8000 => Ok(RomAddress::MappedBank(self.try_into().unwrap())),
_ => Err(AddressError::OutOfBounds),
}
}
}
impl TryInto<IoAddress> for u16 { impl TryInto<IoAddress> for u16 {
type Error = AddressError; type Error = AddressError;
@ -104,6 +104,7 @@ impl TryInto<IoAddress> for u16 {
0xFF10..0xFF27 => Ok(IoAddress::Audio(self.try_into().unwrap())), 0xFF10..0xFF27 => Ok(IoAddress::Audio(self.try_into().unwrap())),
0xFF30..0xFF40 => Ok(IoAddress::WaveRam(self.try_into().unwrap())), 0xFF30..0xFF40 => Ok(IoAddress::WaveRam(self.try_into().unwrap())),
0xFF40..0xFF4C => Ok(IoAddress::Video(self.try_into().unwrap())), 0xFF40..0xFF4C => Ok(IoAddress::Video(self.try_into().unwrap())),
0xFF4D..0xFF78 => Ok(IoAddress::Cgb(self.try_into().unwrap())),
0x0..0xFF00 => Err(AddressError::OutOfBounds), 0x0..0xFF00 => Err(AddressError::OutOfBounds),
0xFFFF => Err(AddressError::OutOfBounds), 0xFFFF => Err(AddressError::OutOfBounds),
_ => Ok(IoAddress::Unused(self)), _ => Ok(IoAddress::Unused(self)),
@ -111,6 +112,23 @@ impl TryInto<IoAddress> for u16 {
} }
} }
impl TryInto<CgbIoAddress> for u16 {
type Error = AddressError;
fn try_into(self) -> Result<CgbIoAddress, Self::Error> {
todo!()
}
}
impl AddressMarker for RomAddress {
fn inner(&self) -> u16 {
match self {
RomAddress::Bank0(v) => v.inner(),
RomAddress::MappedBank(v) => v.inner(),
}
}
}
impl AddressMarker for IoAddress { impl AddressMarker for IoAddress {
fn inner(&self) -> u16 { fn inner(&self) -> u16 {
match self { match self {
@ -122,10 +140,17 @@ impl AddressMarker for IoAddress {
IoAddress::WaveRam(v) => v.inner(), IoAddress::WaveRam(v) => v.inner(),
IoAddress::Video(v) => v.inner(), IoAddress::Video(v) => v.inner(),
IoAddress::Unused(v) => *v, IoAddress::Unused(v) => *v,
IoAddress::Cgb(v) => v.inner(),
} }
} }
} }
impl AddressMarker for CgbIoAddress {
fn inner(&self) -> u16 {
todo!()
}
}
impl AddressMarker for Address { impl AddressMarker for Address {
fn inner(&self) -> u16 { fn inner(&self) -> u16 {
match self { match self {
@ -144,12 +169,6 @@ impl AddressMarker for Address {
} }
} }
impl From<Address> for u16 {
fn from(value: Address) -> Self {
value.inner()
}
}
impl Add for Address { impl Add for Address {
type Output = Address; type Output = Address;

View file

@ -1,6 +1,9 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait}; use crate::{
connect::{CameraWrapperRef, PocketCamera as PocketCameraTrait},
constants::IS_CGB,
};
use std::{ use std::{
fs::{File, OpenOptions}, fs::{File, OpenOptions},
io::{Read, Seek, SeekFrom, Write}, io::{Read, Seek, SeekFrom, Write},
@ -124,6 +127,13 @@ impl Drop for MaybeBufferedSram {
} }
} }
#[derive(Serialize, Deserialize)]
pub(crate) enum CgbRomType {
Dmg,
CgbOptional,
CgbOnly,
}
pub struct Rom<C> pub struct Rom<C>
where where
C: PocketCameraTrait, C: PocketCameraTrait,
@ -197,7 +207,7 @@ where
.expect("Error parsing title") .expect("Error parsing title")
.to_string(); .to_string();
let _gbc_flag = data[0x143]; let _ = IS_CGB.set(get_cgb_rom_type(data[0x143]));
let _sgb_flag = data[0x146]; let _sgb_flag = data[0x146];
let rom_size = data[0x148]; let rom_size = data[0x148];
@ -237,6 +247,7 @@ where
data: Vec<u8>, data: Vec<u8>,
camera: CameraWrapperRef<C>, camera: CameraWrapperRef<C>,
) -> Self { ) -> Self {
let _ = IS_CGB.set(get_cgb_rom_type(data[0x143]));
Self { Self {
title: state.title, title: state.title,
mbc: state.mbc.get_mbc(data, camera), mbc: state.mbc.get_mbc(data, camera),
@ -281,6 +292,14 @@ where
} }
} }
fn get_cgb_rom_type(data: u8) -> CgbRomType {
match data {
0x80 => CgbRomType::CgbOptional,
0xC0 => CgbRomType::CgbOnly,
_ => CgbRomType::Dmg,
}
}
const CHECKSUM_TABLE: [u8; 79] = [ const CHECKSUM_TABLE: [u8; 79] = [
0x00, 0x88, 0x16, 0x36, 0xD1, 0xDB, 0xF2, 0x3C, 0x8C, 0x92, 0x3D, 0x5C, 0x58, 0xC9, 0x3E, 0x70, 0x00, 0x88, 0x16, 0x36, 0xD1, 0xDB, 0xF2, 0x3C, 0x8C, 0x92, 0x3D, 0x5C, 0x58, 0xC9, 0x3E, 0x70,
0x1D, 0x59, 0x69, 0x19, 0x35, 0xA8, 0x14, 0xAA, 0x75, 0x95, 0x99, 0x34, 0x6F, 0x15, 0xFF, 0x97, 0x1D, 0x59, 0x69, 0x19, 0x35, 0xA8, 0x14, 0xAA, 0x75, 0x95, 0x99, 0x34, 0x6F, 0x15, 0xFF, 0x97,

View file

@ -1,10 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use self::memory::{mmio::gpu::Colour, Interrupt, Memory, MemorySaveState}; use self::memory::{mmio::gpu::Colour, Interrupt, Memory, MemorySaveState};
use crate::{ use crate::connect::{AudioOutput, CameraWrapperRef, PocketCamera, Renderer, SerialTarget};
connect::{AudioOutput, CameraWrapperRef, PocketCamera, Renderer, SerialTarget},
verbose_println,
};
mod instructions; mod instructions;
pub mod memory; pub mod memory;
@ -118,12 +115,6 @@ where
} }
self.last_instruction = opcode; self.last_instruction = opcode;
verbose_println!(
"exec {:#4X} from pc: {:#X}",
opcode,
self.last_instruction_addr
);
let cycles = self.run_opcode(opcode); let cycles = self.run_opcode(opcode);
self.memory.user_mode = false; self.memory.user_mode = false;
self.increment_timers(cycles); self.increment_timers(cycles);

View file

@ -1,27 +1,6 @@
use crate::{ use crate::processor::{memory::mmio::gpu::Colour, Direction};
processor::{memory::mmio::gpu::Colour, Direction},
VERBOSE,
};
use std::{io, mem::transmute}; use std::{io, mem::transmute};
#[macro_export]
macro_rules! verbose_println {
($($tts:tt)*) => {
if $crate::util::is_verbose() {
println!($($tts)*);
}
};
}
#[macro_export]
macro_rules! verbose_print {
($($tts:tt)*) => {
if $crate::util::is_verbose() {
print!($($tts)*);
}
};
}
pub(crate) fn pause() -> String { pub(crate) fn pause() -> String {
let mut line = String::new(); let mut line = String::new();
match io::stdin().read_line(&mut line) { match io::stdin().read_line(&mut line) {
@ -30,13 +9,6 @@ pub(crate) fn pause() -> String {
} }
} }
pub(crate) fn is_verbose() -> bool {
match VERBOSE.get() {
Some(v) => *v,
None => false,
}
}
pub(crate) fn as_signed(unsigned: u8) -> i8 { pub(crate) fn as_signed(unsigned: u8) -> i8 {
unsafe { transmute(unsigned) } unsafe { transmute(unsigned) }
} }