-
Notifications
You must be signed in to change notification settings - Fork 87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add push/pop instructions #498
Changes from 7 commits
d667993
bdeea41
2124f49
06e65d3
b339885
7ec2696
0a0e2c2
0e00edf
7e37779
43215e0
745909d
570a4b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ use crate::{ | |
}; | ||
|
||
use fuel_asm::{ | ||
Imm24, | ||
PanicReason, | ||
RegId, | ||
}; | ||
|
@@ -32,6 +33,9 @@ mod tests; | |
#[cfg(test)] | ||
mod allocation_tests; | ||
|
||
#[cfg(test)] | ||
mod stack_tests; | ||
|
||
/// Used to handle `Word` to `usize` conversions for memory addresses, | ||
/// as well as checking that the resulting value is withing the VM ram boundaries. | ||
pub trait ToAddr { | ||
|
@@ -189,6 +193,42 @@ where | |
stack_pointer_overflow(sp, ssp.as_ref(), hp.as_ref(), pc, f, v) | ||
} | ||
|
||
pub(crate) fn push_selected_registers( | ||
&mut self, | ||
segment: ProgramRegistersSegment, | ||
bitmask: Imm24, | ||
) -> Result<(), RuntimeError> { | ||
let (SystemRegisters { sp, hp, pc, .. }, program_regs) = | ||
split_registers(&mut self.registers); | ||
push_selected_registers( | ||
&mut self.memory, | ||
sp, | ||
hp.as_ref(), | ||
pc, | ||
&program_regs, | ||
segment, | ||
bitmask, | ||
) | ||
} | ||
|
||
pub(crate) fn pop_selected_registers( | ||
&mut self, | ||
segment: ProgramRegistersSegment, | ||
bitmask: Imm24, | ||
) -> Result<(), RuntimeError> { | ||
let (SystemRegisters { sp, ssp, pc, .. }, mut program_regs) = | ||
split_registers(&mut self.registers); | ||
pop_selected_registers( | ||
&self.memory, | ||
sp, | ||
ssp.as_ref(), | ||
pc, | ||
&mut program_regs, | ||
segment, | ||
bitmask, | ||
) | ||
} | ||
|
||
pub(crate) fn load_byte( | ||
&mut self, | ||
ra: RegisterId, | ||
|
@@ -287,6 +327,75 @@ where | |
} | ||
} | ||
|
||
pub(crate) fn push_selected_registers( | ||
memory: &mut [u8; MEM_SIZE], | ||
mut sp: RegMut<SP>, | ||
hp: Reg<HP>, | ||
pc: RegMut<PC>, | ||
program_regs: &ProgramRegisters, | ||
segment: ProgramRegistersSegment, | ||
bitmask: Imm24, | ||
) -> Result<(), RuntimeError> { | ||
let bitmask = bitmask.to_u32(); | ||
|
||
// First compute the new stack pointer, as that's the only error condition | ||
let count = bitmask.count_ones(); | ||
let stack_range = MemoryRange::new(*sp, (count as u64) * 8)?; | ||
let new_sp = stack_range.words().end; | ||
if new_sp > *hp { | ||
Dentosal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return Err(PanicReason::MemoryOverflow.into()) | ||
} | ||
|
||
// Write the registers to the stack | ||
let mut it = memory[stack_range.usizes()].chunks_exact_mut(8); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to cross the heap here? Or is it not because we checked that inside of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
for (i, reg) in program_regs.segment(segment).iter().enumerate() { | ||
if (bitmask & (1 << i)) != 0 { | ||
it.next().unwrap().copy_from_slice(®.to_be_bytes()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you use |
||
} | ||
} | ||
|
||
// Apply changes to system registers | ||
*sp = new_sp; | ||
inc_pc(pc) | ||
} | ||
|
||
pub(crate) fn pop_selected_registers( | ||
memory: &[u8; MEM_SIZE], | ||
mut sp: RegMut<SP>, | ||
ssp: Reg<SSP>, | ||
pc: RegMut<PC>, | ||
program_regs: &mut ProgramRegisters, | ||
segment: ProgramRegistersSegment, | ||
bitmask: Imm24, | ||
) -> Result<(), RuntimeError> { | ||
let bitmask = bitmask.to_u32(); | ||
|
||
// First compute the new stack pointer, as that's the only error condition | ||
let count = bitmask.count_ones(); | ||
let size_in_stack = (count as u64) * 8; | ||
Dentosal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
let new_sp = sp | ||
.checked_sub(size_in_stack) | ||
.ok_or(PanicReason::MemoryOverflow)?; | ||
if new_sp < *ssp { | ||
return Err(PanicReason::MemoryOverflow.into()) | ||
Dentosal marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
let stack_range = MemoryRange::new(new_sp, size_in_stack)?.usizes(); | ||
|
||
// Restore registers from the stack | ||
let mut it = memory[stack_range].chunks_exact(8); | ||
for (i, reg) in program_regs.segment_mut(segment).iter_mut().enumerate() { | ||
if (bitmask & (1 << i)) != 0 { | ||
let mut buf = [0u8; 8]; | ||
buf.copy_from_slice(it.next().expect("Count mismatch")); | ||
*reg = Word::from_be_bytes(buf); | ||
} | ||
} | ||
|
||
// Apply changes to system registers | ||
*sp = new_sp; | ||
inc_pc(pc) | ||
} | ||
|
||
pub(crate) fn load_byte( | ||
memory: &[u8; MEM_SIZE], | ||
pc: RegMut<PC>, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That will not work;
u32
doesn't implementToAddr
(unless we expand the implementation to cover it). The as-cast here is extendingu32
returned bycount_ones()
, and is complely harmless. I'm replacing it with a.into()
cast anyway, so it looks less suspicious.