Skip to content

Commit

Permalink
squash some bugs and pass test rom #4
Browse files Browse the repository at this point in the history
  • Loading branch information
pcasaretto committed Apr 26, 2024
1 parent 1badc3a commit 1b17f77
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 24 deletions.
40 changes: 32 additions & 8 deletions src/instructions/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ pub fn adc(target: RegisterTarget) -> impl Fn(&mut Gameboy) -> u8 {
}

pub fn adc_n8(gameboy: &mut Gameboy) -> u8 {
let mut addend = gameboy.read_next_byte();
let addend = gameboy.read_next_byte();
let current_value = gameboy.cpu.registers.a;
if gameboy.cpu.registers.f.carry {
addend += 1;
}
let (new_value, did_overflow) = current_value.overflowing_add(addend);
gameboy.cpu.registers.a = new_value;

gameboy.cpu.registers.f.carry = did_overflow;
let carry_in = if gameboy.cpu.registers.f.carry { 1 } else { 0 };
let new_value = current_value.wrapping_add(addend).wrapping_add(carry_in);
let carry = (current_value as u16 + addend as u16 + carry_in as u16) > 0xFF;
let half_carry = ((current_value & 0xF) + (addend & 0xF) + carry_in) > 0xF;

gameboy.cpu.registers.a = new_value;
gameboy.cpu.registers.f.carry = carry;
gameboy.cpu.registers.f.subtract = false;
gameboy.cpu.registers.f.zero = new_value == 0;
gameboy.cpu.registers.f.half_carry = (current_value & 0xF) + (addend & 0xF) > 0xF;
gameboy.cpu.registers.f.half_carry = half_carry;
const TICKS: u8 = 8;
TICKS
}
Expand Down Expand Up @@ -307,4 +308,27 @@ mod tests {
adc_mem_at_hl(&mut gameboy);
assert!(gameboy.cpu.registers.f.half_carry);
}

#[test]
fn test_adc_n8_half_carry_flag() {
let mut gameboy = Gameboy::default();
gameboy.cpu.registers.pc = 0xC050;
gameboy.cpu.registers.a = 0x00;
gameboy.bus.write_byte(0xC051, 0x0F);
gameboy.cpu.registers.f.carry = true;
adc_n8(&mut gameboy);
gameboy.cpu.registers.a = 0x10;
assert!(gameboy.cpu.registers.f.half_carry);
}

#[test]
fn test_adc_n8_half_carry_flag_2() {
let mut gameboy = Gameboy::default();
gameboy.cpu.registers.pc = 0xC050;
gameboy.cpu.registers.a = 0xFF;
gameboy.bus.write_byte(0xC051, 0x01);
adc_n8(&mut gameboy);
gameboy.cpu.registers.a = 0x00;
assert!(gameboy.cpu.registers.f.half_carry);
}
}
25 changes: 25 additions & 0 deletions src/instructions/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,31 @@ pub fn add_hl_r16(target: Register16bTarget) -> impl Fn(&mut Gameboy) -> u8 {
}
}

pub fn add_sp_n8(gameboy: &mut Gameboy) -> u8 {
let n8 = gameboy.read_next_byte() as i8;
let sp = gameboy.cpu.registers.sp;

let (result, carry, half_carry) = if n8 < 0 {
let t = n8.abs() as u16;
let carry = false;
let half_carry = false;
(sp.wrapping_sub(t), carry, half_carry)
} else {
let carry = sp as u8 > 0xFF - n8 as u8;
let half_carry = sp as u8 & 0xF + n8 as u8 & 0xF > 0xF;
(sp.wrapping_add(n8 as u16), carry, half_carry)
};

gameboy.cpu.registers.sp = result;

gameboy.cpu.registers.f.zero = false;
gameboy.cpu.registers.f.subtract = false;
gameboy.cpu.registers.f.half_carry = half_carry;
gameboy.cpu.registers.f.carry = carry;
const TICKS: u8 = 16;
TICKS
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
10 changes: 8 additions & 2 deletions src/instructions/ld.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,8 @@ pub fn ld_hl_sp_n8(gameboy: &mut Gameboy) -> u8 {

let (result, carry, half_carry) = if n < 0 {
let t = n.abs() as u16;
let carry = sp <= t;
let half_carry = (sp & 0xF) <= (t & 0xF);
let carry = false;
let half_carry = false;
(sp.wrapping_sub(t), carry, half_carry)
} else {
let carry = sp as u8 > 0xFF - n as u8;
Expand Down Expand Up @@ -261,6 +261,12 @@ mod tests {

gameboy.cpu.registers.pc = 0xC050;
gameboy.cpu.registers.sp = 0xDFFD;
gameboy.bus.write_byte(0xC051, 0x03);
ld_hl_sp_n8(&mut gameboy);
assert!(gameboy.cpu.registers.f.carry);

gameboy.cpu.registers.pc = 0xC050;
gameboy.cpu.registers.sp = 0xDF01;
gameboy.bus.write_byte(0xC051, 0xFE);
ld_hl_sp_n8(&mut gameboy);
assert!(gameboy.cpu.registers.f.carry);
Expand Down
1 change: 1 addition & 0 deletions src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ pub fn from_byte(byte: u8) -> Box<Instruction> {
0xF3 => Box::new(pai(int::di)),
0xFB => Box::new(pai(int::ei)),

0xE8 => Box::new(pai(add::add_sp_n8)),
0xF8 => Box::new(pai(ld::ld_hl_sp_n8)),
0xF9 => Box::new(pai(ld::ld_sp_hl)),

Expand Down
67 changes: 53 additions & 14 deletions src/instructions/sbc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,20 @@ pub fn sbc_r_r_a(target: RegisterTarget) -> impl Fn(&mut Gameboy) -> u8 {
}

pub fn sbc_n8(gameboy: &mut Gameboy) -> u8 {
let addr = gameboy.cpu.registers.get_u16(Register16bTarget::PC);
let mut d8 = gameboy.bus.read_byte(addr);
if gameboy.cpu.registers.f.carry {
d8 += 1;
}
let operand = gameboy.read_next_byte();
let current_value = gameboy.cpu.registers.get_u8(RegisterTarget::A);
let (new_value, did_overflow) = current_value.overflowing_sub(d8);

let borrow_in = if gameboy.cpu.registers.f.carry { 1 } else { 0 };
let (new_value, first_overflow) = current_value.overflowing_sub(operand);
let (new_value, second_overflow) = new_value.overflowing_sub(borrow_in);
let half_borrow = (current_value & 0xF) < (operand & 0xF) + borrow_in;

gameboy.cpu.registers.a = new_value;

gameboy.cpu.registers.f.carry = did_overflow;
gameboy.cpu.registers.f.carry = first_overflow || second_overflow;
gameboy.cpu.registers.f.zero = new_value == 0;
gameboy.cpu.registers.f.subtract = true;
gameboy.cpu.registers.f.half_carry = (current_value & 0xF) < (d8 & 0xF);
gameboy.cpu.registers.f.half_carry = half_borrow;
const TICKS: u8 = 8;
TICKS
}
Expand Down Expand Up @@ -178,7 +179,7 @@ mod tests {
cpu: CPU {
registers: Registers {
a: 4,
pc: 0xC051,
pc: 0xC050,
f: FlagsRegister::from(0),
..Default::default()
},
Expand All @@ -196,7 +197,7 @@ mod tests {
let mut gameboy = Gameboy {
cpu: CPU {
registers: Registers {
pc: 0xC051,
pc: 0xC050,
a: 4,
f: FlagsRegister::from(0),
..Default::default()
Expand All @@ -216,7 +217,7 @@ mod tests {
cpu: CPU {
registers: Registers {
a: 4,
pc: 0xC051,
pc: 0xC050,
f: FlagsRegister::from(0),
..Default::default()
},
Expand All @@ -229,12 +230,50 @@ mod tests {
assert!(gameboy.cpu.registers.f.carry);
}

#[test]
fn test_sbc_n8_carry_flag_2() {
let mut gameboy = Gameboy {
cpu: CPU {
registers: Registers {
a: 0,
pc: 0xC050,
f: FlagsRegister::from(0),
..Default::default()
},
..Default::default()
},
..Default::default()
};
gameboy.bus.memory[0xC051] = 0xF0;
sbc_n8(&mut gameboy);
assert!(gameboy.cpu.registers.f.carry);
}

#[test]
fn test_sbc_n8_carry_flag_3() {
let mut gameboy = Gameboy {
cpu: CPU {
registers: Registers {
a: 0,
pc: 0xC050,
f: FlagsRegister::from(0b0010000),
..Default::default()
},
..Default::default()
},
..Default::default()
};
gameboy.bus.memory[0xC051] = 0xFF;
sbc_n8(&mut gameboy);
assert!(gameboy.cpu.registers.f.carry);
}

#[test]
fn test_sbc_n8_zero_flag() {
let mut gameboy = Gameboy {
cpu: CPU {
registers: Registers {
pc: 0xC051,
pc: 0xC050,
a: 5,
f: FlagsRegister::from(0),
..Default::default()
Expand All @@ -253,7 +292,7 @@ mod tests {
let mut gameboy = Gameboy {
cpu: CPU {
registers: Registers {
pc: 0xC051,
pc: 0xC050,
a: 5,
f: FlagsRegister::from(0),
..Default::default()
Expand All @@ -272,7 +311,7 @@ mod tests {
let mut gameboy = Gameboy {
cpu: CPU {
registers: Registers {
pc: 0xC051,
pc: 0xC050,
a: 0b00010000,
f: FlagsRegister::from(0),
..Default::default()
Expand Down

0 comments on commit 1b17f77

Please sign in to comment.