2023-01-17 09:09:53 +11:00
|
|
|
use std::{
|
|
|
|
mem::transmute,
|
|
|
|
ops::{BitAnd, BitOr, BitXor},
|
|
|
|
};
|
2023-01-16 19:28:03 +11:00
|
|
|
|
2023-01-16 12:13:53 +11:00
|
|
|
use crate::{Inner, Memory, Register, State};
|
|
|
|
|
2023-01-22 09:39:45 +11:00
|
|
|
mod opcodes;
|
|
|
|
|
2023-01-16 14:23:43 +11:00
|
|
|
#[allow(dead_code)]
|
2023-01-22 09:18:07 +11:00
|
|
|
#[derive(PartialEq)]
|
2023-01-16 14:23:06 +11:00
|
|
|
enum FLAGS {
|
|
|
|
Z = 7,
|
|
|
|
N = 6,
|
|
|
|
H = 5,
|
|
|
|
C = 4,
|
|
|
|
}
|
|
|
|
|
2023-01-18 13:14:22 +11:00
|
|
|
enum Direction {
|
|
|
|
Left,
|
|
|
|
Right,
|
|
|
|
}
|
|
|
|
|
2023-01-16 12:13:53 +11:00
|
|
|
pub struct CPU {
|
|
|
|
pub memory: Memory,
|
|
|
|
pub state: State,
|
2023-01-18 12:45:56 +11:00
|
|
|
pub last_instruction: u8,
|
|
|
|
pub last_instruction_addr: u16,
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl CPU {
|
2023-01-17 09:09:53 +11:00
|
|
|
pub fn exec_next(&mut self) {
|
2023-01-18 12:45:56 +11:00
|
|
|
unsafe { self.last_instruction_addr = self.state.pc.as_u16 };
|
2023-01-16 12:13:53 +11:00
|
|
|
let opcode = self.next_opcode();
|
2023-01-18 12:45:56 +11:00
|
|
|
self.last_instruction = opcode;
|
2023-01-22 09:32:19 +11:00
|
|
|
println!(
|
|
|
|
"exec {:#4X} from pc: {:#X}",
|
|
|
|
opcode, self.last_instruction_addr
|
|
|
|
);
|
2023-01-22 09:39:45 +11:00
|
|
|
self.run_opcode(opcode);
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
fn next_opcode(&mut self) -> u8 {
|
|
|
|
unsafe {
|
|
|
|
let opcode = self.memory.get(self.state.pc.as_u16);
|
2023-01-20 14:59:17 +11:00
|
|
|
self.state.pc.as_u16 = self.state.pc.as_u16.wrapping_add(0x1);
|
2023-01-16 12:13:53 +11:00
|
|
|
return opcode;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-01-18 14:43:24 +11:00
|
|
|
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 {
|
2023-01-18 13:14:22 +11:00
|
|
|
let (mut rotated, carry) = rotate(byte, &direction);
|
|
|
|
if carry {
|
|
|
|
rotated += get_rotation_carry(&direction);
|
|
|
|
self.set_flag(FLAGS::C);
|
|
|
|
}
|
|
|
|
return rotated;
|
|
|
|
}
|
|
|
|
|
2023-01-18 14:43:24 +11:00
|
|
|
fn rotate(&mut self, byte: u8, direction: Direction) -> u8 {
|
2023-01-18 13:14:22 +11:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-01-18 14:43:24 +11:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2023-01-16 19:28:03 +11:00
|
|
|
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;
|
2023-01-18 14:43:24 +11:00
|
|
|
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);
|
2023-01-16 19:28:03 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_word(&mut self) -> Register {
|
|
|
|
unsafe {
|
|
|
|
let address = self.state.sp.as_u16;
|
2023-01-22 09:18:07 +11:00
|
|
|
self.state.sp.as_u16 = self.state.sp.as_u16.wrapping_add(0x2);
|
2023-01-16 19:28:03 +11:00
|
|
|
Register {
|
|
|
|
as_u8s: Inner {
|
|
|
|
left: self.memory.get(address),
|
2023-01-22 09:18:07 +11:00
|
|
|
right: self.memory.get(address.wrapping_add(1)),
|
2023-01-16 19:28:03 +11:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-16 14:23:06 +11:00
|
|
|
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);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-01-16 12:13:53 +11:00
|
|
|
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()
|
|
|
|
}
|
2023-01-16 14:23:06 +11:00
|
|
|
|
|
|
|
fn get_flag(&mut self, flag: FLAGS) -> u8 {
|
|
|
|
unsafe {
|
2023-01-18 12:45:56 +11:00
|
|
|
if get_bit(self.state.af.as_u8s.right, flag as u8) {
|
|
|
|
0x1
|
|
|
|
} else {
|
|
|
|
0x0
|
|
|
|
}
|
2023-01-16 14:23:06 +11:00
|
|
|
}
|
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
|
|
|
|
fn set_flag(&mut self, flag: FLAGS) {
|
2023-01-22 09:18:07 +11:00
|
|
|
if flag == FLAGS::Z {
|
|
|
|
println!("setting z flag");
|
|
|
|
}
|
2023-01-16 19:28:03 +11:00
|
|
|
unsafe {
|
2023-01-22 09:18:07 +11:00
|
|
|
println!(
|
|
|
|
"setting flag: currently {0:#b} / {0:#X}",
|
|
|
|
self.state.af.as_u8s.right
|
|
|
|
);
|
2023-01-16 19:28:03 +11:00
|
|
|
self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitor(1 << flag as u8);
|
2023-01-22 09:18:07 +11:00
|
|
|
println!(
|
|
|
|
" now {0:#b} / {0:#X}",
|
|
|
|
self.state.af.as_u8s.right
|
|
|
|
);
|
2023-01-16 19:28:03 +11:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
};
|
|
|
|
}
|
2023-01-18 12:45:56 +11:00
|
|
|
|
|
|
|
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);
|
2023-01-22 09:18:07 +11:00
|
|
|
self.set_or_clear_flag(FLAGS::Z, result == 0x0);
|
|
|
|
self.set_or_clear_flag(
|
|
|
|
FLAGS::H,
|
|
|
|
(((first & 0xF).wrapping_add(second & 0xF)) & 0x10) == 0x10,
|
|
|
|
);
|
2023-01-18 12:45:56 +11:00
|
|
|
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);
|
2023-01-22 09:18:07 +11:00
|
|
|
self.set_or_clear_flag(FLAGS::Z, result == 0x0);
|
|
|
|
self.set_or_clear_flag(
|
|
|
|
FLAGS::H,
|
|
|
|
(((first & 0xFFF).wrapping_add(second & 0xFFF)) & 0x1000) == 0x1000,
|
|
|
|
);
|
2023-01-18 12:45:56 +11:00
|
|
|
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);
|
2023-01-22 09:18:07 +11:00
|
|
|
self.set_or_clear_flag(FLAGS::Z, result == 0x0);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.set_or_clear_flag(
|
|
|
|
FLAGS::H,
|
2023-01-22 09:18:07 +11:00
|
|
|
(((first & 0xF).wrapping_sub(second & 0xF)) & 0x10) == 0x10,
|
2023-01-18 12:45:56 +11:00
|
|
|
);
|
|
|
|
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);
|
2023-01-22 09:18:07 +11:00
|
|
|
self.set_or_clear_flag(FLAGS::Z, result == 0x0);
|
2023-01-18 12:45:56 +11:00
|
|
|
self.set_or_clear_flag(
|
|
|
|
FLAGS::H,
|
2023-01-22 09:18:07 +11:00
|
|
|
(((first & 0xFFF).wrapping_sub(second & 0xFFF)) & 0x1000) == 0x1000,
|
2023-01-18 12:45:56 +11:00
|
|
|
);
|
|
|
|
return result;
|
|
|
|
}
|
2023-01-16 12:13:53 +11:00
|
|
|
}
|
2023-01-17 09:09:53 +11:00
|
|
|
|
|
|
|
fn as_signed(unsigned: u8) -> i8 {
|
|
|
|
unsafe {
|
|
|
|
return transmute(unsigned);
|
|
|
|
}
|
|
|
|
}
|
2023-01-18 12:45:56 +11:00
|
|
|
|
|
|
|
fn get_bit(byte: u8, flag: u8) -> bool {
|
|
|
|
let mask = 1 << flag;
|
|
|
|
let got = byte & mask;
|
|
|
|
return got > 0x0;
|
|
|
|
}
|
2023-01-18 13:14:22 +11:00
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
2023-01-18 14:43:24 +11:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|