heheheh
This commit is contained in:
parent
02812aa458
commit
1d09a2500a
|
@ -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);
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue