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>"]
[dependencies]
sdl2 = "0.19.0"
sdl2 = "*"
libc = "*"

View File

@ -1,6 +1,6 @@
use super::mbc::mbc::MBC;
#[derive(Debug,PartialEq)]
#[derive(Debug, PartialEq)]
enum MemoryBankControllerType {
None,
MBC1,
@ -25,10 +25,10 @@ pub struct Cartridge {
impl Cartridge {
pub fn new(rom: Box<[u8]>, save_file: Option<String>) -> Cartridge {
let mbc_type: MemoryBankControllerType = match rom[0x0147] {
0x00 | 0x08 ... 0x09 => MemoryBankControllerType::None,
0x01 ... 0x03 => MemoryBankControllerType::MBC1,
0x05 ... 0x06 => MemoryBankControllerType::MBC2,
0x0F ... 0x13 => MemoryBankControllerType::MBC3,
0x00 | 0x08...0x09 => MemoryBankControllerType::None,
0x01...0x03 => MemoryBankControllerType::MBC1,
0x05...0x06 => MemoryBankControllerType::MBC2,
0x0F...0x13 => MemoryBankControllerType::MBC3,
// 0xFF => MemoryBankControllerType::HuC1,
_ => panic!("Unsupported MBC type: {:02X}", rom[0x0147]),
};
@ -37,11 +37,11 @@ impl Cartridge {
let rom_banks: u16 = match rom[0x0148] {
0x00 => 0,
0x01 ... 0x07 => 2u16.pow(rom[0x0148] as u32 + 1),
0x01...0x07 => 2u16.pow(rom[0x0148] as u32 + 1),
0x52 => 72,
0x53 => 80,
0x54 => 96,
_ => panic!("Unknown rom size: {:?}", rom[0x148])
_ => panic!("Unknown rom size: {:?}", rom[0x148]),
};
let ram_size: RamSize = match rom[0x0149] {
@ -49,7 +49,7 @@ impl Cartridge {
0x01 => RamSize::Ram2KB,
0x02 => RamSize::Ram8KB,
0x03 => RamSize::Ram32KB,
_ => panic!("Unknown ram size: {:?}", rom[0x149])
_ => panic!("Unknown ram size: {:?}", rom[0x149]),
};
println!("Rom size: {} banks", rom_banks);

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],
@ -154,7 +153,10 @@ impl CPU {
self.set_flag(FLAG_N);
self.set_clear_flag(FLAG_Z, new == 0);
self.set_clear_flag(FLAG_C, new > old || (new == old && c == 1));
self.set_clear_flag(FLAG_H, ((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F);
self.set_clear_flag(
FLAG_H,
((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F,
);
}
#[inline]
@ -190,7 +192,7 @@ impl CPU {
self.ip += 1;
match instruction {
0x00 ... 0x07 => {
0x00...0x07 => {
let reg_id = (instruction - 0x00) as usize;
let val = self.get_8bit_reg(reg_id);
if self.debug {
@ -209,8 +211,8 @@ impl CPU {
self.set_clear_flag(FLAG_Z, nval == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
0x08 ... 0x0F => {
}
0x08...0x0F => {
let reg_id = (instruction - 0x08) as usize;
let val = self.get_8bit_reg(reg_id);
if self.debug {
@ -227,8 +229,8 @@ impl CPU {
self.set_clear_flag(FLAG_Z, val == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
0x10 ... 0x17 => {
}
0x10...0x17 => {
let reg_id = (instruction - 0x10) as usize;
let val = self.get_8bit_reg(reg_id);
if self.debug {
@ -247,8 +249,9 @@ impl CPU {
self.set_clear_flag(FLAG_Z, nval == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
0x18 ... 0x1F => { // RR
}
0x18...0x1F => {
// RR
let reg_id = (instruction - 0x18) as usize;
let val = self.get_8bit_reg(reg_id);
if self.debug {
@ -267,8 +270,8 @@ impl CPU {
self.set_clear_flag(FLAG_Z, v == 0);
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
},
0x20 ... 0x27 => {
}
0x20...0x27 => {
let reg_id = (instruction - 0x20) as usize;
if self.debug {
println!("SLA {}", REG_NAMES[reg_id]);
@ -278,8 +281,8 @@ impl CPU {
self.set_clear_flag(FLAG_C, v & 0x80 == 0x80);
self.set_clear_flag(FLAG_Z, v & 0x7F == 0);
self.set_8bit_reg(reg_id, v << 1);
},
0x28 ... 0x2F => {
}
0x28...0x2F => {
let reg_id = (instruction - 0x28) as usize;
if self.debug {
println!("SRA {}", REG_NAMES[reg_id]);
@ -290,8 +293,8 @@ impl CPU {
self.flags = 0;
self.set_clear_flag(FLAG_Z, nv == 0);
self.set_clear_flag(FLAG_C, v & 1 == 1);
},
0x30 ... 0x37 => {
}
0x30...0x37 => {
let reg_id = (instruction - 0x30) as usize;
if self.debug {
println!("SWAP {}", REG_NAMES[reg_id]);
@ -300,8 +303,8 @@ impl CPU {
self.set_8bit_reg(reg_id, (v << 4) | (v >> 4));
self.flags = 0;
self.set_clear_flag(FLAG_Z, v == 0);
},
0x38 ... 0x3F => {
}
0x38...0x3F => {
let reg_id = (instruction - 0x38) as usize;
if self.debug {
println!("SRL {}", REG_NAMES[reg_id]);
@ -312,10 +315,10 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
self.set_clear_flag(FLAG_Z, (v & 0xFE) == 0);
},
}
// Bits
0x40 ... 0x47 => {
0x40...0x47 => {
// Test 0th bit
let reg_id = (instruction - 0x40) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -326,7 +329,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.set_flag(FLAG_H);
}
0x48 ... 0x4F => {
0x48...0x4F => {
// Test 1th bit
let reg_id = (instruction - 0x48) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -337,7 +340,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.set_flag(FLAG_H);
}
0x50 ... 0x57 => {
0x50...0x57 => {
// Test 2th bit
let reg_id = (instruction - 0x50) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -348,7 +351,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.set_flag(FLAG_H);
}
0x58 ... 0x5F => {
0x58...0x5F => {
// Test 3th bit
let reg_id = (instruction - 0x58) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -359,7 +362,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.set_flag(FLAG_H);
}
0x60 ... 0x67 => {
0x60...0x67 => {
// Test 4th bit
let reg_id = (instruction - 0x60) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -370,7 +373,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.set_flag(FLAG_H);
}
0x68 ... 0x6F => {
0x68...0x6F => {
// Test 5th bit
let reg_id = (instruction - 0x68) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -381,7 +384,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.set_flag(FLAG_H);
}
0x70 ... 0x77 => {
0x70...0x77 => {
// Test 6th bit
let reg_id = (instruction - 0x70) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -392,7 +395,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.set_flag(FLAG_H);
}
0x78 ... 0x7F => {
0x78...0x7F => {
// Test 7th bit
let reg_id = (instruction - 0x78) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -405,7 +408,7 @@ impl CPU {
}
// Reset bits
0x80 ... 0x87 => {
0x80...0x87 => {
// Reset 0th bit
let reg_id = (instruction - 0x80) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -414,7 +417,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content & !(1 << 0));
}
0x88 ... 0x8F => {
0x88...0x8F => {
// Reset 1th bit
let reg_id = (instruction - 0x88) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -423,7 +426,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content & !(1 << 1));
}
0x90 ... 0x97 => {
0x90...0x97 => {
// Reset 2nd bit
let reg_id = (instruction - 0x90) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -432,7 +435,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content & !(1 << 2));
}
0x98 ... 0x9F => {
0x98...0x9F => {
// Reset 3th bit
let reg_id = (instruction - 0x98) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -441,7 +444,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content & !(1 << 3));
}
0xA0 ... 0xA7 => {
0xA0...0xA7 => {
// Reset 4th bit
let reg_id = (instruction - 0xA0) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -450,7 +453,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content & !(1 << 4));
}
0xA8 ... 0xAF => {
0xA8...0xAF => {
// Reset 5th bit
let reg_id = (instruction - 0xA8) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -459,7 +462,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content & !(1 << 5));
}
0xB0 ... 0xB7 => {
0xB0...0xB7 => {
// Reset 6th bit
let reg_id = (instruction - 0xB0) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -468,7 +471,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content & !(1 << 6));
}
0xB8 ... 0xBF => {
0xB8...0xBF => {
// Reset 7th bit
let reg_id = (instruction - 0xB8) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -479,7 +482,7 @@ impl CPU {
}
// Set bits
0xC0 ... 0xC7 => {
0xC0...0xC7 => {
// Set 0th bit
let reg_id = (instruction - 0xC0) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -488,7 +491,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content | (1 << 0));
}
0xC8 ... 0xCF => {
0xC8...0xCF => {
// Set 1th bit
let reg_id = (instruction - 0xC8) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -497,7 +500,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content | (1 << 1));
}
0xD0 ... 0xD7 => {
0xD0...0xD7 => {
// Set 2nd bit
let reg_id = (instruction - 0xD0) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -506,7 +509,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content | (1 << 2));
}
0xD8 ... 0xDF => {
0xD8...0xDF => {
// Set 3th bit
let reg_id = (instruction - 0xD8) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -515,7 +518,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content | (1 << 3));
}
0xE0 ... 0xE7 => {
0xE0...0xE7 => {
// Set 4th bit
let reg_id = (instruction - 0xE0) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -524,7 +527,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content | (1 << 4));
}
0xE8 ... 0xEF => {
0xE8...0xEF => {
// Set 5th bit
let reg_id = (instruction - 0xE8) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -533,7 +536,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content | (1 << 5));
}
0xF0 ... 0xF7 => {
0xF0...0xF7 => {
// Set 6th bit
let reg_id = (instruction - 0xF0) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -542,7 +545,7 @@ impl CPU {
}
self.set_8bit_reg(reg_id, reg_content | (1 << 6));
}
0xF8 ... 0xFF => {
0xF8...0xFF => {
// Set 7th bit
let reg_id = (instruction - 0xF8) as usize;
let reg_content = self.get_8bit_reg(reg_id);
@ -766,7 +769,10 @@ impl CPU {
#[inline]
fn add_rr_rr(&mut self, r1: usize, r2: usize, r3: usize, r4: usize) -> u8 {
if self.debug {
println!("ADD {}{}, {}{}", REG_NAMES[r1], REG_NAMES[r2], REG_NAMES[r3], REG_NAMES[r4]);
println!(
"ADD {}{}, {}{}",
REG_NAMES[r1], REG_NAMES[r2], REG_NAMES[r3], REG_NAMES[r4]
);
}
let val1 = self.get_pair_value(r1, r2);
@ -830,7 +836,7 @@ impl CPU {
}
#[inline]
fn int_(&mut self, val: u8){
fn int_(&mut self, val: u8) {
if self.debug {
println!("INT {:02X}", val);
}
@ -868,14 +874,15 @@ impl CPU {
loop {
let mut cycles: i32 = 0;
let start = Instant::now();
for _ in 0 .. 1000 {
for _ in 0..1000 {
cycles += self.run_instruction() as i32;
}
let gb_dur = cycles * 238;
let our_dur = start.elapsed().subsec_nanos() as i32;
let delta = gb_dur - our_dur;
if delta > (20 * 238) { // We're at least 20 cycles faster.
if delta > (20 * 238) {
// We're at least 20 cycles faster.
sleep(Duration::new(0, delta as u32));
} else if delta < 0 {
print!("-");
@ -937,8 +944,11 @@ impl CPU {
// We need to double-check the flags
instruction = self.read_byte(self.ip);
if self.debug {
print!("{:#06x}: [SP: {:#04X}] i={:02X}. ", &self.ip, &self.sp, &instruction);
for i in 0 .. 6 {
print!(
"{:#06x}: [SP: {:#04X}] i={:02X}. ",
&self.ip, &self.sp, &instruction
);
for i in 0..6 {
print!("{}: {:02X} ", REG_NAMES[i], self.get_8bit_reg(i));
}
print!("A: {:02X} ", self.regs[REG_A]);
@ -959,7 +969,7 @@ impl CPU {
println!("NOP");
}
4
},
}
0x01 => self.ld_rr_vv(REG_N_B, REG_N_C),
0x02 => self.ld_dref_rr_a(REG_N_B, REG_N_C),
0x03 => self.inc_rr(REG_N_B, REG_N_C),
@ -985,7 +995,7 @@ impl CPU {
}
0x08 => {
let a: u16 = to_u16(self.load_args(2));
if self.debug{
if self.debug {
println!("LD ({:04X}), sp", a);
}
self.interconnect.write_word(a, self.sp);
@ -996,9 +1006,11 @@ impl CPU {
if self.debug {
println!("LD A, (BC)");
}
self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_N_B, REG_N_C));
self.regs[REG_A] = self
.interconnect
.read_byte(self.get_pair_value(REG_N_B, REG_N_C));
8
},
}
0x0B => self.dec_rr(REG_N_B, REG_N_C),
0x0C => self.reg_inc(REG_N_C),
0x0D => self.reg_dec(REG_N_C),
@ -1023,7 +1035,7 @@ impl CPU {
0x10 => {
println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]);
4
},
}
0x11 => self.ld_rr_vv(REG_N_D, REG_N_E),
0x12 => self.ld_dref_rr_a(REG_N_D, REG_N_E),
0x13 => self.inc_rr(REG_N_D, REG_N_E),
@ -1046,20 +1058,22 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
0x18 => {
let dst = self.load_args(1)[0];
self.jmp_r(dst);
12
},
}
0x19 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_D, REG_N_E),
0x1A => {
if self.debug {
println!("LD A, (DE)");
}
self.regs[REG_A] = self.interconnect.read_byte(self.get_pair_value(REG_N_D, REG_N_E));
self.regs[REG_A] = self
.interconnect
.read_byte(self.get_pair_value(REG_N_D, REG_N_E));
8
},
}
0x1B => self.dec_rr(REG_N_D, REG_N_E),
0x1C => self.reg_inc(REG_N_E),
0x1D => self.reg_dec(REG_N_E),
@ -1080,8 +1094,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
0x20 => {
let c = self.flags & FLAG_Z == 0;
@ -1096,7 +1109,7 @@ impl CPU {
self.interconnect.write_byte(addr, self.regs[REG_A]);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1));
8
},
}
0x23 => self.inc_rr(REG_N_H, REG_N_L),
0x24 => self.reg_inc(REG_N_H),
0x25 => self.reg_dec(REG_N_H),
@ -1138,11 +1151,11 @@ impl CPU {
self.set_clear_flag(FLAG_Z, a == 0);
4
},
}
0x28 => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.jmp_r_condition("Z".to_owned(), c)
},
}
0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L),
0x2A => {
if self.debug {
@ -1152,7 +1165,7 @@ impl CPU {
self.regs[REG_A] = self.interconnect.read_byte(addr);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_add(1));
8
},
}
0x2B => self.dec_rr(REG_N_H, REG_N_L),
0x2C => self.reg_inc(REG_N_L),
0x2D => self.reg_dec(REG_N_L),
@ -1165,13 +1178,12 @@ impl CPU {
self.set_flag(FLAG_N);
self.set_flag(FLAG_H);
4
},
}
0x30 => {
let c = self.flags & FLAG_C == 0;
self.jmp_r_condition("NC".to_owned(), c)
},
}
0x31 => {
let args = self.load_args(2);
self.sp = to_u16(args);
@ -1179,7 +1191,7 @@ impl CPU {
println!("LD SP, {:04x}", self.sp);
}
12
},
}
0x32 => {
if self.debug {
println!("LD (HL-), A");
@ -1188,7 +1200,7 @@ impl CPU {
self.interconnect.write_byte(addr, self.regs[REG_A]);
self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1));
8
},
}
0x33 => {
if self.debug {
println!("INC SP");
@ -1208,11 +1220,11 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
0x38 => {
let c = self.flags & FLAG_C == FLAG_C;
self.jmp_r_condition("C".to_owned(), c)
},
}
0x39 => {
if self.debug {
println!("ADD HL, SP");
@ -1226,7 +1238,7 @@ impl CPU {
self.set_clear_flag(FLAG_C, old > v && sp > 0);
self.set_clear_flag(FLAG_H, ((old & 0xFFF) + (sp & 0xFFF)) > 0xFFF);
8
},
}
0x3A => {
if self.debug {
println!("LD A, (HL-)");
@ -1258,14 +1270,14 @@ impl CPU {
}
// LDs
0x40 ... 0x47 => self.ld_r_r(REG_N_B, (instruction - 0x40) as usize),
0x48 ... 0x4F => self.ld_r_r(REG_N_C, (instruction - 0x48) as usize),
0x50 ... 0x57 => self.ld_r_r(REG_N_D, (instruction - 0x50) as usize),
0x58 ... 0x5F => self.ld_r_r(REG_N_E, (instruction - 0x58) as usize),
0x60 ... 0x67 => self.ld_r_r(REG_N_H, (instruction - 0x60) as usize),
0x68 ... 0x6F => self.ld_r_r(REG_N_L, (instruction - 0x68) as usize),
0x70 ... 0x75 | 0x77 => self.ld_r_r(REG_N_HL, (instruction - 0x70) as usize),
0x78 ... 0x7F => self.ld_r_r(REG_N_A, (instruction - 0x78) as usize),
0x40...0x47 => self.ld_r_r(REG_N_B, (instruction - 0x40) as usize),
0x48...0x4F => self.ld_r_r(REG_N_C, (instruction - 0x48) as usize),
0x50...0x57 => self.ld_r_r(REG_N_D, (instruction - 0x50) as usize),
0x58...0x5F => self.ld_r_r(REG_N_E, (instruction - 0x58) as usize),
0x60...0x67 => self.ld_r_r(REG_N_H, (instruction - 0x60) as usize),
0x68...0x6F => self.ld_r_r(REG_N_L, (instruction - 0x68) as usize),
0x70...0x75 | 0x77 => self.ld_r_r(REG_N_HL, (instruction - 0x70) as usize),
0x78...0x7F => self.ld_r_r(REG_N_A, (instruction - 0x78) as usize),
// HALT
0x76 => {
@ -1274,10 +1286,10 @@ impl CPU {
}
self.halted = true;
4
},
}
// ADD
0x80 ... 0x87 => {
0x80...0x87 => {
let reg_id = (instruction - 0x80) as usize;
if self.debug {
println!("ADD {}", REG_NAMES[reg_id]);
@ -1288,7 +1300,7 @@ impl CPU {
}
// ADC
0x88 ... 0x8F => {
0x88...0x8F => {
let reg_id = (instruction - 0x88) as usize;
if self.debug {
println!("ADC {}", REG_NAMES[reg_id]);
@ -1300,7 +1312,7 @@ impl CPU {
}
// SUBs
0x90 ... 0x97 => {
0x90...0x97 => {
let reg_id = (instruction - 0x90) as usize;
if self.debug {
println!("SUB {}", REG_NAMES[reg_id]);
@ -1311,7 +1323,7 @@ impl CPU {
}
// SBC
0x98 ... 0x9F => {
0x98...0x9F => {
let reg_id = (instruction - 0x98) as usize;
if self.debug {
println!("SBC {}", REG_NAMES[reg_id]);
@ -1322,7 +1334,7 @@ impl CPU {
}
// AND
0xA0 ... 0xA7 => {
0xA0...0xA7 => {
let reg_id = (instruction - 0xA0) as usize;
if self.debug {
println!("AND {}", REG_NAMES[reg_id]);
@ -1338,7 +1350,7 @@ impl CPU {
}
// XOR
0xA8 ... 0xAF => {
0xA8...0xAF => {
let reg_id = (instruction - 0xA8) as usize;
if self.debug {
println!("XOR {}", REG_NAMES[reg_id]);
@ -1351,10 +1363,10 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
4
},
}
// OR
0xB0 ... 0xB7 => {
0xB0...0xB7 => {
let reg_id = (instruction - 0xB0) as usize;
if self.debug {
println!("OR {}", REG_NAMES[reg_id]);
@ -1370,7 +1382,7 @@ impl CPU {
}
// CP
0xB8 ... 0xBF => {
0xB8...0xBF => {
let reg_id = (instruction - 0xB8) as usize;
if self.debug {
println!("CP {}", REG_NAMES[reg_id]);
@ -1379,17 +1391,17 @@ impl CPU {
let v = self.get_8bit_reg(reg_id);
self.cp_r(v);
4
},
}
0xC0 => {
let c = self.flags & FLAG_Z == 0;
self.ret_condition("NZ".to_owned(), c)
},
}
0xC1 => self.pop_rr(REG_N_B, REG_N_C),
0xC2 => {
let c = self.flags & FLAG_Z == 0;
self.jmp_p_condition("NZ".to_owned(), c)
},
}
0xC3 => {
let dst = to_u16(self.load_args(2));
if self.debug {
@ -1397,7 +1409,7 @@ impl CPU {
}
self.jmp_p(dst);
16
},
}
0xC4 => {
let c = self.flags & FLAG_Z == 0;
self.call_condition("NZ".to_owned(), c)
@ -1412,19 +1424,19 @@ impl CPU {
self.add_r(val);
8
},
}
0xC7 => self.rst(0x00),
0xC8 => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.ret_condition("Z".to_owned(), c)
},
}
0xC9 => {
if self.debug {
println!("RET");
}
self.ret();
16
},
}
0xCA => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.jmp_p_condition("Z".to_owned(), c)
@ -1432,11 +1444,11 @@ impl CPU {
0xCB => {
self.run_prefix_instruction();
12 // TODO: Verify that this is the case for all prefix instructions.
},
}
0xCC => {
let c = self.flags & FLAG_Z == FLAG_Z;
self.call_condition("Z".to_owned(), c)
},
}
0xCD => self.call_condition("".to_owned(), true),
0xCE => {
let arg = self.load_args(1)[0];
@ -1445,14 +1457,13 @@ impl CPU {
}
self.adc_r(arg);
8
},
}
0xCF => self.rst(0x08),
0xD0 => {
let c = self.flags & FLAG_C == 0;
self.ret_condition("NC".to_owned(), c)
},
}
0xD1 => self.pop_rr(REG_N_D, REG_N_E),
0xD2 => {
let c = self.flags & FLAG_C == 0;
@ -1472,12 +1483,12 @@ impl CPU {
self.sub_r(val);
8
},
}
0xD7 => self.rst(0x10),
0xD8 => {
let c = self.flags & FLAG_C == FLAG_C;
self.ret_condition("C".to_owned(), c)
},
}
0xD9 => {
if self.debug {
println!("RETI");
@ -1487,7 +1498,7 @@ impl CPU {
0xDA => {
let c = self.flags & FLAG_C == FLAG_C;
self.jmp_p_condition("C".to_owned(), c)
},
}
0xDB => panic!("NON-EXISTING OPCODE"),
0xDC => {
let c = self.flags & FLAG_C == FLAG_C;
@ -1501,7 +1512,7 @@ impl CPU {
}
self.sbc_r(arg);
8
},
}
0xDF => self.rst(0x18),
0xE0 => {
@ -1509,9 +1520,10 @@ impl CPU {
if self.debug {
println!("LDH {:02X}, A", args[0]);
}
self.interconnect.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]);
self.interconnect
.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]);
12
},
}
0xE1 => self.pop_rr(REG_N_H, REG_N_L),
0xE2 => {
if self.debug {
@ -1520,7 +1532,7 @@ impl CPU {
let addr: u16 = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16;
self.interconnect.write_byte(addr, self.regs[REG_A]);
8
},
}
0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"),
0xE5 => self.push_rr(REG_N_H, REG_N_L),
0xE6 => {
@ -1536,7 +1548,7 @@ impl CPU {
self.clear_flag(FLAG_C);
8
},
}
0xE7 => self.rst(0x20),
0xE8 => {
let arg = self.load_args(1)[0] as i8;
@ -1563,16 +1575,16 @@ impl CPU {
}
self.ip = self.get_pair_value(REG_N_H, REG_N_L);
4
},
}
0xEA => {
let addr = to_u16(self.load_args(2));
if self.debug{
if self.debug {
println!("LD ({:04X}), A", addr);
}
self.interconnect.write_byte(addr, self.regs[REG_A]);
16
},
0xEB ... 0xED => panic!("NON-EXISTING OPCODE"),
}
0xEB...0xED => panic!("NON-EXISTING OPCODE"),
0xEE => {
let arg = self.load_args(1)[0];
if self.debug {
@ -1585,7 +1597,7 @@ impl CPU {
self.clear_flag(FLAG_C);
self.clear_flag(FLAG_N);
8
},
}
0xEF => self.rst(0x28),
0xF0 => {
@ -1595,23 +1607,23 @@ impl CPU {
}
self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + args[0] as u16);
12
},
}
0xF1 => self.pop_rr(REG_N_A, REG_N_F),
0xF2 => {
if self.debug{
if self.debug {
println!("LD A, (C)");
}
let addr = 0xFF00 + self.get_8bit_reg(REG_N_C) as u16;
self.regs[REG_A] = self.interconnect.read_byte(addr);
8
},
}
0xF3 => {
if self.debug {
println!("DI");
}
self.ime = false;
4
},
}
0xF4 => panic!("NON-EXISTING OPCODE"),
0xF5 => self.push_rr(REG_N_A, REG_N_F),
0xF6 => {
@ -1626,7 +1638,7 @@ impl CPU {
self.clear_flag(FLAG_N);
self.clear_flag(FLAG_H);
8
},
}
0xF7 => self.rst(0x30),
0xF8 => {
let arg = self.load_args(1)[0] as i8;
@ -1650,14 +1662,14 @@ impl CPU {
self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10);
}
12
},
}
0xF9 => {
if self.debug {
println!("LD SP, HL");
}
self.sp = self.get_pair_value(REG_N_H, REG_N_L);
8
},
}
0xFA => {
let addr = to_u16(self.load_args(2));
if self.debug {
@ -1665,7 +1677,7 @@ impl CPU {
}
self.regs[REG_A] = self.interconnect.read_byte(addr);
16
},
}
0xFB => {
// Enable interrupts - TODO
if self.debug {
@ -1673,7 +1685,7 @@ impl CPU {
}
self.ime = true; // interrupt master enable
4
},
}
0xFC | 0xFD => panic!("NON-EXISTING OPCODE"),
0xFE => {
@ -1684,9 +1696,9 @@ impl CPU {
self.cp_r(args[0]);
8
},
}
0xFF => self.rst(0x38),
_ => panic!("Unknown instruction: {:02x}", instruction)
_ => panic!("Unknown instruction: {:02x}", instruction),
};
}
self.interconnect.tick(cycles);

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 ... 0x100 => {
0x0000...0x100 => {
if self.disable_bootrom == 0 {
self.bios[addr as usize]
} else {
self.cartridge.read_byte(addr)
}
},
0x100 ... 0x7FFF => self.cartridge.read_byte(addr),
0x8000 ... 0x9FFF => self.display.read_byte(addr),
0xA000 ... 0xBFFF => self.cartridge.read_byte(addr),
0xC000 ... 0xCFFF => {
self.ram[(addr - 0xC000) as usize]
},
0xD000 ... 0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000]
},
0xE000 ... 0xEFFF => {
self.ram[(addr - 0xE000) as usize]
}
0x100...0x7FFF => self.cartridge.read_byte(addr),
0x8000...0x9FFF => self.display.read_byte(addr),
0xA000...0xBFFF => self.cartridge.read_byte(addr),
0xC000...0xCFFF => self.ram[(addr - 0xC000) as usize],
0xD000...0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000]
}
0xE000...0xEFFF => self.ram[(addr - 0xE000) as usize],
0xFF00 => {
if self.joy_switch & KEY_REGULAR == 0 {
self.joy_regular_keys
@ -228,39 +283,25 @@ impl Interconnect {
0x3F
}
}
0xFF01 ... 0xFF02 => self.serial.read_byte(addr),
0xFF04 ... 0xFF07 => self.timer.read_byte(addr),
0xFF01...0xFF02 => self.serial.read_byte(addr),
0xFF04...0xFF07 => self.timer.read_byte(addr),
0xFF0F => {
// println!("Reading IF: {:02X}", self.interrupt_request_flags);
self.interrupt_request_flags
},
0xFF10 ... 0xFF26 => {
self.sound.read_byte(addr)
},
0xFF30 ... 0xFF3F => self.sound.read_byte(addr),
0xFF40 ... 0xFF4B => {
self.display.read_byte(addr)
},
0xFF50 => {
self.disable_bootrom
},
}
0xFF10...0xFF26 => self.sound.read_byte(addr),
0xFF30...0xFF3F => self.sound.read_byte(addr),
0xFF40...0xFF4B => self.display.read_byte(addr),
0xFF50 => self.disable_bootrom,
0xFF51 => self.vram_dma_source_high,
0xFF52 => self.vram_dma_source_low,
0xFF53 => self.vram_dma_destination_high,
0xFF54 => self.vram_dma_destination_low,
0xFF55 => {
self.vram_dma_length
}
0xFF56 => {
self.infrared_com_port
},
0xFF55 => self.vram_dma_length,
0xFF56 => self.infrared_com_port,
0xFF70 => self.wram_bank,
0xFF80 ... 0xFFFE => {
self.hiram[(addr - 0xFF80) as usize]
},
0xFFFF => {
self.interrupt
}
0xFF80...0xFFFE => self.hiram[(addr - 0xFF80) as usize],
0xFFFF => self.interrupt,
_ => {
println!("Read from {:04X} not supported.", addr);
0
@ -285,36 +326,36 @@ impl Interconnect {
*/
match addr {
0x0000 ... 0x7FFF => self.cartridge.write_byte(addr, val),
0x8000 ... 0x9FFF => self.display.write_byte(addr, val),
0xA000 ... 0xBFFF => self.cartridge.write_byte(addr, val),
0xC000 ... 0xCFFF => {
0x0000...0x7FFF => self.cartridge.write_byte(addr, val),
0x8000...0x9FFF => self.display.write_byte(addr, val),
0xA000...0xBFFF => self.cartridge.write_byte(addr, val),
0xC000...0xCFFF => {
self.ram[(addr - 0xC000) as usize] = val;
},
0xD000 ... 0xDFFF => {
}
0xD000...0xDFFF => {
self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] = val;
}
0xFE00 ... 0xFE9F => self.display.write_byte(addr, val), // OAM
0xFE00...0xFE9F => self.display.write_byte(addr, val), // OAM
0xFF00 => {
// Joystick select
self.joy_switch = val;
}
0xFF01 ... 0xFF02 => self.serial.write_byte(addr, val),
0xFF04 ... 0xFF07 => self.timer.write_byte(addr, val),
0xFF01...0xFF02 => self.serial.write_byte(addr, val),
0xFF04...0xFF07 => self.timer.write_byte(addr, val),
0xFF0F => {
self.interrupt_request_flags = val;
}
0xFF10 ... 0xFF26 => {
0xFF10...0xFF26 => {
self.sound.write_byte(addr, val);
},
0xFF30 ... 0xFF3F => self.sound.write_byte(addr, val),
}
0xFF30...0xFF3F => self.sound.write_byte(addr, val),
// Exclude DMA transfer, we will do this below
0xFF40 ... 0xFF45 | 0xFF47 ... 0xFF4B => {
0xFF40...0xFF45 | 0xFF47...0xFF4B => {
self.display.write_byte(addr, val);
},
}
0xFF46 => {
// println!("OAM DMA transfer");
for x in 0x00 .. 0x9F {
for x in 0x00..0x9F {
let dma_b = self.read_byte(((val as u16) << 8) | x);
self.write_byte(0xFE00 | x, dma_b);
}
@ -322,17 +363,22 @@ impl Interconnect {
0xFF50 => {
println!("Disabling boot rom.");
self.disable_bootrom = val;
},
}
0xFF51 => self.vram_dma_source_high = val,
0xFF52 => self.vram_dma_source_low = val & 0xF0,
0xFF53 => self.vram_dma_destination_high = val & 0x1F,
0xFF54 => self.vram_dma_destination_low = val & 0xF0,
0xFF55 => {
let src: u16 = ((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16;
let mut dst: u16 = ((self.vram_dma_destination_high as u16) << 8) | self.vram_dma_destination_low as u16;
let src: u16 =
((self.vram_dma_source_high as u16) << 8) | self.vram_dma_source_low as u16;
let mut dst: u16 = ((self.vram_dma_destination_high as u16) << 8)
| self.vram_dma_destination_low as u16;
dst += 0x8000;
println!("VRAM DMA transfer from {:04X} to {:04X}; {:02X}", src, dst, val);
println!(
"VRAM DMA transfer from {:04X} to {:04X}; {:02X}",
src, dst, val
);
let len: u16 = ((val & 0x7F) + 1) as u16 * 0x10 - 1;
for i in 0..len {
let v = self.read_byte(src.wrapping_add(i));
@ -344,7 +390,7 @@ impl Interconnect {
}
0xFF56 => {
self.infrared_com_port = val;
},
}
0xFF70 => {
if self.wram_bank != val {
println!("Switching wram bank to {:02X}", val);
@ -358,13 +404,13 @@ impl Interconnect {
}
}
}
0xFF80 ... 0xFFFE => {
0xFF80...0xFFFE => {
self.hiram[(addr - 0xFF80) as usize] = val;
},
}
0xFFFF => {
println!("Setting interrupt mask value {:02X}", val);
self.interrupt = val;
},
}
_ => {
println!("Write {:02X} to {:04X} not supported.", val, addr);
}

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

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

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

View File

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