From d37699f4a82531418557b3fcb79152a575f89ca8 Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Mon, 11 Oct 2021 12:58:09 -0500 Subject: [PATCH] Functions and tests for some bitwise operations and getter/setter for flag register --- src/bin/main.rs | 3 +- src/cpu.rs | 58 ++++++++++++++++++++++++++++----- src/lib.rs | 1 + src/utils.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 src/utils.rs diff --git a/src/bin/main.rs b/src/bin/main.rs index e7a11a9..a16f297 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,3 +1,4 @@ fn main() { - println!("Hello, world!"); + println!("TEST"); + println!("{}", false as u8); } diff --git a/src/cpu.rs b/src/cpu.rs index 121c44b..d4aede4 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,3 +1,5 @@ +use crate::utils::{BitIndex, get_bit, set_bit}; + pub enum Register { A(u8), // Accumulator F(u8), // Flags @@ -16,6 +18,13 @@ pub enum Register { PC(u16), } +pub enum FlagRegister { + Zero(bool), // Set when the result of a math operation is zero or if two values matches using the CP instruction + Substract(bool), // Set if a substraction was performed in the last math instruction + HalfCarry(bool), // Set if a carry ocurred from the lower nibble in the last math operation + Carry(bool), // Set if a carry was ocurrend from the last math operation or if register A is the smaller value when executing the CP instruction +} + pub struct Registers { a: u8, f: u8, @@ -30,6 +39,21 @@ pub struct Registers { } impl Registers { + pub fn new() -> Self { + Self { + a: 0, + f: 0b11110000, // The first 4 lower bits are always set to 0 + b: 0, + c: 0, + d: 0, + e: 0, + h: 0, + l: 0, + sp: 0, + pc: 0, + } + } + pub fn get(&self, register: Register) -> u16 { match register { Register::A(_) => self.a as u16, @@ -50,14 +74,14 @@ impl Registers { pub fn set(&mut self, register: Register) { match register { - Register::A(val) => self.a = val, - Register::B(val) => self.b = val, - Register::C(val) => self.c = val, - Register::D(val) => self.d = val, - Register::E(val) => self.e = val, - Register::F(val) => self.f = val, - Register::H(val) => self.h = val, - Register::L(val) => self.l = val, + Register::A(val) => self.a = val, + Register::B(val) => self.b = val, + Register::C(val) => self.c = val, + Register::D(val) => self.d = val, + Register::E(val) => self.e = val, + Register::F(val) => self.f = val, + Register::H(val) => self.h = val, + Register::L(val) => self.l = val, Register::BC(val) => self.set_bc(val), Register::DE(val) => self.set_de(val), Register::HL(val) => self.set_hl(val), @@ -66,6 +90,24 @@ impl Registers { } } + pub fn get_flag(&self, flag: FlagRegister) -> bool { + match flag { + FlagRegister::Zero(_) => get_bit(self.f, BitIndex::I7), + FlagRegister::Substract(_) => get_bit(self.f, BitIndex::I6), + FlagRegister::HalfCarry(_) => get_bit(self.f, BitIndex::I5), + FlagRegister::Carry(_) => get_bit(self.f, BitIndex::I4), + } + } + + pub fn set_flag(&mut self, flag: FlagRegister) { + match flag { + FlagRegister::Zero(val) => self.f = set_bit(self.f, val, BitIndex::I7), + FlagRegister::Substract(val) => self.f = set_bit(self.f, val, BitIndex::I6), + FlagRegister::HalfCarry(val) => self.f = set_bit(self.f, val, BitIndex::I5), + FlagRegister::Carry(val) => self.f = set_bit(self.f, val, BitIndex::I4), + } + } + fn get_bc(&self) -> u16 { ((self.b as u16) << 8) | (self.c as u16) } diff --git a/src/lib.rs b/src/lib.rs index 3bfb62f..2144f0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ +pub mod utils; pub mod cpu; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..77a2d7f --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,87 @@ +pub enum BitIndex { + I0, + I1, + I2, + I3, + I4, + I5, + I6, + I7, +} + +pub fn get_bit_index(index: BitIndex) -> u8 { + match index { + BitIndex::I0 => 0, + BitIndex::I1 => 1, + BitIndex::I2 => 2, + BitIndex::I3 => 3, + BitIndex::I4 => 4, + BitIndex::I5 => 5, + BitIndex::I6 => 6, + BitIndex::I7 => 7, + } +} + +pub fn get_bit(byte: u8, index: BitIndex) -> bool { + ((byte >> get_bit_index(index)) & 0b00000001) == 1 +} + +pub fn set_bit(byte: u8, value: bool, index: BitIndex) -> u8 { + match value { + true => 0b00000001 << get_bit_index(index) | byte, + false => ((0b0000001 << get_bit_index(index)) ^ 0b11111111) & byte, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_set_bit() { + assert_eq!(set_bit(0b00000000, true, BitIndex::I0), 0b00000001); + assert_eq!(set_bit(0b00000000, true, BitIndex::I1), 0b00000010); + assert_eq!(set_bit(0b00000000, true, BitIndex::I2), 0b00000100); + assert_eq!(set_bit(0b00000000, true, BitIndex::I3), 0b00001000); + assert_eq!(set_bit(0b00000000, true, BitIndex::I4), 0b00010000); + assert_eq!(set_bit(0b00000000, true, BitIndex::I5), 0b00100000); + assert_eq!(set_bit(0b00000000, true, BitIndex::I6), 0b01000000); + assert_eq!(set_bit(0b00000000, true, BitIndex::I7), 0b10000000); + + assert_eq!(set_bit(0b11111111, false, BitIndex::I0), 0b11111110); + assert_eq!(set_bit(0b11111111, false, BitIndex::I1), 0b11111101); + assert_eq!(set_bit(0b11111111, false, BitIndex::I2), 0b11111011); + assert_eq!(set_bit(0b11111111, false, BitIndex::I3), 0b11110111); + assert_eq!(set_bit(0b11111111, false, BitIndex::I4), 0b11101111); + assert_eq!(set_bit(0b11111111, false, BitIndex::I5), 0b11011111); + assert_eq!(set_bit(0b11111111, false, BitIndex::I6), 0b10111111); + assert_eq!(set_bit(0b11111111, false, BitIndex::I7), 0b01111111); + + // Just a couple of random test + assert_eq!(set_bit(0b00000001, true, BitIndex::I0), 0b00000001); + assert_eq!(set_bit(0b11101111, true, BitIndex::I4), 0b11111111); + assert_eq!(set_bit(0b11111110, false, BitIndex::I0), 0b11111110); + assert_eq!(set_bit(0b00010000, false, BitIndex::I4), 0b00000000); + } + + #[test] + fn test_get_bit() { + assert_eq!(get_bit(0b00000001, BitIndex::I0), true); + assert_eq!(get_bit(0b00000010, BitIndex::I1), true); + assert_eq!(get_bit(0b00000100, BitIndex::I2), true); + assert_eq!(get_bit(0b00001000, BitIndex::I3), true); + assert_eq!(get_bit(0b00010000, BitIndex::I4), true); + assert_eq!(get_bit(0b00100000, BitIndex::I5), true); + assert_eq!(get_bit(0b01000000, BitIndex::I6), true); + assert_eq!(get_bit(0b10000000, BitIndex::I7), true); + + assert_eq!(get_bit(0b11111110, BitIndex::I0), false); + assert_eq!(get_bit(0b11111101, BitIndex::I1), false); + assert_eq!(get_bit(0b11111011, BitIndex::I2), false); + assert_eq!(get_bit(0b11110111, BitIndex::I3), false); + assert_eq!(get_bit(0b11101111, BitIndex::I4), false); + assert_eq!(get_bit(0b11011111, BitIndex::I5), false); + assert_eq!(get_bit(0b10111111, BitIndex::I6), false); + assert_eq!(get_bit(0b01111111, BitIndex::I7), false); + } +}