use std::{ mem::transmute, ops::{BitAnd, BitOr, BitXor}, }; use crate::{verbose_println, Inner, Memory, Register, State}; mod opcodes; #[allow(dead_code)] #[derive(PartialEq)] enum FLAGS { Z = 7, N = 6, H = 5, C = 4, } enum Direction { Left, Right, } pub struct CPU { pub memory: Memory, pub state: State, pub last_instruction: u8, pub last_instruction_addr: u16, } impl CPU { pub fn exec_next(&mut self) { unsafe { self.last_instruction_addr = self.state.pc.as_u16 }; let opcode = self.next_opcode(); self.last_instruction = opcode; verbose_println!( "exec {:#4X} from pc: {:#X}", opcode, self.last_instruction_addr ); self.run_opcode(opcode); } fn next_opcode(&mut self) -> u8 { unsafe { let opcode = self.memory.get(self.state.pc.as_u16); self.state.pc.as_u16 = self.state.pc.as_u16.wrapping_add(0x1); return opcode; }; } fn rlc(&mut self, byte: u8) -> u8 { self.rotate_c(byte, Direction::Left) } fn rrc(&mut self, byte: u8) -> u8 { self.rotate_c(byte, Direction::Right) } fn rl(&mut self, byte: u8) -> u8 { self.rotate(byte, Direction::Left) } fn rr(&mut self, byte: u8) -> u8 { self.rotate(byte, Direction::Right) } fn rotate_c(&mut self, byte: u8, direction: Direction) -> u8 { let (mut rotated, carry) = rotate(byte, &direction); if carry { rotated += get_rotation_carry(&direction); self.set_flag(FLAGS::C); } return rotated; } fn rotate(&mut self, byte: u8, direction: Direction) -> u8 { let old_carry = self.get_flag(FLAGS::C); let (mut rotated, carry) = rotate(byte, &direction); if old_carry > 0 { rotated += get_rotation_carry(&direction); } if carry { self.set_flag(FLAGS::C); } return rotated; } fn sla(&mut self, byte: u8) -> u8 { self.shift(byte, Direction::Left) } fn sra(&mut self, byte: u8) -> u8 { let b = get_bit(byte, 7); let val = self.shift(byte, Direction::Right); if b { val + 0b10000000 } else { val } } fn srl(&mut self, byte: u8) -> u8 { self.shift(byte, Direction::Right) } fn shift(&mut self, byte: u8, direction: Direction) -> u8 { let (rotated, carry) = rotate(byte, &direction); if carry { self.set_flag(FLAGS::C); } return rotated; } fn bit(&mut self, byte: u8, bit: u8) { self.set_or_clear_flag(FLAGS::Z, !get_bit(byte, bit)); } fn rst(&mut self, address: u16) { self.push(self.state.pc); self.state.pc.as_u8s.left = 0x0; self.state.pc.as_u8s.right = self.memory.get(address); } fn push(&mut self, register: Register) { unsafe { let address = self.state.sp.as_u16; self.memory .set(address.wrapping_sub(1), register.as_u8s.right); self.memory .set(address.wrapping_sub(2), register.as_u8s.left); self.state.sp.as_u16 = address.wrapping_sub(2); } } fn pop_word(&mut self) -> Register { unsafe { let address = self.state.sp.as_u16; self.state.sp.as_u16 = self.state.sp.as_u16.wrapping_add(0x2); Register { as_u8s: Inner { left: self.memory.get(address), right: self.memory.get(address.wrapping_add(1)), }, } } } fn store_word(&mut self, address: u16, word: Register) { unsafe { self.memory.set(address, word.as_u8s.left); self.memory.set(address + 1, word.as_u8s.right); }; } fn ld_immediate_word(&mut self) -> Register { Register { as_u8s: Inner { left: self.next_opcode(), right: self.next_opcode(), }, } } fn ld_immediate_byte(&mut self) -> u8 { self.next_opcode() } fn get_flag(&mut self, flag: FLAGS) -> u8 { unsafe { if get_bit(self.state.af.as_u8s.right, flag as u8) { 0x1 } else { 0x0 } } } fn set_flag(&mut self, flag: FLAGS) { if flag == FLAGS::Z { verbose_println!("setting z flag"); } unsafe { verbose_println!( "setting flag: currently {0:#b} / {0:#X}", self.state.af.as_u8s.right ); self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitor(1 << flag as u8); verbose_println!( " now {0:#b} / {0:#X}", self.state.af.as_u8s.right ); }; } fn clear_flag(&mut self, flag: FLAGS) { unsafe { self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitand(!(1 << flag as u8)); }; } fn toggle_flag(&mut self, flag: FLAGS) { unsafe { self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitxor(1 << flag as u8); }; } fn set_or_clear_flag(&mut self, flag: FLAGS, state: bool) { if state { self.set_flag(flag) } else { self.clear_flag(flag) } } fn add_u8s(&mut self, first: u8, second: u8) -> u8 { let (result, carry) = first.overflowing_add(second); self.clear_flag(FLAGS::N); self.set_or_clear_flag(FLAGS::C, carry); self.set_or_clear_flag(FLAGS::Z, result == 0x0); self.set_or_clear_flag( FLAGS::H, (((first & 0xF).wrapping_add(second & 0xF)) & 0x10) == 0x10, ); return result; } fn add_u16s(&mut self, first: u16, second: u16) -> u16 { let (result, carry) = first.overflowing_add(second); self.clear_flag(FLAGS::N); self.set_or_clear_flag(FLAGS::C, carry); self.set_or_clear_flag(FLAGS::Z, result == 0x0); self.set_or_clear_flag( FLAGS::H, (((first & 0xFFF).wrapping_add(second & 0xFFF)) & 0x1000) == 0x1000, ); return result; } fn sub_u8s(&mut self, first: u8, second: u8) -> u8 { let (result, carry) = first.overflowing_sub(second); self.set_flag(FLAGS::N); self.set_or_clear_flag(FLAGS::C, carry); self.set_or_clear_flag(FLAGS::Z, result == 0x0); self.set_or_clear_flag( FLAGS::H, (((first & 0xF).wrapping_sub(second & 0xF)) & 0x10) == 0x10, ); return result; } fn sub_u16s(&mut self, first: u16, second: u16) -> u16 { let (result, carry) = first.overflowing_sub(second); self.set_flag(FLAGS::N); self.set_or_clear_flag(FLAGS::C, carry); self.set_or_clear_flag(FLAGS::Z, result == 0x0); self.set_or_clear_flag( FLAGS::H, (((first & 0xFFF).wrapping_sub(second & 0xFFF)) & 0x1000) == 0x1000, ); return result; } } fn as_signed(unsigned: u8) -> i8 { unsafe { return transmute(unsigned); } } fn get_bit(byte: u8, flag: u8) -> bool { let mask = 1 << flag; let got = byte & mask; return got > 0x0; } fn rotate(byte: u8, direction: &Direction) -> (u8, bool) { match direction { Direction::Left => { let carry = get_bit(byte, 7); let r = byte << 1; return (r, carry); } Direction::Right => { let carry = get_bit(byte, 0); let r = byte >> 1; return (r, carry); } } } fn get_rotation_carry(direction: &Direction) -> u8 { match direction { Direction::Left => 0b1, Direction::Right => 0b10000000, } } fn swap_nibbles(byte: u8) -> u8 { (byte & 0x0F) << 4 | (byte & 0xF0) >> 4 } fn res(byte: u8, bit: u8) -> u8 { byte & !(1 << bit) } fn set(byte: u8, bit: u8) -> u8 { byte | (1 << bit) }