Playing around with reading gameboy roms, and maybe emulation

little clean up

Changed files
+126 -118
src
+124
src/cartridge_header.rs
···
+
use crate::NINTENDO_LOGO;
+
use crate::enums::{
+
CGBFlag, CartridgeHeaderAddress, CartridgeType, DestinationCode, Error, RamSize, RomSize,
+
};
+
+
pub struct CartridgeHeader {
+
//Should be 80 bytes (0x014F(335) - 0x0100(256)) + 1 to include the last address
+
pub buffer: [u8; 80],
+
pub title: [char; 16],
+
pub manufacturer_code: [char; 4],
+
pub cgb_flag: CGBFlag,
+
// https://gbdev.io/pandocs/The_Cartridge_Header.html#01440145--new-licensee-code
+
pub license_code: [char; 2],
+
pub support_gb: bool,
+
pub cart_type: CartridgeType,
+
pub rom_size: RomSize,
+
pub ram_size: RamSize,
+
// If None uses new license code which is just license_code
+
// https://gbdev.io/pandocs/The_Cartridge_Header.html#014b--old-licensee-code
+
pub old_licensee_code: Option<u8>,
+
pub destination_code: DestinationCode,
+
pub version: u8,
+
pub header_checksum: u8,
+
pub global_checksum: u16,
+
}
+
+
impl CartridgeHeader {
+
fn bytes_to_chars<const N: usize>(bytes: &[u8], break_on_null: bool) -> [char; N] {
+
let mut chars = [0x000 as char; N];
+
for (i, byte) in bytes.iter().enumerate() {
+
if break_on_null && *byte == 0x00 {
+
break;
+
}
+
chars[i] = *byte as char;
+
}
+
chars
+
}
+
+
pub fn parse(rom_bytes: &[u8]) -> Result<Self, Error> {
+
let start = CartridgeHeaderAddress::CartridgeHeaderStart as usize;
+
let end = start + 80;
+
let header_buffer: &[u8] = rom_bytes[start..end]
+
.try_into()
+
.map_err(|_| Error::CartridgeReadError)?;
+
+
//Checks if the Nintendo logo matches the device's version. Early anti piracy feature. Neat to take note of
+
let nintendo_logo_from_rom = &rom_bytes[CartridgeHeaderAddress::NintendoLogoStart as usize
+
..CartridgeHeaderAddress::NintendoLogoEnd as usize + 1];
+
for (i, true_logo_byte) in NINTENDO_LOGO.iter().enumerate() {
+
let rom_byte = nintendo_logo_from_rom[i];
+
if rom_byte != *true_logo_byte {
+
return Err(Error::CartridgeReadError);
+
}
+
}
+
+
let title = &rom_bytes[CartridgeHeaderAddress::TitleStart as usize
+
..CartridgeHeaderAddress::TitleEnd as usize + 1];
+
let title_chars = Self::bytes_to_chars::<16>(title, true);
+
+
let manufacturer_code = &rom_bytes[CartridgeHeaderAddress::ManufacturerCodeStart as usize
+
..CartridgeHeaderAddress::ManufacturerCodeEnd as usize + 1];
+
let man_code_chars = Self::bytes_to_chars::<4>(manufacturer_code, false);
+
+
let cgb_flag_byte = rom_bytes[0x0143];
+
let cgb_flag = match cgb_flag_byte {
+
0x80 => CGBFlag::SupportsColorBackwardCompatiable,
+
0xC0 => CGBFlag::ColorOnly,
+
_ => CGBFlag::NotSet,
+
};
+
+
let license_code = &rom_bytes[CartridgeHeaderAddress::NewLicenseStart as usize
+
..CartridgeHeaderAddress::NewLicenseEnd as usize + 1];
+
let license_code_chars = Self::bytes_to_chars::<2>(license_code, false);
+
+
// https://gbdev.io/pandocs/The_Cartridge_Header.html#0146--sgb-flag
+
let sgb_flag = rom_bytes[CartridgeHeaderAddress::SgbFlag as usize] == 0x03;
+
+
let cart_type =
+
CartridgeType::from_byte(rom_bytes[CartridgeHeaderAddress::CartType as usize]);
+
+
let rom_size = RomSize::from_byte(rom_bytes[CartridgeHeaderAddress::RomSize as usize]);
+
let ram_size = RamSize::from_byte(rom_bytes[CartridgeHeaderAddress::RamSize as usize]);
+
+
let mut old_licensee_code = None;
+
if !sgb_flag {
+
old_licensee_code = Some(rom_bytes[CartridgeHeaderAddress::OldLicenseeCode as usize])
+
}
+
+
let destination_code =
+
DestinationCode::from_byte(rom_bytes[CartridgeHeaderAddress::DestinationCode as usize]);
+
+
let version = rom_bytes[CartridgeHeaderAddress::MaskRomVersion as usize];
+
let header_checksum = rom_bytes[CartridgeHeaderAddress::HeaderChecksum as usize];
+
let global_checksum = u16::from_le_bytes([
+
rom_bytes[CartridgeHeaderAddress::GlobalChecksumStart as usize],
+
rom_bytes[CartridgeHeaderAddress::CartridgeHeaderEnd as usize],
+
]);
+
+
Ok(Self {
+
buffer: header_buffer
+
.try_into()
+
.map_err(|_| Error::CartridgeReadError)?,
+
title: title_chars,
+
manufacturer_code: man_code_chars,
+
cgb_flag,
+
license_code: license_code_chars,
+
support_gb: sgb_flag,
+
cart_type,
+
rom_size,
+
ram_size,
+
old_licensee_code,
+
destination_code,
+
version,
+
header_checksum,
+
global_checksum,
+
})
+
}
+
+
fn print_test(&self) {
+
for byte in self.buffer.iter() {
+
print!("{} ", *byte as char);
+
}
+
}
+
}
+2 -118
src/main.rs
···
+
mod cartridge_header;
mod enums;
+
use crate::cartridge_header::CartridgeHeader;
use crate::enums::CartridgeHeaderAddress::OldLicenseeCode;
use crate::enums::{
CGBFlag, CartridgeHeaderAddress, CartridgeType, DestinationCode, Error, RamSize, RomSize,
···
// const ROM_NAME: &str = "OtherLegallyObtainedRom.gb";
const ROM_NAME: &str = "LegallyObtainedRom.gb";
-
-
struct CartridgeHeader {
-
//Should be 80 bytes (0x014F(335) - 0x0100(256)) + 1 to include the last address
-
buffer: [u8; 80],
-
title: [char; 16],
-
manufacturer_code: [char; 4],
-
cgb_flag: CGBFlag,
-
// https://gbdev.io/pandocs/The_Cartridge_Header.html#01440145--new-licensee-code
-
license_code: [char; 2],
-
support_gb: bool,
-
cart_type: CartridgeType,
-
rom_size: RomSize,
-
ram_size: RamSize,
-
old_licensee_code: Option<u8>,
-
destination_code: DestinationCode,
-
version: u8,
-
header_checksum: u8,
-
global_checksum: u16,
-
}
-
-
impl CartridgeHeader {
-
fn bytes_to_chars<const N: usize>(bytes: &[u8], break_on_null: bool) -> [char; N] {
-
let mut chars = [0x000 as char; N];
-
for (i, byte) in bytes.iter().enumerate() {
-
if break_on_null && *byte == 0x00 {
-
break;
-
}
-
chars[i] = *byte as char;
-
}
-
chars
-
}
-
-
fn parse(rom_bytes: &[u8]) -> Result<Self, Error> {
-
let start = CartridgeHeaderAddress::CartridgeHeaderStart as usize;
-
let end = start + 80;
-
let header_buffer: &[u8] = rom_bytes[start..end]
-
.try_into()
-
.map_err(|_| Error::CartridgeReadError)?;
-
-
//Checks if the Nintendo logo matches the device's version. Early anti piracy feature. Neat to take note of
-
let nintendo_logo_from_rom = &rom_bytes[CartridgeHeaderAddress::NintendoLogoStart as usize
-
..CartridgeHeaderAddress::NintendoLogoEnd as usize + 1];
-
for (i, true_logo_byte) in NINTENDO_LOGO.iter().enumerate() {
-
let rom_byte = nintendo_logo_from_rom[i];
-
if rom_byte != *true_logo_byte {
-
return Err(Error::CartridgeReadError);
-
}
-
}
-
-
let title = &rom_bytes[CartridgeHeaderAddress::TitleStart as usize
-
..CartridgeHeaderAddress::TitleEnd as usize + 1];
-
let title_chars = Self::bytes_to_chars::<16>(title, true);
-
-
let manufacturer_code = &rom_bytes[CartridgeHeaderAddress::ManufacturerCodeStart as usize
-
..CartridgeHeaderAddress::ManufacturerCodeEnd as usize + 1];
-
let man_code_chars = Self::bytes_to_chars::<4>(manufacturer_code, false);
-
-
let cgb_flag_byte = rom_bytes[0x0143];
-
let cgb_flag = match cgb_flag_byte {
-
0x80 => CGBFlag::SupportsColorBackwardCompatiable,
-
0xC0 => CGBFlag::ColorOnly,
-
_ => CGBFlag::NotSet,
-
};
-
-
let license_code = &rom_bytes[CartridgeHeaderAddress::NewLicenseStart as usize
-
..CartridgeHeaderAddress::NewLicenseEnd as usize + 1];
-
let license_code_chars = Self::bytes_to_chars::<2>(license_code, false);
-
-
// https://gbdev.io/pandocs/The_Cartridge_Header.html#0146--sgb-flag
-
let sgb_flag = rom_bytes[CartridgeHeaderAddress::SgbFlag as usize] == 0x03;
-
-
let cart_type =
-
CartridgeType::from_byte(rom_bytes[CartridgeHeaderAddress::CartType as usize]);
-
-
let rom_size = RomSize::from_byte(rom_bytes[CartridgeHeaderAddress::RomSize as usize]);
-
let ram_size = RamSize::from_byte(rom_bytes[CartridgeHeaderAddress::RamSize as usize]);
-
-
let mut old_licensee_code = None;
-
if !sgb_flag {
-
old_licensee_code = Some(rom_bytes[CartridgeHeaderAddress::OldLicenseeCode as usize])
-
}
-
-
let destination_code =
-
DestinationCode::from_byte(rom_bytes[CartridgeHeaderAddress::DestinationCode as usize]);
-
-
let version = rom_bytes[CartridgeHeaderAddress::MaskRomVersion as usize];
-
let header_checksum = rom_bytes[CartridgeHeaderAddress::HeaderChecksum as usize];
-
let global_checksum = u16::from_le_bytes([
-
rom_bytes[CartridgeHeaderAddress::GlobalChecksumStart as usize],
-
rom_bytes[CartridgeHeaderAddress::CartridgeHeaderEnd as usize],
-
]);
-
-
Ok(Self {
-
buffer: header_buffer
-
.try_into()
-
.map_err(|_| Error::CartridgeReadError)?,
-
title: title_chars,
-
manufacturer_code: man_code_chars,
-
cgb_flag,
-
license_code: license_code_chars,
-
support_gb: sgb_flag,
-
cart_type,
-
rom_size,
-
ram_size,
-
old_licensee_code,
-
destination_code,
-
version,
-
header_checksum,
-
global_checksum,
-
})
-
}
-
-
fn print_test(&self) {
-
for byte in self.buffer.iter() {
-
print!("{} ", *byte as char);
-
}
-
}
-
}
fn main() -> std::io::Result<()> {
let mut rom_file = File::open(ROM_NAME)?;