diff --git a/Cargo.toml b/Cargo.toml index d760ad2..f0e7bcd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" authors = ["Kevin Hamacher "] [dependencies] -sdl2 = "0.19.0" -libc = "0.2.14" -pulse-simple = "1.0.0" +sdl2 = "*" +libc = "*" +pulse-simple = "*" diff --git a/src/cartridge.rs b/src/cartridge.rs index 3fc4793..ec483cf 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -1,7 +1,8 @@ use super::mbc::mbc::MBC; -#[derive(Debug,PartialEq)] +#[derive(Debug, PartialEq)] enum MemoryBankControllerType { + None, MBC1, MBC2, MBC3, @@ -17,17 +18,17 @@ enum RamSize { } pub struct Cartridge { - mbc: Box, + mbc: Box, savefile: Option, } impl Cartridge { pub fn new(rom: Box<[u8]>, save_file: Option) -> Cartridge { - let mbc_type = match rom[0x0147] { - 0x00 | 0x08 ... 0x09 => None, - 0x01 ... 0x03 => Some(MemoryBankControllerType::MBC1), - 0x05 ... 0x06 => Some(MemoryBankControllerType::MBC2), - 0x0F ... 0x13 => Some(MemoryBankControllerType::MBC3), + let mbc_type: MemoryBankControllerType = match rom[0x0147] { + 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]), }; @@ -36,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] { @@ -48,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); @@ -56,11 +57,11 @@ impl Cartridge { let ram = Cartridge::load_savefile(&save_file, ram_size); - let mbc: Box = match mbc_type { - None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)), - Some(MemoryBankControllerType::MBC1) => Box::new(super::mbc::mbc1::MBC1::new(rom, ram)), - Some(MemoryBankControllerType::MBC2) => Box::new(super::mbc::mbc2::MBC2::new(rom, ram)), - Some(MemoryBankControllerType::MBC3) => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)), + let mbc: Box = match mbc_type { + MemoryBankControllerType::None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)), + MemoryBankControllerType::MBC1 => Box::new(super::mbc::mbc1::MBC1::new(rom, ram)), + MemoryBankControllerType::MBC2 => Box::new(super::mbc::mbc2::MBC2::new(rom, ram)), + MemoryBankControllerType::MBC3 => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)), }; Cartridge { diff --git a/src/cpu.rs b/src/cpu.rs index 1a16af1..dc42050 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], @@ -40,7 +39,7 @@ pub struct CPU { fn to_u16(args: Args) -> u16 { match args { Args::Double(a, b) => (a as u16) | ((b as u16) << 8), - _ => panic!("to_u16 only works with Args::Double") + _ => panic!("to_u16 only works with Args::Double"), } } @@ -92,7 +91,7 @@ impl CPU { self.ip += 1; Args::Double(b1, b2) } - _ => panic!("load_args only supports two bytes") + _ => panic!("load_args only supports two bytes"), } } @@ -177,7 +176,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] @@ -211,7 +213,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 { @@ -230,8 +232,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 { @@ -248,8 +250,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 { @@ -268,8 +270,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 { @@ -288,8 +291,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]); @@ -299,8 +302,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]); @@ -311,8 +314,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]); @@ -321,8 +324,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]); @@ -333,10 +336,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); @@ -347,7 +350,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); @@ -358,7 +361,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); @@ -369,7 +372,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); @@ -380,7 +383,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); @@ -391,7 +394,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); @@ -402,7 +405,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); @@ -413,7 +416,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); @@ -426,7 +429,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); @@ -435,7 +438,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); @@ -444,7 +447,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); @@ -453,7 +456,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); @@ -462,7 +465,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); @@ -471,7 +474,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); @@ -480,7 +483,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); @@ -489,7 +492,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); @@ -500,7 +503,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); @@ -509,7 +512,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); @@ -518,7 +521,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); @@ -527,7 +530,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); @@ -536,7 +539,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); @@ -545,7 +548,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); @@ -554,7 +557,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); @@ -563,7 +566,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); @@ -787,7 +790,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); @@ -851,7 +857,7 @@ impl CPU { } #[inline] - fn int_(&mut self, val: u8){ + fn int_(&mut self, val: u8) { if self.debug { println!("INT {:02X}", val); } @@ -913,7 +919,10 @@ impl CPU { // println!("[+] [{}] {} cycles, gb: {}, we: {}", running_sum, cycles_executed, gb_dur, our_dur); sleep(Duration::new(0, (full_cycles - 10) as u32 * 238 as u32)); } else { - println!("[-] [{}] {} cycles, gb: {}, we: {}", running_sum, cycles_executed, gb_dur, our_dur); + println!( + "[-] [{}] {} cycles, gb: {}, we: {}", + running_sum, cycles_executed, gb_dur, our_dur + ); } } } @@ -984,8 +993,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]); @@ -1006,7 +1018,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), @@ -1032,7 +1044,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); @@ -1043,9 +1055,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), @@ -1068,9 +1082,12 @@ impl CPU { } 0x10 => { - println!("STOP 0 {:02X} not implemented.", self.load_args(1).single_val()); + println!( + "STOP 0 {:02X} not implemented.", + self.load_args(1).single_val() + ); 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), @@ -1093,7 +1110,7 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 - }, + } 0x18 => { let dst = self.load_args(1).single_val(); self.jmp_r(dst); @@ -1101,15 +1118,17 @@ impl CPU { println!("JMPR {:02X}", 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), @@ -1130,8 +1149,7 @@ impl CPU { self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 - }, - + } 0x20 => { let c = self.flags & FLAG_Z == 0; @@ -1146,7 +1164,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), @@ -1188,11 +1206,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", c) - }, + } 0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L), 0x2A => { if self.debug { @@ -1202,7 +1220,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), @@ -1215,13 +1233,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", c) - }, + } 0x31 => { let args = self.load_args(2); self.sp = to_u16(args); @@ -1229,7 +1246,7 @@ impl CPU { println!("LD SP, {:04x}", self.sp); } 12 - }, + } 0x32 => { if self.debug { println!("LD (HL-), A"); @@ -1238,7 +1255,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"); @@ -1258,11 +1275,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", c) - }, + } 0x39 => { if self.debug { println!("ADD HL, SP"); @@ -1276,7 +1293,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-)"); @@ -1308,14 +1325,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 => { @@ -1324,10 +1341,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]); @@ -1338,7 +1355,7 @@ impl CPU { } // ADC - 0x88 ... 0x8F => { + 0x88..=0x8F => { let reg_id = (instruction - 0x88) as usize; if self.debug { println!("ADC {}", REG_NAMES[reg_id]); @@ -1350,7 +1367,7 @@ impl CPU { } // SUBs - 0x90 ... 0x97 => { + 0x90..=0x97 => { let reg_id = (instruction - 0x90) as usize; if self.debug { println!("SUB {}", REG_NAMES[reg_id]); @@ -1361,7 +1378,7 @@ impl CPU { } // SBC - 0x98 ... 0x9F => { + 0x98..=0x9F => { let reg_id = (instruction - 0x98) as usize; if self.debug { println!("SBC {}", REG_NAMES[reg_id]); @@ -1372,7 +1389,7 @@ impl CPU { } // AND - 0xA0 ... 0xA7 => { + 0xA0..=0xA7 => { let reg_id = (instruction - 0xA0) as usize; if self.debug { println!("AND {}", REG_NAMES[reg_id]); @@ -1388,7 +1405,7 @@ impl CPU { } // XOR - 0xA8 ... 0xAF => { + 0xA8..=0xAF => { let reg_id = (instruction - 0xA8) as usize; if self.debug { println!("XOR {}", REG_NAMES[reg_id]); @@ -1401,10 +1418,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]); @@ -1420,7 +1437,7 @@ impl CPU { } // CP - 0xB8 ... 0xBF => { + 0xB8..=0xBF => { let reg_id = (instruction - 0xB8) as usize; if self.debug { println!("CP {}", REG_NAMES[reg_id]); @@ -1429,17 +1446,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", c) - }, + } 0xC1 => self.pop_rr(REG_N_B, REG_N_C), 0xC2 => { let c = self.flags & FLAG_Z == 0; self.jmp_p_condition("NZ", c) - }, + } 0xC3 => { let dst = to_u16(self.load_args(2)); if self.debug { @@ -1447,7 +1464,7 @@ impl CPU { } self.jmp_p(dst); 16 - }, + } 0xC4 => { let c = self.flags & FLAG_Z == 0; self.call_condition("NZ", c) @@ -1462,19 +1479,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", c) - }, + } 0xC9 => { if self.debug { println!("RET"); } self.ret(); 16 - }, + } 0xCA => { let c = self.flags & FLAG_Z == FLAG_Z; self.jmp_p_condition("Z", c) @@ -1482,11 +1499,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", c) - }, + } 0xCD => self.call_condition("", true), 0xCE => { let arg = self.load_args(1).single_val(); @@ -1495,14 +1512,13 @@ impl CPU { } self.adc_r(arg); 8 - }, + } 0xCF => self.rst(0x08), - 0xD0 => { let c = self.flags & FLAG_C == 0; self.ret_condition("NC", c) - }, + } 0xD1 => self.pop_rr(REG_N_D, REG_N_E), 0xD2 => { let c = self.flags & FLAG_C == 0; @@ -1522,12 +1538,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", c) - }, + } 0xD9 => { if self.debug { println!("RETI"); @@ -1537,7 +1553,7 @@ impl CPU { 0xDA => { let c = self.flags & FLAG_C == FLAG_C; self.jmp_p_condition("C", c) - }, + } 0xDB => panic!("NON-EXISTING OPCODE"), 0xDC => { let c = self.flags & FLAG_C == FLAG_C; @@ -1551,7 +1567,7 @@ impl CPU { } self.sbc_r(arg); 8 - }, + } 0xDF => self.rst(0x18), 0xE0 => { @@ -1559,9 +1575,10 @@ impl CPU { if self.debug { println!("LDH {:02X}, A", arg); } - self.interconnect.write_byte(0xFF00 + arg as u16, self.regs[REG_A]); + self.interconnect + .write_byte(0xFF00 + arg as u16, self.regs[REG_A]); 12 - }, + } 0xE1 => self.pop_rr(REG_N_H, REG_N_L), 0xE2 => { if self.debug { @@ -1570,7 +1587,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 => { @@ -1586,7 +1603,7 @@ impl CPU { self.clear_flag(FLAG_C); 8 - }, + } 0xE7 => self.rst(0x20), 0xE8 => { let arg = self.load_args(1).single_val() as i8; @@ -1613,16 +1630,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).single_val(); if self.debug { @@ -1635,7 +1652,7 @@ impl CPU { self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); 8 - }, + } 0xEF => self.rst(0x28), 0xF0 => { @@ -1645,23 +1662,23 @@ impl CPU { } self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + arg 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 => { @@ -1676,7 +1693,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).single_val() as i8; @@ -1700,14 +1717,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 { @@ -1715,14 +1732,14 @@ impl CPU { } self.regs[REG_A] = self.interconnect.read_byte(addr); 16 - }, + } 0xFB => { if self.debug { println!("EI"); } self.ime = true; // interrupt master enable 4 - }, + } 0xFC | 0xFD => panic!("NON-EXISTING OPCODE"), 0xFE => { @@ -1733,9 +1750,9 @@ impl CPU { self.cp_r(arg); 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 e33507c..8f7784e 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 5480ca1..ef4f089 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 ... 0xFF => { + 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.sound_object.lock().unwrap().read_byte(addr) - }, - 0xFF30 ... 0xFF3F => self.sound.sound_object.lock().unwrap().read_byte(addr), - 0xFF40 ... 0xFF4B => { - self.display.read_byte(addr) - }, - 0xFF50 => { - self.disable_bootrom - }, + } + 0xFF10...0xFF26 => self.sound.sound_object.lock().unwrap().read_byte(addr), + 0xFF30...0xFF3F => self.sound.sound_object.lock().unwrap().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,45 @@ 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 => { - self.sound.sound_object.lock().unwrap().write_byte(addr, val); - }, - 0xFF30 ... 0xFF3F => self.sound.sound_object.lock().unwrap().write_byte(addr, val), + 0xFF10...0xFF26 => { + self.sound + .sound_object + .lock() + .unwrap() + .write_byte(addr, val); + } + 0xFF30...0xFF3F => self + .sound + .sound_object + .lock() + .unwrap() + .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 +372,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 +399,7 @@ impl Interconnect { } 0xFF56 => { self.infrared_com_port = val; - }, + } 0xFF70 => { if self.wram_bank != val { println!("Switching wram bank to {:02X}", val); @@ -358,13 +413,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..e52ef62 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(); @@ -44,14 +43,14 @@ fn main() { } pub fn read_file>(rom_path: P) -> Result, io::Error> { - let mut file = try!(fs::File::open(rom_path)); + let mut file = r#try!(fs::File::open(rom_path)); let mut buf = Vec::new(); - try!(file.read_to_end(&mut buf)); + r#try!(file.read_to_end(&mut buf)); Ok(buf.into_boxed_slice()) } pub fn write_file>(path: P, data: &Box<[u8]>) -> Result<(), io::Error> { - let mut file = try!(fs::File::create(path)); - try!(file.write(&data)); + let mut file = r#try!(fs::File::create(path)); + r#try!(file.write(&data)); Ok(()) } diff --git a/src/mbc/mbc.rs b/src/mbc/mbc.rs index 50506e2..4cf2e13 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..46b9527 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..eba415a 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..73c8a0c 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/mod.rs b/src/sound/mod.rs index e047cef..1536cf8 100644 --- a/src/sound/mod.rs +++ b/src/sound/mod.rs @@ -1,7 +1,7 @@ extern crate pulse_simple; mod envelope; -mod square; mod length; +mod square; mod wave; use self::pulse_simple::Playback; @@ -30,7 +30,7 @@ struct Channel1 { tick_state: u8, - stored_regs: [u8; 5] + stored_regs: [u8; 5], } impl Channel1 { @@ -73,7 +73,10 @@ impl Channel1 { pub fn read_byte(&self, addr: u16) -> u8 { match addr { 0xFF10...0xFF14 => self.stored_regs[(addr - 0xFF10) as usize], - _ => {println!("Channel1 does not support reading ({:04X})", addr); 0}, + _ => { + println!("Channel1 does not support reading ({:04X})", addr); + 0 + } } } @@ -150,7 +153,10 @@ impl Channel2 { pub fn read_byte(&self, addr: u16) -> u8 { match addr { - _ => {println!("Channel2 does not support reading ({:04X})", addr); 0}, + _ => { + println!("Channel2 does not support reading ({:04X})", addr); + 0 + } } } @@ -192,7 +198,6 @@ struct Channel3 { wave_gen: wave::WaveGenerator, length_counter: length::LengthCounter, // TODO: Volume - tick_state: u8, } @@ -268,7 +273,6 @@ impl Channel3 { } } - #[derive(Default)] pub struct Sound { channel1: Channel1, @@ -299,36 +303,39 @@ impl SoundManager { if false { return; } - thread::Builder::new().name("Audio".into()).spawn(move || { - // PulseAudio playback object - let playback = Playback::new("GBC", "Output", None, (OUTPUT_SAMPLE_RATE) as _ ); + thread::Builder::new() + .name("Audio".into()) + .spawn(move || { + // PulseAudio playback object + let playback = Playback::new("GBC", "Output", None, (OUTPUT_SAMPLE_RATE) as _); - // Counter, used for calling the 512 Hz timer - let mut counter = 0; + // Counter, used for calling the 512 Hz timer + let mut counter = 0; - loop { - let (s1, s2) = { - let mut c_obj = obj.lock().unwrap(); + loop { + let (s1, s2) = { + let mut c_obj = obj.lock().unwrap(); - // Check for 512 Hz timer - if counter >= (OUTPUT_SAMPLE_RATE / 512) { - c_obj.clock(); - counter = 0; - } else { - counter += 1; - } + // Check for 512 Hz timer + if counter >= (OUTPUT_SAMPLE_RATE / 512) { + c_obj.clock(); + counter = 0; + } else { + counter += 1; + } - // Sample clock - c_obj.sample_clock(); + // Sample clock + c_obj.sample_clock(); - // Get sample - c_obj.sample() - }; - let samps = [[s1, s2]]; - // No sleep needed, it seems like the playback.write is blocking - playback.write(&samps[..]); - } - }).unwrap(); + // Get sample + c_obj.sample() + }; + let samps = [[s1, s2]]; + // No sleep needed, it seems like the playback.write is blocking + playback.write(&samps[..]); + } + }) + .unwrap(); } } @@ -365,38 +372,38 @@ impl Sound { if s01_volume > 0 { if self.sound_output_terminal_selector & 1 > 0 { // Output Channel1 - s[0] += c1_sample as _; + s[0] += c1_sample as u16; } if self.sound_output_terminal_selector & 2 > 0 && false { // Output Channel2 - s[0] += c2_sample as _; + s[0] += c2_sample as u16; } if self.sound_output_terminal_selector & 4 > 0 { // Output Channel3 - s[0] += c3_sample as _; + s[0] += c3_sample as u16; } if self.sound_output_terminal_selector & 8 > 0 { // Output Channel4 - s[0] += c4_sample as _; + s[0] += c4_sample as u16; } } if s02_volume > 0 { if self.sound_output_terminal_selector & 0x10 > 0 && false { // Output Channel1 - s[1] += c1_sample as _; + s[1] += c1_sample as u16; } if self.sound_output_terminal_selector & 0x20 > 0 { // Output Channel2 - s[1] += c2_sample as _; + s[1] += c2_sample as u16; } if self.sound_output_terminal_selector & 0x40 > 0 { // Output Channel3 - s[1] += c3_sample as _; + s[1] += c3_sample as u16; } if self.sound_output_terminal_selector & 0x80 > 0 { // Output Channel4 - s[1] += c4_sample as _; + s[1] += c4_sample as u16; } } } @@ -419,7 +426,7 @@ impl Sound { _ => { // panic!("Sound: Write {:02X} to {:04X} unsupported", val, addr); println!("Sound: Write {:02X} to {:04X} unsupported", val, addr); - }, + } } } diff --git a/src/timer.rs b/src/timer.rs index b9571ec..78c9802 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -74,15 +74,16 @@ impl Timer { } pub fn read_byte(&self, addr: u16) -> u8 { - let r = match addr { + match addr { 0xFF04 => self.div, 0xFF05 => self.tima, 0xFF06 => self.tma, 0xFF07 => self.tac, - _ => unreachable!(), - }; - // println!("Timer RD: {:04X} = {:02X}", addr, r); - r + _ => { + println!("Timer: Read from {:04X} unsupported", addr); + 0 + } + } } pub fn timer_interrupt(&mut self) -> bool {