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}