Skip to content

Commit

Permalink
cpu: implement push & pop
Browse files Browse the repository at this point in the history
  • Loading branch information
choffmann committed May 13, 2024
1 parent c510a02 commit 491aa17
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 1 deletion.
12 changes: 12 additions & 0 deletions gameboy-lib/src/cpu/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub enum Instruction {
LdAn, // Load $FF00 + n into A
LdHi, // Load A into HL + 1
LdHd, // Load A into HL - 1
Push(Register), // Push register onto stack
Pop(Register), // Pop register from stack
}

impl Instruction {
Expand Down Expand Up @@ -139,6 +141,16 @@ impl Instruction {
0xF8 => Some(Instruction::Ld16(Register::SP, Register::D8)),
0x08 => Some(Instruction::Ld16(Register::D16, Register::SP)),

0xF5 => Some(Instruction::Push(Register::AF)),
0xC5 => Some(Instruction::Push(Register::BC)),
0xD5 => Some(Instruction::Push(Register::DE)),
0xE5 => Some(Instruction::Push(Register::HL)),

0xF1 => Some(Instruction::Pop(Register::AF)),
0xC1 => Some(Instruction::Pop(Register::BC)),
0xD1 => Some(Instruction::Pop(Register::DE)),
0xE1 => Some(Instruction::Pop(Register::HL)),

_ => None,
}
}
Expand Down
63 changes: 62 additions & 1 deletion gameboy-lib/src/cpu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,32 @@ impl Cpu {
| Instruction::LdAn
| Instruction::LdHi
| Instruction::LdHd => self.load_special(instruction),
Instruction::Push(register) => self.push(register),
Instruction::Pop(register) => self.pop(register),
_ => panic!("[CPU] Not implementet {:?}", instruction),
}
}

fn push(&mut self, register: Register) -> u16 {
let value = self.registers.get_16(&register);
self.registers
.sp
.set(self.registers.sp.get().wrapping_sub(2));
self.memory.write_16(self.registers.sp.get(), value);

self.pc.wrapping_add(1)
}

fn pop(&mut self, register: Register) -> u16 {
let value = self.memory.read_16(self.registers.sp.get());
self.registers.set_16(&register, value);
self.registers
.sp
.set(self.registers.sp.get().wrapping_add(2));

self.pc.wrapping_add(1)
}

fn load_8(&mut self, instruction: Instruction) -> u16 {
match instruction {
Instruction::Ld8(to, from) => match (&to, &from) {
Expand Down Expand Up @@ -126,7 +148,12 @@ impl Cpu {
(Register::SP, Register::D8) => {
let n = self.memory.read(self.pc + 1) as u16;
let address = self.registers.sp.get().wrapping_add(n);
println!("[CPU] SP: 0x{:x} + 0x{:x} = 0x{:x}", self.registers.sp.get(), n, address);
println!(
"[CPU] SP: 0x{:x} + 0x{:x} = 0x{:x}",
self.registers.sp.get(),
n,
address
);
self.registers.set_16(&Register::HL, address);

self.registers.f.zero = false;
Expand Down Expand Up @@ -606,4 +633,38 @@ mod tests {
assert_eq!(cpu.registers.f.half_carry, true);
assert_eq!(cpu.registers.f.carry, false);
}

#[test]
fn execute_push_pop() {
let mut cpu = Cpu::new();
cpu.registers.set_16(&Register::BC, 0x1234);
cpu.registers.set_16(&Register::DE, 0x5678);
cpu.registers.set_16(&Register::HL, 0x9ABC);
cpu.registers.set_16(&Register::AF, 0xAA55);
cpu.registers.sp.set(0xFFFE);

cpu.boot(vec![0xC5, 0xD5, 0xE5, 0xF5, 0xF1, 0xC1, 0xD1, 0xE1]);
cpu.step();
assert_eq!(cpu.memory.read_16(0xFFFC), 0x1234);
cpu.step();
assert_eq!(cpu.memory.read_16(0xFFFA), 0x5678);
cpu.step();
assert_eq!(cpu.memory.read_16(0xFFF8), 0x9ABC);
cpu.step();
assert_eq!(cpu.memory.read_16(0xFFF6), 0xAA55);

cpu.registers.set_16(&Register::BC, 0x0000);
cpu.registers.set_16(&Register::DE, 0x0000);
cpu.registers.set_16(&Register::HL, 0x0000);
cpu.registers.set_16(&Register::AF, 0x0000);

cpu.step();
assert_eq!(cpu.registers.get_16(&Register::AF), 0xAA55);
cpu.step();
assert_eq!(cpu.registers.get_16(&Register::BC), 0x9ABC);
cpu.step();
assert_eq!(cpu.registers.get_16(&Register::DE), 0x5678);
cpu.step();
assert_eq!(cpu.registers.get_16(&Register::HL), 0x1234);
}
}
24 changes: 24 additions & 0 deletions gameboy-lib/src/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ impl Memory {
}
}

pub fn write_16(&mut self, address: u16, value: u16) {
let low = value as u8;
let high = (value >> 8) as u8;
self.write(address, low);
self.write(address + 1, high);
}

pub fn write_vec(&mut self, start_address: u16, data: Vec<u8>) {
for (i, byte) in data.iter().enumerate() {
self.write(start_address + i as u16, *byte);
Expand Down Expand Up @@ -249,4 +256,21 @@ mod tests {
assert_eq!(memory.read(0xFF80), 0x0A);
assert_eq!(memory.read(0xFFFF), 0x0B);
}

#[test]
fn test_read_write_16() {
let mut memory = Memory::new();
memory.write_16(0x0000, 0x0102);
assert_eq!(memory.read(0x0000), 0x02);
assert_eq!(memory.read(0x0001), 0x01);
}

#[test]
fn test_read_write_vec() {
let mut memory = Memory::new();
memory.write_vec(0x0000, vec![0x01, 0x02, 0x03]);
assert_eq!(memory.read(0x0000), 0x01);
assert_eq!(memory.read(0x0001), 0x02);
assert_eq!(memory.read(0x0002), 0x03);
}
}

0 comments on commit 491aa17

Please sign in to comment.