Playing around with reading gameboy roms, and maybe emulation
1mod cartridge_header; 2mod enums; 3mod tile_map; 4use crate::cartridge_header::CartridgeHeader; 5use crate::enums::CartridgeHeaderAddress::OldLicenseeCode; 6use crate::enums::{ 7 CGBFlag, CartridgeHeaderAddress, CartridgeType, DestinationCode, Error, RamSize, RomSize, 8}; 9use crate::tile_map::{GPU, VRAM_BEGIN, VRAM_END}; 10use minifb::{Key, Window, WindowOptions}; 11use std::fs::File; 12use std::io::Read; 13 14const WINDOW_DIMENSIONS: [usize; 2] = [(160 * 1), (144 * 1)]; 15 16// https://github.com/ISSOtm/gb-bootroms/blob/2dce25910043ce2ad1d1d3691436f2c7aabbda00/src/dmg.asm#L259-L269 17// Each tile is encoded using 2 (!) bytes 18// The tiles are represented below 19// XX.. .XX. XX.. .... .... .... .... .... .... ...X X... .... 20// XXX. .XX. XX.. .... ..XX .... .... .... .... ...X X... .... 21// XXX. .XX. .... .... .XXX X... .... .... .... ...X X... .... 22// XX.X .XX. XX.X X.XX ..XX ..XX XX.. XX.X X... XXXX X..X XXX. 23// XX.X .XX. XX.X XX.X X.XX .XX. .XX. XXX. XX.X X..X X.XX ..XX 24// XX.. XXX. XX.X X..X X.XX .XXX XXX. XX.. XX.X X..X X.XX ..XX 25// XX.. XXX. XX.X X..X X.XX .XX. .... XX.. XX.X X..X X.XX ..XX 26// XX.. .XX. XX.X X..X X.XX ..XX XXX. XX.. XX.. XXXX X..X XXX. 27const NINTENDO_LOGO: [u8; 48] = [ 28 0x0CE, 0x0ED, 0x066, 0x066, 0x0CC, 0x00D, 0x000, 0x00B, 0x003, 0x073, 0x000, 0x083, 0x000, 29 0x00C, 0x000, 0x00D, 0x000, 0x008, 0x011, 0x01F, 0x088, 0x089, 0x000, 0x00E, 0x0DC, 0x0CC, 30 0x06E, 0x0E6, 0x0DD, 0x0DD, 0x0D9, 0x099, 0x0BB, 0x0BB, 0x067, 0x063, 0x06E, 0x00E, 0x0EC, 31 0x0CC, 0x0DD, 0x0DC, 0x099, 0x09F, 0x0BB, 0x0B9, 0x033, 0x03E, 32]; 33 34// const ROM_NAME: &str = "OtherLegallyObtainedRom.gb"; 35const ROM_NAME: &str = "LegallyObtainedRom.gb"; 36 37fn main() -> std::io::Result<()> { 38 let mut rom_file = File::open(ROM_NAME)?; 39 let mut rom_buffer: Vec<u8> = Vec::new(); 40 rom_file.read_to_end(&mut rom_buffer)?; 41 let cart_header = match CartridgeHeader::parse(&*rom_buffer) { 42 Ok(header) => header, 43 Err(err) => { 44 return Err(std::io::Error::new( 45 std::io::ErrorKind::Other, 46 "Rom failed to parse", 47 )); 48 } 49 }; 50 51 let title: String = String::from_iter(cart_header.title); 52 println!("Title: {}", title); 53 let manufacturer_code = String::from_iter(cart_header.manufacturer_code); 54 println!("Manufacturer Code: {}", manufacturer_code); 55 56 match cart_header.old_licensee_code { 57 Some(code) => println!("Uses Old Licensee Code: {:#X}", code), 58 None => println!( 59 "Uses New Licensee Code: {}", 60 String::from_iter(cart_header.license_code) 61 ), 62 } 63 64 println!("CGB Flag: {:?}", cart_header.cgb_flag); 65 println!("Supports SGB: {:?}", cart_header.support_gb); 66 println!("Cartridge Type: {:?}", cart_header.cart_type); 67 println!("ROM Size: {:?}", cart_header.rom_size); 68 println!("RAM Size: {:?}", cart_header.ram_size); 69 match cart_header.destination_code { 70 DestinationCode::Japan => println!("Destination Code: Japan"), 71 DestinationCode::NotJapan => println!("Destination Code: Not Japan"), 72 } 73 println!("Version: {:?}", cart_header.version); 74 println!("Header Checksum: {:#X}", cart_header.header_checksum); 75 println!("Global Checksum: {:#X}", cart_header.global_checksum); 76 77 let mut gpu = GPU::new(); 78 let tile_map_buffer = &rom_buffer[VRAM_BEGIN as usize..VRAM_END as usize]; 79 for (i, byte) in tile_map_buffer.iter().enumerate() { 80 gpu.write_vram(i, *byte); 81 } 82 gpu.render_tile_to_rgb(0); 83 // let range_of_tiles = 0..255; 84 // for tile_id in range_of_tiles { 85 // let idk = gpu.print_tile_ascii(tile_id); 86 // println!("{:?}", idk); 87 // } 88 let mut window = Window::new( 89 "DMG-01", 90 WINDOW_DIMENSIONS[0], 91 WINDOW_DIMENSIONS[1], 92 WindowOptions { 93 scale: minifb::Scale::X2, 94 ..WindowOptions::default() 95 }, 96 ) 97 .unwrap(); 98 let mut tile_ids: Vec<u8> = (0..100).collect(); 99 let tile_map_buffer = gpu.render_tile_map(&tile_ids, 166, 144); 100 // let idk = gpu.render_tile_to_rgb(1).unwrap(); 101 let buffer_u32: Vec<u32> = tile_map_buffer 102 .iter() 103 .map(|(r, g, b)| ((*r as u32) << 16) | ((*g as u32) << 8) | (*b as u32)) 104 .collect(); 105 while window.is_open() && !window.is_key_down(Key::Escape) { 106 window.update_with_buffer(&buffer_u32).unwrap(); 107 } 108 109 Ok(()) 110}