use crate::interconnect; use std::convert::TryFrom; use std::thread::sleep; use std::time::{Duration, Instant}; const REG_A: usize = 6; const REG_N_B: usize = 0; const REG_N_C: usize = 1; const REG_N_D: usize = 2; const REG_N_E: usize = 3; const REG_N_H: usize = 4; const REG_N_L: usize = 5; const REG_N_HL: usize = 6; const REG_N_A: usize = 7; const REG_N_F: usize = 8; const REG_NAMES: [&str; 9] = ["B", "C", "D", "E", "H", "L", "(HL)", "A", "F"]; const FLAG_Z: u8 = 1 << 7; const FLAG_N: u8 = 1 << 6; const FLAG_H: u8 = 1 << 5; const FLAG_C: u8 = 1 << 4; use interconnect::TickResult; pub enum CpuTickResult { Continue { cycles_executed: usize }, Shutdown { cycles_executed: usize }, } pub struct CPU { // Registers: B, C, D, E, H, L, A regs: [u8; 7], flags: u8, ip: u16, sp: u16, interconnect: interconnect::Interconnect, ime: bool, debug: bool, halted: bool, trigger_once: bool, } enum Args { Single(u8), Double(u8, u8), } impl TryFrom for u8 { type Error = (); fn try_from(val: Args) -> Result { match val { Args::Single(x) => Ok(x), _ => Err(()), } } } impl TryFrom for u16 { type Error = (); fn try_from(val: Args) -> Result { match val { Args::Double(a, b) => Ok((a as u16) | ((b as u16) << 8)), _ => Err(()), } } } impl CPU { pub fn new(interconnect: interconnect::Interconnect) -> CPU { CPU { flags: 0, regs: [0, 0, 0, 0, 0, 0, 0], ip: 0, sp: 0xFFFE, interconnect, ime: false, debug: false, halted: false, trigger_once: false, } } fn read_byte(&self, addr: u16) -> u8 { self.interconnect.read_byte(addr) } 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"), } } fn set_8bit_reg(&mut self, reg_id: usize, value: u8) { // Make sure that we skip the (HL) part. if reg_id == REG_N_A { self.regs[REG_A] = value; } else if reg_id == REG_N_F { self.flags = value & 0xF0; } else if reg_id == REG_N_HL { let addr: u16 = self.get_pair_value(REG_N_H, REG_N_L); self.interconnect.write_byte(addr, value); } else { self.regs[reg_id] = value; } } fn get_8bit_reg(&self, reg_id: usize) -> u8 { // Make sure that we skip the (HL) part. if reg_id == REG_N_A { self.regs[REG_A] } else if reg_id == REG_N_F { self.flags } else if reg_id == REG_N_HL { let addr: u16 = self.get_pair_value(REG_N_H, REG_N_L); self.interconnect.read_byte(addr) } else { self.regs[reg_id] } } fn adc_r(&mut self, val: u8) { let old: u8 = self.regs[REG_A]; let mut new: u8 = old; let c: u8; if self.flags & FLAG_C == FLAG_C { c = 1; } else { c = 0; } new = new.wrapping_add(val); new = new.wrapping_add(c); self.regs[REG_A] = new; self.clear_flag(FLAG_N); self.set_clear_flag(FLAG_Z, new == 0); self.set_clear_flag(FLAG_C, (new < old) || (c == 1 && new == old)); self.set_clear_flag(FLAG_H, ((old & 0x0F) + (val & 0x0F) + c) > 0x0F); } fn add_r(&mut self, val: u8) { let old: u8 = self.regs[REG_A]; let new: u8 = old.wrapping_add(val); let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16); self.regs[REG_A] = new; self.clear_flag(FLAG_N); self.set_clear_flag(FLAG_Z, new == 0); self.set_clear_flag(FLAG_C, val > 0 && new < old); self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10); } fn sbc_r(&mut self, val: u8) { let old: u8 = self.regs[REG_A]; let mut new: u8 = old as u8; let c: u8; if self.flags & FLAG_C == FLAG_C { c = 1; } else { c = 0; } new = new.wrapping_sub(val); new = new.wrapping_sub(c); self.regs[REG_A] = new; 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, ); } fn sub_r(&mut self, val: u8) { let old: u8 = self.regs[REG_A]; let new: u8 = old.wrapping_sub(val); let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16); self.regs[REG_A] = new; self.set_flag(FLAG_N); self.set_clear_flag(FLAG_Z, new == 0); self.set_clear_flag(FLAG_C, new > old); self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10); } fn cp_r(&mut self, val: u8) { let old: u8 = self.regs[REG_A]; let new: u8 = old.wrapping_sub(val); let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16); self.set_flag(FLAG_N); self.set_clear_flag(FLAG_Z, new == 0); self.set_clear_flag(FLAG_C, new > old); self.set_clear_flag(FLAG_H, carry & 0x10 == 0x10); } fn run_prefix_instruction(&mut self) { let instruction = self.read_byte(self.ip); self.ip += 1; match instruction { 0x00..=0x07 => { let reg_id = (instruction - 0x00) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { println!("RLC {}", REG_NAMES[reg_id]); } let nval: u8; if val & 0x80 == 0x80 { nval = val << 1 | 1; } else { nval = val << 1; } self.set_8bit_reg(reg_id, nval); self.set_clear_flag(FLAG_C, val & 0x80 == 0x80); self.set_clear_flag(FLAG_Z, nval == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); } 0x08..=0x0F => { let reg_id = (instruction - 0x08) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { println!("RRC {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_C, val & 1 == 1); if val & 1 > 0 { self.set_8bit_reg(reg_id, val >> 1 | 0x80); } else { self.set_8bit_reg(reg_id, val >> 1); } self.set_clear_flag(FLAG_Z, val == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); } 0x10..=0x17 => { let reg_id = (instruction - 0x10) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { println!("RL {}", REG_NAMES[reg_id]); } let carry = self.flags & FLAG_C > 0; let nval: u8; if !carry { nval = val << 1; } else { nval = val << 1 | 1; } self.set_8bit_reg(reg_id, nval); self.set_clear_flag(FLAG_C, val & 0x80 == 0x80); self.set_clear_flag(FLAG_Z, nval == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); } 0x18..=0x1F => { // RR let reg_id = (instruction - 0x18) as usize; let val = self.get_8bit_reg(reg_id); if self.debug { println!("RR {}", REG_NAMES[reg_id]); } let carry = self.flags & FLAG_C > 0; let v: u8; if !carry { v = val >> 1; } else { v = (val >> 1) | 0x80; } self.set_8bit_reg(reg_id, v); self.set_clear_flag(FLAG_C, val & 1 == 1); self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); } 0x20..=0x27 => { let reg_id = (instruction - 0x20) as usize; if self.debug { println!("SLA {}", REG_NAMES[reg_id]); } let v: u8 = self.get_8bit_reg(reg_id); self.flags = 0; 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 => { let reg_id = (instruction - 0x28) as usize; if self.debug { println!("SRA {}", REG_NAMES[reg_id]); } let v: u8 = self.get_8bit_reg(reg_id); let nv = (v >> 1) | (v & 0x80); self.set_8bit_reg(reg_id, nv); self.flags = 0; self.set_clear_flag(FLAG_Z, nv == 0); self.set_clear_flag(FLAG_C, v & 1 == 1); } 0x30..=0x37 => { let reg_id = (instruction - 0x30) as usize; if self.debug { println!("SWAP {}", REG_NAMES[reg_id]); } let v: u8 = self.get_8bit_reg(reg_id); self.set_8bit_reg(reg_id, (v << 4) | (v >> 4)); self.flags = 0; self.set_clear_flag(FLAG_Z, v == 0); } 0x38..=0x3F => { let reg_id = (instruction - 0x38) as usize; if self.debug { println!("SRL {}", REG_NAMES[reg_id]); } let v: u8 = self.get_8bit_reg(reg_id); self.set_8bit_reg(reg_id, v >> 1); self.set_clear_flag(FLAG_C, v & 1 == 1); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); self.set_clear_flag(FLAG_Z, (v & 0xFE) == 0); } // Bits 0x40..=0x47 => { // Test 0th bit let reg_id = (instruction - 0x40) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 0, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 0) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } 0x48..=0x4F => { // Test 1th bit let reg_id = (instruction - 0x48) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 1, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 1) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } 0x50..=0x57 => { // Test 2th bit let reg_id = (instruction - 0x50) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 2, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 2) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } 0x58..=0x5F => { // Test 3th bit let reg_id = (instruction - 0x58) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 3, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 3) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } 0x60..=0x67 => { // Test 4th bit let reg_id = (instruction - 0x60) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 4, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 4) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } 0x68..=0x6F => { // Test 5th bit let reg_id = (instruction - 0x68) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 5, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 5) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } 0x70..=0x77 => { // Test 6th bit let reg_id = (instruction - 0x70) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 6, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 6) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } 0x78..=0x7F => { // Test 7th bit let reg_id = (instruction - 0x78) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("BIT 7, {}", REG_NAMES[reg_id]); } self.set_clear_flag(FLAG_Z, reg_content & (1 << 7) == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); } // Reset bits 0x80..=0x87 => { // Reset 0th bit let reg_id = (instruction - 0x80) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 0, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 0)); } 0x88..=0x8F => { // Reset 1th bit let reg_id = (instruction - 0x88) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 1, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 1)); } 0x90..=0x97 => { // Reset 2nd bit let reg_id = (instruction - 0x90) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 2, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 2)); } 0x98..=0x9F => { // Reset 3th bit let reg_id = (instruction - 0x98) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 3, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 3)); } 0xA0..=0xA7 => { // Reset 4th bit let reg_id = (instruction - 0xA0) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 4, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 4)); } 0xA8..=0xAF => { // Reset 5th bit let reg_id = (instruction - 0xA8) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 5, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 5)); } 0xB0..=0xB7 => { // Reset 6th bit let reg_id = (instruction - 0xB0) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 6, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 6)); } 0xB8..=0xBF => { // Reset 7th bit let reg_id = (instruction - 0xB8) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("RES 7, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content & !(1 << 7)); } // Set bits 0xC0..=0xC7 => { // Set 0th bit let reg_id = (instruction - 0xC0) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 0, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 0)); } 0xC8..=0xCF => { // Set 1th bit let reg_id = (instruction - 0xC8) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 1, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 1)); } 0xD0..=0xD7 => { // Set 2nd bit let reg_id = (instruction - 0xD0) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 2, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 2)); } 0xD8..=0xDF => { // Set 3th bit let reg_id = (instruction - 0xD8) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 3, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 3)); } 0xE0..=0xE7 => { // Set 4th bit let reg_id = (instruction - 0xE0) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 4, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 4)); } 0xE8..=0xEF => { // Set 5th bit let reg_id = (instruction - 0xE8) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 5, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 5)); } 0xF0..=0xF7 => { // Set 6th bit let reg_id = (instruction - 0xF0) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 6, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 6)); } 0xF8..=0xFF => { // Set 7th bit let reg_id = (instruction - 0xF8) as usize; let reg_content = self.get_8bit_reg(reg_id); if self.debug { println!("SET 7, {}", REG_NAMES[reg_id]); } self.set_8bit_reg(reg_id, reg_content | (1 << 7)); } } } fn get_pair_value(&self, a: usize, b: usize) -> u16 { (self.get_8bit_reg(a) as u16) << 8 | self.get_8bit_reg(b) as u16 } fn set_pair_value(&mut self, a: usize, b: usize, value: u16) { self.set_8bit_reg(a, (value >> 8) as u8); self.set_8bit_reg(b, value as u8); } fn call(&mut self, dst: u16) { let ip = self.ip; self.push(ip); //self.dump_stack(); self.ip = dst; } fn call_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { let dst = u16::try_from(self.load_args(2)).unwrap(); if self.debug { println!("CALL {} {:04X}", cond_str, dst); } if cond { self.call(dst); 24 } else { 12 } } fn ret_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { if self.debug { println!("RET {}", cond_str); } if cond { self.ret(); 20 } else { 8 } } fn jmp_r(&mut self, addr: u8) { let off: i8 = addr as i8; if off < 0 { self.ip -= (-off) as u16; } else { self.ip += off as u16; } } fn jmp_r_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { let t = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("JR {} {:02X}", cond_str, t); } if cond { self.jmp_r(t); 12 } else { 8 } } fn jmp_p(&mut self, addr: u16) { self.ip = addr; } fn jmp_p_condition(&mut self, cond_str: &'static str, cond: bool) -> u8 { let t = u16::try_from(self.load_args(2)).unwrap(); if self.debug { println!("JP {} {:04X}", cond_str, t); } if cond { self.jmp_p(t); 12 } else { 8 } } fn rst(&mut self, val: u8) -> u8 { // Make sure this is correct. if self.debug { println!("RST {:02X}", val); } self.call(val as u16); 16 } fn pop_rr(&mut self, r1: usize, r2: usize) -> u8 { if self.debug { println!("POP {}{}", REG_NAMES[r1], REG_NAMES[r2]); } let val: u16 = self.pop(); self.set_pair_value(r1, r2, val); 12 } fn push_rr(&mut self, r1: usize, r2: usize) -> u8 { if self.debug { println!("PUSH {}{}", REG_NAMES[r1], REG_NAMES[r2]); } let val: u16 = self.get_pair_value(r1, r2); self.push(val); 16 } fn dec_rr(&mut self, r1: usize, r2: usize) -> u8 { if self.debug { println!("DEC {}{}", REG_NAMES[r1], REG_NAMES[r2]); } let v = self.get_pair_value(r1, r2); let v = v.wrapping_sub(1); self.set_pair_value(r1, r2, v); 8 } fn inc_rr(&mut self, r1: usize, r2: usize) -> u8 { if self.debug { println!("INC {}{}", REG_NAMES[r1], REG_NAMES[r2]); } let v = self.get_pair_value(r1, r2); let v = v.wrapping_add(1); self.set_pair_value(r1, r2, v); 8 } fn push(&mut self, val: u16) { self.interconnect.write_word(self.sp - 2, val); self.sp -= 2; } fn pop(&mut self) -> u16 { let v: u16 = self.interconnect.read_word(self.sp); self.sp += 2; v } fn ld_r_r(&mut self, reg_dst: usize, reg_src: usize) -> u8 { if self.debug { println!("LD {}, {}", REG_NAMES[reg_dst], REG_NAMES[reg_src]) } let sv = self.get_8bit_reg(reg_src); self.set_8bit_reg(reg_dst, sv); if reg_dst == REG_N_HL || reg_src == REG_N_HL { 8 } else { 4 } } fn ld_r_v(&mut self, r: usize) -> u8 { let val = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("LD {}, {:02X}", REG_NAMES[r], val); } self.set_8bit_reg(r, val); if r == REG_N_HL { 12 } else { 8 } } fn ld_rr_vv(&mut self, r1: usize, r2: usize) -> u8 { let val = u16::try_from(self.load_args(2)).unwrap(); if self.debug { println!("LD {}{}, {:04X}", REG_NAMES[r1], REG_NAMES[r2], val); } self.set_pair_value(r1, r2, val); 12 } fn reg_inc(&mut self, reg_id: usize) -> u8 { if self.debug { println!("INC {}", REG_NAMES[reg_id]); } let old = self.get_8bit_reg(reg_id); let val = old.wrapping_add(1); self.set_8bit_reg(reg_id, val); self.set_clear_flag(FLAG_Z, val == 0); self.set_clear_flag(FLAG_H, (old & 0xF) + 1 > 0xF); self.clear_flag(FLAG_N); 4 } 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] ); } let val1 = self.get_pair_value(r1, r2); let val2 = self.get_pair_value(r3, r4); let res = val1.wrapping_add(val2); self.set_pair_value(r1, r2, res); // We need to update the flags self.clear_flag(FLAG_N); // Some magic formula self.set_clear_flag(FLAG_C, val1 as usize + val2 as usize & 0x10000 == 0x10000); self.set_clear_flag(FLAG_H, (val1 ^ val2 ^ res) & 0x1000 == 0x1000); 8 } fn reg_dec(&mut self, reg_id: usize) -> u8 { if self.debug { println!("DEC {}", REG_NAMES[reg_id]); } let old = self.get_8bit_reg(reg_id); let val = old.wrapping_sub(1); self.set_8bit_reg(reg_id, val); self.set_clear_flag(FLAG_Z, val == 0); // self.set_clear_flag(FLAG_C, val == 255); self.set_clear_flag(FLAG_H, old & 0x0F == 0); self.set_flag(FLAG_N); 4 } fn ld_dref_rr_a(&mut self, r1: usize, r2: usize) -> u8 { if self.debug { println!("LD ({}{}), A", REG_NAMES[r1], REG_NAMES[r2]); } let dst: u16 = self.get_pair_value(r1, r2); let val: u8 = self.get_8bit_reg(REG_N_A); self.interconnect.write_byte(dst, val); 8 } fn set_flag(&mut self, flag: u8) { self.flags |= flag; } fn clear_flag(&mut self, flag: u8) { self.flags &= !flag; } fn set_clear_flag(&mut self, flag: u8, dep: bool) { if dep { self.set_flag(flag); } else { self.clear_flag(flag); } } fn int_(&mut self, val: u8) { if self.debug { println!("INT {:02X}", val); } // TODO: Clear interrupt register self.ime = false; self.call(val as u16); } fn ret(&mut self) { let new_ip: u16 = self.pop(); //self.dump_stack(); self.ip = new_ip; } fn reti(&mut self) -> u8 { self.ret(); self.ime = true; 16 } fn handle_interrupt(&mut self, offset: u8, flag: u8) { // Remove interrupt requested flag let new_flag = self.interconnect.read_byte(0xFF0F) & !flag; self.interconnect.write_byte(0xFF0F, new_flag); // Run interrupt handler self.int_(offset); self.halted = false; } #[allow(unused_variables)] pub fn run(&mut self) { let start = Instant::now(); let mut cycles_executed = 0u128; loop { // Calculate the amount of cycles we should've executed by now. // The gameboy has a freq of 4.194304MHz // This means it takes it 238.418569ns to execute a single // cycle. let expected_cycles = start.elapsed().as_nanos() / (238 / 2); while cycles_executed < expected_cycles { if let CpuTickResult::Continue { cycles_executed: x, .. } = self.run_instruction() { cycles_executed += x as u128; } else { return; } } sleep(Duration::new(0, 10 * 238)); } } fn check_interrupts(&mut self, execute: bool) -> bool { // read pending interrupts let pending = self.interconnect.read_byte(0xFF0F); let enabled = self.interconnect.read_byte(0xFFFF); let e_pending = pending & enabled; // Handling interrupts. Do only execute the one with the highest // priority if e_pending & interconnect::INTERRUPT_DISPLAY_VBLANK > 0 { if execute { self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK); } return true; } else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 { if execute { self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT); } return true; } else if e_pending & interconnect::INTERRUPT_TIMER_OVERFLOW > 0 { if execute { self.handle_interrupt(0x50, interconnect::INTERRUPT_TIMER_OVERFLOW); } return true; } else if e_pending & interconnect::INTERRUPT_SERIAL > 0 { if execute { self.handle_interrupt(0x58, interconnect::INTERRUPT_SERIAL); } return true; } else if e_pending & interconnect::INTERRUPT_INPUT > 0 { if execute { self.handle_interrupt(0x60, interconnect::INTERRUPT_INPUT); } return true; } else if e_pending > 0 { panic!("Unknown pending interrupt: {:02X}", e_pending); } false } pub fn run_instruction(&mut self) -> CpuTickResult { // self.debug = !self.interconnect.is_boot_rom(); if !self.trigger_once && !self.interconnect.is_boot_rom() { self.trigger_once = true; self.regs[REG_A] = 0x11; println!("Patching reg"); } /* 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); } else if self.halted && self.check_interrupts(false) { self.halted = false; } let mut cycles: u8 = 255; let instruction: u8; if !self.halted { // 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 (idx, reg) in REG_NAMES.iter().enumerate() { print!("{}: {:02X} ", reg, self.get_8bit_reg(idx)); } print!("A: {:02X} ", self.regs[REG_A]); print!("I: {:02X} ", self.interconnect.read_byte(0xFFFF)); // Flags print!("Z={} ", self.flags & FLAG_Z != 0); print!("N={} ", self.flags & FLAG_N != 0); print!("H={} ", self.flags & FLAG_H != 0); print!("C={} ", self.flags & FLAG_C != 0); } self.ip = self.ip.wrapping_add(1); cycles = match instruction { 0x00 => { if self.debug { 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), 0x04 => self.reg_inc(REG_N_B), 0x05 => self.reg_dec(REG_N_B), 0x06 => self.ld_r_v(REG_N_B), 0x07 => { if self.debug { println!("RLCA"); } let val = self.regs[REG_A]; let carry = val & 0x80 == 0x80; self.set_clear_flag(FLAG_C, carry); if !carry { self.regs[REG_A] <<= 1; } else { self.regs[REG_A] <<= 1; self.regs[REG_A] |= 1; } self.clear_flag(FLAG_Z); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 } 0x08 => { let a = u16::try_from(self.load_args(2)).unwrap(); if self.debug { println!("LD ({:04X}), sp", a); } self.interconnect.write_word(a, self.sp); 20 } 0x09 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_B, REG_N_C), 0x0A => { 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)); 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), 0x0E => self.ld_r_v(REG_N_C), 0x0F => { if self.debug { println!("RRCA"); } let val = self.regs[REG_A]; self.set_clear_flag(FLAG_C, val & 1 == 1); if val & 1 == 0 { self.regs[REG_A] >>= 1; } else { self.regs[REG_A] >>= 1; self.regs[REG_A] |= 0x80; } self.clear_flag(FLAG_Z); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 } 0x10 => { println!( "STOP 0 {:02X} not implemented.", u8::try_from(self.load_args(1)).unwrap() ); 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), 0x14 => self.reg_inc(REG_N_D), 0x15 => self.reg_dec(REG_N_D), 0x16 => self.ld_r_v(REG_N_D), 0x17 => { if self.debug { println!("RLA"); } let carry = self.flags & FLAG_C > 0; let val = self.regs[REG_A]; self.set_clear_flag(FLAG_C, val & 0x80 == 0x80); if !carry { self.regs[REG_A] <<= 1; } else { self.regs[REG_A] <<= 1; self.regs[REG_A] |= 1; } self.clear_flag(FLAG_Z); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 } 0x18 => { let dst = u8::try_from(self.load_args(1)).unwrap(); 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), 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)); 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), 0x1E => self.ld_r_v(REG_N_E), 0x1F => { if self.debug { println!("RRA"); } let carry = self.flags & FLAG_C > 0; let val = self.regs[REG_A]; self.set_clear_flag(FLAG_C, val & 1 == 1); if !carry { self.regs[REG_A] >>= 1; } else { self.regs[REG_A] >>= 1; self.regs[REG_A] |= 0x80; } self.clear_flag(FLAG_Z); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 } 0x20 => { let c = self.flags & FLAG_Z == 0; self.jmp_r_condition("NZ", c) } 0x21 => self.ld_rr_vv(REG_N_H, REG_N_L), 0x22 => { if self.debug { println!("LD (HL+), A"); } let addr: u16 = self.get_pair_value(REG_N_H, REG_N_L); 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), 0x26 => self.ld_r_v(REG_N_H), 0x27 => { // Logic copied from some other emulator let a = self.regs[REG_A]; if self.debug { println!("DAA"); } let mut cor: u8 = 0; if (self.flags & FLAG_H) == FLAG_H { cor |= 0x06; } if (self.flags & FLAG_C) == FLAG_C { cor |= 0x60; } if (self.flags & FLAG_N) == FLAG_N { self.regs[REG_A] = a.wrapping_sub(cor); } else { if (a & 0x0F) > 0x09 { cor |= 0x06; } if a > 0x99 { cor |= 0x60; } self.regs[REG_A] = a.wrapping_add(cor); } self.clear_flag(FLAG_H); if cor & 0x60 == 0x60 { self.set_flag(FLAG_C); } let a = self.regs[REG_A]; self.set_clear_flag(FLAG_Z, a == 0); 4 } 0x28 => { let c = self.flags & FLAG_Z == FLAG_Z; self.jmp_r_condition("Z", c) } 0x29 => self.add_rr_rr(REG_N_H, REG_N_L, REG_N_H, REG_N_L), 0x2A => { if self.debug { println!("LD A, (HL+)"); } let addr: u16 = self.get_pair_value(REG_N_H, REG_N_L); 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), 0x2E => self.ld_r_v(REG_N_L), 0x2F => { if self.debug { println!("CPL"); } self.regs[REG_A] = !self.regs[REG_A]; self.set_flag(FLAG_N); self.set_flag(FLAG_H); 4 } 0x30 => { let c = self.flags & FLAG_C == 0; self.jmp_r_condition("NC", c) } 0x31 => { let args = self.load_args(2); self.sp = u16::try_from(args).unwrap(); if self.debug { println!("LD SP, {:04x}", self.sp); } 12 } 0x32 => { if self.debug { println!("LD (HL-), A"); } let addr = self.get_pair_value(REG_N_H, REG_N_L); 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"); } let sp = self.sp.wrapping_add(1); self.sp = sp; 8 } 0x34 => self.reg_inc(REG_N_HL), 0x35 => self.reg_dec(REG_N_HL), 0x36 => self.ld_r_v(REG_N_HL), 0x37 => { if self.debug { println!("SCF"); } self.set_flag(FLAG_C); 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", c) } 0x39 => { if self.debug { println!("ADD HL, SP"); } let sp = self.sp; let old = self.get_pair_value(REG_N_H, REG_N_L); let v = old.wrapping_add(sp); self.set_pair_value(REG_N_H, REG_N_L, v); self.clear_flag(FLAG_N); 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-)"); } let addr = self.get_pair_value(REG_N_H, REG_N_L); self.regs[REG_A] = self.interconnect.read_byte(addr); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1)); 8 } 0x3B => { if self.debug { println!("DEC SP"); } let sp = self.sp.wrapping_sub(1); self.sp = sp; 8 } 0x3C => self.reg_inc(REG_N_A), 0x3D => self.reg_dec(REG_N_A), 0x3E => self.ld_r_v(REG_N_A), 0x3F => { if self.debug { println!("CCF"); } self.flags ^= FLAG_C; self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 } // 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), // HALT 0x76 => { if self.debug { println!("HALT"); } self.halted = true; 4 } // ADD 0x80..=0x87 => { let reg_id = (instruction - 0x80) as usize; if self.debug { println!("ADD {}", REG_NAMES[reg_id]); } let v = self.get_8bit_reg(reg_id); self.add_r(v); 4 } // ADC 0x88..=0x8F => { let reg_id = (instruction - 0x88) as usize; if self.debug { println!("ADC {}", REG_NAMES[reg_id]); } let v = self.get_8bit_reg(reg_id); self.adc_r(v); 4 } // SUBs 0x90..=0x97 => { let reg_id = (instruction - 0x90) as usize; if self.debug { println!("SUB {}", REG_NAMES[reg_id]); } let r = self.get_8bit_reg(reg_id); self.sub_r(r); 4 } // SBC 0x98..=0x9F => { let reg_id = (instruction - 0x98) as usize; if self.debug { println!("SBC {}", REG_NAMES[reg_id]); } let r = self.get_8bit_reg(reg_id); self.sbc_r(r); 4 } // AND 0xA0..=0xA7 => { let reg_id = (instruction - 0xA0) as usize; if self.debug { println!("AND {}", REG_NAMES[reg_id]); } self.regs[REG_A] &= self.get_8bit_reg(reg_id); let v = self.regs[REG_A]; self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); self.clear_flag(FLAG_C); 4 } // XOR 0xA8..=0xAF => { let reg_id = (instruction - 0xA8) as usize; if self.debug { println!("XOR {}", REG_NAMES[reg_id]); } self.regs[REG_A] ^= self.get_8bit_reg(reg_id); let v = self.regs[REG_A]; self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 } // OR 0xB0..=0xB7 => { let reg_id = (instruction - 0xB0) as usize; if self.debug { println!("OR {}", REG_NAMES[reg_id]); } self.regs[REG_A] |= self.get_8bit_reg(reg_id); let v = self.regs[REG_A]; self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 4 } // CP 0xB8..=0xBF => { let reg_id = (instruction - 0xB8) as usize; if self.debug { println!("CP {}", REG_NAMES[reg_id]); } 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", c) } 0xC1 => self.pop_rr(REG_N_B, REG_N_C), 0xC2 => { let c = self.flags & FLAG_Z == 0; self.jmp_p_condition("NZ", c) } 0xC3 => { let dst = u16::try_from(self.load_args(2)).unwrap(); if self.debug { println!("JMP {:04X}", dst); } self.jmp_p(dst); 16 } 0xC4 => { let c = self.flags & FLAG_Z == 0; self.call_condition("NZ", c) } 0xC5 => self.push_rr(REG_N_B, REG_N_C), 0xC6 => { let val = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("ADD A, {:02X}", val); } self.add_r(val); 8 } 0xC7 => self.rst(0x00), 0xC8 => { let c = self.flags & FLAG_Z == FLAG_Z; self.ret_condition("Z", c) } 0xC9 => { if self.debug { println!("RET"); } self.ret(); 16 } 0xCA => { let c = self.flags & FLAG_Z == FLAG_Z; self.jmp_p_condition("Z", c) } 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", c) } 0xCD => self.call_condition("", true), 0xCE => { let arg = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("ADC A, {:02X}", arg); } self.adc_r(arg); 8 } 0xCF => self.rst(0x08), 0xD0 => { let c = self.flags & FLAG_C == 0; 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", c) } 0xD3 => panic!("NON-EXISTING OPCODE"), 0xD4 => { let c = self.flags & FLAG_C == 0; self.call_condition("NC", c) } 0xD5 => self.push_rr(REG_N_D, REG_N_E), 0xD6 => { let val = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("SUB {:02X}", val); } self.sub_r(val); 8 } 0xD7 => self.rst(0x10), 0xD8 => { let c = self.flags & FLAG_C == FLAG_C; self.ret_condition("C", c) } 0xD9 => { if self.debug { println!("RETI"); } self.reti() } 0xDA => { let c = self.flags & FLAG_C == FLAG_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", c) } 0xDD => panic!("NON-EXISTING OPCODE"), 0xDE => { let arg = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("SBC {:02X}", arg); } self.sbc_r(arg); 8 } 0xDF => self.rst(0x18), 0xE0 => { let arg = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("LDH {:02X}, A", arg); } self.interconnect .write_byte(0xFF00 + arg as u16, self.regs[REG_A]); 12 } 0xE1 => self.pop_rr(REG_N_H, REG_N_L), 0xE2 => { if self.debug { println!("LD (C), A"); } 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 => { let val = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("AND {:02X}", val); } let v = self.regs[REG_A] & val; self.regs[REG_A] = v; self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_N); self.set_flag(FLAG_H); self.clear_flag(FLAG_C); 8 } 0xE7 => self.rst(0x20), 0xE8 => { let arg = u8::try_from(self.load_args(1)).unwrap() as i8; if self.debug { println!("ADD SP, {:02X}", arg); } let t: u16; if arg > 0 { t = self.sp.wrapping_add(arg as u16); } else { t = self.sp.wrapping_sub((-arg) as u16); } let sp = self.sp; self.clear_flag(FLAG_N); self.clear_flag(FLAG_Z); self.set_clear_flag(FLAG_C, (sp ^ arg as u16 ^ t) & 0x100 == 0x100); self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ t) & 0x10 == 0x10); self.sp = t; 16 } 0xE9 => { if self.debug { println!("JP (HL)"); } self.ip = self.get_pair_value(REG_N_H, REG_N_L); 4 } 0xEA => { let addr = u16::try_from(self.load_args(2)).unwrap(); if self.debug { println!("LD ({:04X}), A", addr); } self.interconnect.write_byte(addr, self.regs[REG_A]); 16 } 0xEB..=0xED => panic!("NON-EXISTING OPCODE"), 0xEE => { let arg = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("XOR {:02X}", arg); } let v = self.regs[REG_A] ^ arg; self.regs[REG_A] = v; self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_H); self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); 8 } 0xEF => self.rst(0x28), 0xF0 => { let arg = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("LDH A, {:02X}", arg); } self.regs[REG_A] = self.interconnect.read_byte(0xFF00 + arg as u16); 12 } 0xF1 => self.pop_rr(REG_N_A, REG_N_F), 0xF2 => { 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 => { let val = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("OR {:02X}", val); } let v = self.regs[REG_A] | val; self.regs[REG_A] = v; self.set_clear_flag(FLAG_Z, v == 0); self.clear_flag(FLAG_C); self.clear_flag(FLAG_N); self.clear_flag(FLAG_H); 8 } 0xF7 => self.rst(0x30), 0xF8 => { let arg = u8::try_from(self.load_args(1)).unwrap() as i8; if self.debug { println!("LD HL, SP+{:02X}", arg); } self.clear_flag(FLAG_N); self.clear_flag(FLAG_Z); let sp = self.sp; if arg < 0 { let v: u16 = self.sp.wrapping_sub((-arg) as u16); self.set_pair_value(REG_N_H, REG_N_L, v); self.set_clear_flag(FLAG_C, (sp ^ arg as u16 ^ v) & 0x100 == 0x100); self.set_clear_flag(FLAG_H, (sp ^ arg as u16 ^ v) & 0x10 == 0x10); } else { let v: u16 = self.sp.wrapping_add(arg as u16); self.set_pair_value(REG_N_H, REG_N_L, v); self.set_clear_flag(FLAG_C, (sp ^ arg as u16 ^ v) & 0x100 == 0x100); 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 = u16::try_from(self.load_args(2)).unwrap(); if self.debug { println!("LD A, ({:04X})", addr); } self.regs[REG_A] = self.interconnect.read_byte(addr); 16 } 0xFB => { if self.debug { println!("EI"); } self.ime = true; // interrupt master enable 4 } 0xFC | 0xFD => panic!("NON-EXISTING OPCODE"), 0xFE => { let arg = u8::try_from(self.load_args(1)).unwrap(); if self.debug { println!("CP {:02X}", arg); } self.cp_r(arg); 8 } 0xFF => self.rst(0x38), }; } if self.interconnect.tick(cycles) == TickResult::Shutdown { return CpuTickResult::Shutdown { cycles_executed: cycles as usize, }; } CpuTickResult::Continue { cycles_executed: cycles as usize, } } }