Playing around with reading gameboy roms, and maybe emulation

little clean up

Changed files
+126 -118
src
+124
src/cartridge_header.rs
··· 1 + use crate::NINTENDO_LOGO; 2 + use crate::enums::{ 3 + CGBFlag, CartridgeHeaderAddress, CartridgeType, DestinationCode, Error, RamSize, RomSize, 4 + }; 5 + 6 + pub struct CartridgeHeader { 7 + //Should be 80 bytes (0x014F(335) - 0x0100(256)) + 1 to include the last address 8 + pub buffer: [u8; 80], 9 + pub title: [char; 16], 10 + pub manufacturer_code: [char; 4], 11 + pub cgb_flag: CGBFlag, 12 + // https://gbdev.io/pandocs/The_Cartridge_Header.html#01440145--new-licensee-code 13 + pub license_code: [char; 2], 14 + pub support_gb: bool, 15 + pub cart_type: CartridgeType, 16 + pub rom_size: RomSize, 17 + pub ram_size: RamSize, 18 + // If None uses new license code which is just license_code 19 + // https://gbdev.io/pandocs/The_Cartridge_Header.html#014b--old-licensee-code 20 + pub old_licensee_code: Option<u8>, 21 + pub destination_code: DestinationCode, 22 + pub version: u8, 23 + pub header_checksum: u8, 24 + pub global_checksum: u16, 25 + } 26 + 27 + impl CartridgeHeader { 28 + fn bytes_to_chars<const N: usize>(bytes: &[u8], break_on_null: bool) -> [char; N] { 29 + let mut chars = [0x000 as char; N]; 30 + for (i, byte) in bytes.iter().enumerate() { 31 + if break_on_null && *byte == 0x00 { 32 + break; 33 + } 34 + chars[i] = *byte as char; 35 + } 36 + chars 37 + } 38 + 39 + pub fn parse(rom_bytes: &[u8]) -> Result<Self, Error> { 40 + let start = CartridgeHeaderAddress::CartridgeHeaderStart as usize; 41 + let end = start + 80; 42 + let header_buffer: &[u8] = rom_bytes[start..end] 43 + .try_into() 44 + .map_err(|_| Error::CartridgeReadError)?; 45 + 46 + //Checks if the Nintendo logo matches the device's version. Early anti piracy feature. Neat to take note of 47 + let nintendo_logo_from_rom = &rom_bytes[CartridgeHeaderAddress::NintendoLogoStart as usize 48 + ..CartridgeHeaderAddress::NintendoLogoEnd as usize + 1]; 49 + for (i, true_logo_byte) in NINTENDO_LOGO.iter().enumerate() { 50 + let rom_byte = nintendo_logo_from_rom[i]; 51 + if rom_byte != *true_logo_byte { 52 + return Err(Error::CartridgeReadError); 53 + } 54 + } 55 + 56 + let title = &rom_bytes[CartridgeHeaderAddress::TitleStart as usize 57 + ..CartridgeHeaderAddress::TitleEnd as usize + 1]; 58 + let title_chars = Self::bytes_to_chars::<16>(title, true); 59 + 60 + let manufacturer_code = &rom_bytes[CartridgeHeaderAddress::ManufacturerCodeStart as usize 61 + ..CartridgeHeaderAddress::ManufacturerCodeEnd as usize + 1]; 62 + let man_code_chars = Self::bytes_to_chars::<4>(manufacturer_code, false); 63 + 64 + let cgb_flag_byte = rom_bytes[0x0143]; 65 + let cgb_flag = match cgb_flag_byte { 66 + 0x80 => CGBFlag::SupportsColorBackwardCompatiable, 67 + 0xC0 => CGBFlag::ColorOnly, 68 + _ => CGBFlag::NotSet, 69 + }; 70 + 71 + let license_code = &rom_bytes[CartridgeHeaderAddress::NewLicenseStart as usize 72 + ..CartridgeHeaderAddress::NewLicenseEnd as usize + 1]; 73 + let license_code_chars = Self::bytes_to_chars::<2>(license_code, false); 74 + 75 + // https://gbdev.io/pandocs/The_Cartridge_Header.html#0146--sgb-flag 76 + let sgb_flag = rom_bytes[CartridgeHeaderAddress::SgbFlag as usize] == 0x03; 77 + 78 + let cart_type = 79 + CartridgeType::from_byte(rom_bytes[CartridgeHeaderAddress::CartType as usize]); 80 + 81 + let rom_size = RomSize::from_byte(rom_bytes[CartridgeHeaderAddress::RomSize as usize]); 82 + let ram_size = RamSize::from_byte(rom_bytes[CartridgeHeaderAddress::RamSize as usize]); 83 + 84 + let mut old_licensee_code = None; 85 + if !sgb_flag { 86 + old_licensee_code = Some(rom_bytes[CartridgeHeaderAddress::OldLicenseeCode as usize]) 87 + } 88 + 89 + let destination_code = 90 + DestinationCode::from_byte(rom_bytes[CartridgeHeaderAddress::DestinationCode as usize]); 91 + 92 + let version = rom_bytes[CartridgeHeaderAddress::MaskRomVersion as usize]; 93 + let header_checksum = rom_bytes[CartridgeHeaderAddress::HeaderChecksum as usize]; 94 + let global_checksum = u16::from_le_bytes([ 95 + rom_bytes[CartridgeHeaderAddress::GlobalChecksumStart as usize], 96 + rom_bytes[CartridgeHeaderAddress::CartridgeHeaderEnd as usize], 97 + ]); 98 + 99 + Ok(Self { 100 + buffer: header_buffer 101 + .try_into() 102 + .map_err(|_| Error::CartridgeReadError)?, 103 + title: title_chars, 104 + manufacturer_code: man_code_chars, 105 + cgb_flag, 106 + license_code: license_code_chars, 107 + support_gb: sgb_flag, 108 + cart_type, 109 + rom_size, 110 + ram_size, 111 + old_licensee_code, 112 + destination_code, 113 + version, 114 + header_checksum, 115 + global_checksum, 116 + }) 117 + } 118 + 119 + fn print_test(&self) { 120 + for byte in self.buffer.iter() { 121 + print!("{} ", *byte as char); 122 + } 123 + } 124 + }
+2 -118
src/main.rs
··· 1 + mod cartridge_header; 1 2 mod enums; 2 3 4 + use crate::cartridge_header::CartridgeHeader; 3 5 use crate::enums::CartridgeHeaderAddress::OldLicenseeCode; 4 6 use crate::enums::{ 5 7 CGBFlag, CartridgeHeaderAddress, CartridgeType, DestinationCode, Error, RamSize, RomSize, ··· 27 29 28 30 // const ROM_NAME: &str = "OtherLegallyObtainedRom.gb"; 29 31 const ROM_NAME: &str = "LegallyObtainedRom.gb"; 30 - 31 - struct CartridgeHeader { 32 - //Should be 80 bytes (0x014F(335) - 0x0100(256)) + 1 to include the last address 33 - buffer: [u8; 80], 34 - title: [char; 16], 35 - manufacturer_code: [char; 4], 36 - cgb_flag: CGBFlag, 37 - // https://gbdev.io/pandocs/The_Cartridge_Header.html#01440145--new-licensee-code 38 - license_code: [char; 2], 39 - support_gb: bool, 40 - cart_type: CartridgeType, 41 - rom_size: RomSize, 42 - ram_size: RamSize, 43 - old_licensee_code: Option<u8>, 44 - destination_code: DestinationCode, 45 - version: u8, 46 - header_checksum: u8, 47 - global_checksum: u16, 48 - } 49 - 50 - impl CartridgeHeader { 51 - fn bytes_to_chars<const N: usize>(bytes: &[u8], break_on_null: bool) -> [char; N] { 52 - let mut chars = [0x000 as char; N]; 53 - for (i, byte) in bytes.iter().enumerate() { 54 - if break_on_null && *byte == 0x00 { 55 - break; 56 - } 57 - chars[i] = *byte as char; 58 - } 59 - chars 60 - } 61 - 62 - fn parse(rom_bytes: &[u8]) -> Result<Self, Error> { 63 - let start = CartridgeHeaderAddress::CartridgeHeaderStart as usize; 64 - let end = start + 80; 65 - let header_buffer: &[u8] = rom_bytes[start..end] 66 - .try_into() 67 - .map_err(|_| Error::CartridgeReadError)?; 68 - 69 - //Checks if the Nintendo logo matches the device's version. Early anti piracy feature. Neat to take note of 70 - let nintendo_logo_from_rom = &rom_bytes[CartridgeHeaderAddress::NintendoLogoStart as usize 71 - ..CartridgeHeaderAddress::NintendoLogoEnd as usize + 1]; 72 - for (i, true_logo_byte) in NINTENDO_LOGO.iter().enumerate() { 73 - let rom_byte = nintendo_logo_from_rom[i]; 74 - if rom_byte != *true_logo_byte { 75 - return Err(Error::CartridgeReadError); 76 - } 77 - } 78 - 79 - let title = &rom_bytes[CartridgeHeaderAddress::TitleStart as usize 80 - ..CartridgeHeaderAddress::TitleEnd as usize + 1]; 81 - let title_chars = Self::bytes_to_chars::<16>(title, true); 82 - 83 - let manufacturer_code = &rom_bytes[CartridgeHeaderAddress::ManufacturerCodeStart as usize 84 - ..CartridgeHeaderAddress::ManufacturerCodeEnd as usize + 1]; 85 - let man_code_chars = Self::bytes_to_chars::<4>(manufacturer_code, false); 86 - 87 - let cgb_flag_byte = rom_bytes[0x0143]; 88 - let cgb_flag = match cgb_flag_byte { 89 - 0x80 => CGBFlag::SupportsColorBackwardCompatiable, 90 - 0xC0 => CGBFlag::ColorOnly, 91 - _ => CGBFlag::NotSet, 92 - }; 93 - 94 - let license_code = &rom_bytes[CartridgeHeaderAddress::NewLicenseStart as usize 95 - ..CartridgeHeaderAddress::NewLicenseEnd as usize + 1]; 96 - let license_code_chars = Self::bytes_to_chars::<2>(license_code, false); 97 - 98 - // https://gbdev.io/pandocs/The_Cartridge_Header.html#0146--sgb-flag 99 - let sgb_flag = rom_bytes[CartridgeHeaderAddress::SgbFlag as usize] == 0x03; 100 - 101 - let cart_type = 102 - CartridgeType::from_byte(rom_bytes[CartridgeHeaderAddress::CartType as usize]); 103 - 104 - let rom_size = RomSize::from_byte(rom_bytes[CartridgeHeaderAddress::RomSize as usize]); 105 - let ram_size = RamSize::from_byte(rom_bytes[CartridgeHeaderAddress::RamSize as usize]); 106 - 107 - let mut old_licensee_code = None; 108 - if !sgb_flag { 109 - old_licensee_code = Some(rom_bytes[CartridgeHeaderAddress::OldLicenseeCode as usize]) 110 - } 111 - 112 - let destination_code = 113 - DestinationCode::from_byte(rom_bytes[CartridgeHeaderAddress::DestinationCode as usize]); 114 - 115 - let version = rom_bytes[CartridgeHeaderAddress::MaskRomVersion as usize]; 116 - let header_checksum = rom_bytes[CartridgeHeaderAddress::HeaderChecksum as usize]; 117 - let global_checksum = u16::from_le_bytes([ 118 - rom_bytes[CartridgeHeaderAddress::GlobalChecksumStart as usize], 119 - rom_bytes[CartridgeHeaderAddress::CartridgeHeaderEnd as usize], 120 - ]); 121 - 122 - Ok(Self { 123 - buffer: header_buffer 124 - .try_into() 125 - .map_err(|_| Error::CartridgeReadError)?, 126 - title: title_chars, 127 - manufacturer_code: man_code_chars, 128 - cgb_flag, 129 - license_code: license_code_chars, 130 - support_gb: sgb_flag, 131 - cart_type, 132 - rom_size, 133 - ram_size, 134 - old_licensee_code, 135 - destination_code, 136 - version, 137 - header_checksum, 138 - global_checksum, 139 - }) 140 - } 141 - 142 - fn print_test(&self) { 143 - for byte in self.buffer.iter() { 144 - print!("{} ", *byte as char); 145 - } 146 - } 147 - } 148 32 149 33 fn main() -> std::io::Result<()> { 150 34 let mut rom_file = File::open(ROM_NAME)?;