2023-01-31 10:05:36 +11:00
|
|
|
use std::mem::transmute;
|
2023-01-16 19:28:03 +11:00
|
|
|
|
2023-01-31 10:05:36 +11:00
|
|
|
use crate::{verbose_println, Memory, State};
|
2023-01-16 12:13:53 +11:00
|
|
|
|
2023-01-31 10:05:36 +11:00
|
|
|
mod instructions;
|
2023-01-22 09:39:45 +11:00
|
|
|
mod opcodes;
|
|
|
|
|
2023-01-22 09:18:07 +11:00
|
|
|
#[derive(PartialEq)]
|
2023-01-31 10:05:36 +11:00
|
|
|
pub(crate) enum FLAGS {
|
2023-01-22 13:09:31 +11:00
|
|
|
Zero = 7,
|
|
|
|
NSubtract = 6,
|
|
|
|
HalfCarry = 5,
|
|
|
|
Carry = 4,
|
2023-01-16 14:23:06 +11:00
|
|
|
}
|
|
|
|
|
2023-01-31 10:05:36 +11:00
|
|
|
pub(crate) enum Direction {
|
2023-01-18 13:14:22 +11:00
|
|
|
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 12:13:02 +11:00
|
|
|
verbose_println!(
|
2023-01-22 09:32:19 +11:00
|
|
|
"exec {:#4X} from pc: {:#X}",
|
2023-01-22 12:13:02 +11:00
|
|
|
opcode,
|
|
|
|
self.last_instruction_addr
|
2023-01-22 09:32:19 +11:00
|
|
|
);
|
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-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)
|
|
|
|
}
|