Interrupts tests passing

This commit is contained in:
Franco Colmenarez 2021-11-03 08:36:30 -05:00
parent 806a4bf211
commit 659f602b2a
5 changed files with 31 additions and 22 deletions

View File

@ -1,6 +1,9 @@
use rmg_001::render::start_eventloop; use rmg_001::render::start_eventloop;
use rmg_001::emulator::Emulator;
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
start_eventloop(); start_eventloop();
/* let mut emulator = Emulator::new();
emulator.cpu_loop(); */
Ok(()) Ok(())
} }

View File

@ -59,10 +59,10 @@ pub struct Bus {
impl Bus { impl Bus {
pub fn new() -> Self { pub fn new() -> Self {
// let game_rom = match ROM::load_file("ignore/dr-mario.gb".to_string()) { let game_rom = match ROM::load_file("ignore/tetris.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/01-special.gb".to_string()) {
let game_rom = match ROM::load_file("roms/cpu_instrs_individual/02-interrupts.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/02-interrupts.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/03-op sp,hl.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/03-op sp,hl.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/04-op r,imm.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/04-op r,imm.gb".to_string()) {
// let game_rom = match ROM::load_file("roms/cpu_instrs_individual/05-op rp.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/05-op rp.gb".to_string()) {
@ -77,6 +77,7 @@ impl Bus {
_ => panic!("Could not read ROM"), _ => panic!("Could not read ROM"),
}; };
let mut data = [0x00; 0x10000]; let mut data = [0x00; 0x10000];
// Hardware registers after the bootrom
data[0xFF00] = 0b11001111; data[0xFF00] = 0b11001111;
data[0xFF01] = 0x00; data[0xFF01] = 0x00;
data[0xFF02] = 0x7E; data[0xFF02] = 0x7E;
@ -122,10 +123,6 @@ impl Bus {
// print!("{}", data as char); // print!("{}", data as char);
} }
if address == 0xFF06 {
println!("Writing {:02X} to modulo", data);
}
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) { if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
// println!("WRITING TO ROM"); // println!("WRITING TO ROM");
} else if WORK_RAM_1.in_range(address) || WORK_RAM_2.in_range(address) { } else if WORK_RAM_1.in_range(address) || WORK_RAM_2.in_range(address) {
@ -138,7 +135,6 @@ impl Bus {
self.data[address as usize] = data; self.data[address as usize] = data;
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
} else if address == TIMER_DIVIDER_REGISTER_ADDRESS { } else if address == TIMER_DIVIDER_REGISTER_ADDRESS {
println!("bus timer reset");
self.reset_timer = true; self.reset_timer = true;
} else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) { } else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) {
self.data[address as usize] = data; self.data[address as usize] = data;

View File

@ -914,19 +914,17 @@ impl CPU {
println!("Interrupt: {:?}", interrupt); println!("Interrupt: {:?}", interrupt);
bus.set_interrupt_flag(interrupt, false); bus.set_interrupt_flag(interrupt, false);
self.ime = false; self.ime = false;
self.registers.decrement(Register::PC, 3);
self.exec(Opcode::CALL(OpcodeParameter::U16(interrupt.get_vector())), bus); self.exec(Opcode::CALL(OpcodeParameter::U16(interrupt.get_vector())), bus);
} }
pub fn check_interrupts(&mut self, bus: &mut Bus) -> Option<Interrupt> { pub fn check_interrupts(&mut self, bus: &mut Bus) -> Option<Interrupt> {
/* println!("IE {:08b}", bus.read(INTERRUPT_ENABLE_ADDRESS));
println!("IF {:08b}", bus.read(INTERRUPT_FLAG_ADDRESS));
println!("---"); */
if !self.ime && !self.is_halted {
return None;
}
if bus.read(INTERRUPT_ENABLE_ADDRESS) & bus.read(INTERRUPT_FLAG_ADDRESS) != 0 { if bus.read(INTERRUPT_ENABLE_ADDRESS) & bus.read(INTERRUPT_FLAG_ADDRESS) != 0 {
self.is_halted = false; self.is_halted = false;
} }
if !self.ime {
return None;
}
if bus.get_interrupt(Interrupt::VBlank) { if bus.get_interrupt(Interrupt::VBlank) {
return Some(Interrupt::VBlank); return Some(Interrupt::VBlank);
@ -942,6 +940,14 @@ impl CPU {
None None
} }
pub fn ei_delay(&mut self, bus: &mut Bus) {
if self.ei_delay && !self.ime {
self.ei_delay = false;
self.run(bus);
self.ime = true;
}
}
pub fn run(&mut self, bus: &mut Bus) { pub fn run(&mut self, bus: &mut Bus) {
let cycles_start = self.get_cycles(); let cycles_start = self.get_cycles();
if let Some(interrupt) = self.check_interrupts(bus) { if let Some(interrupt) = self.check_interrupts(bus) {
@ -953,15 +959,11 @@ impl CPU {
let (opcode, cycles) = parameter_bytes.parse_opcode(); let (opcode, cycles) = parameter_bytes.parse_opcode();
if !env::var("CPU_LOG").is_err() { if !env::var("CPU_LOG").is_err() {
self.log(parameter_bytes); self.log(parameter_bytes);
self.increment_exec_calls_count();
} }
self.increment_cycles(cycles); self.increment_cycles(cycles);
self.exec(opcode, bus); self.exec(opcode, bus);
if self.ei_delay && !self.ime { self.ei_delay(bus);
println!("EI delay");
self.ei_delay = false;
self.run(bus);
self.ime = true;
}
} else if self.is_halted { } else if self.is_halted {
self.increment_cycles(Cycles(1)); self.increment_cycles(Cycles(1));
} }
@ -1789,7 +1791,6 @@ impl CPU {
}, },
// Enable interrupts // Enable interrupts
Opcode::EI => { Opcode::EI => {
println!("EI");
self.registers.increment(Register::PC, 1); self.registers.increment(Register::PC, 1);
self.ei_delay = true; self.ei_delay = true;
}, },

View File

@ -118,6 +118,10 @@ impl Emulator {
} }
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
// 1 CPU cycle = 238.42ns
// thread::sleep(time::Duration::from_nanos((self.cpu.get_last_op_cycles().0 * 238).try_into().unwrap()));
} }
} }
@ -125,8 +129,15 @@ impl Emulator {
let mut exit = false; let mut exit = false;
while !exit { while !exit {
self.cpu.run(&mut self.bus); self.cpu.run(&mut self.bus);
if self.bus.reset_timer {
self.bus.reset_timer = false;
self.timer.reset(&mut self.bus);
}
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
// exit = self.cpu.get_exec_calls_count() >= 1258895; // log 1 // exit = self.cpu.get_exec_calls_count() >= 1258895; // log 1
exit = self.cpu.get_exec_calls_count() >= 161502; // log 2
// exit = self.cpu.get_exec_calls_count() >= 1068422; // log 3 // exit = self.cpu.get_exec_calls_count() >= 1068422; // log 3
// exit = self.cpu.get_exec_calls_count() >= 1262766; // log 4 // exit = self.cpu.get_exec_calls_count() >= 1262766; // log 4
// exit = self.cpu.get_exec_calls_count() >= 1763388; // log 5 // exit = self.cpu.get_exec_calls_count() >= 1763388; // log 5

View File

@ -25,7 +25,6 @@ impl Timer {
} }
pub fn reset(&mut self, bus: &mut Bus) { pub fn reset(&mut self, bus: &mut Bus) {
println!("timer reset");
self.divider = 0; self.divider = 0;
bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, 0); bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, 0);
} }
@ -49,7 +48,6 @@ impl Timer {
if tima == 0 { if tima == 0 {
bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS)); bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS));
bus.set_interrupt_flag(Interrupt::Timer, true); bus.set_interrupt_flag(Interrupt::Timer, true);
println!("Timer interrupt set");
} else { } else {
bus.write(TIMER_COUNTER_ADDRESS, tima); bus.write(TIMER_COUNTER_ADDRESS, tima);
} }