mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-23 10:12:11 +00:00
Refactor timer
This commit is contained in:
parent
98be8f29dd
commit
806a4bf211
15
src/bus.rs
15
src/bus.rs
@ -54,14 +54,15 @@ pub const INTERRUPT_FLAG_ADDRESS: u16 = 0xFF0F;
|
|||||||
pub struct Bus {
|
pub struct Bus {
|
||||||
game_rom: ROM,
|
game_rom: ROM,
|
||||||
data: [u8; 0x10000],
|
data: [u8; 0x10000],
|
||||||
|
pub reset_timer: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bus {
|
impl Bus {
|
||||||
pub fn new() -> Self {
|
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.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()) {
|
||||||
@ -101,6 +102,7 @@ impl Bus {
|
|||||||
Self {
|
Self {
|
||||||
data,
|
data,
|
||||||
game_rom,
|
game_rom,
|
||||||
|
reset_timer: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +122,10 @@ 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) {
|
||||||
@ -132,13 +138,14 @@ 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 {
|
||||||
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) {
|
} else if address == LCD_CONTROL_ADDRESS && get_bit(data, BitIndex::I7) {
|
||||||
self.data[address as usize] = data;
|
self.data[address as usize] = data;
|
||||||
self.data[LCD_Y_ADDRESS as usize] = 0x00;
|
self.data[LCD_Y_ADDRESS as usize] = 0x00;
|
||||||
} else if address == JOYPAD_ADDRESS {
|
} else if address == JOYPAD_ADDRESS {
|
||||||
let byte = self.data[JOYPAD_ADDRESS as usize];
|
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 {
|
} else {
|
||||||
self.data[address as usize] = data;
|
self.data[address as usize] = data;
|
||||||
}
|
}
|
||||||
|
17
src/cpu.rs
17
src/cpu.rs
@ -911,13 +911,16 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_interrupt(&mut self, bus: &mut Bus, interrupt: Interrupt) {
|
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);
|
bus.set_interrupt_flag(interrupt, false);
|
||||||
let vector = interrupt.get_vector();
|
self.ime = false;
|
||||||
self.exec(Opcode::CALL(OpcodeParameter::U16(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 {
|
if !self.ime && !self.is_halted {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -1809,9 +1812,11 @@ impl CPU {
|
|||||||
self.registers.increment(Register::PC, 2);
|
self.registers.increment(Register::PC, 2);
|
||||||
},
|
},
|
||||||
Opcode::NOP => self.registers.increment(Register::PC, 1),
|
Opcode::NOP => self.registers.increment(Register::PC, 1),
|
||||||
/* Opcode::IllegalInstruction => {panic!("Illegal instruction");},
|
Opcode::IllegalInstruction => {
|
||||||
_ => {panic!("Illegal instruction");}, */
|
println!("Illegal instruction!");
|
||||||
_ => self.registers.increment(Register::PC, 1),
|
self.registers.increment(Register::PC, 1);
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,10 @@ impl Emulator {
|
|||||||
self.cpu.reset_cycles();
|
self.cpu.reset_cycles();
|
||||||
while self.cpu.get_cycles().0 <= cpu_cycles.0 {
|
while self.cpu.get_cycles().0 <= cpu_cycles.0 {
|
||||||
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.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());
|
||||||
}
|
}
|
||||||
|
@ -73,8 +73,7 @@ impl Joypad {
|
|||||||
let direction = !get_bit(byte, BitIndex::I4);
|
let direction = !get_bit(byte, BitIndex::I4);
|
||||||
let action = !get_bit(byte, BitIndex::I5);
|
let action = !get_bit(byte, BitIndex::I5);
|
||||||
|
|
||||||
let data = 0b11000000 |
|
let data = (byte & 0b11110000) |
|
||||||
(byte & 0b00110000) |
|
|
||||||
(
|
(
|
||||||
(!((direction && self.down) || (action && self.start)) as u8) << 3
|
(!((direction && self.down) || (action && self.start)) as u8) << 3
|
||||||
) | (
|
) | (
|
||||||
|
@ -174,7 +174,6 @@ impl PPU {
|
|||||||
fn check_lyc(bus: &mut Bus) {
|
fn check_lyc(bus: &mut Bus) {
|
||||||
let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
|
let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
|
||||||
if PPU::get_lcd_status(bus, LCDStatus::LYCInterrupt) && lyc_compare {
|
if PPU::get_lcd_status(bus, LCDStatus::LYCInterrupt) && lyc_compare {
|
||||||
println!("lyc");
|
|
||||||
PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare);
|
PPU::set_lcd_status(bus, LCDStatus::LYCFlag, lyc_compare);
|
||||||
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
PPU::request_interrupt(bus, Interrupt::LCDSTAT);
|
||||||
}
|
}
|
||||||
@ -334,24 +333,22 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_palette(index: u8, palette_byte: u8) -> u8 {
|
fn get_palette(index: u8, palette_byte: u8) -> u8 {
|
||||||
let index = index & 0b11;
|
|
||||||
match index {
|
match index {
|
||||||
0b00 => palette_byte & 0b11,
|
0b00 => palette_byte & 0b11,
|
||||||
0b01 => (palette_byte >> 2) & 0b11,
|
0b01 => (palette_byte >> 2) & 0b11,
|
||||||
0b10 => (palette_byte >> 4) & 0b11,
|
0b10 => (palette_byte >> 4) & 0b11,
|
||||||
0b11 => (palette_byte >> 6) & 0b11,
|
0b11 => (palette_byte >> 6) & 0b11,
|
||||||
_ => 0b00,
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_pixel(two_bit_pixel: u8) -> Pixel {
|
fn get_pixel(two_bit_pixel: u8) -> Pixel {
|
||||||
let two_bit_pixel = two_bit_pixel & 0b11;
|
|
||||||
match two_bit_pixel {
|
match two_bit_pixel {
|
||||||
0b00 => Pixel::White,
|
0b00 => Pixel::White,
|
||||||
0b01 => Pixel::Light,
|
0b01 => Pixel::Light,
|
||||||
0b10 => Pixel::Dark,
|
0b10 => Pixel::Dark,
|
||||||
0b11 => Pixel::Black,
|
0b11 => Pixel::Black,
|
||||||
_ => Pixel::White,
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
49
src/timer.rs
49
src/timer.rs
@ -11,23 +11,23 @@ pub const TIMER_MODULO_ADDRESS: u16 = 0xFF06;
|
|||||||
pub const TIMER_CONTROL_ADDRESS: u16 = 0xFF07;
|
pub const TIMER_CONTROL_ADDRESS: u16 = 0xFF07;
|
||||||
|
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
cycles: Cycles,
|
divider: u16,
|
||||||
|
prev_result: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
cycles: Cycles(0),
|
divider: 0,
|
||||||
|
prev_result: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment_cycles(&mut self, cycles: Cycles) {
|
pub fn reset(&mut self, bus: &mut Bus) {
|
||||||
self.cycles.0 += cycles.0;
|
println!("timer reset");
|
||||||
}
|
self.divider = 0;
|
||||||
|
bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, 0);
|
||||||
fn reset_cycles(&mut self) {
|
|
||||||
self.cycles.0 = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles) {
|
pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles) {
|
||||||
@ -39,38 +39,37 @@ impl Timer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cycle(&mut self, bus: &mut Bus) {
|
fn cycle(&mut self, bus: &mut Bus) {
|
||||||
let div = bus.read(TIMER_DIVIDER_REGISTER_ADDRESS);
|
self.divider = self.divider.wrapping_add(1);
|
||||||
bus.write(TIMER_DIVIDER_REGISTER_ADDRESS, div.wrapping_add(1));
|
bus.force_write(TIMER_DIVIDER_REGISTER_ADDRESS, self.divider.to_be_bytes()[0]);
|
||||||
|
|
||||||
if Timer::is_timer_enabled(bus) {
|
let result = Timer::is_timer_enabled(bus) && self.get_tima_rate(bus);
|
||||||
let tima = bus.read(TIMER_COUNTER_ADDRESS);
|
|
||||||
let tima_rate = Timer::get_tima_rate(bus);
|
if self.prev_result && !result {
|
||||||
if self.cycles.0 >= tima_rate {
|
let tima = bus.read(TIMER_COUNTER_ADDRESS).wrapping_add(1);
|
||||||
if tima.checked_add(1) == None {
|
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.wrapping_add(1));
|
bus.write(TIMER_COUNTER_ADDRESS, tima);
|
||||||
}
|
|
||||||
self.reset_cycles();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.increment_cycles(Cycles(1));
|
self.prev_result = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_timer_enabled(bus: &Bus) -> bool {
|
fn is_timer_enabled(bus: &Bus) -> bool {
|
||||||
get_bit(bus.read(TIMER_CONTROL_ADDRESS), BitIndex::I2)
|
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;
|
let clock_select = bus.read(TIMER_CONTROL_ADDRESS) & 0b0000_0011;
|
||||||
match clock_select {
|
match clock_select {
|
||||||
0b00 => 16,
|
0b00 => ((self.divider >> 9) & 1) == 1,
|
||||||
0b01 => 64,
|
0b01 => ((self.divider >> 3) & 1) == 1,
|
||||||
0b10 => 256,
|
0b10 => ((self.divider >> 5) & 1) == 1,
|
||||||
0b11 => 1024,
|
0b11 => ((self.divider >> 7) & 1) == 1,
|
||||||
_ => 1,
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user