new register layout
This commit is contained in:
parent
3a599b069f
commit
fffb6e0278
55
src/main.rs
55
src/main.rs
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue