Compare commits

...

3 commits

3 changed files with 84 additions and 34 deletions

View file

@ -1,4 +1,5 @@
use crate::{get_register, structs::set_register, EmulatorState, Register};
use crate::structs::{get_register_pair, set_register, set_register_pair};
use crate::{get_register, EmulatorState, Register};
/// Sets the condition code flags according to `result`. `flags` parameter
/// indicates which flags will be set, 0b1111 will set all (Z, S, C, P)
@ -20,7 +21,7 @@ fn set_cc(state: &mut EmulatorState, result: u16, flags: u8) {
/// Add values of `register` and `A`
pub fn add(register: Register, state: &mut EmulatorState) {
let result = get_register(&register, state) as u16 + state.a as u16;
let result = get_register(register, state) as u16 + state.a as u16;
set_cc(state, result, 0b1111);
state.a = (result & 0xff) as u8;
}
@ -34,7 +35,7 @@ pub fn adi(byte: u8, state: &mut EmulatorState) {
/// Add values of `register` and `A` and add +1 if carry bit is set
pub fn adc(register: Register, state: &mut EmulatorState) {
let result = get_register(&register, state) as u16 + state.a as u16 + u16::from(state.cc.c);
let result = get_register(register, state) as u16 + state.a as u16 + u16::from(state.cc.c);
set_cc(state, result, 0b1111);
state.a = (result & 0xff) as u8;
}
@ -48,30 +49,22 @@ pub fn aci(byte: u8, state: &mut EmulatorState) {
/// Double precision add - Add B&C, D&E or H&L to H&L
pub fn dad(register: Register, state: &mut EmulatorState) {
let num = match register {
Register::B => u16::from_le_bytes([state.c, state.b]),
Register::D => u16::from_le_bytes([state.e, state.d]),
Register::H => u16::from_le_bytes([state.l, state.h]),
Register::SP => state.sp,
_ => panic!("Cannot perform DAD on register {:?}", register),
};
let num = get_register_pair(register, state);
let (result, overflow) = num.overflowing_add(u16::from_le_bytes([state.l, state.h]));
state.cc.c = overflow;
state.h = (result >> 8) as u8;
state.l = result as u8;
set_register_pair(register, result, state);
}
/// Increase register
pub fn inr(register: Register, state: &mut EmulatorState) {
let (result, _) = get_register(&register, state).overflowing_add(1);
let (result, _) = get_register(register, state).overflowing_add(1);
set_cc(state, result as u16, 0b1101);
set_register(&register, result, state);
set_register(register, result, state);
}
/// Decrease register
pub fn dcr(register: Register, state: &mut EmulatorState) {
let (result, _) = get_register(&register, state).overflowing_sub(1);
let (result, _) = get_register(register, state).overflowing_sub(1);
set_cc(state, result as u16, 0b1101);
set_register(&register, result, state);
set_register(register, result, state);
}

View file

@ -58,6 +58,20 @@ fn tick(state: &mut EmulatorState) {
match instruction {
0x00 => {} // NOP
/* Special */
0xfb => state.ei = true, // EI
0xf3 => state.ei = false, // DI
0x76 => {
if state.ei {
todo!()
} else {
// HLT
println!("HLT called after DI; exiting.");
print_state(state);
std::process::exit(0);
}
}
/* Maths */
// INR
0x04 => arithmetic::inr(Register::B, state),
@ -90,20 +104,6 @@ fn tick(state: &mut EmulatorState) {
0xc6 => arithmetic::adi(next_byte(), state), // ADI
0xce => arithmetic::aci(next_byte(), state), // ACI
/* Special */
0xfb => state.ei = true, // EI
0xf3 => state.ei = false, // DI
0x76 => {
if state.ei {
todo!()
} else {
// HLT
println!("HLT called after DI; exiting.");
print_state(state);
std::process::exit(0);
}
}
_ => not_implemented(state),
}

View file

@ -1,5 +1,6 @@
use crate::MEMORY_SIZE;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct EmulatorState {
pub a: u8,
pub b: u8,
@ -21,6 +22,7 @@ pub struct EmulatorState {
pub memory: [u8; MEMORY_SIZE],
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct ConditionCodes {
/// Zero (Z), set if the result is zero.
pub z: bool,
@ -35,7 +37,7 @@ pub struct ConditionCodes {
// ac: bool,
}
#[derive(PartialEq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Register {
B,
C,
@ -63,7 +65,7 @@ pub fn register_from_num(b: u8) -> Register {
}
}
pub fn get_register(register: &Register, state: &EmulatorState) -> u8 {
pub fn get_register(register: Register, state: &EmulatorState) -> u8 {
match register {
Register::B => state.b,
Register::C => state.c,
@ -77,7 +79,7 @@ pub fn get_register(register: &Register, state: &EmulatorState) -> u8 {
}
}
pub fn set_register(register: &Register, value: u8, state: &mut EmulatorState) {
pub fn set_register(register: Register, value: u8, state: &mut EmulatorState) {
match register {
Register::B => state.b = value,
Register::C => state.c = value,
@ -91,6 +93,61 @@ pub fn set_register(register: &Register, value: u8, state: &mut EmulatorState) {
};
}
pub fn get_register_pair(register: Register, state: &mut EmulatorState) -> u16 {
match register {
Register::B => u16::from_le_bytes([state.c, state.b]),
Register::D => u16::from_le_bytes([state.e, state.d]),
Register::H => u16::from_le_bytes([state.l, state.h]),
Register::A => {
// the PSW looks like this: SZ0A0P1C
let flags: u8 = u8::from(state.cc.s) << 7 // bit 7
| u8::from(state.cc.z) << 6 // bit 6
//| u8::from(state.cc.a) << 4 // bit 4
| u8::from(state.cc.p) << 2 // bit 2
| 0x02 // bit 1
| u8::from(state.cc.c); // bit 0
u16::from_le_bytes([flags, state.a])
}
Register::SP => state.sp,
_ => unreachable!(),
}
}
pub fn set_register_pair(register: Register, value: u16, state: &mut EmulatorState) {
let arr = value.to_le_bytes();
let high = arr[1];
let low = arr[0];
match register {
Register::B => {
state.b = high;
state.c = low;
}
Register::D => {
state.d = high;
state.e = low;
}
Register::H => {
state.h = high;
state.l = low;
}
Register::A => {
state.a = high;
// the PSW looks like this: SZ0A0P1C
state.cc.s = low & 0b1000_0000 > 0;
state.cc.z = low & 0b0100_0000 > 0;
debug_assert!(low & 0b0010_0000 == 0, "malformed PSW");
//state.cc.a = low & 0b0001_0000 > 0;
debug_assert!(low & 0b0000_1000 == 0, "malformed PSW");
state.cc.p = low & 0b0000_0100 > 0;
debug_assert!(low & 0b0000_0010 > 0, "malformed PSW");
state.cc.c = low & 0b0000_0001 > 0;
}
Register::SP => state.sp = value,
_ => unreachable!(),
}
}
/// Print values of registers and flags to stdout
pub fn print_state(state: &EmulatorState) {
// State