diff --git a/Cargo.toml b/Cargo.toml index 97e19fb..2af4de6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" authors = ["Kevin Hamacher "] [dependencies] -sdl2 = "0.19.0" +sdl2 = "*" libc = "*" diff --git a/src/cartridge.rs b/src/cartridge.rs index 2889082..eb6e905 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -1,6 +1,6 @@ use super::mbc::mbc::MBC; -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] enum MemoryBankControllerType { None, MBC1, @@ -25,10 +25,10 @@ pub struct Cartridge { impl Cartridge { pub fn new(rom: Box<[u8]>, save_file: Option) -> Cartridge { let mbc_type: MemoryBankControllerType = match rom[0x0147] { - 0x00 | 0x08 ... 0x09 => MemoryBankControllerType::None, - 0x01 ... 0x03 => MemoryBankControllerType::MBC1, - 0x05 ... 0x06 => MemoryBankControllerType::MBC2, - 0x0F ... 0x13 => MemoryBankControllerType::MBC3, + 0x00 | 0x08...0x09 => MemoryBankControllerType::None, + 0x01...0x03 => MemoryBankControllerType::MBC1, + 0x05...0x06 => MemoryBankControllerType::MBC2, + 0x0F...0x13 => MemoryBankControllerType::MBC3, // 0xFF => MemoryBankControllerType::HuC1, _ => panic!("Unsupported MBC type: {:02X}", rom[0x0147]), }; @@ -37,11 +37,11 @@ impl Cartridge { let rom_banks: u16 = match rom[0x0148] { 0x00 => 0, - 0x01 ... 0x07 => 2u16.pow(rom[0x0148] as u32 + 1), + 0x01...0x07 => 2u16.pow(rom[0x0148] as u32 + 1), 0x52 => 72, 0x53 => 80, 0x54 => 96, - _ => panic!("Unknown rom size: {:?}", rom[0x148]) + _ => panic!("Unknown rom size: {:?}", rom[0x148]), }; let ram_size: RamSize = match rom[0x0149] { @@ -49,7 +49,7 @@ impl Cartridge { 0x01 => RamSize::Ram2KB, 0x02 => RamSize::Ram8KB, 0x03 => RamSize::Ram32KB, - _ => panic!("Unknown ram size: {:?}", rom[0x149]) + _ => panic!("Unknown ram size: {:?}", rom[0x149]), }; println!("Rom size: {} banks", rom_banks); diff --git a/src/cpu.rs b/src/cpu.rs index 11db72d..b9cb12a 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,7 +1,7 @@ use super::interconnect; -use std::time::{Duration, Instant}; use std::thread::sleep; +use std::time::{Duration, Instant}; const REG_A: usize = 6; @@ -21,7 +21,6 @@ const FLAG_N: u8 = 1 << 6; const FLAG_H: u8 = 1 << 5; const FLAG_C: u8 = 1 << 4; - pub struct CPU { // Registers: B, C, D, E, H, L, A regs: [u8; 7], @@ -154,7 +153,10 @@ impl CPU { self.set_flag(FLAG_N); self.set_clear_flag(FLAG_Z, new == 0); self.set_clear_flag(FLAG_C, new > old || (new == old && c == 1)); - self.set_clear_flag(FLAG_H, ((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F); + self.set_clear_flag( + FLAG_H, + ((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F, + ); } #[inline] @@ -190,7 +192,7 @@ impl CPU { self.ip += 1; match instruction { - 0x00 ... 0x07 => { + 0x00...0x07 => { let reg_id = (instruction - 0x00) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { @@ -209,8 +211,8 @@ impl CPU { self.set_clear_flag(FLAG_Z, nval == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); - }, - 0x08 ... 0x0F => { + } + 0x08...0x0F => { let reg_id = (instruction - 0x08) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { @@ -227,8 +229,8 @@ impl CPU { self.set_clear_flag(FLAG_Z, val == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); - }, - 0x10 ... 0x17 => { + } + 0x10...0x17 => { let reg_id = (instruction - 0x10) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { @@ -247,8 +249,9 @@ impl CPU { self.set_clear_flag(FLAG_Z, nval == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); - }, - 0x18 ... 0x1F => { // RR + } + 0x18...0x1F => { + // RR let reg_id = (instruction - 0x18) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { @@ -267,8 +270,8 @@ impl CPU { self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); - }, - 0x20 ... 0x27 => { + } + 0x20...0x27 => { let reg_id = (instruction - 0x20) as usize; if self.debug { println!("SLA {}", REG_NAMES[reg_id]); @@ -278,8 +281,8 @@ impl CPU { self.set_clear_flag(FLAG_C, v & 0x80 == 0x80); self.set_clear_flag(FLAG_Z, v & 0x7F == 0); self.set_8bit_reg(reg_id, v << 1); - }, - 0x28 ... 0x2F => { + } + 0x28...0x2F => { let reg_id = (instruction - 0x28) as usize; if self.debug { println!("SRA {}", REG_NAMES[reg_id]); @@ -290,8 +293,8 @@ impl CPU { self.flags = 0; self.set_clear_flag(FLAG_Z, nv == 0); self.set_clear_flag(FLAG_C, v & 1 == 1); - }, - 0x30 ... 0x37 => { + } + 0x30...0x37 => { let reg_id = (instruction - 0x30) as usize; if self.debug { println!("SWAP {}", REG_NAMES[reg_id]); @@ -300,8 +303,8 @@ impl CPU { self.set_8bit_reg(reg_id, (v << 4) | (v >> 4)); self.flags = 0; self.set_clear_flag(FLAG_Z, v == 0); - }, - 0x38 ... 0x3F => { + } + 0x38...0x3F => { let reg_id = (instruction - 0x38) as usize; if self.debug { println!("SRL {}", REG_NAMES[reg_id]); @@ -312,10 +315,10 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); self.set_clear_flag(FLAG_Z, (v & 0xFE) == 0); - }, + } // Bits - 0x40 ... 0x47 => { + 0x40...0x47 => { // Test 0th bit let reg_id = (instruction - 0x40) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -326,7 +329,7 @@ impl CPU { self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } - 0x48 ... 0x4F => { + 0x48...0x4F => { // Test 1th bit let reg_id = (instruction - 0x48) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -337,7 +340,7 @@ impl CPU { self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } - 0x50 ... 0x57 => { + 0x50...0x57 => { // Test 2th bit let reg_id = (instruction - 0x50) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -348,7 +351,7 @@ impl CPU { self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } - 0x58 ... 0x5F => { + 0x58...0x5F => { // Test 3th bit let reg_id = (instruction - 0x58) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -359,7 +362,7 @@ impl CPU { self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } - 0x60 ... 0x67 => { + 0x60...0x67 => { // Test 4th bit let reg_id = (instruction - 0x60) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -370,7 +373,7 @@ impl CPU { self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } - 0x68 ... 0x6F => { + 0x68...0x6F => { // Test 5th bit let reg_id = (instruction - 0x68) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -381,7 +384,7 @@ impl CPU { self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } - 0x70 ... 0x77 => { + 0x70...0x77 => { // Test 6th bit let reg_id = (instruction - 0x70) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -392,7 +395,7 @@ impl CPU { self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } - 0x78 ... 0x7F => { + 0x78...0x7F => { // Test 7th bit let reg_id = (instruction - 0x78) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -405,7 +408,7 @@ impl CPU { } // Reset bits - 0x80 ... 0x87 => { + 0x80...0x87 => { // Reset 0th bit let reg_id = (instruction - 0x80) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -414,7 +417,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 0)); } - 0x88 ... 0x8F => { + 0x88...0x8F => { // Reset 1th bit let reg_id = (instruction - 0x88) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -423,7 +426,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 1)); } - 0x90 ... 0x97 => { + 0x90...0x97 => { // Reset 2nd bit let reg_id = (instruction - 0x90) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -432,7 +435,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 2)); } - 0x98 ... 0x9F => { + 0x98...0x9F => { // Reset 3th bit let reg_id = (instruction - 0x98) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -441,7 +444,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 3)); } - 0xA0 ... 0xA7 => { + 0xA0...0xA7 => { // Reset 4th bit let reg_id = (instruction - 0xA0) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -450,7 +453,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 4)); } - 0xA8 ... 0xAF => { + 0xA8...0xAF => { // Reset 5th bit let reg_id = (instruction - 0xA8) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -459,7 +462,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 5)); } - 0xB0 ... 0xB7 => { + 0xB0...0xB7 => { // Reset 6th bit let reg_id = (instruction - 0xB0) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -468,7 +471,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content & !(1 << 6)); } - 0xB8 ... 0xBF => { + 0xB8...0xBF => { // Reset 7th bit let reg_id = (instruction - 0xB8) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -479,7 +482,7 @@ impl CPU { } // Set bits - 0xC0 ... 0xC7 => { + 0xC0...0xC7 => { // Set 0th bit let reg_id = (instruction - 0xC0) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -488,7 +491,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content | (1 << 0)); } - 0xC8 ... 0xCF => { + 0xC8...0xCF => { // Set 1th bit let reg_id = (instruction - 0xC8) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -497,7 +500,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content | (1 << 1)); } - 0xD0 ... 0xD7 => { + 0xD0...0xD7 => { // Set 2nd bit let reg_id = (instruction - 0xD0) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -506,7 +509,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content | (1 << 2)); } - 0xD8 ... 0xDF => { + 0xD8...0xDF => { // Set 3th bit let reg_id = (instruction - 0xD8) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -515,7 +518,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content | (1 << 3)); } - 0xE0 ... 0xE7 => { + 0xE0...0xE7 => { // Set 4th bit let reg_id = (instruction - 0xE0) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -524,7 +527,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content | (1 << 4)); } - 0xE8 ... 0xEF => { + 0xE8...0xEF => { // Set 5th bit let reg_id = (instruction - 0xE8) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -533,7 +536,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content | (1 << 5)); } - 0xF0 ... 0xF7 => { + 0xF0...0xF7 => { // Set 6th bit let reg_id = (instruction - 0xF0) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -542,7 +545,7 @@ impl CPU { } self.set_8bit_reg(reg_id, reg_content | (1 << 6)); } - 0xF8 ... 0xFF => { + 0xF8...0xFF => { // Set 7th bit let reg_id = (instruction - 0xF8) as usize; let reg_content = self.get_8bit_reg(reg_id); @@ -766,7 +769,10 @@ impl CPU { #[inline] fn add_rr_rr(&mut self, r1: usize, r2: usize, r3: usize, r4: usize) -> u8 { if self.debug { - println!("ADD {}{}, {}{}", REG_NAMES[r1], REG_NAMES[r2], REG_NAMES[r3], REG_NAMES[r4]); + println!( + "ADD {}{}, {}{}", + REG_NAMES[r1], REG_NAMES[r2], REG_NAMES[r3], REG_NAMES[r4] + ); } let val1 = self.get_pair_value(r1, r2); @@ -830,7 +836,7 @@ impl CPU { } #[inline] - fn int_(&mut self, val: u8){ + fn int_(&mut self, val: u8) { if self.debug { println!("INT {:02X}", val); } @@ -868,14 +874,15 @@ impl CPU { loop { let mut cycles: i32 = 0; let start = Instant::now(); - for _ in 0 .. 1000 { + for _ in 0..1000 { cycles += self.run_instruction() as i32; } let gb_dur = cycles * 238; let our_dur = start.elapsed().subsec_nanos() as i32; let delta = gb_dur - our_dur; - if delta > (20 * 238) { // We're at least 20 cycles faster. + if delta > (20 * 238) { + // We're at least 20 cycles faster. sleep(Duration::new(0, delta as u32)); } else if delta < 0 { print!("-"); @@ -937,8 +944,11 @@ impl CPU { // We need to double-check the flags instruction = self.read_byte(self.ip); if self.debug { - print!("{:#06x}: [SP: {:#04X}] i={:02X}. ", &self.ip, &self.sp, &instruction); - for i in 0 .. 6 { + print!( + "{:#06x}: [SP: {:#04X}] i={:02X}. ", + &self.ip, &self.sp, &instruction + ); + for i in 0..6 { print!("{}: {:02X} ", REG_NAMES[i], self.get_8bit_reg(i)); } print!("A: {:02X} ", self.regs[REG_A]); @@ -959,7 +969,7 @@ impl CPU { println!("NOP"); } 4 - }, + } 0x01 => self.ld_rr_vv(REG_N_B, REG_N_C), 0x02 => self.ld_dref_rr_a(REG_N_B, REG_N_C), 0x03 => self.inc_rr(REG_N_B, REG_N_C), @@ -985,7 +995,7 @@ impl CPU { } 0x08 => { let a: u16 = to_u16(self.load_args(2)); - if self.debug{ + if self.debug { println!("LD ({:04X}), sp", a); } self.interconnect.write_word(a, self.sp); @@ -996,9 +1006,11 @@ impl CPU { if self.debug { println!("LD A, (BC)"); } - self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_N_B, REG_N_C)); + self.regs[REG_A] = self + .interconnect + .read_byte(self.get_pair_value(REG_N_B, REG_N_C)); 8 - }, + } 0x0B => self.dec_rr(REG_N_B, REG_N_C), 0x0C => self.reg_inc(REG_N_C), 0x0D => self.reg_dec(REG_N_C), @@ -1023,7 +1035,7 @@ impl CPU { 0x10 => { println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]); 4 - }, + } 0x11 => self.ld_rr_vv(REG_N_D, REG_N_E), 0x12 => self.ld_dref_rr_a(REG_N_D, REG_N_E), 0x13 => self.inc_rr(REG_N_D, REG_N_E), @@ -1046,20 +1058,22 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 - }, + } 0x18 => { let dst = self.load_args(1)[0]; self.jmp_r(dst); 12 - }, + } 0x19 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_D, REG_N_E), 0x1A => { if self.debug { println!("LD A, (DE)"); } - self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_N_D, REG_N_E)); + self.regs[REG_A] = self + .interconnect + .read_byte(self.get_pair_value(REG_N_D, REG_N_E)); 8 - }, + } 0x1B => self.dec_rr(REG_N_D, REG_N_E), 0x1C => self.reg_inc(REG_N_E), 0x1D => self.reg_dec(REG_N_E), @@ -1080,8 +1094,7 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 - }, - + } 0x20 => { let c = self.flags & FLAG_Z == 0; @@ -1096,7 +1109,7 @@ impl CPU { self.interconnect.write_byte(addr, self.regs[REG_A]); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1)); 8 - }, + } 0x23 => self.inc_rr(REG_N_H, REG_N_L), 0x24 => self.reg_inc(REG_N_H), 0x25 => self.reg_dec(REG_N_H), @@ -1138,11 +1151,11 @@ impl CPU { self.set_clear_flag(FLAG_Z, a == 0); 4 - }, + } 0x28 => { let c = self.flags & FLAG_Z == FLAG_Z; self.jmp_r_condition("Z".to_owned(), c) - }, + } 0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L), 0x2A => { if self.debug { @@ -1152,7 +1165,7 @@ impl CPU { self.regs[REG_A] = self.interconnect.read_byte(addr); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1)); 8 - }, + } 0x2B => self.dec_rr(REG_N_H, REG_N_L), 0x2C => self.reg_inc(REG_N_L), 0x2D => self.reg_dec(REG_N_L), @@ -1165,13 +1178,12 @@ impl CPU { self.set_flag(FLAG_N); self.set_flag(FLAG_H); 4 - }, - + } 0x30 => { let c = self.flags & FLAG_C == 0; self.jmp_r_condition("NC".to_owned(), c) - }, + } 0x31 => { let args = self.load_args(2); self.sp = to_u16(args); @@ -1179,7 +1191,7 @@ impl CPU { println!("LD SP, {:04x}", self.sp); } 12 - }, + } 0x32 => { if self.debug { println!("LD (HL-), A"); @@ -1188,7 +1200,7 @@ impl CPU { self.interconnect.write_byte(addr, self.regs[REG_A]); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1)); 8 - }, + } 0x33 => { if self.debug { println!("INC SP"); @@ -1208,11 +1220,11 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 - }, + } 0x38 => { let c = self.flags & FLAG_C == FLAG_C; self.jmp_r_condition("C".to_owned(), c) - }, + } 0x39 => { if self.debug { println!("ADD HL, SP"); @@ -1226,7 +1238,7 @@ impl CPU { self.set_clear_flag(FLAG_C, old > v && sp > 0); self.set_clear_flag(FLAG_H, ((old & 0xFFF) + (sp & 0xFFF)) > 0xFFF); 8 - }, + } 0x3A => { if self.debug { println!("LD A, (HL-)"); @@ -1258,14 +1270,14 @@ impl CPU { } // LDs - 0x40 ... 0x47 => self.ld_r_r(REG_N_B, (instruction - 0x40) as usize), - 0x48 ... 0x4F => self.ld_r_r(REG_N_C, (instruction - 0x48) as usize), - 0x50 ... 0x57 => self.ld_r_r(REG_N_D, (instruction - 0x50) as usize), - 0x58 ... 0x5F => self.ld_r_r(REG_N_E, (instruction - 0x58) as usize), - 0x60 ... 0x67 => self.ld_r_r(REG_N_H, (instruction - 0x60) as usize), - 0x68 ... 0x6F => self.ld_r_r(REG_N_L, (instruction - 0x68) as usize), - 0x70 ... 0x75 | 0x77 => self.ld_r_r(REG_N_HL, (instruction - 0x70) as usize), - 0x78 ... 0x7F => self.ld_r_r(REG_N_A, (instruction - 0x78) as usize), + 0x40...0x47 => self.ld_r_r(REG_N_B, (instruction - 0x40) as usize), + 0x48...0x4F => self.ld_r_r(REG_N_C, (instruction - 0x48) as usize), + 0x50...0x57 => self.ld_r_r(REG_N_D, (instruction - 0x50) as usize), + 0x58...0x5F => self.ld_r_r(REG_N_E, (instruction - 0x58) as usize), + 0x60...0x67 => self.ld_r_r(REG_N_H, (instruction - 0x60) as usize), + 0x68...0x6F => self.ld_r_r(REG_N_L, (instruction - 0x68) as usize), + 0x70...0x75 | 0x77 => self.ld_r_r(REG_N_HL, (instruction - 0x70) as usize), + 0x78...0x7F => self.ld_r_r(REG_N_A, (instruction - 0x78) as usize), // HALT 0x76 => { @@ -1274,10 +1286,10 @@ impl CPU { } self.halted = true; 4 - }, + } // ADD - 0x80 ... 0x87 => { + 0x80...0x87 => { let reg_id = (instruction - 0x80) as usize; if self.debug { println!("ADD {}", REG_NAMES[reg_id]); @@ -1288,7 +1300,7 @@ impl CPU { } // ADC - 0x88 ... 0x8F => { + 0x88...0x8F => { let reg_id = (instruction - 0x88) as usize; if self.debug { println!("ADC {}", REG_NAMES[reg_id]); @@ -1300,7 +1312,7 @@ impl CPU { } // SUBs - 0x90 ... 0x97 => { + 0x90...0x97 => { let reg_id = (instruction - 0x90) as usize; if self.debug { println!("SUB {}", REG_NAMES[reg_id]); @@ -1311,7 +1323,7 @@ impl CPU { } // SBC - 0x98 ... 0x9F => { + 0x98...0x9F => { let reg_id = (instruction - 0x98) as usize; if self.debug { println!("SBC {}", REG_NAMES[reg_id]); @@ -1322,7 +1334,7 @@ impl CPU { } // AND - 0xA0 ... 0xA7 => { + 0xA0...0xA7 => { let reg_id = (instruction - 0xA0) as usize; if self.debug { println!("AND {}", REG_NAMES[reg_id]); @@ -1338,7 +1350,7 @@ impl CPU { } // XOR - 0xA8 ... 0xAF => { + 0xA8...0xAF => { let reg_id = (instruction - 0xA8) as usize; if self.debug { println!("XOR {}", REG_NAMES[reg_id]); @@ -1351,10 +1363,10 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 - }, + } // OR - 0xB0 ... 0xB7 => { + 0xB0...0xB7 => { let reg_id = (instruction - 0xB0) as usize; if self.debug { println!("OR {}", REG_NAMES[reg_id]); @@ -1370,7 +1382,7 @@ impl CPU { } // CP - 0xB8 ... 0xBF => { + 0xB8...0xBF => { let reg_id = (instruction - 0xB8) as usize; if self.debug { println!("CP {}", REG_NAMES[reg_id]); @@ -1379,17 +1391,17 @@ impl CPU { let v = self.get_8bit_reg(reg_id); self.cp_r(v); 4 - }, + } 0xC0 => { let c = self.flags & FLAG_Z == 0; self.ret_condition("NZ".to_owned(), c) - }, + } 0xC1 => self.pop_rr(REG_N_B, REG_N_C), 0xC2 => { let c = self.flags & FLAG_Z == 0; self.jmp_p_condition("NZ".to_owned(), c) - }, + } 0xC3 => { let dst = to_u16(self.load_args(2)); if self.debug { @@ -1397,7 +1409,7 @@ impl CPU { } self.jmp_p(dst); 16 - }, + } 0xC4 => { let c = self.flags & FLAG_Z == 0; self.call_condition("NZ".to_owned(), c) @@ -1412,19 +1424,19 @@ impl CPU { self.add_r(val); 8 - }, + } 0xC7 => self.rst(0x00), 0xC8 => { let c = self.flags & FLAG_Z == FLAG_Z; self.ret_condition("Z".to_owned(), c) - }, + } 0xC9 => { if self.debug { println!("RET"); } self.ret(); 16 - }, + } 0xCA => { let c = self.flags & FLAG_Z == FLAG_Z; self.jmp_p_condition("Z".to_owned(), c) @@ -1432,11 +1444,11 @@ impl CPU { 0xCB => { self.run_prefix_instruction(); 12 // TODO: Verify that this is the case for all prefix instructions. - }, + } 0xCC => { let c = self.flags & FLAG_Z == FLAG_Z; self.call_condition("Z".to_owned(), c) - }, + } 0xCD => self.call_condition("".to_owned(), true), 0xCE => { let arg = self.load_args(1)[0]; @@ -1445,14 +1457,13 @@ impl CPU { } self.adc_r(arg); 8 - }, + } 0xCF => self.rst(0x08), - 0xD0 => { let c = self.flags & FLAG_C == 0; self.ret_condition("NC".to_owned(), c) - }, + } 0xD1 => self.pop_rr(REG_N_D, REG_N_E), 0xD2 => { let c = self.flags & FLAG_C == 0; @@ -1472,12 +1483,12 @@ impl CPU { self.sub_r(val); 8 - }, + } 0xD7 => self.rst(0x10), 0xD8 => { let c = self.flags & FLAG_C == FLAG_C; self.ret_condition("C".to_owned(), c) - }, + } 0xD9 => { if self.debug { println!("RETI"); @@ -1487,7 +1498,7 @@ impl CPU { 0xDA => { let c = self.flags & FLAG_C == FLAG_C; self.jmp_p_condition("C".to_owned(), c) - }, + } 0xDB => panic!("NON-EXISTING OPCODE"), 0xDC => { let c = self.flags & FLAG_C == FLAG_C; @@ -1501,7 +1512,7 @@ impl CPU { } self.sbc_r(arg); 8 - }, + } 0xDF => self.rst(0x18), 0xE0 => { @@ -1509,9 +1520,10 @@ impl CPU { if self.debug { println!("LDH {:02X}, A", args[0]); } - self.interconnect.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]); + self.interconnect + .write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]); 12 - }, + } 0xE1 => self.pop_rr(REG_N_H, REG_N_L), 0xE2 => { if self.debug { @@ -1520,7 +1532,7 @@ impl CPU { let addr: u16 = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16; self.interconnect.write_byte(addr, self.regs[REG_A]); 8 - }, + } 0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"), 0xE5 => self.push_rr(REG_N_H, REG_N_L), 0xE6 => { @@ -1536,7 +1548,7 @@ impl CPU { self.clear_flag(FLAG_C); 8 - }, + } 0xE7 => self.rst(0x20), 0xE8 => { let arg = self.load_args(1)[0] as i8; @@ -1563,16 +1575,16 @@ impl CPU { } self.ip = self.get_pair_value(REG_N_H, REG_N_L); 4 - }, + } 0xEA => { let addr = to_u16(self.load_args(2)); - if self.debug{ + if self.debug { println!("LD ({:04X}), A", addr); } self.interconnect.write_byte(addr, self.regs[REG_A]); 16 - }, - 0xEB ... 0xED => panic!("NON-EXISTING OPCODE"), + } + 0xEB...0xED => panic!("NON-EXISTING OPCODE"), 0xEE => { let arg = self.load_args(1)[0]; if self.debug { @@ -1585,7 +1597,7 @@ impl CPU { self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); 8 - }, + } 0xEF => self.rst(0x28), 0xF0 => { @@ -1595,23 +1607,23 @@ impl CPU { } self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + args[0] as u16); 12 - }, + } 0xF1 => self.pop_rr(REG_N_A, REG_N_F), 0xF2 => { - if self.debug{ + if self.debug { println!("LD A, (C)"); } let addr = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16; self.regs[REG_A] = self.interconnect.read_byte(addr); 8 - }, + } 0xF3 => { if self.debug { println!("DI"); } self.ime = false; 4 - }, + } 0xF4 => panic!("NON-EXISTING OPCODE"), 0xF5 => self.push_rr(REG_N_A, REG_N_F), 0xF6 => { @@ -1626,7 +1638,7 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 8 - }, + } 0xF7 => self.rst(0x30), 0xF8 => { let arg = self.load_args(1)[0] as i8; @@ -1650,14 +1662,14 @@ impl CPU { self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10); } 12 - }, + } 0xF9 => { if self.debug { println!("LD SP, HL"); } self.sp = self.get_pair_value(REG_N_H, REG_N_L); 8 - }, + } 0xFA => { let addr = to_u16(self.load_args(2)); if self.debug { @@ -1665,7 +1677,7 @@ impl CPU { } self.regs[REG_A] = self.interconnect.read_byte(addr); 16 - }, + } 0xFB => { // Enable interrupts - TODO if self.debug { @@ -1673,7 +1685,7 @@ impl CPU { } self.ime = true; // interrupt master enable 4 - }, + } 0xFC | 0xFD => panic!("NON-EXISTING OPCODE"), 0xFE => { @@ -1684,9 +1696,9 @@ impl CPU { self.cp_r(args[0]); 8 - }, + } 0xFF => self.rst(0x38), - _ => panic!("Unknown instruction: {:02x}", instruction) + _ => panic!("Unknown instruction: {:02x}", instruction), }; } self.interconnect.tick(cycles); diff --git a/src/display.rs b/src/display.rs index d3e568c..e4c730c 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,5 +1,5 @@ -extern crate sdl2; extern crate libc; +extern crate sdl2; // Internal ram size const VRAM_SIZE: usize = 0x2000; @@ -42,7 +42,7 @@ const SPRITE_OBJ_BG_PRIORITY: u8 = 1 << 7; const SPRITE_Y_FLIP: u8 = 1 << 6; const SPRITE_X_FLIP: u8 = 1 << 5; const SPRITE_PALETTE_NO: u8 = 1 << 4; // NonCGB only -// const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only + // const SPRITE_TILE_VRAM_BANK: u8 = 1 << 3; // CGB only // Display color /* @@ -65,7 +65,7 @@ enum PixelOrigin { Empty, Background, Window, - Sprite + Sprite, } #[derive(Copy, Clone)] @@ -149,8 +149,7 @@ pub struct Display { current_ticks: u16, current_mode: DisplayMode, // TODO - - renderer: sdl2::render::Renderer<'static>, + renderer: sdl2::render::Canvas, pub event_pump: sdl2::EventPump, @@ -167,8 +166,12 @@ impl Display { pub fn new() -> Display { let sdl_ctx = sdl2::init().unwrap(); let video_ctx = sdl_ctx.video().unwrap(); - let wnd = video_ctx.window("RustBoy", WND_RES_X as u32, WND_RES_Y as u32).position_centered().build().expect("Failed to create window :<"); - let renderer = wnd.renderer().build().expect("Could not build renderer"); + let wnd = video_ctx + .window("RustBoy", WND_RES_X as u32, WND_RES_Y as u32) + .position_centered() + .build() + .expect("Failed to create window :<"); + let renderer = wnd.into_canvas().build().expect("Could not build renderer"); let event_pump = sdl_ctx.event_pump().expect("Getting event pump failed"); let pixels = [Pixel::default(); (GB_PIXELS_X as usize) * (GB_PIXELS_Y as usize)]; @@ -214,33 +217,34 @@ impl Display { } fn render_screen(&mut self) { - for y in 0 .. GB_PIXELS_Y { - for x in 0 .. GB_PIXELS_X { + for y in 0..GB_PIXELS_Y { + for x in 0..GB_PIXELS_X { let f = &mut self.pixels[(x as usize) + (y as usize) * GB_PIXELS_X]; self.renderer.set_draw_color(f.color); - self.renderer.fill_rect( - sdl2::rect::Rect::new( + self.renderer + .fill_rect(sdl2::rect::Rect::new( x as i32 * SCALE as i32, y as i32 * SCALE as i32, SCALE as u32, SCALE as u32, - ) - ).expect("Rendering failed"); + )) + .expect("Rendering failed"); // Clear origin after rendering f.origin = PixelOrigin::Empty; } } - self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 255)); - self.renderer.draw_rect( - sdl2::rect::Rect::new( + self.renderer + .set_draw_color(sdl2::pixels::Color::RGB(255, 0, 255)); + self.renderer + .draw_rect(sdl2::rect::Rect::new( 0, 0, (GB_PIXELS_X * SCALE) as u32, (GB_PIXELS_Y * SCALE) as u32, - ) - ).expect("Rendering failed"); + )) + .expect("Rendering failed"); } #[inline] @@ -268,8 +272,8 @@ impl Display { #[inline] pub fn write_byte(&mut self, addr: u16, val: u8) { match addr { - 0x8000 ... 0x9FFF => self.vram[(addr - 0x8000) as usize] = val, - 0xFE00 ... 0xFE9F => self.oam[(addr - 0xFE00) as usize] = val, + 0x8000...0x9FFF => self.vram[(addr - 0x8000) as usize] = val, + 0xFE00...0xFE9F => self.oam[(addr - 0xFE00) as usize] = val, 0xFF40 => self.control = val, 0xFF41 => self.status = val, 0xFF42 => self.scrolly = val, @@ -298,8 +302,8 @@ impl Display { #[inline] pub fn read_byte(&self, addr: u16) -> u8 { match addr { - 0x8000 ... 0x9FFF => self.vram[(addr - 0x8000) as usize], - 0xFE00 ... 0xFE9F => self.oam[(addr - 0xFE00) as usize], + 0x8000...0x9FFF => self.vram[(addr - 0x8000) as usize], + 0xFE00...0xFE9F => self.oam[(addr - 0xFE00) as usize], 0xFF40 => self.control, 0xFF41 => self.status, 0xFF42 => self.scrolly, @@ -329,15 +333,17 @@ impl Display { self.current_ticks += ticks; match self.current_mode { - DisplayMode::ReadOAMMemory => { // Mode 2, Reading OAM memory, RAM may be accessed. + DisplayMode::ReadOAMMemory => { + // Mode 2, Reading OAM memory, RAM may be accessed. if self.current_ticks > TICKS_END_SCANLINE { self.current_ticks = 0; self.current_mode = DisplayMode::ReadFullMemory; } self.status |= 2; - }, - DisplayMode::ReadFullMemory => { // Mode 3, reading OAM, VMEM and palette data. - // Nothing may be accessed. + } + DisplayMode::ReadFullMemory => { + // Mode 3, reading OAM, VMEM and palette data. + // Nothing may be accessed. if self.current_ticks > TICKS_END_READMODE { self.current_ticks = 0; self.current_mode = DisplayMode::HBlank; @@ -349,8 +355,9 @@ impl Display { } } self.status |= 3; - }, - DisplayMode::HBlank => { // Mode 0, H-Blank, Memory (RAM, OAM) may be accessed. + } + DisplayMode::HBlank => { + // Mode 0, H-Blank, Memory (RAM, OAM) may be accessed. if self.current_ticks > TICKS_END_HBLANK { self.current_ticks = 0; self.curline += 1; @@ -369,9 +376,10 @@ impl Display { } self.status &= 0xFC; self.status |= 0; - }, - DisplayMode::VBlank => { // Mode 1, V-Blank (or display disabled), Memory (RAM, OAM) - // may be accessed + } + DisplayMode::VBlank => { + // Mode 1, V-Blank (or display disabled), Memory (RAM, OAM) + // may be accessed if self.current_ticks > TICKS_END_VBLANK { self.current_ticks = 0; self.curline += 1; @@ -383,7 +391,8 @@ impl Display { if self.frameskip < self.frame_no { self.render_screen(); self.renderer.present(); - self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 255, 255)); + self.renderer + .set_draw_color(sdl2::pixels::Color::RGB(255, 255, 255)); self.renderer.clear(); self.frame_no = 0; } else { @@ -413,7 +422,7 @@ impl Display { fn render_sprites(&mut self, sprites: &Vec) { if self.control & CTRL_BG_SPRITE_ENABLE > 0 { let mut num_rendered: u8 = 0; - for i in 0 .. 39 { + for i in 0..39 { // Gameboy limitation if num_rendered > 10 { break; @@ -425,7 +434,6 @@ impl Display { continue; } - // Calculate correct coords let x: u8 = sprite.x.wrapping_sub(8); let y: u8 = sprite.y.wrapping_sub(16); @@ -438,7 +446,7 @@ impl Display { // Flip sprite, TODO: Validate let y_o: u8 = match sprite.is_y_flipped() { true => y ^ 7, - false => y + false => y, }; let tile_offset_y: usize = render_y as usize - y_o as usize; let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode? @@ -456,9 +464,9 @@ impl Display { } let limit = match wide_mode { true => 16, - false => 8 + false => 8, }; - for x_o in 0 .. limit { + for x_o in 0..limit { let b1: bool; let b2: bool; @@ -513,7 +521,12 @@ impl Display { let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize]; // Draw stuff. We're currently only in monochrome mode - self.set_pixel(x.wrapping_add(x_o), render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), PixelOrigin::Sprite); + self.set_pixel( + x.wrapping_add(x_o), + render_y, + sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), + PixelOrigin::Sprite, + ); } } } @@ -557,8 +570,8 @@ impl Display { let render_y: u8 = self.curline; // Order sprites by priority let mut queue: Vec = Vec::new(); - for i in 0 .. 39 { - queue.push(Sprite{ + for i in 0..39 { + queue.push(Sprite { y: self.oam[i * 4 + 0], x: self.oam[i * 4 + 1], tile: self.oam[i * 4 + 2], @@ -571,20 +584,19 @@ impl Display { use std::cmp; queue.sort_by(|x, y| { if x.x > y.x { - cmp::Ordering::Greater - } else if x.x < y.x { - cmp::Ordering::Less - } else { - cmp::Ordering::Equal - } + cmp::Ordering::Greater + } else if x.x < y.x { + cmp::Ordering::Less + } else { + cmp::Ordering::Equal + } }); queue.reverse(); - // Render background if (self.control & CTRL_BG_DISPLAY) == CTRL_BG_DISPLAY { // Render pixels (20 tiles) - for render_x in 0 .. 160 { + for render_x in 0..160 { // Absolute render coordinates let render_abs_x = map_offset_x.wrapping_add(render_x); let render_abs_y = map_offset_y.wrapping_add(render_y); @@ -595,7 +607,8 @@ impl Display { let tile_index_y: u8 = render_abs_y >> 3; let tile_offset_y: u8 = render_abs_y & 7; - let vram_offset: usize = background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize; + let vram_offset: usize = + background_map + ((tile_index_y as usize) * 32) + tile_index_x as usize; // Obtain tile ID in this area let tile_id = self.vram[vram_offset]; @@ -624,7 +637,12 @@ impl Display { 0 => PixelOrigin::Empty, // Hack so that objects will be in front of it. _ => PixelOrigin::Background, }; - self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin); + self.set_pixel( + render_x, + render_y, + sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), + origin, + ); } } @@ -635,7 +653,7 @@ impl Display { //let rx = self.windowx.wrapping_add(7); let rx = 7u8.wrapping_sub(self.windowx); let ry = render_y.wrapping_add(self.windowy); - for r_x in 0 .. 160u8 { + for r_x in 0..160u8 { let render_x = r_x.wrapping_add(rx); // Absolute render coordinates let tile_index_x: u8 = render_x >> 3; @@ -643,7 +661,8 @@ impl Display { let tile_index_y: u8 = ry >> 3; let tile_offset_y: u8 = ry & 7; - let vram_offset: usize = window_map + (tile_index_y as usize) * 32 + tile_index_x as usize; + let vram_offset: usize = + window_map + (tile_index_y as usize) * 32 + tile_index_x as usize; // Obtain tile ID in this area let tile_id = self.vram[vram_offset]; @@ -672,7 +691,12 @@ impl Display { 0 => PixelOrigin::Empty, // Hack so that objects will be in front of it. _ => PixelOrigin::Window, }; - self.set_pixel(render_x, render_y, sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), origin); + self.set_pixel( + render_x, + render_y, + sdl2::pixels::Color::RGB(entry[0], entry[1], entry[2]), + origin, + ); } } } diff --git a/src/interconnect.rs b/src/interconnect.rs index aee15f7..9ed8c39 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -21,11 +21,11 @@ const KEY_SELECT: u8 = 1 << 2; const KEY_B: u8 = 1 << 1; const KEY_A: u8 = 1 << 0; +use super::cartridge; use super::display; +use super::serial; use super::sound; use super::timer; -use super::serial; -use super::cartridge; extern crate sdl2; @@ -34,7 +34,14 @@ use self::sdl2::keyboard::Keycode; #[derive(Debug)] enum Key { - UP, LEFT, DOWN, RIGHT, START, SELECT, A, B + UP, + LEFT, + DOWN, + RIGHT, + START, + SELECT, + A, + B, } pub struct Interconnect { @@ -153,29 +160,81 @@ impl Interconnect { // Make sure the window is responsive: if self.cycles > 500 { loop { - if let Some(event) = self.display.event_pump.poll_event(){ + if let Some(event) = self.display.event_pump.poll_event() { match event { - Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { + Event::Quit { .. } + | Event::KeyDown { + keycode: Some(Keycode::Escape), + .. + } => { self.cartridge.save(); panic!("TODO: Proper shutdown"); - }, - Event::KeyDown { keycode: Some(Keycode::Left), .. } => self.press_key(Key::LEFT), - Event::KeyDown { keycode: Some(Keycode::Down), .. } => self.press_key(Key::DOWN), - Event::KeyDown { keycode: Some(Keycode::Up), .. } => self.press_key(Key::UP), - Event::KeyDown { keycode: Some(Keycode::Right), .. } => self.press_key(Key::RIGHT), - Event::KeyDown { keycode: Some(Keycode::A), .. } => self.press_key(Key::START), - Event::KeyDown { keycode: Some(Keycode::S), .. } => self.press_key(Key::SELECT), - Event::KeyDown { keycode: Some(Keycode::Z), .. } => self.press_key(Key::A), - Event::KeyDown { keycode: Some(Keycode::X), .. } => self.press_key(Key::B), + } + Event::KeyDown { + keycode: Some(Keycode::Left), + .. + } => self.press_key(Key::LEFT), + Event::KeyDown { + keycode: Some(Keycode::Down), + .. + } => self.press_key(Key::DOWN), + Event::KeyDown { + keycode: Some(Keycode::Up), + .. + } => self.press_key(Key::UP), + Event::KeyDown { + keycode: Some(Keycode::Right), + .. + } => self.press_key(Key::RIGHT), + Event::KeyDown { + keycode: Some(Keycode::A), + .. + } => self.press_key(Key::START), + Event::KeyDown { + keycode: Some(Keycode::S), + .. + } => self.press_key(Key::SELECT), + Event::KeyDown { + keycode: Some(Keycode::Z), + .. + } => self.press_key(Key::A), + Event::KeyDown { + keycode: Some(Keycode::X), + .. + } => self.press_key(Key::B), - Event::KeyUp { keycode: Some(Keycode::Left), .. } => self.release_key(Key::LEFT), - Event::KeyUp { keycode: Some(Keycode::Down), .. } => self.release_key(Key::DOWN), - Event::KeyUp { keycode: Some(Keycode::Up), .. } => self.release_key(Key::UP), - Event::KeyUp { keycode: Some(Keycode::Right), .. } => self.release_key(Key::RIGHT), - Event::KeyUp { keycode: Some(Keycode::A), .. } => self.release_key(Key::START), - Event::KeyUp { keycode: Some(Keycode::S), .. } => self.release_key(Key::SELECT), - Event::KeyUp { keycode: Some(Keycode::Z), .. } => self.release_key(Key::A), - Event::KeyUp { keycode: Some(Keycode::X), .. } => self.release_key(Key::B), + Event::KeyUp { + keycode: Some(Keycode::Left), + .. + } => self.release_key(Key::LEFT), + Event::KeyUp { + keycode: Some(Keycode::Down), + .. + } => self.release_key(Key::DOWN), + Event::KeyUp { + keycode: Some(Keycode::Up), + .. + } => self.release_key(Key::UP), + Event::KeyUp { + keycode: Some(Keycode::Right), + .. + } => self.release_key(Key::RIGHT), + Event::KeyUp { + keycode: Some(Keycode::A), + .. + } => self.release_key(Key::START), + Event::KeyUp { + keycode: Some(Keycode::S), + .. + } => self.release_key(Key::SELECT), + Event::KeyUp { + keycode: Some(Keycode::Z), + .. + } => self.release_key(Key::A), + Event::KeyUp { + keycode: Some(Keycode::X), + .. + } => self.release_key(Key::B), _ => {} } } else { @@ -199,25 +258,21 @@ impl Interconnect { // TODO: if some flag set, use bios, otherwise only use rom // For now, just use bios match addr { - 0x0000 ... 0x100 => { + 0x0000...0x100 => { if self.disable_bootrom == 0 { self.bios[addr as usize] } else { self.cartridge.read_byte(addr) } - }, - 0x100 ... 0x7FFF => self.cartridge.read_byte(addr), - 0x8000 ... 0x9FFF => self.display.read_byte(addr), - 0xA000 ... 0xBFFF => self.cartridge.read_byte(addr), - 0xC000 ... 0xCFFF => { - self.ram[(addr - 0xC000) as usize] - }, - 0xD000 ... 0xDFFF => { - self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] - }, - 0xE000 ... 0xEFFF => { - self.ram[(addr - 0xE000) as usize] } + 0x100...0x7FFF => self.cartridge.read_byte(addr), + 0x8000...0x9FFF => self.display.read_byte(addr), + 0xA000...0xBFFF => self.cartridge.read_byte(addr), + 0xC000...0xCFFF => self.ram[(addr - 0xC000) as usize], + 0xD000...0xDFFF => { + self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] + } + 0xE000...0xEFFF => self.ram[(addr - 0xE000) as usize], 0xFF00 => { if self.joy_switch & KEY_REGULAR == 0 { self.joy_regular_keys @@ -228,39 +283,25 @@ impl Interconnect { 0x3F } } - 0xFF01 ... 0xFF02 => self.serial.read_byte(addr), - 0xFF04 ... 0xFF07 => self.timer.read_byte(addr), + 0xFF01...0xFF02 => self.serial.read_byte(addr), + 0xFF04...0xFF07 => self.timer.read_byte(addr), 0xFF0F => { // println!("Reading IF: {:02X}", self.interrupt_request_flags); self.interrupt_request_flags - }, - 0xFF10 ... 0xFF26 => { - self.sound.read_byte(addr) - }, - 0xFF30 ... 0xFF3F => self.sound.read_byte(addr), - 0xFF40 ... 0xFF4B => { - self.display.read_byte(addr) - }, - 0xFF50 => { - self.disable_bootrom - }, + } + 0xFF10...0xFF26 => self.sound.read_byte(addr), + 0xFF30...0xFF3F => self.sound.read_byte(addr), + 0xFF40...0xFF4B => self.display.read_byte(addr), + 0xFF50 => self.disable_bootrom, 0xFF51 => self.vram_dma_source_high, 0xFF52 => self.vram_dma_source_low, 0xFF53 => self.vram_dma_destination_high, 0xFF54 => self.vram_dma_destination_low, - 0xFF55 => { - self.vram_dma_length - } - 0xFF56 => { - self.infrared_com_port - }, + 0xFF55 => self.vram_dma_length, + 0xFF56 => self.infrared_com_port, 0xFF70 => self.wram_bank, - 0xFF80 ... 0xFFFE => { - self.hiram[(addr - 0xFF80) as usize] - }, - 0xFFFF => { - self.interrupt - } + 0xFF80...0xFFFE => self.hiram[(addr - 0xFF80) as usize], + 0xFFFF => self.interrupt, _ => { println!("Read from {:04X} not supported.", addr); 0 @@ -285,36 +326,36 @@ impl Interconnect { */ match addr { - 0x0000 ... 0x7FFF => self.cartridge.write_byte(addr, val), - 0x8000 ... 0x9FFF => self.display.write_byte(addr, val), - 0xA000 ... 0xBFFF => self.cartridge.write_byte(addr, val), - 0xC000 ... 0xCFFF => { + 0x0000...0x7FFF => self.cartridge.write_byte(addr, val), + 0x8000...0x9FFF => self.display.write_byte(addr, val), + 0xA000...0xBFFF => self.cartridge.write_byte(addr, val), + 0xC000...0xCFFF => { self.ram[(addr - 0xC000) as usize] = val; - }, - 0xD000 ... 0xDFFF => { + } + 0xD000...0xDFFF => { self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] = val; } - 0xFE00 ... 0xFE9F => self.display.write_byte(addr, val), // OAM + 0xFE00...0xFE9F => self.display.write_byte(addr, val), // OAM 0xFF00 => { // Joystick select self.joy_switch = val; } - 0xFF01 ... 0xFF02 => self.serial.write_byte(addr, val), - 0xFF04 ... 0xFF07 => self.timer.write_byte(addr, val), + 0xFF01...0xFF02 => self.serial.write_byte(addr, val), + 0xFF04...0xFF07 => self.timer.write_byte(addr, val), 0xFF0F => { self.interrupt_request_flags = val; } - 0xFF10 ... 0xFF26 => { + 0xFF10...0xFF26 => { self.sound.write_byte(addr, val); - }, - 0xFF30 ... 0xFF3F => self.sound.write_byte(addr, val), + } + 0xFF30...0xFF3F => self.sound.write_byte(addr, val), // Exclude DMA transfer, we will do this below - 0xFF40 ... 0xFF45 | 0xFF47 ... 0xFF4B => { + 0xFF40...0xFF45 | 0xFF47...0xFF4B => { self.display.write_byte(addr, val); - }, + } 0xFF46 => { // println!("OAM DMA transfer"); - for x in 0x00 .. 0x9F { + for x in 0x00..0x9F { let dma_b = self.read_byte(((val as u16) << 8) | x); self.write_byte(0xFE00 | x, dma_b); } @@ -322,17 +363,22 @@ impl Interconnect { 0xFF50 => { println!("Disabling boot rom."); self.disable_bootrom = val; - }, + } 0xFF51 => self.vram_dma_source_high = val, 0xFF52 => self.vram_dma_source_low = val & 0xF0, 0xFF53 => self.vram_dma_destination_high = val & 0x1F, 0xFF54 => self.vram_dma_destination_low = val & 0xF0, 0xFF55 => { - let src: u16 = ((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16; - let mut dst: u16 = ((self.vram_dma_destination_high as u16) << 8) | self.vram_dma_destination_low as u16; + let src: u16 = + ((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16; + let mut dst: u16 = ((self.vram_dma_destination_high as u16) << 8) + | self.vram_dma_destination_low as u16; dst += 0x8000; - println!("VRAM DMA transfer from {:04X} to {:04X}; {:02X}", src, dst, val); + println!( + "VRAM DMA transfer from {:04X} to {:04X}; {:02X}", + src, dst, val + ); let len: u16 = ((val & 0x7F) + 1) as u16 * 0x10 - 1; for i in 0..len { let v = self.read_byte(src.wrapping_add(i)); @@ -344,7 +390,7 @@ impl Interconnect { } 0xFF56 => { self.infrared_com_port = val; - }, + } 0xFF70 => { if self.wram_bank != val { println!("Switching wram bank to {:02X}", val); @@ -358,13 +404,13 @@ impl Interconnect { } } } - 0xFF80 ... 0xFFFE => { + 0xFF80...0xFFFE => { self.hiram[(addr - 0xFF80) as usize] = val; - }, + } 0xFFFF => { println!("Setting interrupt mask value {:02X}", val); self.interrupt = val; - }, + } _ => { println!("Write {:02X} to {:04X} not supported.", val, addr); } diff --git a/src/main.rs b/src/main.rs index fc90f43..749f915 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,21 @@ // let's try to write our own, awesome emulator. // gameboy (color?) -use std::path::Path; +use std::env; +use std::fs; use std::io; use std::io::Read; use std::io::Write; -use std::fs; -use std::env; +use std::path::Path; mod cartridge; mod cpu; mod display; mod interconnect; +mod mbc; +mod serial; mod sound; mod timer; -mod serial; -mod mbc; - fn main() { let args: Vec = env::args().collect(); diff --git a/src/mbc/mbc.rs b/src/mbc/mbc.rs index 50506e2..1c0bc72 100644 --- a/src/mbc/mbc.rs +++ b/src/mbc/mbc.rs @@ -12,31 +12,34 @@ pub struct NoMBC { impl NoMBC { pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC { - NoMBC { - rom: rom, - ram: ram, - } + NoMBC { rom: rom, ram: ram } } } impl MBC for NoMBC { - fn dump_ram(&self, file: &String){ + fn dump_ram(&self, file: &String) { super::super::write_file(&file, &self.ram).expect("Saving failed"); } fn write_byte(&mut self, addr: u16, val: u8) { - println!("Writing not supported for cartridges without MBC. (Tried to set {:04X} to {:02X})", addr, val); + println!( + "Writing not supported for cartridges without MBC. (Tried to set {:04X} to {:02X})", + addr, val + ); } fn read_byte(&self, addr: u16) -> u8 { match addr { - 0x0000 ... 0x7FFF => self.rom[addr as usize], - 0xA000 ... 0xBFFF => { + 0x0000...0x7FFF => self.rom[addr as usize], + 0xA000...0xBFFF => { // TODO: Check for ram let addr = (addr as usize) - 0xA000; if addr >= self.ram.len() { - println!("Tried to access {:04X}, however the memory is not present.", addr + 0xA000); + println!( + "Tried to access {:04X}, however the memory is not present.", + addr + 0xA000 + ); 0 } else { self.ram[addr] diff --git a/src/mbc/mbc1.rs b/src/mbc/mbc1.rs index 6c575e5..006ff83 100644 --- a/src/mbc/mbc1.rs +++ b/src/mbc/mbc1.rs @@ -30,33 +30,33 @@ impl MBC1 { fn active_rom_bank(&self) -> u8 { match self.bank_mode { BankMode::RomBankMode => self.rom_bank_no | (self.bank_no_high << 5), - BankMode::RamBankMode => self.rom_bank_no + BankMode::RamBankMode => self.rom_bank_no, } } fn active_ram_bank(&self) -> u8 { match self.bank_mode { BankMode::RomBankMode => 0, - BankMode::RamBankMode => self.bank_no_high + BankMode::RamBankMode => self.bank_no_high, } } - } +} impl MBC for MBC1 { - fn dump_ram(&self, file: &String){ + fn dump_ram(&self, file: &String) { super::super::write_file(&file, &self.ram).expect("Saving failed"); } fn read_byte(&self, addr: u16) -> u8 { match addr { - 0x0000 ... 0x3FFF => self.rom[addr as usize], - 0x4000 ... 0x7FFF => { + 0x0000...0x3FFF => self.rom[addr as usize], + 0x4000...0x7FFF => { let addr = addr - 0x4000; let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000; let val: u8 = self.rom[abs_addr]; val - }, - 0xA000 ... 0xBFFF => { + } + 0xA000...0xBFFF => { let addr = addr - 0xA000; println!("Access [{:02X}] {:04X}", self.active_ram_bank(), addr); self.ram[self.active_ram_bank() as usize * 0x2000 + addr as usize] @@ -69,14 +69,12 @@ impl MBC for MBC1 { fn write_byte(&mut self, addr: u16, val: u8) { match addr { - 0x0000 ... 0x1FFF => { - match val { - 0x0A => self.ram_enable = true, - 0x00 => self.ram_enable = false, - _ => println!("Unknown MBC1 value {:02X} for {:04X}", val, addr) - } + 0x0000...0x1FFF => match val { + 0x0A => self.ram_enable = true, + 0x00 => self.ram_enable = false, + _ => println!("Unknown MBC1 value {:02X} for {:04X}", val, addr), }, - 0x2000 ... 0x3FFF => { + 0x2000...0x3FFF => { if val != 0 { self.rom_bank_no = val & 0x1F; } else { @@ -84,18 +82,18 @@ impl MBC for MBC1 { } println!("MBC1: Selecting bank {:02X}", self.rom_bank_no); } - 0x4000 ... 0x5FFF => { + 0x4000...0x5FFF => { // Upper ROM bank / RAM bank select self.bank_no_high = val & 3; - }, - 0x6000 ... 0x7FFF => { + } + 0x6000...0x7FFF => { // Select upper ROM bytes or RAM bytes match val { 0 => self.bank_mode = BankMode::RomBankMode, 1 => self.bank_mode = BankMode::RamBankMode, _ => panic!("Invalid bank mode {:02X}", val), } - }, + } _ => panic!("MBC1: Writing {:02X} to {:04X} not supported", val, addr), } } diff --git a/src/mbc/mbc2.rs b/src/mbc/mbc2.rs index f6c3fc0..b3d8380 100644 --- a/src/mbc/mbc2.rs +++ b/src/mbc/mbc2.rs @@ -20,23 +20,23 @@ impl MBC2 { fn active_rom_bank(&self) -> u8 { self.rom_bank_no } - } +} impl MBC for MBC2 { - fn dump_ram(&self, file: &String){ + fn dump_ram(&self, file: &String) { super::super::write_file(&file, &self.ram).expect("Saving failed"); } fn read_byte(&self, addr: u16) -> u8 { match addr { - 0x0000 ... 0x3FFF => self.rom[addr as usize], - 0x4000 ... 0x7FFF => { + 0x0000...0x3FFF => self.rom[addr as usize], + 0x4000...0x7FFF => { let addr = addr - 0x4000; let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000; let val: u8 = self.rom[abs_addr]; val - }, - 0xA000 ... 0xA1FF => { + } + 0xA000...0xA1FF => { let addr = addr - 0xA000; self.ram[addr as usize] & 0x0F } @@ -48,19 +48,19 @@ impl MBC for MBC2 { fn write_byte(&mut self, addr: u16, val: u8) { match addr { - 0x0000 ... 0x1FFF => { + 0x0000...0x1FFF => { // To enable the ram, the LSB of the higher byte must be 0 if addr & 0x0100 == 0 { match val { 0x0A => self.ram_enable = true, 0x00 => self.ram_enable = false, - _ => println!("Unknown MBC2 value {:02X} for {:04X}", val, addr) + _ => println!("Unknown MBC2 value {:02X} for {:04X}", val, addr), } } else { println!("MBC2: Write {:02X} to {:04X} has no effect", val, addr); } - }, - 0x2000 ... 0x3FFF => { + } + 0x2000...0x3FFF => { if addr & 0x0100 == 1 { self.rom_bank_no = val & 0x0F; println!("MBC2: Selecting bank {:02X}", self.rom_bank_no); diff --git a/src/mbc/mbc3.rs b/src/mbc/mbc3.rs index c059d1c..ac91bfb 100644 --- a/src/mbc/mbc3.rs +++ b/src/mbc/mbc3.rs @@ -25,35 +25,37 @@ impl MBC3 { fn active_ram_bank(&self) -> u8 { self.ram_bank_no } - } impl MBC for MBC3 { - fn dump_ram(&self, file: &String){ + fn dump_ram(&self, file: &String) { super::super::write_file(&file, &self.ram).expect("Saving failed"); } fn read_byte(&self, addr: u16) -> u8 { match addr { - 0x0000 ... 0x3FFF => self.rom[addr as usize], - 0x4000 ... 0x7FFF => { + 0x0000...0x3FFF => self.rom[addr as usize], + 0x4000...0x7FFF => { let addr = addr - 0x4000; let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000; let val: u8 = self.rom[abs_addr]; val - }, - 0xA000 ... 0xBFFF => { + } + 0xA000...0xBFFF => { let addr = addr - 0xA000; match self.active_ram_bank() { - 0x00 ... 0x03 => { + 0x00...0x03 => { self.ram[self.active_ram_bank() as usize * 0x2000 + addr as usize] } - 0x08 ... 0x0C => { + 0x08...0x0C => { // TODO println!("MBC3: Ignoring RTC read"); 0 } - _ => panic!("MBC3: Accessing unknown RAM bank {:02X}", self.active_ram_bank()) + _ => panic!( + "MBC3: Accessing unknown RAM bank {:02X}", + self.active_ram_bank() + ), } } _ => { @@ -64,42 +66,43 @@ impl MBC for MBC3 { fn write_byte(&mut self, addr: u16, val: u8) { match addr { - 0x0000 ... 0x1FFF => { - match val { - 0x0A => self.ram_rtc_enabled = true, - 0x00 => self.ram_rtc_enabled = false, - _ => println!("MBC3: Unknown MBC value {:02X} for {:04X}", val, addr) - } + 0x0000...0x1FFF => match val { + 0x0A => self.ram_rtc_enabled = true, + 0x00 => self.ram_rtc_enabled = false, + _ => println!("MBC3: Unknown MBC value {:02X} for {:04X}", val, addr), }, - 0x2000 ... 0x3FFF => self.rom_bank_no = val & 0x7F, - 0x4000 ... 0x5FFF => { + 0x2000...0x3FFF => self.rom_bank_no = val & 0x7F, + 0x4000...0x5FFF => { // RAM bank select match val { - 0x00 ... 0x03 => self.ram_bank_no = val, - 0x08 ... 0x0C => self.ram_bank_no = val, - _ => panic!("MBC3: Unknown RAM bank {:02X}", val) + 0x00...0x03 => self.ram_bank_no = val, + 0x08...0x0C => self.ram_bank_no = val, + _ => panic!("MBC3: Unknown RAM bank {:02X}", val), } - }, - 0x6000 ... 0x7FFF => { + } + 0x6000...0x7FFF => { // Latch clock data match val { 0x00 => println!("latch = 0"), 0x01 => println!("latch = 1"), // TODO: This should copy the current clock to the register - _ => panic!("MBC3: Unknown latch value {:02X}", val) + _ => panic!("MBC3: Unknown latch value {:02X}", val), } - }, - 0xA000 ... 0xBFFF => { + } + 0xA000...0xBFFF => { let addr = addr - 0xA000; match self.active_ram_bank() { - 0x00 ... 0x03 => { + 0x00...0x03 => { let active_bank = self.active_ram_bank() as usize; self.ram[active_bank * 0x2000 + addr as usize] = val; } - 0x08 ... 0x0C => { + 0x08...0x0C => { // TODO println!("MBC3: Ignoring RTC write ({:02X})", val); } - _ => panic!("MBC3: Writing unknown RAM bank {:02X}", self.active_ram_bank()) + _ => panic!( + "MBC3: Writing unknown RAM bank {:02X}", + self.active_ram_bank() + ), } } _ => panic!("MBC3: Writing {:02X} to {:04X} not supported", val, addr), diff --git a/src/sound.rs b/src/sound.rs index 6a6313d..05019c7 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -36,7 +36,7 @@ impl Sound { 0xFF26 => self.enabled = val, _ => { // println!("Sound: Write {:02X} to {:04X} unsupported", val, addr); - }, + } } } diff --git a/src/timer.rs b/src/timer.rs index 105d54d..5e22604 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -27,7 +27,8 @@ impl Timer { self.div_tick_counter -= TIMER_SPEED[3]; } - if (self.tac & TIMER_ENABLE) == TIMER_ENABLE { // Is timer enabled? + if (self.tac & TIMER_ENABLE) == TIMER_ENABLE { + // Is timer enabled? self.tick_counter += 1; let req_ticks = TIMER_SPEED[(self.tac & 3) as usize]; @@ -72,7 +73,7 @@ impl Timer { _ => { println!("Timer: Read from {:04X} unsupported", addr); 0 - }, + } } }