Update SDL + rust fmt

This commit is contained in:
Kevin Hamacher 2020-02-14 11:21:48 +01:00
parent cc9cef785e
commit 50471f1ec6
12 changed files with 432 additions and 346 deletions

View File

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

View File

@ -41,7 +41,7 @@ impl Cartridge {
0x52 => 72, 0x52 => 72,
0x53 => 80, 0x53 => 80,
0x54 => 96, 0x54 => 96,
_ => panic!("Unknown rom size: {:?}", rom[0x148]) _ => panic!("Unknown rom size: {:?}", rom[0x148]),
}; };
let ram_size: RamSize = match rom[0x0149] { let ram_size: RamSize = match rom[0x0149] {
@ -49,7 +49,7 @@ impl Cartridge {
0x01 => RamSize::Ram2KB, 0x01 => RamSize::Ram2KB,
0x02 => RamSize::Ram8KB, 0x02 => RamSize::Ram8KB,
0x03 => RamSize::Ram32KB, 0x03 => RamSize::Ram32KB,
_ => panic!("Unknown ram size: {:?}", rom[0x149]) _ => panic!("Unknown ram size: {:?}", rom[0x149]),
}; };
println!("Rom size: {} banks", rom_banks); println!("Rom size: {} banks", rom_banks);

View File

@ -1,7 +1,7 @@
use super::interconnect; use super::interconnect;
use std::time::{Duration, Instant};
use std::thread::sleep; use std::thread::sleep;
use std::time::{Duration, Instant};
const REG_A: usize = 6; const REG_A: usize = 6;
@ -21,7 +21,6 @@ const FLAG_N: u8 = 1 << 6;
const FLAG_H: u8 = 1 << 5; const FLAG_H: u8 = 1 << 5;
const FLAG_C: u8 = 1 << 4; const FLAG_C: u8 = 1 << 4;
pub struct CPU { pub struct CPU {
// Registers: B, C, D, E, H, L, A // Registers: B, C, D, E, H, L, A
regs: [u8; 7], regs: [u8; 7],
@ -154,7 +153,10 @@ impl CPU {
self.set_flag(FLAG_N); self.set_flag(FLAG_N);
self.set_clear_flag(FLAG_Z, new == 0); 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_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] #[inline]
@ -209,7 +211,7 @@ impl CPU {
self.set_clear_flag(FLAG_Z, nval == 0); self.set_clear_flag(FLAG_Z, nval == 0);
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
}, }
0x08...0x0F => { 0x08...0x0F => {
let reg_id = (instruction - 0x08) as usize; let reg_id = (instruction - 0x08) as usize;
let val = self.get_8bit_reg(reg_id); let val = self.get_8bit_reg(reg_id);
@ -227,7 +229,7 @@ impl CPU {
self.set_clear_flag(FLAG_Z, val == 0); self.set_clear_flag(FLAG_Z, val == 0);
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
}, }
0x10...0x17 => { 0x10...0x17 => {
let reg_id = (instruction - 0x10) as usize; let reg_id = (instruction - 0x10) as usize;
let val = self.get_8bit_reg(reg_id); let val = self.get_8bit_reg(reg_id);
@ -247,8 +249,9 @@ impl CPU {
self.set_clear_flag(FLAG_Z, nval == 0); self.set_clear_flag(FLAG_Z, nval == 0);
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
}, }
0x18 ... 0x1F => { // RR 0x18...0x1F => {
// RR
let reg_id = (instruction - 0x18) as usize; let reg_id = (instruction - 0x18) as usize;
let val = self.get_8bit_reg(reg_id); let val = self.get_8bit_reg(reg_id);
if self.debug { if self.debug {
@ -267,7 +270,7 @@ impl CPU {
self.set_clear_flag(FLAG_Z, v == 0); self.set_clear_flag(FLAG_Z, v == 0);
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
}, }
0x20...0x27 => { 0x20...0x27 => {
let reg_id = (instruction - 0x20) as usize; let reg_id = (instruction - 0x20) as usize;
if self.debug { if self.debug {
@ -278,7 +281,7 @@ impl CPU {
self.set_clear_flag(FLAG_C, v & 0x80 == 0x80); self.set_clear_flag(FLAG_C, v & 0x80 == 0x80);
self.set_clear_flag(FLAG_Z, v & 0x7F == 0); self.set_clear_flag(FLAG_Z, v & 0x7F == 0);
self.set_8bit_reg(reg_id, v << 1); self.set_8bit_reg(reg_id, v << 1);
}, }
0x28...0x2F => { 0x28...0x2F => {
let reg_id = (instruction - 0x28) as usize; let reg_id = (instruction - 0x28) as usize;
if self.debug { if self.debug {
@ -290,7 +293,7 @@ impl CPU {
self.flags = 0; self.flags = 0;
self.set_clear_flag(FLAG_Z, nv == 0); self.set_clear_flag(FLAG_Z, nv == 0);
self.set_clear_flag(FLAG_C, v & 1 == 1); self.set_clear_flag(FLAG_C, v & 1 == 1);
}, }
0x30...0x37 => { 0x30...0x37 => {
let reg_id = (instruction - 0x30) as usize; let reg_id = (instruction - 0x30) as usize;
if self.debug { if self.debug {
@ -300,7 +303,7 @@ impl CPU {
self.set_8bit_reg(reg_id, (v << 4) | (v >> 4)); self.set_8bit_reg(reg_id, (v << 4) | (v >> 4));
self.flags = 0; self.flags = 0;
self.set_clear_flag(FLAG_Z, v == 0); self.set_clear_flag(FLAG_Z, v == 0);
}, }
0x38...0x3F => { 0x38...0x3F => {
let reg_id = (instruction - 0x38) as usize; let reg_id = (instruction - 0x38) as usize;
if self.debug { if self.debug {
@ -312,7 +315,7 @@ impl CPU {
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
self.set_clear_flag(FLAG_Z, (v & 0xFE) == 0); self.set_clear_flag(FLAG_Z, (v & 0xFE) == 0);
}, }
// Bits // Bits
0x40...0x47 => { 0x40...0x47 => {
@ -766,7 +769,10 @@ impl CPU {
#[inline] #[inline]
fn add_rr_rr(&mut self, r1: usize, r2: usize, r3: usize, r4: usize) -> u8 { fn add_rr_rr(&mut self, r1: usize, r2: usize, r3: usize, r4: usize) -> u8 {
if self.debug { 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); let val1 = self.get_pair_value(r1, r2);
@ -875,7 +881,8 @@ impl CPU {
let gb_dur = cycles * 238; let gb_dur = cycles * 238;
let our_dur = start.elapsed().subsec_nanos() as i32; let our_dur = start.elapsed().subsec_nanos() as i32;
let delta = gb_dur - our_dur; let delta = gb_dur - our_dur;
if delta > (20 * 238) { // We're at least 20 cycles faster. if delta > (20 * 238) {
// We're at least 20 cycles faster.
sleep(Duration::new(0, delta as u32)); sleep(Duration::new(0, delta as u32));
} else if delta < 0 { } else if delta < 0 {
print!("-"); print!("-");
@ -937,7 +944,10 @@ impl CPU {
// We need to double-check the flags // We need to double-check the flags
instruction = self.read_byte(self.ip); instruction = self.read_byte(self.ip);
if self.debug { if self.debug {
print!("{:#06x}: [SP: {:#04X}] i={:02X}. ", &self.ip, &self.sp, &instruction); print!(
"{:#06x}: [SP: {:#04X}] i={:02X}. ",
&self.ip, &self.sp, &instruction
);
for i in 0..6 { for i in 0..6 {
print!("{}: {:02X} ", REG_NAMES[i], self.get_8bit_reg(i)); print!("{}: {:02X} ", REG_NAMES[i], self.get_8bit_reg(i));
} }
@ -959,7 +969,7 @@ impl CPU {
println!("NOP"); println!("NOP");
} }
4 4
}, }
0x01 => self.ld_rr_vv(REG_N_B, REG_N_C), 0x01 => self.ld_rr_vv(REG_N_B, REG_N_C),
0x02 => self.ld_dref_rr_a(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), 0x03 => self.inc_rr(REG_N_B, REG_N_C),
@ -996,9 +1006,11 @@ impl CPU {
if self.debug { if self.debug {
println!("LD A, (BC)"); 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 8
}, }
0x0B => self.dec_rr(REG_N_B, REG_N_C), 0x0B => self.dec_rr(REG_N_B, REG_N_C),
0x0C => self.reg_inc(REG_N_C), 0x0C => self.reg_inc(REG_N_C),
0x0D => self.reg_dec(REG_N_C), 0x0D => self.reg_dec(REG_N_C),
@ -1023,7 +1035,7 @@ impl CPU {
0x10 => { 0x10 => {
println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]); println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]);
4 4
}, }
0x11 => self.ld_rr_vv(REG_N_D, REG_N_E), 0x11 => self.ld_rr_vv(REG_N_D, REG_N_E),
0x12 => self.ld_dref_rr_a(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), 0x13 => self.inc_rr(REG_N_D, REG_N_E),
@ -1046,20 +1058,22 @@ impl CPU {
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
4 4
}, }
0x18 => { 0x18 => {
let dst = self.load_args(1)[0]; let dst = self.load_args(1)[0];
self.jmp_r(dst); self.jmp_r(dst);
12 12
}, }
0x19 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_D, REG_N_E), 0x19 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_D, REG_N_E),
0x1A => { 0x1A => {
if self.debug { if self.debug {
println!("LD A, (DE)"); 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 8
}, }
0x1B => self.dec_rr(REG_N_D, REG_N_E), 0x1B => self.dec_rr(REG_N_D, REG_N_E),
0x1C => self.reg_inc(REG_N_E), 0x1C => self.reg_inc(REG_N_E),
0x1D => self.reg_dec(REG_N_E), 0x1D => self.reg_dec(REG_N_E),
@ -1080,8 +1094,7 @@ impl CPU {
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
4 4
}, }
0x20 => { 0x20 => {
let c = self.flags & FLAG_Z == 0; let c = self.flags & FLAG_Z == 0;
@ -1096,7 +1109,7 @@ impl CPU {
self.interconnect.write_byte(addr, self.regs[REG_A]); self.interconnect.write_byte(addr, self.regs[REG_A]);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1)); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1));
8 8
}, }
0x23 => self.inc_rr(REG_N_H, REG_N_L), 0x23 => self.inc_rr(REG_N_H, REG_N_L),
0x24 => self.reg_inc(REG_N_H), 0x24 => self.reg_inc(REG_N_H),
0x25 => self.reg_dec(REG_N_H), 0x25 => self.reg_dec(REG_N_H),
@ -1138,11 +1151,11 @@ impl CPU {
self.set_clear_flag(FLAG_Z, a == 0); self.set_clear_flag(FLAG_Z, a == 0);
4 4
}, }
0x28 => { 0x28 => {
let c = self.flags & FLAG_Z == FLAG_Z; let c = self.flags & FLAG_Z == FLAG_Z;
self.jmp_r_condition("Z".to_owned(), c) self.jmp_r_condition("Z".to_owned(), c)
}, }
0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L), 0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L),
0x2A => { 0x2A => {
if self.debug { if self.debug {
@ -1152,7 +1165,7 @@ impl CPU {
self.regs[REG_A] = self.interconnect.read_byte(addr); self.regs[REG_A] = self.interconnect.read_byte(addr);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1)); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1));
8 8
}, }
0x2B => self.dec_rr(REG_N_H, REG_N_L), 0x2B => self.dec_rr(REG_N_H, REG_N_L),
0x2C => self.reg_inc(REG_N_L), 0x2C => self.reg_inc(REG_N_L),
0x2D => self.reg_dec(REG_N_L), 0x2D => self.reg_dec(REG_N_L),
@ -1165,13 +1178,12 @@ impl CPU {
self.set_flag(FLAG_N); self.set_flag(FLAG_N);
self.set_flag(FLAG_H); self.set_flag(FLAG_H);
4 4
}, }
0x30 => { 0x30 => {
let c = self.flags & FLAG_C == 0; let c = self.flags & FLAG_C == 0;
self.jmp_r_condition("NC".to_owned(), c) self.jmp_r_condition("NC".to_owned(), c)
}, }
0x31 => { 0x31 => {
let args = self.load_args(2); let args = self.load_args(2);
self.sp = to_u16(args); self.sp = to_u16(args);
@ -1179,7 +1191,7 @@ impl CPU {
println!("LD SP, {:04x}", self.sp); println!("LD SP, {:04x}", self.sp);
} }
12 12
}, }
0x32 => { 0x32 => {
if self.debug { if self.debug {
println!("LD (HL-), A"); println!("LD (HL-), A");
@ -1188,7 +1200,7 @@ impl CPU {
self.interconnect.write_byte(addr, self.regs[REG_A]); self.interconnect.write_byte(addr, self.regs[REG_A]);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1)); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1));
8 8
}, }
0x33 => { 0x33 => {
if self.debug { if self.debug {
println!("INC SP"); println!("INC SP");
@ -1208,11 +1220,11 @@ impl CPU {
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
4 4
}, }
0x38 => { 0x38 => {
let c = self.flags & FLAG_C == FLAG_C; let c = self.flags & FLAG_C == FLAG_C;
self.jmp_r_condition("C".to_owned(), c) self.jmp_r_condition("C".to_owned(), c)
}, }
0x39 => { 0x39 => {
if self.debug { if self.debug {
println!("ADD HL, SP"); println!("ADD HL, SP");
@ -1226,7 +1238,7 @@ impl CPU {
self.set_clear_flag(FLAG_C, old > v && sp > 0); self.set_clear_flag(FLAG_C, old > v && sp > 0);
self.set_clear_flag(FLAG_H, ((old & 0xFFF) + (sp & 0xFFF)) > 0xFFF); self.set_clear_flag(FLAG_H, ((old & 0xFFF) + (sp & 0xFFF)) > 0xFFF);
8 8
}, }
0x3A => { 0x3A => {
if self.debug { if self.debug {
println!("LD A, (HL-)"); println!("LD A, (HL-)");
@ -1274,7 +1286,7 @@ impl CPU {
} }
self.halted = true; self.halted = true;
4 4
}, }
// ADD // ADD
0x80...0x87 => { 0x80...0x87 => {
@ -1351,7 +1363,7 @@ impl CPU {
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
4 4
}, }
// OR // OR
0xB0...0xB7 => { 0xB0...0xB7 => {
@ -1379,17 +1391,17 @@ impl CPU {
let v = self.get_8bit_reg(reg_id); let v = self.get_8bit_reg(reg_id);
self.cp_r(v); self.cp_r(v);
4 4
}, }
0xC0 => { 0xC0 => {
let c = self.flags & FLAG_Z == 0; let c = self.flags & FLAG_Z == 0;
self.ret_condition("NZ".to_owned(), c) self.ret_condition("NZ".to_owned(), c)
}, }
0xC1 => self.pop_rr(REG_N_B, REG_N_C), 0xC1 => self.pop_rr(REG_N_B, REG_N_C),
0xC2 => { 0xC2 => {
let c = self.flags & FLAG_Z == 0; let c = self.flags & FLAG_Z == 0;
self.jmp_p_condition("NZ".to_owned(), c) self.jmp_p_condition("NZ".to_owned(), c)
}, }
0xC3 => { 0xC3 => {
let dst = to_u16(self.load_args(2)); let dst = to_u16(self.load_args(2));
if self.debug { if self.debug {
@ -1397,7 +1409,7 @@ impl CPU {
} }
self.jmp_p(dst); self.jmp_p(dst);
16 16
}, }
0xC4 => { 0xC4 => {
let c = self.flags & FLAG_Z == 0; let c = self.flags & FLAG_Z == 0;
self.call_condition("NZ".to_owned(), c) self.call_condition("NZ".to_owned(), c)
@ -1412,19 +1424,19 @@ impl CPU {
self.add_r(val); self.add_r(val);
8 8
}, }
0xC7 => self.rst(0x00), 0xC7 => self.rst(0x00),
0xC8 => { 0xC8 => {
let c = self.flags & FLAG_Z == FLAG_Z; let c = self.flags & FLAG_Z == FLAG_Z;
self.ret_condition("Z".to_owned(), c) self.ret_condition("Z".to_owned(), c)
}, }
0xC9 => { 0xC9 => {
if self.debug { if self.debug {
println!("RET"); println!("RET");
} }
self.ret(); self.ret();
16 16
}, }
0xCA => { 0xCA => {
let c = self.flags & FLAG_Z == FLAG_Z; let c = self.flags & FLAG_Z == FLAG_Z;
self.jmp_p_condition("Z".to_owned(), c) self.jmp_p_condition("Z".to_owned(), c)
@ -1432,11 +1444,11 @@ impl CPU {
0xCB => { 0xCB => {
self.run_prefix_instruction(); self.run_prefix_instruction();
12 // TODO: Verify that this is the case for all prefix instructions. 12 // TODO: Verify that this is the case for all prefix instructions.
}, }
0xCC => { 0xCC => {
let c = self.flags & FLAG_Z == FLAG_Z; let c = self.flags & FLAG_Z == FLAG_Z;
self.call_condition("Z".to_owned(), c) self.call_condition("Z".to_owned(), c)
}, }
0xCD => self.call_condition("".to_owned(), true), 0xCD => self.call_condition("".to_owned(), true),
0xCE => { 0xCE => {
let arg = self.load_args(1)[0]; let arg = self.load_args(1)[0];
@ -1445,14 +1457,13 @@ impl CPU {
} }
self.adc_r(arg); self.adc_r(arg);
8 8
}, }
0xCF => self.rst(0x08), 0xCF => self.rst(0x08),
0xD0 => { 0xD0 => {
let c = self.flags & FLAG_C == 0; let c = self.flags & FLAG_C == 0;
self.ret_condition("NC".to_owned(), c) self.ret_condition("NC".to_owned(), c)
}, }
0xD1 => self.pop_rr(REG_N_D, REG_N_E), 0xD1 => self.pop_rr(REG_N_D, REG_N_E),
0xD2 => { 0xD2 => {
let c = self.flags & FLAG_C == 0; let c = self.flags & FLAG_C == 0;
@ -1472,12 +1483,12 @@ impl CPU {
self.sub_r(val); self.sub_r(val);
8 8
}, }
0xD7 => self.rst(0x10), 0xD7 => self.rst(0x10),
0xD8 => { 0xD8 => {
let c = self.flags & FLAG_C == FLAG_C; let c = self.flags & FLAG_C == FLAG_C;
self.ret_condition("C".to_owned(), c) self.ret_condition("C".to_owned(), c)
}, }
0xD9 => { 0xD9 => {
if self.debug { if self.debug {
println!("RETI"); println!("RETI");
@ -1487,7 +1498,7 @@ impl CPU {
0xDA => { 0xDA => {
let c = self.flags & FLAG_C == FLAG_C; let c = self.flags & FLAG_C == FLAG_C;
self.jmp_p_condition("C".to_owned(), c) self.jmp_p_condition("C".to_owned(), c)
}, }
0xDB => panic!("NON-EXISTING OPCODE"), 0xDB => panic!("NON-EXISTING OPCODE"),
0xDC => { 0xDC => {
let c = self.flags & FLAG_C == FLAG_C; let c = self.flags & FLAG_C == FLAG_C;
@ -1501,7 +1512,7 @@ impl CPU {
} }
self.sbc_r(arg); self.sbc_r(arg);
8 8
}, }
0xDF => self.rst(0x18), 0xDF => self.rst(0x18),
0xE0 => { 0xE0 => {
@ -1509,9 +1520,10 @@ impl CPU {
if self.debug { if self.debug {
println!("LDH {:02X}, A", args[0]); println!("LDH {:02X}, A", args[0]);
} }
self.interconnect.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]); self.interconnect
.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]);
12 12
}, }
0xE1 => self.pop_rr(REG_N_H, REG_N_L), 0xE1 => self.pop_rr(REG_N_H, REG_N_L),
0xE2 => { 0xE2 => {
if self.debug { if self.debug {
@ -1520,7 +1532,7 @@ impl CPU {
let addr: u16 = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16; let addr: u16 = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16;
self.interconnect.write_byte(addr, self.regs[REG_A]); self.interconnect.write_byte(addr, self.regs[REG_A]);
8 8
}, }
0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"), 0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"),
0xE5 => self.push_rr(REG_N_H, REG_N_L), 0xE5 => self.push_rr(REG_N_H, REG_N_L),
0xE6 => { 0xE6 => {
@ -1536,7 +1548,7 @@ impl CPU {
self.clear_flag(FLAG_C); self.clear_flag(FLAG_C);
8 8
}, }
0xE7 => self.rst(0x20), 0xE7 => self.rst(0x20),
0xE8 => { 0xE8 => {
let arg = self.load_args(1)[0] as i8; let arg = self.load_args(1)[0] as i8;
@ -1563,7 +1575,7 @@ impl CPU {
} }
self.ip = self.get_pair_value(REG_N_H, REG_N_L); self.ip = self.get_pair_value(REG_N_H, REG_N_L);
4 4
}, }
0xEA => { 0xEA => {
let addr = to_u16(self.load_args(2)); let addr = to_u16(self.load_args(2));
if self.debug { if self.debug {
@ -1571,7 +1583,7 @@ impl CPU {
} }
self.interconnect.write_byte(addr, self.regs[REG_A]); self.interconnect.write_byte(addr, self.regs[REG_A]);
16 16
}, }
0xEB...0xED => panic!("NON-EXISTING OPCODE"), 0xEB...0xED => panic!("NON-EXISTING OPCODE"),
0xEE => { 0xEE => {
let arg = self.load_args(1)[0]; let arg = self.load_args(1)[0];
@ -1585,7 +1597,7 @@ impl CPU {
self.clear_flag(FLAG_C); self.clear_flag(FLAG_C);
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
8 8
}, }
0xEF => self.rst(0x28), 0xEF => self.rst(0x28),
0xF0 => { 0xF0 => {
@ -1595,7 +1607,7 @@ impl CPU {
} }
self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + args[0] as u16); self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + args[0] as u16);
12 12
}, }
0xF1 => self.pop_rr(REG_N_A, REG_N_F), 0xF1 => self.pop_rr(REG_N_A, REG_N_F),
0xF2 => { 0xF2 => {
if self.debug { if self.debug {
@ -1604,14 +1616,14 @@ impl CPU {
let addr = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16; let addr = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16;
self.regs[REG_A] = self.interconnect.read_byte(addr); self.regs[REG_A] = self.interconnect.read_byte(addr);
8 8
}, }
0xF3 => { 0xF3 => {
if self.debug { if self.debug {
println!("DI"); println!("DI");
} }
self.ime = false; self.ime = false;
4 4
}, }
0xF4 => panic!("NON-EXISTING OPCODE"), 0xF4 => panic!("NON-EXISTING OPCODE"),
0xF5 => self.push_rr(REG_N_A, REG_N_F), 0xF5 => self.push_rr(REG_N_A, REG_N_F),
0xF6 => { 0xF6 => {
@ -1626,7 +1638,7 @@ impl CPU {
self.clear_flag(FLAG_N); self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H); self.clear_flag(FLAG_H);
8 8
}, }
0xF7 => self.rst(0x30), 0xF7 => self.rst(0x30),
0xF8 => { 0xF8 => {
let arg = self.load_args(1)[0] as i8; let arg = self.load_args(1)[0] as i8;
@ -1650,14 +1662,14 @@ impl CPU {
self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10); self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10);
} }
12 12
}, }
0xF9 => { 0xF9 => {
if self.debug { if self.debug {
println!("LD SP, HL"); println!("LD SP, HL");
} }
self.sp = self.get_pair_value(REG_N_H, REG_N_L); self.sp = self.get_pair_value(REG_N_H, REG_N_L);
8 8
}, }
0xFA => { 0xFA => {
let addr = to_u16(self.load_args(2)); let addr = to_u16(self.load_args(2));
if self.debug { if self.debug {
@ -1665,7 +1677,7 @@ impl CPU {
} }
self.regs[REG_A] = self.interconnect.read_byte(addr); self.regs[REG_A] = self.interconnect.read_byte(addr);
16 16
}, }
0xFB => { 0xFB => {
// Enable interrupts - TODO // Enable interrupts - TODO
if self.debug { if self.debug {
@ -1673,7 +1685,7 @@ impl CPU {
} }
self.ime = true; // interrupt master enable self.ime = true; // interrupt master enable
4 4
}, }
0xFC | 0xFD => panic!("NON-EXISTING OPCODE"), 0xFC | 0xFD => panic!("NON-EXISTING OPCODE"),
0xFE => { 0xFE => {
@ -1684,9 +1696,9 @@ impl CPU {
self.cp_r(args[0]); self.cp_r(args[0]);
8 8
}, }
0xFF => self.rst(0x38), 0xFF => self.rst(0x38),
_ => panic!("Unknown instruction: {:02x}", instruction) _ => panic!("Unknown instruction: {:02x}", instruction),
}; };
} }
self.interconnect.tick(cycles); self.interconnect.tick(cycles);

View File

@ -1,5 +1,5 @@
extern crate sdl2;
extern crate libc; extern crate libc;
extern crate sdl2;
// Internal ram size // Internal ram size
const VRAM_SIZE: usize = 0x2000; const VRAM_SIZE: usize = 0x2000;
@ -65,7 +65,7 @@ enum PixelOrigin {
Empty, Empty,
Background, Background,
Window, Window,
Sprite Sprite,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -149,8 +149,7 @@ pub struct Display {
current_ticks: u16, current_ticks: u16,
current_mode: DisplayMode, current_mode: DisplayMode,
// TODO // TODO
renderer: sdl2::render::Canvas<sdl2::video::Window>,
renderer: sdl2::render::Renderer<'static>,
pub event_pump: sdl2::EventPump, pub event_pump: sdl2::EventPump,
@ -167,8 +166,12 @@ impl Display {
pub fn new() -> Display { pub fn new() -> Display {
let sdl_ctx = sdl2::init().unwrap(); let sdl_ctx = sdl2::init().unwrap();
let video_ctx = sdl_ctx.video().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 wnd = video_ctx
let renderer = wnd.renderer().build().expect("Could not build renderer"); .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 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)]; let pixels = [Pixel::default(); (GB_PIXELS_X as usize) * (GB_PIXELS_Y as usize)];
@ -218,29 +221,30 @@ impl Display {
for x in 0..GB_PIXELS_X { for x in 0..GB_PIXELS_X {
let f = &mut self.pixels[(x as usize) + (y as usize) * 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.set_draw_color(f.color);
self.renderer.fill_rect( self.renderer
sdl2::rect::Rect::new( .fill_rect(sdl2::rect::Rect::new(
x as i32 * SCALE as i32, x as i32 * SCALE as i32,
y as i32 * SCALE as i32, y as i32 * SCALE as i32,
SCALE as u32, SCALE as u32,
SCALE as u32, SCALE as u32,
) ))
).expect("Rendering failed"); .expect("Rendering failed");
// Clear origin after rendering // Clear origin after rendering
f.origin = PixelOrigin::Empty; f.origin = PixelOrigin::Empty;
} }
} }
self.renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 255)); self.renderer
self.renderer.draw_rect( .set_draw_color(sdl2::pixels::Color::RGB(255, 0, 255));
sdl2::rect::Rect::new( self.renderer
.draw_rect(sdl2::rect::Rect::new(
0, 0,
0, 0,
(GB_PIXELS_X * SCALE) as u32, (GB_PIXELS_X * SCALE) as u32,
(GB_PIXELS_Y * SCALE) as u32, (GB_PIXELS_Y * SCALE) as u32,
) ))
).expect("Rendering failed"); .expect("Rendering failed");
} }
#[inline] #[inline]
@ -329,14 +333,16 @@ impl Display {
self.current_ticks += ticks; self.current_ticks += ticks;
match self.current_mode { 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 { if self.current_ticks > TICKS_END_SCANLINE {
self.current_ticks = 0; self.current_ticks = 0;
self.current_mode = DisplayMode::ReadFullMemory; self.current_mode = DisplayMode::ReadFullMemory;
} }
self.status |= 2; self.status |= 2;
}, }
DisplayMode::ReadFullMemory => { // Mode 3, reading OAM, VMEM and palette data. DisplayMode::ReadFullMemory => {
// Mode 3, reading OAM, VMEM and palette data.
// Nothing may be accessed. // Nothing may be accessed.
if self.current_ticks > TICKS_END_READMODE { if self.current_ticks > TICKS_END_READMODE {
self.current_ticks = 0; self.current_ticks = 0;
@ -349,8 +355,9 @@ impl Display {
} }
} }
self.status |= 3; 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 { if self.current_ticks > TICKS_END_HBLANK {
self.current_ticks = 0; self.current_ticks = 0;
self.curline += 1; self.curline += 1;
@ -369,8 +376,9 @@ impl Display {
} }
self.status &= 0xFC; self.status &= 0xFC;
self.status |= 0; self.status |= 0;
}, }
DisplayMode::VBlank => { // Mode 1, V-Blank (or display disabled), Memory (RAM, OAM) DisplayMode::VBlank => {
// Mode 1, V-Blank (or display disabled), Memory (RAM, OAM)
// may be accessed // may be accessed
if self.current_ticks > TICKS_END_VBLANK { if self.current_ticks > TICKS_END_VBLANK {
self.current_ticks = 0; self.current_ticks = 0;
@ -383,7 +391,8 @@ impl Display {
if self.frameskip < self.frame_no { if self.frameskip < self.frame_no {
self.render_screen(); self.render_screen();
self.renderer.present(); 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.renderer.clear();
self.frame_no = 0; self.frame_no = 0;
} else { } else {
@ -425,7 +434,6 @@ impl Display {
continue; continue;
} }
// Calculate correct coords // Calculate correct coords
let x: u8 = sprite.x.wrapping_sub(8); let x: u8 = sprite.x.wrapping_sub(8);
let y: u8 = sprite.y.wrapping_sub(16); let y: u8 = sprite.y.wrapping_sub(16);
@ -438,7 +446,7 @@ impl Display {
// Flip sprite, TODO: Validate // Flip sprite, TODO: Validate
let y_o: u8 = match sprite.is_y_flipped() { let y_o: u8 = match sprite.is_y_flipped() {
true => y ^ 7, true => y ^ 7,
false => y false => y,
}; };
let tile_offset_y: usize = render_y as usize - y_o as usize; 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? let tile_base_addr: usize = sprite.tile as usize * 16; // Should this be twice as wide in wide mode?
@ -456,7 +464,7 @@ impl Display {
} }
let limit = match wide_mode { let limit = match wide_mode {
true => 16, true => 16,
false => 8 false => 8,
}; };
for x_o in 0..limit { for x_o in 0..limit {
let b1: bool; let b1: bool;
@ -513,7 +521,12 @@ impl Display {
let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize]; let entry = MONOCHROME_PALETTE[lookup[c as usize] as usize];
// Draw stuff. We're currently only in monochrome mode // 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,
);
} }
} }
} }
@ -580,7 +593,6 @@ impl Display {
}); });
queue.reverse(); queue.reverse();
// Render background // Render background
if (self.control & CTRL_BG_DISPLAY) == CTRL_BG_DISPLAY { if (self.control & CTRL_BG_DISPLAY) == CTRL_BG_DISPLAY {
// Render pixels (20 tiles) // Render pixels (20 tiles)
@ -595,7 +607,8 @@ impl Display {
let tile_index_y: u8 = render_abs_y >> 3; let tile_index_y: u8 = render_abs_y >> 3;
let tile_offset_y: u8 = render_abs_y & 7; 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 // Obtain tile ID in this area
let tile_id = self.vram[vram_offset]; 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. 0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
_ => PixelOrigin::Background, _ => 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,
);
} }
} }
@ -643,7 +661,8 @@ impl Display {
let tile_index_y: u8 = ry >> 3; let tile_index_y: u8 = ry >> 3;
let tile_offset_y: u8 = ry & 7; 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 // Obtain tile ID in this area
let tile_id = self.vram[vram_offset]; 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. 0 => PixelOrigin::Empty, // Hack so that objects will be in front of it.
_ => PixelOrigin::Window, _ => 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_B: u8 = 1 << 1;
const KEY_A: u8 = 1 << 0; const KEY_A: u8 = 1 << 0;
use super::cartridge;
use super::display; use super::display;
use super::serial;
use super::sound; use super::sound;
use super::timer; use super::timer;
use super::serial;
use super::cartridge;
extern crate sdl2; extern crate sdl2;
@ -34,7 +34,14 @@ use self::sdl2::keyboard::Keycode;
#[derive(Debug)] #[derive(Debug)]
enum Key { enum Key {
UP, LEFT, DOWN, RIGHT, START, SELECT, A, B UP,
LEFT,
DOWN,
RIGHT,
START,
SELECT,
A,
B,
} }
pub struct Interconnect { pub struct Interconnect {
@ -155,27 +162,79 @@ impl Interconnect {
loop { loop {
if let Some(event) = self.display.event_pump.poll_event() { if let Some(event) = self.display.event_pump.poll_event() {
match event { match event {
Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => {
self.cartridge.save(); self.cartridge.save();
panic!("TODO: Proper shutdown"); panic!("TODO: Proper shutdown");
}, }
Event::KeyDown { keycode: Some(Keycode::Left), .. } => self.press_key(Key::LEFT), Event::KeyDown {
Event::KeyDown { keycode: Some(Keycode::Down), .. } => self.press_key(Key::DOWN), keycode: Some(Keycode::Left),
Event::KeyDown { keycode: Some(Keycode::Up), .. } => self.press_key(Key::UP), ..
Event::KeyDown { keycode: Some(Keycode::Right), .. } => self.press_key(Key::RIGHT), } => self.press_key(Key::LEFT),
Event::KeyDown { keycode: Some(Keycode::A), .. } => self.press_key(Key::START), Event::KeyDown {
Event::KeyDown { keycode: Some(Keycode::S), .. } => self.press_key(Key::SELECT), keycode: Some(Keycode::Down),
Event::KeyDown { keycode: Some(Keycode::Z), .. } => self.press_key(Key::A), ..
Event::KeyDown { keycode: Some(Keycode::X), .. } => self.press_key(Key::B), } => 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 {
Event::KeyUp { keycode: Some(Keycode::Down), .. } => self.release_key(Key::DOWN), keycode: Some(Keycode::Left),
Event::KeyUp { keycode: Some(Keycode::Up), .. } => self.release_key(Key::UP), ..
Event::KeyUp { keycode: Some(Keycode::Right), .. } => self.release_key(Key::RIGHT), } => self.release_key(Key::LEFT),
Event::KeyUp { keycode: Some(Keycode::A), .. } => self.release_key(Key::START), Event::KeyUp {
Event::KeyUp { keycode: Some(Keycode::S), .. } => self.release_key(Key::SELECT), keycode: Some(Keycode::Down),
Event::KeyUp { keycode: Some(Keycode::Z), .. } => self.release_key(Key::A), ..
Event::KeyUp { keycode: Some(Keycode::X), .. } => self.release_key(Key::B), } => 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 { } else {
@ -205,19 +264,15 @@ impl Interconnect {
} else { } else {
self.cartridge.read_byte(addr) self.cartridge.read_byte(addr)
} }
}, }
0x100...0x7FFF => self.cartridge.read_byte(addr), 0x100...0x7FFF => self.cartridge.read_byte(addr),
0x8000...0x9FFF => self.display.read_byte(addr), 0x8000...0x9FFF => self.display.read_byte(addr),
0xA000...0xBFFF => self.cartridge.read_byte(addr), 0xA000...0xBFFF => self.cartridge.read_byte(addr),
0xC000 ... 0xCFFF => { 0xC000...0xCFFF => self.ram[(addr - 0xC000) as usize],
self.ram[(addr - 0xC000) as usize]
},
0xD000...0xDFFF => { 0xD000...0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000]
},
0xE000 ... 0xEFFF => {
self.ram[(addr - 0xE000) as usize]
} }
0xE000...0xEFFF => self.ram[(addr - 0xE000) as usize],
0xFF00 => { 0xFF00 => {
if self.joy_switch & KEY_REGULAR == 0 { if self.joy_switch & KEY_REGULAR == 0 {
self.joy_regular_keys self.joy_regular_keys
@ -233,34 +288,20 @@ impl Interconnect {
0xFF0F => { 0xFF0F => {
// println!("Reading IF: {:02X}", self.interrupt_request_flags); // println!("Reading IF: {:02X}", self.interrupt_request_flags);
self.interrupt_request_flags self.interrupt_request_flags
}, }
0xFF10 ... 0xFF26 => { 0xFF10...0xFF26 => self.sound.read_byte(addr),
self.sound.read_byte(addr)
},
0xFF30...0xFF3F => self.sound.read_byte(addr), 0xFF30...0xFF3F => self.sound.read_byte(addr),
0xFF40 ... 0xFF4B => { 0xFF40...0xFF4B => self.display.read_byte(addr),
self.display.read_byte(addr) 0xFF50 => self.disable_bootrom,
},
0xFF50 => {
self.disable_bootrom
},
0xFF51 => self.vram_dma_source_high, 0xFF51 => self.vram_dma_source_high,
0xFF52 => self.vram_dma_source_low, 0xFF52 => self.vram_dma_source_low,
0xFF53 => self.vram_dma_destination_high, 0xFF53 => self.vram_dma_destination_high,
0xFF54 => self.vram_dma_destination_low, 0xFF54 => self.vram_dma_destination_low,
0xFF55 => { 0xFF55 => self.vram_dma_length,
self.vram_dma_length 0xFF56 => self.infrared_com_port,
}
0xFF56 => {
self.infrared_com_port
},
0xFF70 => self.wram_bank, 0xFF70 => self.wram_bank,
0xFF80 ... 0xFFFE => { 0xFF80...0xFFFE => self.hiram[(addr - 0xFF80) as usize],
self.hiram[(addr - 0xFF80) as usize] 0xFFFF => self.interrupt,
},
0xFFFF => {
self.interrupt
}
_ => { _ => {
println!("Read from {:04X} not supported.", addr); println!("Read from {:04X} not supported.", addr);
0 0
@ -290,7 +331,7 @@ impl Interconnect {
0xA000...0xBFFF => self.cartridge.write_byte(addr, val), 0xA000...0xBFFF => self.cartridge.write_byte(addr, val),
0xC000...0xCFFF => { 0xC000...0xCFFF => {
self.ram[(addr - 0xC000) as usize] = val; self.ram[(addr - 0xC000) as usize] = val;
}, }
0xD000...0xDFFF => { 0xD000...0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] = val; self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] = val;
} }
@ -306,12 +347,12 @@ impl Interconnect {
} }
0xFF10...0xFF26 => { 0xFF10...0xFF26 => {
self.sound.write_byte(addr, val); self.sound.write_byte(addr, val);
}, }
0xFF30...0xFF3F => self.sound.write_byte(addr, val), 0xFF30...0xFF3F => self.sound.write_byte(addr, val),
// Exclude DMA transfer, we will do this below // Exclude DMA transfer, we will do this below
0xFF40...0xFF45 | 0xFF47...0xFF4B => { 0xFF40...0xFF45 | 0xFF47...0xFF4B => {
self.display.write_byte(addr, val); self.display.write_byte(addr, val);
}, }
0xFF46 => { 0xFF46 => {
// println!("OAM DMA transfer"); // println!("OAM DMA transfer");
for x in 0x00..0x9F { for x in 0x00..0x9F {
@ -322,17 +363,22 @@ impl Interconnect {
0xFF50 => { 0xFF50 => {
println!("Disabling boot rom."); println!("Disabling boot rom.");
self.disable_bootrom = val; self.disable_bootrom = val;
}, }
0xFF51 => self.vram_dma_source_high = val, 0xFF51 => self.vram_dma_source_high = val,
0xFF52 => self.vram_dma_source_low = val & 0xF0, 0xFF52 => self.vram_dma_source_low = val & 0xF0,
0xFF53 => self.vram_dma_destination_high = val & 0x1F, 0xFF53 => self.vram_dma_destination_high = val & 0x1F,
0xFF54 => self.vram_dma_destination_low = val & 0xF0, 0xFF54 => self.vram_dma_destination_low = val & 0xF0,
0xFF55 => { 0xFF55 => {
let src: u16 = ((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16; let src: u16 =
let mut dst: u16 = ((self.vram_dma_destination_high as u16) << 8) | self.vram_dma_destination_low as 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; 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; let len: u16 = ((val & 0x7F) + 1) as u16 * 0x10 - 1;
for i in 0..len { for i in 0..len {
let v = self.read_byte(src.wrapping_add(i)); let v = self.read_byte(src.wrapping_add(i));
@ -344,7 +390,7 @@ impl Interconnect {
} }
0xFF56 => { 0xFF56 => {
self.infrared_com_port = val; self.infrared_com_port = val;
}, }
0xFF70 => { 0xFF70 => {
if self.wram_bank != val { if self.wram_bank != val {
println!("Switching wram bank to {:02X}", val); println!("Switching wram bank to {:02X}", val);
@ -360,11 +406,11 @@ impl Interconnect {
} }
0xFF80...0xFFFE => { 0xFF80...0xFFFE => {
self.hiram[(addr - 0xFF80) as usize] = val; self.hiram[(addr - 0xFF80) as usize] = val;
}, }
0xFFFF => { 0xFFFF => {
println!("Setting interrupt mask value {:02X}", val); println!("Setting interrupt mask value {:02X}", val);
self.interrupt = val; self.interrupt = val;
}, }
_ => { _ => {
println!("Write {:02X} to {:04X} not supported.", val, addr); println!("Write {:02X} to {:04X} not supported.", val, addr);
} }

View File

@ -1,22 +1,21 @@
// let's try to write our own, awesome emulator. // let's try to write our own, awesome emulator.
// gameboy (color?) // gameboy (color?)
use std::path::Path; use std::env;
use std::fs;
use std::io; use std::io;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use std::fs; use std::path::Path;
use std::env;
mod cartridge; mod cartridge;
mod cpu; mod cpu;
mod display; mod display;
mod interconnect; mod interconnect;
mod mbc;
mod serial;
mod sound; mod sound;
mod timer; mod timer;
mod serial;
mod mbc;
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();

View File

@ -12,10 +12,7 @@ pub struct NoMBC {
impl NoMBC { impl NoMBC {
pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC { pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC {
NoMBC { NoMBC { rom: rom, ram: ram }
rom: rom,
ram: ram,
}
} }
} }
@ -25,7 +22,10 @@ impl MBC for NoMBC {
} }
fn write_byte(&mut self, addr: u16, val: u8) { 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 { fn read_byte(&self, addr: u16) -> u8 {
@ -36,7 +36,10 @@ impl MBC for NoMBC {
let addr = (addr as usize) - 0xA000; let addr = (addr as usize) - 0xA000;
if addr >= self.ram.len() { 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 0
} else { } else {
self.ram[addr] self.ram[addr]

View File

@ -30,14 +30,14 @@ impl MBC1 {
fn active_rom_bank(&self) -> u8 { fn active_rom_bank(&self) -> u8 {
match self.bank_mode { match self.bank_mode {
BankMode::RomBankMode => self.rom_bank_no | (self.bank_no_high << 5), 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 { fn active_ram_bank(&self) -> u8 {
match self.bank_mode { match self.bank_mode {
BankMode::RomBankMode => 0, BankMode::RomBankMode => 0,
BankMode::RamBankMode => self.bank_no_high BankMode::RamBankMode => self.bank_no_high,
} }
} }
} }
@ -55,7 +55,7 @@ impl MBC for MBC1 {
let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000; let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000;
let val: u8 = self.rom[abs_addr]; let val: u8 = self.rom[abs_addr];
val val
}, }
0xA000...0xBFFF => { 0xA000...0xBFFF => {
let addr = addr - 0xA000; let addr = addr - 0xA000;
println!("Access [{:02X}] {:04X}", self.active_ram_bank(), addr); println!("Access [{:02X}] {:04X}", self.active_ram_bank(), addr);
@ -69,12 +69,10 @@ impl MBC for MBC1 {
fn write_byte(&mut self, addr: u16, val: u8) { fn write_byte(&mut self, addr: u16, val: u8) {
match addr { match addr {
0x0000 ... 0x1FFF => { 0x0000...0x1FFF => match val {
match val {
0x0A => self.ram_enable = true, 0x0A => self.ram_enable = true,
0x00 => self.ram_enable = false, 0x00 => self.ram_enable = false,
_ => println!("Unknown MBC1 value {:02X} for {:04X}", val, addr) _ => println!("Unknown MBC1 value {:02X} for {:04X}", val, addr),
}
}, },
0x2000...0x3FFF => { 0x2000...0x3FFF => {
if val != 0 { if val != 0 {
@ -87,7 +85,7 @@ impl MBC for MBC1 {
0x4000...0x5FFF => { 0x4000...0x5FFF => {
// Upper ROM bank / RAM bank select // Upper ROM bank / RAM bank select
self.bank_no_high = val & 3; self.bank_no_high = val & 3;
}, }
0x6000...0x7FFF => { 0x6000...0x7FFF => {
// Select upper ROM bytes or RAM bytes // Select upper ROM bytes or RAM bytes
match val { match val {
@ -95,7 +93,7 @@ impl MBC for MBC1 {
1 => self.bank_mode = BankMode::RamBankMode, 1 => self.bank_mode = BankMode::RamBankMode,
_ => panic!("Invalid bank mode {:02X}", val), _ => panic!("Invalid bank mode {:02X}", val),
} }
}, }
_ => panic!("MBC1: Writing {:02X} to {:04X} not supported", val, addr), _ => panic!("MBC1: Writing {:02X} to {:04X} not supported", val, addr),
} }
} }

View File

@ -35,7 +35,7 @@ impl MBC for MBC2 {
let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000; let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000;
let val: u8 = self.rom[abs_addr]; let val: u8 = self.rom[abs_addr];
val val
}, }
0xA000...0xA1FF => { 0xA000...0xA1FF => {
let addr = addr - 0xA000; let addr = addr - 0xA000;
self.ram[addr as usize] & 0x0F self.ram[addr as usize] & 0x0F
@ -54,12 +54,12 @@ impl MBC for MBC2 {
match val { match val {
0x0A => self.ram_enable = true, 0x0A => self.ram_enable = true,
0x00 => self.ram_enable = false, 0x00 => self.ram_enable = false,
_ => println!("Unknown MBC2 value {:02X} for {:04X}", val, addr) _ => println!("Unknown MBC2 value {:02X} for {:04X}", val, addr),
} }
} else { } else {
println!("MBC2: Write {:02X} to {:04X} has no effect", val, addr); println!("MBC2: Write {:02X} to {:04X} has no effect", val, addr);
} }
}, }
0x2000...0x3FFF => { 0x2000...0x3FFF => {
if addr & 0x0100 == 1 { if addr & 0x0100 == 1 {
self.rom_bank_no = val & 0x0F; self.rom_bank_no = val & 0x0F;

View File

@ -25,7 +25,6 @@ impl MBC3 {
fn active_ram_bank(&self) -> u8 { fn active_ram_bank(&self) -> u8 {
self.ram_bank_no self.ram_bank_no
} }
} }
impl MBC for MBC3 { impl MBC for MBC3 {
@ -41,7 +40,7 @@ impl MBC for MBC3 {
let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000; let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000;
let val: u8 = self.rom[abs_addr]; let val: u8 = self.rom[abs_addr];
val val
}, }
0xA000...0xBFFF => { 0xA000...0xBFFF => {
let addr = addr - 0xA000; let addr = addr - 0xA000;
match self.active_ram_bank() { match self.active_ram_bank() {
@ -53,7 +52,10 @@ impl MBC for MBC3 {
println!("MBC3: Ignoring RTC read"); println!("MBC3: Ignoring RTC read");
0 0
} }
_ => panic!("MBC3: Accessing unknown RAM bank {:02X}", self.active_ram_bank()) _ => panic!(
"MBC3: Accessing unknown RAM bank {:02X}",
self.active_ram_bank()
),
} }
} }
_ => { _ => {
@ -64,12 +66,10 @@ impl MBC for MBC3 {
fn write_byte(&mut self, addr: u16, val: u8) { fn write_byte(&mut self, addr: u16, val: u8) {
match addr { match addr {
0x0000 ... 0x1FFF => { 0x0000...0x1FFF => match val {
match val {
0x0A => self.ram_rtc_enabled = true, 0x0A => self.ram_rtc_enabled = true,
0x00 => self.ram_rtc_enabled = false, 0x00 => self.ram_rtc_enabled = false,
_ => println!("MBC3: Unknown MBC value {:02X} for {:04X}", val, addr) _ => println!("MBC3: Unknown MBC value {:02X} for {:04X}", val, addr),
}
}, },
0x2000...0x3FFF => self.rom_bank_no = val & 0x7F, 0x2000...0x3FFF => self.rom_bank_no = val & 0x7F,
0x4000...0x5FFF => { 0x4000...0x5FFF => {
@ -77,17 +77,17 @@ impl MBC for MBC3 {
match val { match val {
0x00...0x03 => self.ram_bank_no = val, 0x00...0x03 => self.ram_bank_no = val,
0x08...0x0C => self.ram_bank_no = val, 0x08...0x0C => self.ram_bank_no = val,
_ => panic!("MBC3: Unknown RAM bank {:02X}", val) _ => panic!("MBC3: Unknown RAM bank {:02X}", val),
}
} }
},
0x6000...0x7FFF => { 0x6000...0x7FFF => {
// Latch clock data // Latch clock data
match val { match val {
0x00 => println!("latch = 0"), 0x00 => println!("latch = 0"),
0x01 => println!("latch = 1"), // TODO: This should copy the current clock to the register 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; let addr = addr - 0xA000;
match self.active_ram_bank() { match self.active_ram_bank() {
@ -99,7 +99,10 @@ impl MBC for MBC3 {
// TODO // TODO
println!("MBC3: Ignoring RTC write ({:02X})", val); 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), _ => panic!("MBC3: Writing {:02X} to {:04X} not supported", val, addr),

View File

@ -36,7 +36,7 @@ impl Sound {
0xFF26 => self.enabled = val, 0xFF26 => self.enabled = val,
_ => { _ => {
// println!("Sound: Write {:02X} to {:04X} unsupported", val, addr); // println!("Sound: Write {:02X} to {:04X} unsupported", val, addr);
}, }
} }
} }

View File

@ -27,7 +27,8 @@ impl Timer {
self.div_tick_counter -= TIMER_SPEED[3]; self.div_tick_counter -= TIMER_SPEED[3];
} }
if (self.tac & TIMER_ENABLE) == TIMER_ENABLE { // Is timer enabled? if (self.tac & TIMER_ENABLE) == TIMER_ENABLE {
// Is timer enabled?
self.tick_counter += 1; self.tick_counter += 1;
let req_ticks = TIMER_SPEED[(self.tac & 3) as usize]; let req_ticks = TIMER_SPEED[(self.tac & 3) as usize];
@ -72,7 +73,7 @@ impl Timer {
_ => { _ => {
println!("Timer: Read from {:04X} unsupported", addr); println!("Timer: Read from {:04X} unsupported", addr);
0 0
}, }
} }
} }