Merge branch 'master' into audio

This commit is contained in:
Kevin Hamacher 2020-02-14 11:39:01 +01:00
commit 57b8438144
12 changed files with 512 additions and 404 deletions

View File

@ -4,6 +4,6 @@ version = "0.1.0"
authors = ["Kevin Hamacher <kevin.hamacher@rub.de>"]
[dependencies]
sdl2 = "0.19.0"
libc = "0.2.14"
pulse-simple = "1.0.0"
sdl2 = "*"
libc = "*"
pulse-simple = "*"

View File

@ -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<super::mbc::mbc::MBC>,
mbc: Box<dyn super::mbc::mbc::MBC>,
savefile: Option<String>,
}
impl Cartridge {
pub fn new(rom: Box<[u8]>, save_file: Option<String>) -> 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<super::mbc::mbc::MBC> = 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<dyn super::mbc::mbc::MBC> = 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 {

View File

@ -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);

View File

@ -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<sdl2::video::Window>,
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<Sprite>) {
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<Sprite> = 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,
);
}
}
}

View File

@ -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);
}

View File

@ -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<String> = env::args().collect();
@ -44,14 +43,14 @@ fn main() {
}
pub fn read_file<P: AsRef<Path>>(rom_path: P) -> Result<Box<[u8]>, 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<P: AsRef<Path>>(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(())
}

View File

@ -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]

View File

@ -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),
}
}

View File

@ -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);

View File

@ -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),

View File

@ -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<u8>,
// 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);
},
}
}
}

View File

@ -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 {