better processor modularisation
This commit is contained in:
parent
8413dedb89
commit
3a599b069f
43
src/processor/instructions/instructions.rs
Normal file
43
src/processor/instructions/instructions.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
use crate::processor::{get_bit, Direction, CPU};
|
||||||
|
|
||||||
|
impl CPU {
|
||||||
|
pub(crate) fn rlc(&mut self, byte: u8) -> u8 {
|
||||||
|
self.rotate_c(byte, Direction::Left)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rrc(&mut self, byte: u8) -> u8 {
|
||||||
|
self.rotate_c(byte, Direction::Right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rl(&mut self, byte: u8) -> u8 {
|
||||||
|
self.rotate(byte, Direction::Left)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rr(&mut self, byte: u8) -> u8 {
|
||||||
|
self.rotate(byte, Direction::Right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sla(&mut self, byte: u8) -> u8 {
|
||||||
|
self.shift(byte, Direction::Left)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn srl(&mut self, byte: u8) -> u8 {
|
||||||
|
self.shift(byte, Direction::Right)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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);
|
||||||
|
}
|
||||||
|
}
|
2
src/processor/instructions/mod.rs
Normal file
2
src/processor/instructions/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod instructions;
|
||||||
|
pub mod primitives;
|
180
src/processor/instructions/primitives.rs
Normal file
180
src/processor/instructions/primitives.rs
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
use std::ops::{BitAnd, BitOr, BitXor};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
processor::{get_bit, get_rotation_carry, rotate, Direction, CPU, FLAGS},
|
||||||
|
verbose_println, Inner, Register,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl CPU {
|
||||||
|
pub(crate) 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)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ld_immediate_byte(&mut self) -> u8 {
|
||||||
|
self.next_opcode()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ld_immediate_word(&mut self) -> Register {
|
||||||
|
Register {
|
||||||
|
as_u8s: Inner {
|
||||||
|
left: self.next_opcode(),
|
||||||
|
right: self.next_opcode(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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::Carry);
|
||||||
|
}
|
||||||
|
return rotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rotate(&mut self, byte: u8, direction: Direction) -> u8 {
|
||||||
|
let old_carry = self.get_flag(FLAGS::Carry);
|
||||||
|
let (mut rotated, carry) = rotate(byte, &direction);
|
||||||
|
if old_carry > 0 {
|
||||||
|
rotated += get_rotation_carry(&direction);
|
||||||
|
}
|
||||||
|
if carry {
|
||||||
|
self.set_flag(FLAGS::Carry);
|
||||||
|
}
|
||||||
|
return rotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn shift(&mut self, byte: u8, direction: Direction) -> u8 {
|
||||||
|
let (rotated, carry) = rotate(byte, &direction);
|
||||||
|
if carry {
|
||||||
|
self.set_flag(FLAGS::Carry);
|
||||||
|
}
|
||||||
|
return rotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn bit(&mut self, byte: u8, bit: u8) {
|
||||||
|
self.set_or_clear_flag(FLAGS::Zero, !get_bit(byte, bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_flag(&mut self, flag: FLAGS) -> u8 {
|
||||||
|
unsafe {
|
||||||
|
if get_bit(self.state.af.as_u8s.right, flag as u8) {
|
||||||
|
0x1
|
||||||
|
} else {
|
||||||
|
0x0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_flag(&mut self, flag: FLAGS) {
|
||||||
|
if flag == FLAGS::Zero {
|
||||||
|
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
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_or_clear_flag(&mut self, flag: FLAGS, state: bool) {
|
||||||
|
if state {
|
||||||
|
self.set_flag(flag)
|
||||||
|
} else {
|
||||||
|
self.clear_flag(flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_u8s(&mut self, first: u8, second: u8) -> u8 {
|
||||||
|
let (result, carry) = first.overflowing_add(second);
|
||||||
|
self.clear_flag(FLAGS::NSubtract);
|
||||||
|
self.set_or_clear_flag(FLAGS::Carry, carry);
|
||||||
|
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
||||||
|
self.set_or_clear_flag(
|
||||||
|
FLAGS::HalfCarry,
|
||||||
|
(((first & 0xF).wrapping_add(second & 0xF)) & 0x10) == 0x10,
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_u16s(&mut self, first: u16, second: u16) -> u16 {
|
||||||
|
let (result, carry) = first.overflowing_add(second);
|
||||||
|
self.clear_flag(FLAGS::NSubtract);
|
||||||
|
self.set_or_clear_flag(FLAGS::Carry, carry);
|
||||||
|
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
||||||
|
self.set_or_clear_flag(
|
||||||
|
FLAGS::HalfCarry,
|
||||||
|
(((first & 0xFFF).wrapping_add(second & 0xFFF)) & 0x1000) == 0x1000,
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sub_u8s(&mut self, first: u8, second: u8) -> u8 {
|
||||||
|
let (result, carry) = first.overflowing_sub(second);
|
||||||
|
self.set_flag(FLAGS::NSubtract);
|
||||||
|
self.set_or_clear_flag(FLAGS::Carry, carry);
|
||||||
|
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
||||||
|
self.set_or_clear_flag(
|
||||||
|
FLAGS::HalfCarry,
|
||||||
|
(((first & 0xF).wrapping_sub(second & 0xF)) & 0x10) == 0x10,
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn sub_u16s(&mut self, first: u16, second: u16) -> u16 {
|
||||||
|
let (result, carry) = first.overflowing_sub(second);
|
||||||
|
self.set_flag(FLAGS::NSubtract);
|
||||||
|
self.set_or_clear_flag(FLAGS::Carry, carry);
|
||||||
|
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
||||||
|
self.set_or_clear_flag(
|
||||||
|
FLAGS::HalfCarry,
|
||||||
|
(((first & 0xFFF).wrapping_sub(second & 0xFFF)) & 0x1000) == 0x1000,
|
||||||
|
);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,19 @@
|
||||||
use std::{
|
use std::mem::transmute;
|
||||||
mem::transmute,
|
|
||||||
ops::{BitAnd, BitOr, BitXor},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{verbose_println, Inner, Memory, Register, State};
|
use crate::{verbose_println, Memory, State};
|
||||||
|
|
||||||
|
mod instructions;
|
||||||
mod opcodes;
|
mod opcodes;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
enum FLAGS {
|
pub(crate) enum FLAGS {
|
||||||
Zero = 7,
|
Zero = 7,
|
||||||
NSubtract = 6,
|
NSubtract = 6,
|
||||||
HalfCarry = 5,
|
HalfCarry = 5,
|
||||||
Carry = 4,
|
Carry = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Direction {
|
pub(crate) enum Direction {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
@ -47,218 +45,6 @@ impl CPU {
|
||||||
return opcode;
|
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::Carry);
|
|
||||||
}
|
|
||||||
return rotated;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rotate(&mut self, byte: u8, direction: Direction) -> u8 {
|
|
||||||
let old_carry = self.get_flag(FLAGS::Carry);
|
|
||||||
let (mut rotated, carry) = rotate(byte, &direction);
|
|
||||||
if old_carry > 0 {
|
|
||||||
rotated += get_rotation_carry(&direction);
|
|
||||||
}
|
|
||||||
if carry {
|
|
||||||
self.set_flag(FLAGS::Carry);
|
|
||||||
}
|
|
||||||
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::Carry);
|
|
||||||
}
|
|
||||||
return rotated;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bit(&mut self, byte: u8, bit: u8) {
|
|
||||||
self.set_or_clear_flag(FLAGS::Zero, !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::Zero {
|
|
||||||
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::NSubtract);
|
|
||||||
self.set_or_clear_flag(FLAGS::Carry, carry);
|
|
||||||
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
|
||||||
self.set_or_clear_flag(
|
|
||||||
FLAGS::HalfCarry,
|
|
||||||
(((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::NSubtract);
|
|
||||||
self.set_or_clear_flag(FLAGS::Carry, carry);
|
|
||||||
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
|
||||||
self.set_or_clear_flag(
|
|
||||||
FLAGS::HalfCarry,
|
|
||||||
(((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::NSubtract);
|
|
||||||
self.set_or_clear_flag(FLAGS::Carry, carry);
|
|
||||||
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
|
||||||
self.set_or_clear_flag(
|
|
||||||
FLAGS::HalfCarry,
|
|
||||||
(((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::NSubtract);
|
|
||||||
self.set_or_clear_flag(FLAGS::Carry, carry);
|
|
||||||
self.set_or_clear_flag(FLAGS::Zero, result == 0x0);
|
|
||||||
self.set_or_clear_flag(
|
|
||||||
FLAGS::HalfCarry,
|
|
||||||
(((first & 0xFFF).wrapping_sub(second & 0xFFF)) & 0x1000) == 0x1000,
|
|
||||||
);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_signed(unsigned: u8) -> i8 {
|
fn as_signed(unsigned: u8) -> i8 {
|
||||||
|
|
Loading…
Reference in a new issue