diff --git a/src/bus.rs b/src/bus.rs index b577a94..bd53f41 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -54,14 +54,15 @@ pub const INTERRUPT_FLAG_ADDRESS: u16 = 0xFF0F; pub struct Bus { game_rom: ROM, data: [u8; 0x10000], + pub reset_timer: bool, } impl Bus { pub fn new() -> Self { - let game_rom = match ROM::load_file("ignore/dmg-acid2.gb".to_string()) { + // let game_rom = match ROM::load_file("ignore/dr-mario.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/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/04-op r,imm.gb".to_string()) { // let game_rom = match ROM::load_file("roms/cpu_instrs_individual/05-op rp.gb".to_string()) { @@ -101,6 +102,7 @@ impl Bus { Self { data, game_rom, + reset_timer: false, } } @@ -120,6 +122,10 @@ impl Bus { // print!("{}", data as char); } + if address == 0xFF06 { + println!("Writing {:02X} to modulo", data); + } + if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) { // println!("WRITING TO ROM"); } else if WORK_RAM_1.in_range(address) || WORK_RAM_2.in_range(address) { @@ -132,13 +138,14 @@ impl Bus { self.data[address as usize] = data; 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 { - self.data[address as usize] = 0x00; + println!("bus timer reset"); + self.reset_timer = true; } else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) { self.data[address as usize] = data; self.data[LCD_Y_ADDRESS as usize] = 0x00; } else if address == JOYPAD_ADDRESS { let byte = self.data[JOYPAD_ADDRESS as usize]; - self.data[JOYPAD_ADDRESS as usize] = (data & 0b00110000) | 0b11000000 | (byte & 0b00001111); + self.data[JOYPAD_ADDRESS as usize] = (data & 0b11110000) | (byte & 0b00001111); } else { self.data[address as usize] = data; } diff --git a/src/cpu.rs b/src/cpu.rs index d2c3a23..ad40e5c 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -911,13 +911,16 @@ impl CPU { } pub fn handle_interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) { - bus.set_interrupt_enable(interrupt, false); + println!("Interrupt: {:?}", interrupt); bus.set_interrupt_flag(interrupt, false); - let vector = interrupt.get_vector(); - self.exec(Opcode::CALL(OpcodeParameter::U16(vector)), bus); + self.ime = false; + self.exec(Opcode::CALL(OpcodeParameter::U16(interrupt.get_vector())), bus); } pub fn check_interrupts(&mut self, bus: &mut Bus) -> Option { + /* 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; } @@ -1809,9 +1812,11 @@ impl CPU { self.registers.increment(Register::PC, 2); }, Opcode::NOP => self.registers.increment(Register::PC, 1), - /* Opcode::IllegalInstruction => {panic!("Illegal instruction");}, - _ => {panic!("Illegal instruction");}, */ - _ => self.registers.increment(Register::PC, 1), + Opcode::IllegalInstruction => { + println!("Illegal instruction!"); + self.registers.increment(Register::PC, 1); + }, + _ => unreachable!(), }; } } diff --git a/src/emulator.rs b/src/emulator.rs index f566db1..6e65acd 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -112,6 +112,10 @@ impl Emulator { self.cpu.reset_cycles(); while self.cpu.get_cycles().0 <= cpu_cycles.0 { 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()); } diff --git a/src/joypad.rs b/src/joypad.rs index a733997..c28c5c0 100644 --- a/src/joypad.rs +++ b/src/joypad.rs @@ -73,8 +73,7 @@ impl Joypad { let direction = !get_bit(byte, BitIndex::I4); let action = !get_bit(byte, BitIndex::I5); - let data = 0b11000000 | - (byte & 0b00110000) | + let data = (byte & 0b11110000) | ( (!((direction && self.down) || (action && self.start)) as u8) << 3 ) | ( diff --git a/src/ppu.rs b/src/ppu.rs index 4241e29..c179680 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -54,14 +54,14 @@ pub enum LCDControl { impl LCDControl { fn index(&self) -> BitIndex { match self { - LCDControl::LCDEnable => BitIndex::I7, - LCDControl::WindowTileMapAddress => BitIndex::I6, - LCDControl::WindowEnable => BitIndex::I5, - LCDControl::TileAddressMode => BitIndex::I4, - LCDControl::BackgroundTileMapAddress => BitIndex::I3, - LCDControl::ObjectSize => BitIndex::I2, - LCDControl::ObjectEnable => BitIndex::I1, - LCDControl::BackgroundPriority => BitIndex::I0, + LCDControl::LCDEnable => BitIndex::I7, + LCDControl::WindowTileMapAddress => BitIndex::I6, + LCDControl::WindowEnable => BitIndex::I5, + LCDControl::TileAddressMode => BitIndex::I4, + LCDControl::BackgroundTileMapAddress => BitIndex::I3, + LCDControl::ObjectSize => BitIndex::I2, + LCDControl::ObjectEnable => BitIndex::I1, + LCDControl::BackgroundPriority => BitIndex::I0, } } @@ -174,7 +174,6 @@ impl PPU { fn check_lyc(bus: &mut Bus) { let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS); if PPU::get_lcd_status(bus, LCDStatus::LYCInterrupt) && lyc_compare { - println!("lyc"); PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare); PPU::request_interrupt(bus, Interrupt::LCDSTAT); } @@ -334,24 +333,22 @@ impl PPU { } fn get_palette(index: u8, palette_byte: u8) -> u8 { - let index = index & 0b11; match index { 0b00 => palette_byte & 0b11, 0b01 => (palette_byte >> 2) & 0b11, 0b10 => (palette_byte >> 4) & 0b11, 0b11 => (palette_byte >> 6) & 0b11, - _ => 0b00, + _ => unreachable!(), } } fn get_pixel(two_bit_pixel: u8) -> Pixel { - let two_bit_pixel = two_bit_pixel & 0b11; match two_bit_pixel { 0b00 => Pixel::White, 0b01 => Pixel::Light, 0b10 => Pixel::Dark, 0b11 => Pixel::Black, - _ => Pixel::White, + _ => unreachable!(), } } diff --git a/src/timer.rs b/src/timer.rs index 7ca3ed5..bdfdcdf 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -11,23 +11,23 @@ pub const TIMER_MODULO_ADDRESS: u16 = 0xFF06; pub const TIMER_CONTROL_ADDRESS: u16 = 0xFF07; pub struct Timer { - cycles: Cycles, + divider: u16, + prev_result: bool, } impl Timer { pub fn new() -> Self { Self { - cycles: Cycles(0), + divider: 0, + prev_result: false, } } - fn increment_cycles(&mut self, cycles: Cycles) { - self.cycles.0 += cycles.0; - } - - fn reset_cycles(&mut self) { - self.cycles.0 = 0; + pub fn reset(&mut self, bus: &mut Bus) { + println!("timer reset"); + self.divider = 0; + bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, 0); } pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles) { @@ -39,38 +39,37 @@ impl Timer { } fn cycle(&mut self, bus: &mut Bus) { - let div = bus.read(TIMER_DIVIDER_REGISTER_ADDRESS); - bus.write(TIMER_DIVIDER_REGISTER_ADDRESS, div.wrapping_add(1)); + self.divider = self.divider.wrapping_add(1); + bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, self.divider.to_be_bytes()[0]); - if Timer::is_timer_enabled(bus) { - let tima = bus.read(TIMER_COUNTER_ADDRESS); - let tima_rate = Timer::get_tima_rate(bus); - if self.cycles.0 >= tima_rate { - if tima.checked_add(1) == None { - bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS)); - bus.set_interrupt_flag(Interrupt::Timer, true); - } else { - bus.write(TIMER_COUNTER_ADDRESS, tima.wrapping_add(1)); - } - self.reset_cycles(); + let result = Timer::is_timer_enabled(bus) && self.get_tima_rate(bus); + + if self.prev_result && !result { + let tima = bus.read(TIMER_COUNTER_ADDRESS).wrapping_add(1); + if tima == 0 { + bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS)); + bus.set_interrupt_flag(Interrupt::Timer, true); + println!("Timer interrupt set"); + } else { + bus.write(TIMER_COUNTER_ADDRESS, tima); } } - self.increment_cycles(Cycles(1)); + self.prev_result = result; } fn is_timer_enabled(bus: &Bus) -> bool { get_bit(bus.read(TIMER_CONTROL_ADDRESS), BitIndex::I2) } - fn get_tima_rate(bus: &Bus) -> usize { + fn get_tima_rate(&self, bus: &Bus) -> bool { let clock_select = bus.read(TIMER_CONTROL_ADDRESS) & 0b0000_0011; match clock_select { - 0b00 => 16, - 0b01 => 64, - 0b10 => 256, - 0b11 => 1024, - _ => 1, + 0b00 => ((self.divider >> 9) & 1) == 1, + 0b01 => ((self.divider >> 3) & 1) == 1, + 0b10 => ((self.divider >> 5) & 1) == 1, + 0b11 => ((self.divider >> 7) & 1) == 1, + _ => unreachable!(), } } }