Move stack push/pop into their own functions

old-bit-manip
Nick Krichevsky 2023-11-21 13:47:14 -05:00
parent 66c7e4287c
commit 710e293a0e
5 changed files with 88 additions and 62 deletions

View File

@ -163,4 +163,76 @@ impl Processor {
load_res load_res
} }
} }
fn push_16bit_register_to_stack(
&mut self,
register: register::SixteenBit,
) -> Result<(), Error> {
let current_sp = self
.registers
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
// we want to pop the LSB first (i.e. we write the MSB first)
// https://rgbds.gbdev.io/docs/v0.5.2/gbz80.7#PUSH_r16
let [lower_bits, higher_bits] = self.registers.get_16bit_register(register).to_le_bytes();
let res = self.memory.set_both((
((current_sp - 1).into(), higher_bits),
((current_sp - 2).into(), lower_bits),
));
if let Err(memory::Error::SetInvalidAddress(bad_addr, _)) = res {
return Err(Error::InvalidRegisterAddress(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
bad_addr,
));
} else if let Err(err) = res {
return Err(Error::Unknown(Box::new(err)));
}
self.registers.set_16bit_register(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
current_sp - 2,
);
Ok(())
}
fn pop_from_stack_to_16bit_register(
&mut self,
register: register::SixteenBit,
) -> Result<(), Error> {
let current_sp = self
.registers
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
let get_from_memory = |addr| {
let res = self.memory.get(addr);
match res {
Ok(value) => Ok(value),
Err(memory::Error::GetInvalidAddress(bad_addr)) => {
Err(Error::InvalidRegisterAddress(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
bad_addr,
))
}
Err(err) => Err(Error::Unknown(Box::new(err))),
}
};
let popped_bytes = [
get_from_memory(current_sp.into())?,
get_from_memory((current_sp + 1).into())?,
];
let popped_value = u16::from_le_bytes(popped_bytes);
self.registers.set_16bit_register(register, popped_value);
self.registers.set_16bit_register(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
current_sp + 2,
);
Ok(())
}
} }

View File

@ -47,70 +47,13 @@ impl Run for SixteenBitLoadInstruction {
} }
SixteenBitLoadInstruction::Push { src } => { SixteenBitLoadInstruction::Push { src } => {
let current_sp = processor processor.push_16bit_register_to_stack(src.into())?;
.registers
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
// we want to pop the LSB first (i.e. we write the MSB first)
// https://rgbds.gbdev.io/docs/v0.5.2/gbz80.7#PUSH_r16
let [lower_bits, higher_bits] =
processor.registers.get_combined_register(src).to_le_bytes();
let res = processor.memory.set_both((
((current_sp - 1).into(), higher_bits),
((current_sp - 2).into(), lower_bits),
));
if let Err(memory::Error::SetInvalidAddress(bad_addr, _)) = res {
return Err(Error::InvalidRegisterAddress(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
bad_addr,
));
} else if let Err(err) = res {
return Err(Error::Unknown(Box::new(err)));
}
processor.registers.set_16bit_register(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
current_sp - 2,
);
Ok(Cycles(16)) Ok(Cycles(16))
} }
SixteenBitLoadInstruction::Pop { dst } => { SixteenBitLoadInstruction::Pop { dst } => {
let current_sp = processor processor.pop_from_stack_to_16bit_register(dst.into())?;
.registers
.get_single_16bit_register(register::SingleSixteenBit::StackPointer);
let get_from_memory = |addr| {
let res = processor.memory.get(addr);
match res {
Ok(value) => Ok(value),
Err(memory::Error::GetInvalidAddress(bad_addr)) => {
Err(Error::InvalidRegisterAddress(
register::SixteenBit::Single(
register::SingleSixteenBit::StackPointer,
),
bad_addr,
))
}
Err(err) => Err(Error::Unknown(Box::new(err))),
}
};
let popped_bytes = [
get_from_memory(current_sp.into())?,
get_from_memory((current_sp + 1).into())?,
];
let popped_value = u16::from_le_bytes(popped_bytes);
processor.registers.set_combined_register(dst, popped_value);
processor.registers.set_16bit_register(
register::SixteenBit::Single(register::SingleSixteenBit::StackPointer),
current_sp + 2,
);
Ok(Cycles(12)) Ok(Cycles(12))
} }

View File

@ -69,7 +69,7 @@ impl Run for MiscInstruction {
processor.enable_interrupts(); processor.enable_interrupts();
Ok(Cycles(4)) Ok(Cycles(4))
}, }
MiscInstruction::DisableInterrupts => { MiscInstruction::DisableInterrupts => {
processor.disable_interrupts(); processor.disable_interrupts();

View File

@ -108,6 +108,18 @@ impl Default for Registers {
} }
} }
impl From<Combined> for SixteenBit {
fn from(value: Combined) -> Self {
Self::Combined(value)
}
}
impl From<SingleSixteenBit> for SixteenBit {
fn from(value: SingleSixteenBit) -> Self {
Self::Single(value)
}
}
impl Registers { impl Registers {
/// Get the a flag in the flag register. /// Get the a flag in the flag register.
/// It is suggested that you use the constants in the `flag` module when calling this method. /// It is suggested that you use the constants in the `flag` module when calling this method.

View File

@ -210,8 +210,7 @@ fn test_disable_interrupts_disables_interrupts_once_enabled() {
[ [
// Enable interrupts // Enable interrupts
0xFB, // Nop 0xFB, // Nop
0x00, 0x00, 0xF3,
0xF3,
] ]
.iter() .iter()
.copied() .copied()