From 2367e891a4c87e5707d0f69b85160189211e8898 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Thu, 19 Jan 2017 22:34:15 +0100 Subject: [PATCH] As good as working --- src/cpu.rs | 172 +++++++++++++++++++++++++++++--------------- src/interconnect.rs | 2 +- src/sound/mod.rs | 126 +++++++++++++++++++++++--------- src/sound/square.rs | 41 +++++++++++ src/timer.rs | 39 ++++++---- 5 files changed, 272 insertions(+), 108 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 8ff25e1..1a16af1 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -37,8 +37,25 @@ pub struct CPU { halted: bool, } -fn to_u16(bytes: Box<[u8]>) -> u16 { - (bytes[1] as u16) << 8 | (bytes[0] as u16) +fn to_u16(args: Args) -> u16 { + match args { + Args::Double(a, b) => (a as u16) | ((b as u16) << 8), + _ => panic!("to_u16 only works with Args::Double") + } +} + +enum Args { + Single(u8), + Double(u8, u8), +} + +impl Args { + fn single_val(&self) -> u8 { + match self { + &Args::Single(x) => x, + _ => panic!("single_val only works with Args::Single"), + } + } } impl CPU { @@ -61,13 +78,22 @@ impl CPU { } #[inline] - fn load_args(&mut self, num_args: u8) -> Box<[u8]> { - let mut args = Vec::new(); - for i in 0..num_args { - args.push(self.read_byte(self.ip + i as u16)); + fn load_args(&mut self, num_args: u8) -> Args { + match num_args { + 1 => { + let val = self.read_byte(self.ip); + self.ip += 1; + Args::Single(val) + } + 2 => { + let b1 = self.read_byte(self.ip); + self.ip += 1; + let b2 = self.read_byte(self.ip); + self.ip += 1; + Args::Double(b1, b2) + } + _ => panic!("load_args only supports two bytes") } - self.ip += num_args as u16; - args.into_boxed_slice() } #[inline] @@ -572,7 +598,7 @@ impl CPU { } #[inline] - fn call_condition(&mut self, cond_str: String, cond: bool) -> u8 { + fn call_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { let dst = to_u16(self.load_args(2)); if self.debug { println!("CALL {} {:04X}", cond_str, dst); @@ -586,7 +612,7 @@ impl CPU { } #[inline] - fn ret_condition(&mut self, cond_str: String, cond: bool) -> u8 { + fn ret_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { if self.debug { println!("RET {}", cond_str); } @@ -609,8 +635,8 @@ impl CPU { } #[inline] - fn jmp_r_condition(&mut self, cond_str: String, cond: bool) -> u8 { - let t = self.load_args(1)[0]; + fn jmp_r_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { + let t = self.load_args(1).single_val(); if self.debug { println!("JR {} {:02X}", cond_str, t); } @@ -628,7 +654,7 @@ impl CPU { } #[inline] - fn jmp_p_condition(&mut self, cond_str: String, cond: bool) -> u8 { + fn jmp_p_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { let t = to_u16(self.load_args(2)); if self.debug { println!("JP {} {:04X}", cond_str, t); @@ -722,7 +748,7 @@ impl CPU { #[inline] fn ld_r_v(&mut self, r: usize) -> u8 { - let val: u8 = self.load_args(1)[0]; + let val: u8 = self.load_args(1).single_val(); if self.debug { println!("LD {}, {:02X}", REG_NAMES[r], val); } @@ -859,20 +885,35 @@ impl CPU { self.halted = false; } + #[allow(unused_variables)] pub fn run(&mut self) { + let mut running_sum: i32 = 0; + const INSTRUCTIONS_PER_ROUND: usize = 500; + loop { - // Some attempt at limiting our speed - let mut cycles: i32 = 0; let start = Instant::now(); - for _ in 0 .. 1000 { - cycles += self.run_instruction() as i32; + let mut cycles_executed: usize = 0; + for _ in 0..INSTRUCTIONS_PER_ROUND { + cycles_executed += self.run_instruction() as usize; } - let gb_dur = cycles * 238; + // Time that the gameboy would have required to execute the + // instructions above. + // + // The gameboy has a freq of 4.194304MHz + // This means it takes it 238.418569ns to execute a single + // cycle. + let gb_dur = cycles_executed as i32 * 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. - sleep(Duration::new(0, delta as u32)); + + let full_cycles: i32 = delta / 238; + running_sum += full_cycles; + if full_cycles > 0 { + // println!("[+] [{}] {} cycles, gb: {}, we: {}", running_sum, cycles_executed, gb_dur, our_dur); + sleep(Duration::new(0, (full_cycles - 10) as u32 * 238 as u32)); + } else { + println!("[-] [{}] {} cycles, gb: {}, we: {}", running_sum, cycles_executed, gb_dur, our_dur); } } } @@ -918,6 +959,16 @@ impl CPU { pub fn run_instruction(&mut self) -> u8 { // self.debug = !self.interconnect.is_boot_rom(); + + /* + if self.ip >= 100 && self.ip < 120 { + self.debug = true; + } else { + self.debug = false; + } + */ + + // self.debug = true; // Check for interrupts. if self.ime { self.check_interrupts(true); @@ -927,7 +978,7 @@ impl CPU { } } - let mut cycles: u8 = 1; + let mut cycles: u8 = 255; let instruction: u8; if !self.halted { // We need to double-check the flags @@ -1017,7 +1068,7 @@ impl CPU { } 0x10 => { - println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]); + println!("STOP 0 {:02X} not implemented.", self.load_args(1).single_val()); 4 }, 0x11 => self.ld_rr_vv(REG_N_D, REG_N_E), @@ -1044,8 +1095,11 @@ impl CPU { 4 }, 0x18 => { - let dst = self.load_args(1)[0]; + let dst = self.load_args(1).single_val(); self.jmp_r(dst); + if self.debug { + println!("JMPR {:02X}", dst); + } 12 }, 0x19 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_D, REG_N_E), @@ -1081,7 +1135,7 @@ impl CPU { 0x20 => { let c = self.flags & FLAG_Z == 0; - self.jmp_r_condition("NZ".to_owned(), c) + self.jmp_r_condition("NZ", c) } 0x21 => self.ld_rr_vv(REG_N_H, REG_N_L), 0x22 => { @@ -1137,7 +1191,7 @@ impl CPU { }, 0x28 => { let c = self.flags & FLAG_Z == FLAG_Z; - self.jmp_r_condition("Z".to_owned(), c) + self.jmp_r_condition("Z", c) }, 0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L), 0x2A => { @@ -1166,7 +1220,7 @@ impl CPU { 0x30 => { let c = self.flags & FLAG_C == 0; - self.jmp_r_condition("NC".to_owned(), c) + self.jmp_r_condition("NC", c) }, 0x31 => { let args = self.load_args(2); @@ -1207,7 +1261,7 @@ impl CPU { }, 0x38 => { let c = self.flags & FLAG_C == FLAG_C; - self.jmp_r_condition("C".to_owned(), c) + self.jmp_r_condition("C", c) }, 0x39 => { if self.debug { @@ -1379,12 +1433,12 @@ impl CPU { 0xC0 => { let c = self.flags & FLAG_Z == 0; - self.ret_condition("NZ".to_owned(), c) + self.ret_condition("NZ", 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) + self.jmp_p_condition("NZ", c) }, 0xC3 => { let dst = to_u16(self.load_args(2)); @@ -1396,11 +1450,11 @@ impl CPU { }, 0xC4 => { let c = self.flags & FLAG_Z == 0; - self.call_condition("NZ".to_owned(), c) + self.call_condition("NZ", c) } 0xC5 => self.push_rr(REG_N_B, REG_N_C), 0xC6 => { - let val = self.load_args(1)[0]; + let val = self.load_args(1).single_val(); if self.debug { println!("ADD A, {:02X}", val); } @@ -1412,7 +1466,7 @@ impl CPU { 0xC7 => self.rst(0x00), 0xC8 => { let c = self.flags & FLAG_Z == FLAG_Z; - self.ret_condition("Z".to_owned(), c) + self.ret_condition("Z", c) }, 0xC9 => { if self.debug { @@ -1423,7 +1477,7 @@ impl CPU { }, 0xCA => { let c = self.flags & FLAG_Z == FLAG_Z; - self.jmp_p_condition("Z".to_owned(), c) + self.jmp_p_condition("Z", c) } 0xCB => { self.run_prefix_instruction(); @@ -1431,11 +1485,11 @@ impl CPU { }, 0xCC => { let c = self.flags & FLAG_Z == FLAG_Z; - self.call_condition("Z".to_owned(), c) + self.call_condition("Z", c) }, - 0xCD => self.call_condition("".to_owned(), true), + 0xCD => self.call_condition("", true), 0xCE => { - let arg = self.load_args(1)[0]; + let arg = self.load_args(1).single_val(); if self.debug { println!("ADC A, {:02X}", arg); } @@ -1447,21 +1501,21 @@ impl CPU { 0xD0 => { let c = self.flags & FLAG_C == 0; - self.ret_condition("NC".to_owned(), c) + self.ret_condition("NC", c) }, 0xD1 => self.pop_rr(REG_N_D, REG_N_E), 0xD2 => { let c = self.flags & FLAG_C == 0; - self.jmp_p_condition("NC".to_owned(), c) + self.jmp_p_condition("NC", c) } 0xD3 => panic!("NON-EXISTING OPCODE"), 0xD4 => { let c = self.flags & FLAG_C == 0; - self.call_condition("NC".to_owned(), c) + self.call_condition("NC", c) } 0xD5 => self.push_rr(REG_N_D, REG_N_E), 0xD6 => { - let val = self.load_args(1)[0]; + let val = self.load_args(1).single_val(); if self.debug { println!("SUB {:02X}", val); } @@ -1472,7 +1526,7 @@ impl CPU { 0xD7 => self.rst(0x10), 0xD8 => { let c = self.flags & FLAG_C == FLAG_C; - self.ret_condition("C".to_owned(), c) + self.ret_condition("C", c) }, 0xD9 => { if self.debug { @@ -1482,16 +1536,16 @@ impl CPU { } 0xDA => { let c = self.flags & FLAG_C == FLAG_C; - self.jmp_p_condition("C".to_owned(), c) + self.jmp_p_condition("C", c) }, 0xDB => panic!("NON-EXISTING OPCODE"), 0xDC => { let c = self.flags & FLAG_C == FLAG_C; - self.call_condition("C".to_owned(), c) + self.call_condition("C", c) } 0xDD => panic!("NON-EXISTING OPCODE"), 0xDE => { - let arg = self.load_args(1)[0]; + let arg = self.load_args(1).single_val(); if self.debug { println!("SBC {:02X}", arg); } @@ -1501,11 +1555,11 @@ impl CPU { 0xDF => self.rst(0x18), 0xE0 => { - let args = self.load_args(1); + let arg = self.load_args(1).single_val(); if self.debug { - println!("LDH {:02X}, A", args[0]); + println!("LDH {:02X}, A", arg); } - self.interconnect.write_byte(0xFF00 + args[0] as u16, self.regs[REG_A]); + self.interconnect.write_byte(0xFF00 + arg as u16, self.regs[REG_A]); 12 }, 0xE1 => self.pop_rr(REG_N_H, REG_N_L), @@ -1520,7 +1574,7 @@ impl CPU { 0xE3 | 0xE4 => panic!("NON-EXISTING OPCODE"), 0xE5 => self.push_rr(REG_N_H, REG_N_L), 0xE6 => { - let val = self.load_args(1)[0]; + let val = self.load_args(1).single_val(); if self.debug { println!("AND {:02X}", val); } @@ -1535,7 +1589,7 @@ impl CPU { }, 0xE7 => self.rst(0x20), 0xE8 => { - let arg = self.load_args(1)[0] as i8; + let arg = self.load_args(1).single_val() as i8; if self.debug { println!("ADD SP, {:02X}", arg); } @@ -1570,7 +1624,7 @@ impl CPU { }, 0xEB ... 0xED => panic!("NON-EXISTING OPCODE"), 0xEE => { - let arg = self.load_args(1)[0]; + let arg = self.load_args(1).single_val(); if self.debug { println!("XOR {:02X}", arg); } @@ -1585,11 +1639,11 @@ impl CPU { 0xEF => self.rst(0x28), 0xF0 => { - let args = self.load_args(1); + let arg = self.load_args(1).single_val(); if self.debug { - println!("LDH A, {:02X}", args[0]); + println!("LDH A, {:02X}", arg); } - self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + args[0] as u16); + self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + arg as u16); 12 }, 0xF1 => self.pop_rr(REG_N_A, REG_N_F), @@ -1611,7 +1665,7 @@ impl CPU { 0xF4 => panic!("NON-EXISTING OPCODE"), 0xF5 => self.push_rr(REG_N_A, REG_N_F), 0xF6 => { - let val = self.load_args(1)[0]; + let val = self.load_args(1).single_val(); if self.debug { println!("OR {:02X}", val); } @@ -1625,7 +1679,7 @@ impl CPU { }, 0xF7 => self.rst(0x30), 0xF8 => { - let arg = self.load_args(1)[0] as i8; + let arg = self.load_args(1).single_val() as i8; if self.debug { println!("LD HL, SP+{:02X}", arg); } @@ -1672,12 +1726,12 @@ impl CPU { 0xFC | 0xFD => panic!("NON-EXISTING OPCODE"), 0xFE => { - let args = self.load_args(1); + let arg = self.load_args(1).single_val(); if self.debug { - println!("CP {:02X}", args[0]); + println!("CP {:02X}", arg); } - self.cp_r(args[0]); + self.cp_r(arg); 8 }, 0xFF => self.rst(0x38), diff --git a/src/interconnect.rs b/src/interconnect.rs index 5839190..5480ca1 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -199,7 +199,7 @@ impl Interconnect { // TODO: if some flag set, use bios, otherwise only use rom // For now, just use bios match addr { - 0x0000 ... 0x100 => { + 0x0000 ... 0xFF => { if self.disable_bootrom == 0 { self.bios[addr as usize] } else { diff --git a/src/sound/mod.rs b/src/sound/mod.rs index 7ffdaa9..e047cef 100644 --- a/src/sound/mod.rs +++ b/src/sound/mod.rs @@ -8,17 +8,15 @@ use self::pulse_simple::Playback; use std::sync::{Arc, Mutex}; use std::thread; -//use std::f64::consts::PI; - -//const TICK_RATE: usize = 4194304; -const OUTPUT_SAMPLE_RATE: usize = 32768; -//const OUTPUT_SAMPLE_RATE: usize = 1024; -//const TICKS_PER_SAMPLE: usize = TICK_RATE / OUTPUT_SAMPLE_RATE; +const OUTPUT_SAMPLE_RATE: usize = 48100; +//const OUTPUT_SAMPLE_RATE: usize = 32768; +/// Represents an 'audio module', transforming an input sample to an output sample trait AudioModule { fn transform(&self, sample: T) -> T; } +/// Clockable audio components trait AudioComponent { fn clock(&mut self); } @@ -31,26 +29,33 @@ struct Channel1 { envelope: envelope::VolumeEnvelope, tick_state: u8, + + stored_regs: [u8; 5] } impl Channel1 { pub fn write_byte(&mut self, addr: u16, val: u8) { match addr { 0xFF10 => { - println!("Channel1: Sweep not implemented yet :<"); + self.wave_gen.set_sweep_reg(val); + self.stored_regs[0] = val; } 0xFF11 => { self.length_counter.set_length(val & 0x3F); self.wave_gen.set_duty_cycle(val >> 6); + self.stored_regs[1] = val; } 0xFF12 => { self.envelope.set_register(val); + self.stored_regs[2] = val; } 0xFF13 => { // Set lower frequency self.wave_gen.set_lower_freq(val); + self.stored_regs[3] = val; } 0xFF14 => { + self.stored_regs[4] = val; // Set higher self.wave_gen.set_higher_freq(val); @@ -67,7 +72,8 @@ impl Channel1 { pub fn read_byte(&self, addr: u16) -> u8 { match addr { - _ => panic!("Channel1 does not support reading ({:04X}", addr), + 0xFF10...0xFF14 => self.stored_regs[(addr - 0xFF10) as usize], + _ => {println!("Channel1 does not support reading ({:04X})", addr); 0}, } } @@ -88,7 +94,7 @@ impl Channel1 { } if self.tick_state == 2 || self.tick_state == 6 { - // TODO: Sweep + self.wave_gen.sweep_clock(); } if self.tick_state == 7 { @@ -144,7 +150,7 @@ impl Channel2 { pub fn read_byte(&self, addr: u16) -> u8 { match addr { - _ => panic!("Channel2 does not support reading ({:04X}", addr), + _ => {println!("Channel2 does not support reading ({:04X})", addr); 0}, } } @@ -192,7 +198,7 @@ struct Channel3 { impl Channel3 { pub fn write_byte(&mut self, addr: u16, val: u8) { - println!("C3 WB: {:04X} = {:02X} ({:08b})", addr, val, val); + // println!("C3 WB: {:04X} = {:02X} ({:08b})", addr, val, val); match addr { 0xFF1A => { self.wave_gen.enabled = (val & (1 << 7)) > 0; @@ -226,7 +232,7 @@ impl Channel3 { pub fn read_byte(&self, addr: u16) -> u8 { match addr { - _ => panic!("Channel3 does not support reading ({:04X}", addr), + _ => panic!("Channel3 does not support reading ({:04X})", addr), } } @@ -237,8 +243,7 @@ impl Channel3 { pub fn sample(&self) -> u8 { let input = self.wave_gen.sample(); // Follow the chain - let input = self.length_counter.transform(input); - // self.envelope.transform(input) + // let input = self.length_counter.transform(input); input } @@ -291,7 +296,10 @@ impl SoundManager { pub fn launch_thread(&self) { let obj = self.sound_object.clone(); - thread::spawn(move || { + if false { + return; + } + thread::Builder::new().name("Audio".into()).spawn(move || { // PulseAudio playback object let playback = Playback::new("GBC", "Output", None, (OUTPUT_SAMPLE_RATE) as _ ); @@ -299,20 +307,9 @@ impl SoundManager { let mut counter = 0; loop { - { + let (s1, s2) = { let mut c_obj = obj.lock().unwrap(); - c_obj.channel1.sample_clock(); - c_obj.channel2.sample_clock(); - c_obj.channel3.sample_clock(); - - // let s = c_obj.sample(); - let s1 = c_obj.channel1.sample(); - let s2 = c_obj.channel2.sample(); - let s3 = c_obj.channel3.sample(); - let samps = [[s3 as u8, s3 as u8]]; - playback.write(&samps[..]); - // Check for 512 Hz timer if counter >= (OUTPUT_SAMPLE_RATE / 512) { c_obj.clock(); @@ -320,11 +317,18 @@ impl SoundManager { } else { counter += 1; } - } + + // Sample clock + c_obj.sample_clock(); + + // Get sample + c_obj.sample() + }; + let samps = [[s1, s2]]; // No sleep needed, it seems like the playback.write is blocking - // thread::sleep(time::Duration::new(0, sleep_duration)); + playback.write(&samps[..]); } - }); + }).unwrap(); } } @@ -339,9 +343,65 @@ impl Sound { self.channel3.clock(); } - pub fn sample(&self) -> u8 { - // TODO: Mixing - (self.channel1.sample() >> 1) + (self.channel2.sample() >> 1) + (self.channel3.sample() >> 1) + pub fn sample_clock(&mut self) { + self.channel1.sample_clock(); + self.channel2.sample_clock(); + self.channel3.sample_clock(); + } + + pub fn sample(&self) -> (u8, u8) { + // Some basic mixing + // Output value + let mut s = [0u16; 2]; + let s01_volume = self.sound_channel_volume_control & 7; + let s02_volume = (self.sound_channel_volume_control >> 4) & 7; + + let c1_sample = self.channel1.sample(); + let c2_sample = self.channel2.sample(); + let c3_sample = self.channel3.sample(); + let c4_sample = 0; + + if self.enabled != 0 { + if s01_volume > 0 { + if self.sound_output_terminal_selector & 1 > 0 { + // Output Channel1 + s[0] += c1_sample as _; + } + if self.sound_output_terminal_selector & 2 > 0 && false { + // Output Channel2 + s[0] += c2_sample as _; + } + if self.sound_output_terminal_selector & 4 > 0 { + // Output Channel3 + s[0] += c3_sample as _; + } + if self.sound_output_terminal_selector & 8 > 0 { + // Output Channel4 + s[0] += c4_sample as _; + } + } + + if s02_volume > 0 { + if self.sound_output_terminal_selector & 0x10 > 0 && false { + // Output Channel1 + s[1] += c1_sample as _; + } + if self.sound_output_terminal_selector & 0x20 > 0 { + // Output Channel2 + s[1] += c2_sample as _; + } + if self.sound_output_terminal_selector & 0x40 > 0 { + // Output Channel3 + s[1] += c3_sample as _; + } + if self.sound_output_terminal_selector & 0x80 > 0 { + // Output Channel4 + s[1] += c4_sample as _; + } + } + } + // (self.channel1.sample() >> 1) + (self.channel2.sample() >> 1) + (self.channel3.sample() >> 1) + ((s[0] >> 2) as _, (s[1] >> 2) as _) } pub fn write_byte(&mut self, addr: u16, val: u8) { diff --git a/src/sound/square.rs b/src/sound/square.rs index 51a7949..b514c0a 100644 --- a/src/sound/square.rs +++ b/src/sound/square.rs @@ -23,6 +23,18 @@ pub struct SquareWaveGenerator { duty_cycle: DutyCycle, gb_reg_freq: u16, + + // Sweep settings (if existing) + sweep_change_period: u8, + // selects the inc/dec mode of the sweep. Dec if set + sweep_dec: bool, + // Sweep speed (n/128th) + sweep_change: u8, + + // Current sweep clock cycle + sweep_clock: u8, + + // sweep_freq_shadow: f32, } impl SquareWaveGenerator { @@ -42,6 +54,35 @@ impl SquareWaveGenerator { self.update_frequency(); } + pub fn set_sweep_reg(&mut self, reg: u8) { + //Bit 6-4 - Sweep Time + //Bit 3 - Sweep Increase/Decrease + // 0: Addition (frequency increases) + // 1: Subtraction (frequency decreases) + //Bit 2-0 - Number of sweep shift (n: 0-7) + self.sweep_change_period = (reg >> 4) & 7; + self.sweep_dec = reg & (1 << 3) > 0; + self.sweep_change = reg & 7; + self.sweep_clock = 0; + } + + pub fn sweep_clock(&mut self) { + // self.sweep_freq_shadow = self.frequency; + if self.sweep_change_period > 0 { + if self.sweep_change > 0 { + if self.sweep_clock >= self.sweep_change_period { + self.sweep_clock = 0; + let change = self.frequency / (2f32.powi(self.sweep_change as _)); + self.frequency += if self.sweep_dec { + change + } else { + -change + }; + } + } + } + } + pub fn reset(&mut self) { self.time = 0f32; } diff --git a/src/timer.rs b/src/timer.rs index 105d54d..b9571ec 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -11,6 +11,11 @@ pub struct Timer { gb_ticks: u16, } +// Timer speed contains 4 different scales: +// [0] = 64 = 4096 Hz +// [1] = 1 = 262144 Hz +// [2] = 4 = 65536 Hz +// [3] = 16 = 16384 Hz const TIMER_SPEED: [u16; 4] = [64, 1, 4, 16]; const TIMER_ENABLE: u8 = (1 << 2); @@ -19,34 +24,38 @@ impl Timer { Timer::default() } + /// This clock is ticking at 262.144 Hz fn timer_clock_tick(&mut self) { // The div reg will always tick self.div_tick_counter += 1; - if self.div_tick_counter >= TIMER_SPEED[3] { + + // 262144 Hz / 16 = 16384 Hz + if self.div_tick_counter >= 16 { self.div = self.div.wrapping_add(1); - self.div_tick_counter -= TIMER_SPEED[3]; + self.div_tick_counter -= 16; } - if (self.tac & TIMER_ENABLE) == TIMER_ENABLE { // Is timer enabled? + // Check if the timer is enabled + if (self.tac & TIMER_ENABLE) != 0 { self.tick_counter += 1; let req_ticks = TIMER_SPEED[(self.tac & 3) as usize]; - if self.tick_counter >= req_ticks { + if self.tick_counter == req_ticks { if self.tima == 0xFF { self.timer_interrupt = true; - self.tima = 0; + self.tima = self.tma; } else { self.tima += 1; } - self.tick_counter -= req_ticks; + self.tick_counter = 0; } } } pub fn tick(&mut self, ticks: u16) { - // One tick 1/4.194304MHz on regular speed => 16 gb ticks + // One tick 1/4.194304MHz on regular speed => 16 gb ticks = prescaler self.gb_ticks += ticks; - // If we're in GBC fast mode, we'd require 32 ticks instead of 16 + while self.gb_ticks >= 16 { self.timer_clock_tick(); self.gb_ticks -= 16; @@ -54,26 +63,26 @@ impl Timer { } pub fn write_byte(&mut self, addr: u16, val: u8) { + // println!("Timer WR: {:04X} = {:02X}", addr, val); match addr { 0xFF04 => self.div = 0, 0xFF05 => self.tima = val, 0xFF06 => self.tma = val, 0xFF07 => self.tac = val, - _ => println!("Timer: Write {:02X} to {:04X} unsupported", val, addr), + _ => unreachable!(), } } pub fn read_byte(&self, addr: u16) -> u8 { - match addr { + let r = match addr { 0xFF04 => self.div, 0xFF05 => self.tima, 0xFF06 => self.tma, 0xFF07 => self.tac, - _ => { - println!("Timer: Read from {:04X} unsupported", addr); - 0 - }, - } + _ => unreachable!(), + }; + // println!("Timer RD: {:04X} = {:02X}", addr, r); + r } pub fn timer_interrupt(&mut self) -> bool {