diff --git a/src/emulator/instructions/transfer.rs b/src/emulator/instructions/transfer.rs index db7102e..6e41239 100644 --- a/src/emulator/instructions/transfer.rs +++ b/src/emulator/instructions/transfer.rs @@ -1,4 +1,7 @@ -use crate::{get_register, get_register_pair, set_register, EmulatorState, Register}; +use crate::{ + get_register, get_register_pair, set_register, structs::set_register_pair, EmulatorState, + Register, +}; /// Move (copy) value from source to destination register pub fn mov(src: Register, dest: Register, state: &mut EmulatorState) { @@ -34,3 +37,53 @@ pub fn lhld(address: u16, state: &mut EmulatorState) { state.l = state.memory[address as usize]; state.h = state.memory[address as usize + 1]; } + +/* STACK */ +/// Push a 16-bit value from a register pair onto the stack +pub fn push_reg(register: Register, state: &mut EmulatorState) { + push(get_register_pair(register, state), state); +} + +pub fn push(value: u16, state: &mut EmulatorState) { + state.write_word(state.sp.overflowing_sub(1).0, value); + (state.sp, ..) = state.sp.overflowing_sub(2); +} + +/// Pop a 16-bit value from the stack into a register pair +pub fn pop_reg(register: Register, state: &mut EmulatorState) { + set_register_pair(register, pop(state), state); +} + +pub fn pop(state: &mut EmulatorState) -> u16 { + (state.sp, ..) = state.sp.overflowing_add(2); + state.read_word(state.sp.overflowing_sub(1).0) +} + +#[cfg(test)] +mod tests { + use crate::EmulatorState; + + #[test] + fn push() { + let mut state = EmulatorState { + sp: 0x12, + ..Default::default() + }; + + super::push(0x1234, &mut state); + assert_eq!(state.sp, 0x10); + assert_eq!(state.memory[0x11..=0x12], [0x34, 0x12]); + } + + #[test] + fn pop() { + let mut state = EmulatorState { + sp: 0x10, + ..Default::default() + }; + + state.memory[0x11] = 0x34; + state.memory[0x12] = 0x12; + assert_eq!(super::pop(&mut state), 0x1234); + } +} diff --git a/src/emulator/main.rs b/src/emulator/main.rs index 378a6b5..d2aa2b9 100644 --- a/src/emulator/main.rs +++ b/src/emulator/main.rs @@ -80,6 +80,16 @@ fn tick(state: &mut EmulatorState) { 0x22 => transfer::shld(state.next_word(), state), // SHLD 0x2a => transfer::lhld(state.next_word(), state), // LHLD + // Stack instructions + 0xc1 => transfer::pop_reg(Register::B, state), // POP B + 0xc5 => transfer::push_reg(Register::B, state), // PUSH B + 0xd1 => transfer::pop_reg(Register::D, state), // POP D + 0xd5 => transfer::push_reg(Register::D, state), // PUSH D + 0xe1 => transfer::pop_reg(Register::H, state), // POP H + 0xe5 => transfer::push_reg(Register::H, state), // PUSH H + 0xf1 => transfer::pop_reg(Register::A, state), // POP PSW + 0xf5 => transfer::push_reg(Register::A, state), // PUSH PSW + /* Maths */ // INR 0x04 => arithmetic::inr(Register::B, state), diff --git a/src/emulator/structs.rs b/src/emulator/structs.rs index 4d586d7..a129516 100644 --- a/src/emulator/structs.rs +++ b/src/emulator/structs.rs @@ -241,7 +241,7 @@ mod tests { fn write_word() { let mut state = EmulatorState::default(); state.write_word(0x10, 0x1234); - assert_eq!([0x34, 0x12], state.memory[0x10..0x12]); + assert_eq!(state.memory[0x10..=0x11], [0x34, 0x12]); } #[test]