Move stack push/pop into their own functions
parent
66c7e4287c
commit
710e293a0e
72
src/cpu.rs
72
src/cpu.rs
|
@ -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(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue