new register layout

This commit is contained in:
Alex Janka 2023-02-01 17:18:08 +11:00
parent 3a599b069f
commit fffb6e0278
5 changed files with 542 additions and 1312 deletions

View file

@ -10,6 +10,8 @@ use std::{
sync::RwLock,
};
use crate::processor::Registers;
#[macro_export]
macro_rules! verbose_println {
($($tts:tt)*) => {
@ -61,18 +63,6 @@ struct Args {
type Address = u16;
type ROM = Vec<u8>;
#[derive(Clone, Copy)]
struct Inner {
left: u8,
right: u8,
}
#[derive(Clone, Copy)]
union Register {
as_u8s: Inner,
as_u16: u16,
}
#[allow(dead_code)]
pub struct Memory {
bootrom: ROM,
@ -215,31 +205,6 @@ impl Memory {
}
}
#[derive(Clone, Copy)]
pub struct State {
af: Register,
bc: Register,
de: Register,
hl: Register,
sp: Register,
pc: Register,
}
impl Default for State {
fn default() -> Self {
// default post-bootrom values
Self {
af: Register { as_u16: 0x00B0 },
// af: Register { as_u16: 0x01B0 },
bc: Register { as_u16: 0x0013 },
de: Register { as_u16: 0x00D8 },
hl: Register { as_u16: 0x014D },
sp: Register { as_u16: 0xFFFE },
pc: Register { as_u16: 0x0100 },
}
}
}
fn cpu_ram_init(cpu: &mut CPU) {
cpu.memory.set(0xFF10, 0x80);
cpu.memory.set(0xFF11, 0xBF);
@ -288,21 +253,21 @@ fn main() {
let rom: ROM = fs::read(args.rom).expect("Could not load ROM");
let bootrom: ROM = fs::read(args.bootrom).expect("Could not load BootROM");
let mut state = State::default();
let mut reg = Registers::default();
if args.run_bootrom {
state.pc = Register { as_u16: 0x0 };
reg.pc = 0x0;
}
let mut cpu = CPU {
memory: Memory::init(bootrom, args.run_bootrom, rom),
state,
reg,
last_instruction: 0x0,
last_instruction_addr: 0x0,
};
cpu_ram_init(&mut cpu);
let mut cycle_num = 0;
let mut instructions_seen = vec![];
let mut last_state = cpu.state.clone();
let mut last_state = cpu.reg.clone();
let mut next_state = last_state;
verbose_println!("\n\n Begin execution...\n");
@ -344,8 +309,8 @@ fn main() {
fn run_cycle(
cpu: &mut CPU,
next_state: &mut State,
last_state: &mut State,
next_state: &mut Registers,
last_state: &mut Registers,
instructions_seen: &mut Vec<u8>,
) {
let will_pause;
@ -354,9 +319,9 @@ fn run_cycle(
}
cpu.exec_next();
unsafe {
*next_state = cpu.state;
*next_state = cpu.reg;
if !PAUSE_ENABLED {
if next_state.pc.as_u16 >= 0x100 {
if next_state.pc >= 0x100 {
PAUSE_ENABLED = true;
}
}

View file

@ -1,6 +1,32 @@
use crate::processor::{get_bit, Direction, CPU};
use crate::processor::{get_bit, Direction, SplitRegister, CPU, FLAGS};
impl CPU {
pub(crate) fn add(&mut self, first: u8, second: u8) -> u8 {
self.add_u8s(first, second)
}
pub(crate) fn adc(&mut self, first: u8, second: u8) -> u8 {
let val = second + self.get_flag(FLAGS::Carry);
self.add_u8s(first, val)
}
pub(crate) fn sub(&mut self, first: u8, second: u8) -> u8 {
self.sub_u8s(first, second)
}
pub(crate) fn sbc(&mut self, first: u8, second: u8) -> u8 {
let val = second + self.get_flag(FLAGS::Carry);
self.sub_u8s(first, val)
}
pub(crate) fn inc(&mut self, val: u8) -> u8 {
self.add_u8s(val, 0x1)
}
pub(crate) fn dec(&mut self, val: u8) -> u8 {
self.sub_u8s(val, 0x1)
}
pub(crate) fn rlc(&mut self, byte: u8) -> u8 {
self.rotate_c(byte, Direction::Left)
}
@ -35,9 +61,9 @@ impl CPU {
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);
pub(crate) fn rst(&mut self, address: u8) {
self.push(self.reg.pc);
self.reg.pc.set_high(0x0);
self.reg.pc.set_low(address);
}
}

View file

@ -1,53 +1,41 @@
use std::ops::{BitAnd, BitOr, BitXor};
use crate::{
processor::{get_bit, get_rotation_carry, rotate, Direction, CPU, FLAGS},
verbose_println, Inner, Register,
processor::{get_bit, get_rotation_carry, rotate, Direction, SplitRegister, CPU, FLAGS},
verbose_println,
};
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 pop_word(&mut self) -> u16 {
let address = self.reg.sp;
self.reg.sp = self.reg.sp.wrapping_add(0x2);
let mut word: u16 = 0x0;
word.set_low(self.memory.get(address));
word.set_high(self.memory.get(address.wrapping_add(1)));
word
}
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 store_word(&mut self, address: u16, word: u16) {
// self.memory.set(address, word.get_high());
// self.memory.set(address + 1, word.get_low());
// }
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 push(&mut self, word: u16) {
let address = self.reg.sp;
self.memory.set(address.wrapping_sub(1), word.get_high());
self.memory.set(address.wrapping_sub(2), word.get_low());
self.reg.sp = 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 ld_immediate_word(&mut self) -> u16 {
let mut word: u16 = 0x0;
word.set_low(self.next_opcode());
word.set_high(self.next_opcode());
word
}
pub(crate) fn rotate_c(&mut self, byte: u8, direction: Direction) -> u8 {
@ -84,12 +72,10 @@ impl CPU {
}
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
}
if get_bit(self.reg.af.get_low(), flag as u8) {
0x1
} else {
0x0
}
}
@ -97,29 +83,29 @@ impl CPU {
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
);
};
verbose_println!(
"setting flag: currently {0:#b} / {0:#X}",
self.reg.af.get_low()
);
self.reg
.af
.set_low(self.reg.af.get_low().bitor(1 << flag as u8));
verbose_println!(
" now {0:#b} / {0:#X}",
self.reg.af.get_low()
);
}
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));
};
self.reg
.af
.set_low(self.reg.af.get_low().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);
};
self.reg
.af
.set_low(self.reg.af.get_low().bitxor(1 << flag as u8));
}
pub(crate) fn set_or_clear_flag(&mut self, flag: FLAGS, state: bool) {

View file

@ -1,6 +1,6 @@
use std::mem::transmute;
use crate::{verbose_println, Memory, State};
use crate::{verbose_println, Memory};
mod instructions;
mod opcodes;
@ -20,14 +20,14 @@ pub(crate) enum Direction {
pub struct CPU {
pub memory: Memory,
pub state: State,
pub reg: Registers,
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 };
self.last_instruction_addr = self.reg.pc;
let opcode = self.next_opcode();
self.last_instruction = opcode;
verbose_println!(
@ -39,11 +39,97 @@ impl CPU {
}
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;
};
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;
}
}

File diff suppressed because it is too large Load diff