basic flag setting and add some testcases
This commit is contained in:
parent
d6bec3fa88
commit
0638bcf635
162
src/emu.rs
162
src/emu.rs
|
|
@ -21,30 +21,7 @@ pub struct GameBoy {
|
||||||
bp_manager: BreakPointManager,
|
bp_manager: BreakPointManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(a: u8, b: u8) -> u8 {
|
#[derive(Clone, Copy, Debug)]
|
||||||
if std::u8::MAX - b < a {
|
|
||||||
((a as u16 + b as u16) - std::u8::MAX as u16) as u8 - 1
|
|
||||||
} else {
|
|
||||||
a + b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sub(a: u8, b: u8) -> u8 {
|
|
||||||
if a < b {
|
|
||||||
std::u8::MAX - (b - a) + 1
|
|
||||||
} else {
|
|
||||||
a - b
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_inplace(a: &mut u8, b: u8) {
|
|
||||||
*a = add(*a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sub_inplace(a: &mut u8, b: u8) {
|
|
||||||
*a = sub(*a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Flag {
|
enum Flag {
|
||||||
Z, N, H ,CY
|
Z, N, H ,CY
|
||||||
}
|
}
|
||||||
|
|
@ -53,12 +30,36 @@ fn flag_set(f: Flag, v: u8) -> bool {
|
||||||
use Flag::*;
|
use Flag::*;
|
||||||
match f {
|
match f {
|
||||||
Z => v << 0 >> 7 == 1,
|
Z => v << 0 >> 7 == 1,
|
||||||
N => v << 1 >> 6 == 1,
|
N => v << 1 >> 7 == 1,
|
||||||
H => v << 2 >> 5 == 1,
|
H => v << 2 >> 7 == 1,
|
||||||
CY => v << 3 >> 4 == 1,
|
CY => v << 3 >> 7 == 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_noflag(a: u8, b: u8) -> u8 {
|
||||||
|
if std::u8::MAX - b < a {
|
||||||
|
((a as u16 + b as u16) - std::u8::MAX as u16) as u8 - 1
|
||||||
|
} else {
|
||||||
|
a + b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sub_noflag(a: u8, b: u8) -> u8 {
|
||||||
|
if a < b {
|
||||||
|
std::u8::MAX - (b - a) + 1
|
||||||
|
} else {
|
||||||
|
a - b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_inplace(a: &mut u8, b: u8) {
|
||||||
|
*a = add_noflag(*a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sub_inplace(a: &mut u8, b: u8) {
|
||||||
|
*a = sub_noflag(*a, b)
|
||||||
|
}
|
||||||
|
|
||||||
impl GameBoy {
|
impl GameBoy {
|
||||||
pub fn new() -> GameBoy {
|
pub fn new() -> GameBoy {
|
||||||
GameBoy {
|
GameBoy {
|
||||||
|
|
@ -73,6 +74,31 @@ impl GameBoy {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn add(&mut self, a: u8, b: u8) -> u8 {
|
||||||
|
let val = add_noflag(a, b);
|
||||||
|
println!("{}", val);
|
||||||
|
|
||||||
|
self.set_flag(Flag::Z, val == 0);
|
||||||
|
self.set_flag(Flag::N, false);
|
||||||
|
self.set_flag(Flag::H, false); // FIXME
|
||||||
|
self.set_flag(Flag::CY, false); // FIXME
|
||||||
|
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sub(&mut self, a: u8, b: u8) -> u8 {
|
||||||
|
let val = sub_noflag(a, b);
|
||||||
|
|
||||||
|
self.set_flag(Flag::Z, val == 0);
|
||||||
|
self.set_flag(Flag::N, true);
|
||||||
|
self.set_flag(Flag::H, false); // FIXME
|
||||||
|
self.set_flag(Flag::CY, false); // FIXME
|
||||||
|
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn set(adr: u16, val: u8) {
|
fn set(adr: u16, val: u8) {
|
||||||
// check for special registers
|
// check for special registers
|
||||||
}
|
}
|
||||||
|
|
@ -80,12 +106,13 @@ impl GameBoy {
|
||||||
fn set_flag(&mut self, f: Flag, v: bool) {
|
fn set_flag(&mut self, f: Flag, v: bool) {
|
||||||
let r = &mut self.reg[Register::F];
|
let r = &mut self.reg[Register::F];
|
||||||
let v = v as u8;
|
let v = v as u8;
|
||||||
|
//println!("setting {f:?}: {v}");
|
||||||
use Flag::*;
|
use Flag::*;
|
||||||
match f {
|
match f {
|
||||||
Z => *r = v << 7,
|
Z => *r = (v << 7) | (*r & 0b0111_1111),
|
||||||
N => *r = v << 6,
|
N => *r = (v << 6) | (*r & 0b1011_1111),
|
||||||
H => *r = v << 5,
|
H => *r = (v << 5) | (*r & 0b1101_1111),
|
||||||
CY => *r = v << 4
|
CY => *r = (v << 4) | (*r & 0b1110_1111),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,7 +305,8 @@ impl GameBoy {
|
||||||
BpCommand::Kill => panic!("kill from breakpoint"),
|
BpCommand::Kill => panic!("kill from breakpoint"),
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("pc:{pc:#08x}:{win:02x?} {op:?}");
|
let regs = &self.reg[..8];
|
||||||
|
println!("\u{1B}[1;31mpc:{pc:#08x}:{win:02x?} {op:?} {regs:?}\u{1B}[0m");
|
||||||
|
|
||||||
match op.inst {
|
match op.inst {
|
||||||
Unimpl(instr) => {
|
Unimpl(instr) => {
|
||||||
|
|
@ -318,6 +346,8 @@ impl GameBoy {
|
||||||
println!("jr {new_pc:#06x} <- {old_pc:#06x} + {e}");
|
println!("jr {new_pc:#06x} <- {old_pc:#06x} + {e}");
|
||||||
// TODO remember cycle count 3 for jump, 2 for not!!!
|
// TODO remember cycle count 3 for jump, 2 for not!!!
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
println!("jr cond not met");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Call => {
|
Call => {
|
||||||
|
|
@ -355,14 +385,14 @@ impl GameBoy {
|
||||||
}
|
}
|
||||||
Inc(dst) => {
|
Inc(dst) => {
|
||||||
match dst {
|
match dst {
|
||||||
ValSrc::Reg(reg) => add_inplace(&mut self.reg[reg], 1),
|
ValSrc::Reg(reg) => self.reg[reg] = self.add(self.reg[reg], 1),
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
println!("Inc {dst:?}");
|
println!("Inc {dst:?}");
|
||||||
}
|
}
|
||||||
Dec(dst) => {
|
Dec(dst) => {
|
||||||
match dst {
|
match dst {
|
||||||
ValSrc::Reg(reg) => sub_inplace(&mut self.reg[reg], 1),
|
ValSrc::Reg(reg) => self.reg[reg] = self.sub(self.reg[reg], 1),
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
}
|
}
|
||||||
println!("Dec {dst:?}");
|
println!("Dec {dst:?}");
|
||||||
|
|
@ -402,25 +432,55 @@ impl GameBoy {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
// #[test]
|
#[test]
|
||||||
// fn add_overflow() {
|
fn add_overflow() {
|
||||||
// use crate::emu::add;
|
let mut gb = crate::emu::GameBoy::new();
|
||||||
// assert_eq!(add(1, 1), 2);
|
|
||||||
|
|
||||||
// assert_eq!(add(std::u8::MAX, 1), 0);
|
assert_eq!(gb.add(1, 1), 2);
|
||||||
// assert_eq!(add(std::u8::MAX, 2), 1);
|
|
||||||
// assert_eq!(add(1, std::u8::MAX), 0);
|
|
||||||
|
|
||||||
// assert_eq!(add(std::u8::MAX - 3, 3), std::u8::MAX);
|
assert_eq!(gb.add(std::u8::MAX, 1), 0);
|
||||||
// assert_eq!(add(3, std::u8::MAX - 3), std::u8::MAX);
|
assert_eq!(gb.add(std::u8::MAX, 2), 1);
|
||||||
// }
|
assert_eq!(gb.add(1, std::u8::MAX), 0);
|
||||||
|
|
||||||
// #[test]
|
assert_eq!(gb.add(std::u8::MAX - 3, 3), std::u8::MAX);
|
||||||
// fn sub_underflow() {
|
assert_eq!(gb.add(3, std::u8::MAX - 3), std::u8::MAX);
|
||||||
// use crate::emu::sub;
|
}
|
||||||
// assert_eq!(sub(1, 1), 0);
|
|
||||||
// assert_eq!(sub(1, 2), std::u8::MAX);
|
#[test]
|
||||||
// assert_eq!(sub(1, 3), std::u8::MAX - 1);
|
fn sub_underflow() {
|
||||||
// }
|
let mut gb = crate::emu::GameBoy::new();
|
||||||
|
|
||||||
|
assert_eq!(gb.sub(1, 1), 0);
|
||||||
|
assert_eq!(gb.sub(1, 2), std::u8::MAX);
|
||||||
|
assert_eq!(gb.sub(1, 3), std::u8::MAX - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn flag_check() {
|
||||||
|
let mut gb = crate::emu::GameBoy::new();
|
||||||
|
|
||||||
|
use crate::emu::*;
|
||||||
|
|
||||||
|
for f in [Flag::Z, Flag::N, Flag::H, Flag::CY] {
|
||||||
|
assert!(!flag_set(f, gb.reg[Register::F]));
|
||||||
|
gb.set_flag(f, true);
|
||||||
|
assert!(flag_set(f, gb.reg[Register::F]));
|
||||||
|
gb.set_flag(f, false);
|
||||||
|
assert!(!flag_set(f, gb.reg[Register::F]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn flag_set() {
|
||||||
|
use crate::emu::*;
|
||||||
|
|
||||||
|
let mut gb = GameBoy::new();
|
||||||
|
|
||||||
|
assert!(!flag_set(Flag::Z, gb.reg[Register::F]));
|
||||||
|
gb.add(std::u8::MAX - 1 , 1);
|
||||||
|
assert!(!flag_set(Flag::Z, gb.reg[Register::F]));
|
||||||
|
gb.add(std::u8::MAX, 1);
|
||||||
|
assert!(flag_set(Flag::Z, gb.reg[Register::F]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue