2023-01-31 10:05:36 +11:00
|
|
|
use std::mem::transmute;
|
2023-01-16 19:28:03 +11:00
|
|
|
|
2023-02-01 17:18:08 +11:00
|
|
|
use crate::{verbose_println, Memory};
|
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,
|
2023-02-01 17:18:08 +11:00
|
|
|
pub reg: Registers,
|
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-02-01 17:18:08 +11:00
|
|
|
self.last_instruction_addr = self.reg.pc;
|
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 {
|
2023-02-01 17:18:08 +11:00
|
|
|
let opcode = self.memory.get(self.reg.pc);
|
|
|
|
self.reg.pc = self.reg.pc.wrapping_add(0x1);
|
|
|
|
return opcode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Reg8 {
|
|
|
|
A,
|
|
|
|
F,
|
|
|
|
B,
|
|
|
|
C,
|
|
|
|
D,
|
|
|
|
E,
|
|
|
|
H,
|
|
|
|
L,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct Registers {
|
|
|
|
pub af: u16,
|
|
|
|
pub bc: u16,
|
|
|
|
pub de: u16,
|
|
|
|
pub hl: u16,
|
|
|
|
pub sp: u16,
|
|
|
|
pub pc: u16,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for Registers {
|
|
|
|
fn default() -> Self {
|
|
|
|
// default post-bootrom values
|
|
|
|
Self {
|
|
|
|
af: 0x00B0,
|
|
|
|
// af: 0x01B0,
|
|
|
|
bc: 0x0013,
|
|
|
|
de: 0x00D8,
|
|
|
|
hl: 0x014D,
|
|
|
|
sp: 0xFFFE,
|
|
|
|
pc: 0x0100,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Registers {
|
|
|
|
fn get_8(&self, register: Reg8) -> u8 {
|
|
|
|
match register {
|
|
|
|
Reg8::A => self.af.get_high(),
|
|
|
|
Reg8::F => self.af.get_low(),
|
|
|
|
Reg8::B => self.bc.get_high(),
|
|
|
|
Reg8::C => self.bc.get_low(),
|
|
|
|
Reg8::D => self.de.get_high(),
|
|
|
|
Reg8::E => self.de.get_low(),
|
|
|
|
Reg8::H => self.hl.get_high(),
|
|
|
|
Reg8::L => self.hl.get_low(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn set_8(&mut self, register: Reg8, val: u8) {
|
|
|
|
match register {
|
|
|
|
Reg8::A => self.af.set_high(val),
|
|
|
|
Reg8::F => self.af.set_low(val),
|
|
|
|
Reg8::B => self.bc.set_high(val),
|
|
|
|
Reg8::C => self.bc.set_low(val),
|
|
|
|
Reg8::D => self.de.set_high(val),
|
|
|
|
Reg8::E => self.de.set_low(val),
|
|
|
|
Reg8::H => self.hl.set_high(val),
|
|
|
|
Reg8::L => self.hl.set_low(val),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trait SplitRegister {
|
|
|
|
fn get_low(&self) -> u8;
|
|
|
|
fn get_high(&self) -> u8;
|
|
|
|
fn set_low(&mut self, val: u8);
|
|
|
|
fn set_high(&mut self, val: u8);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SplitRegister for u16 {
|
|
|
|
fn get_low(&self) -> u8 {
|
|
|
|
(*self & 0xFF) as u8
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_high(&self) -> u8 {
|
|
|
|
((*self >> 8) & 0xFF) as u8
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_low(&mut self, val: u8) {
|
|
|
|
*self = (*self & !0xff) | val as u16;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_high(&mut self, val: u8) {
|
|
|
|
*self = (*self & !0xff00) | (val as u16) << 8;
|
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)
|
|
|
|
}
|