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, sync::RwLock,
}; };
use crate::processor::Registers;
#[macro_export] #[macro_export]
macro_rules! verbose_println { macro_rules! verbose_println {
($($tts:tt)*) => { ($($tts:tt)*) => {
@ -61,18 +63,6 @@ struct Args {
type Address = u16; type Address = u16;
type ROM = Vec<u8>; 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)] #[allow(dead_code)]
pub struct Memory { pub struct Memory {
bootrom: ROM, 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) { fn cpu_ram_init(cpu: &mut CPU) {
cpu.memory.set(0xFF10, 0x80); cpu.memory.set(0xFF10, 0x80);
cpu.memory.set(0xFF11, 0xBF); cpu.memory.set(0xFF11, 0xBF);
@ -288,21 +253,21 @@ fn main() {
let rom: ROM = fs::read(args.rom).expect("Could not load ROM"); 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 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 { if args.run_bootrom {
state.pc = Register { as_u16: 0x0 }; reg.pc = 0x0;
} }
let mut cpu = CPU { let mut cpu = CPU {
memory: Memory::init(bootrom, args.run_bootrom, rom), memory: Memory::init(bootrom, args.run_bootrom, rom),
state, reg,
last_instruction: 0x0, last_instruction: 0x0,
last_instruction_addr: 0x0, last_instruction_addr: 0x0,
}; };
cpu_ram_init(&mut cpu); cpu_ram_init(&mut cpu);
let mut cycle_num = 0; let mut cycle_num = 0;
let mut instructions_seen = vec![]; 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; let mut next_state = last_state;
verbose_println!("\n\n Begin execution...\n"); verbose_println!("\n\n Begin execution...\n");
@ -344,8 +309,8 @@ fn main() {
fn run_cycle( fn run_cycle(
cpu: &mut CPU, cpu: &mut CPU,
next_state: &mut State, next_state: &mut Registers,
last_state: &mut State, last_state: &mut Registers,
instructions_seen: &mut Vec<u8>, instructions_seen: &mut Vec<u8>,
) { ) {
let will_pause; let will_pause;
@ -354,9 +319,9 @@ fn run_cycle(
} }
cpu.exec_next(); cpu.exec_next();
unsafe { unsafe {
*next_state = cpu.state; *next_state = cpu.reg;
if !PAUSE_ENABLED { if !PAUSE_ENABLED {
if next_state.pc.as_u16 >= 0x100 { if next_state.pc >= 0x100 {
PAUSE_ENABLED = true; 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 { 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 { pub(crate) fn rlc(&mut self, byte: u8) -> u8 {
self.rotate_c(byte, Direction::Left) self.rotate_c(byte, Direction::Left)
} }
@ -35,9 +61,9 @@ impl CPU {
self.shift(byte, Direction::Right) self.shift(byte, Direction::Right)
} }
pub(crate) fn rst(&mut self, address: u16) { pub(crate) fn rst(&mut self, address: u8) {
self.push(self.state.pc); self.push(self.reg.pc);
self.state.pc.as_u8s.left = 0x0; self.reg.pc.set_high(0x0);
self.state.pc.as_u8s.right = self.memory.get(address); self.reg.pc.set_low(address);
} }
} }

View file

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

View file

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