VM_RET_N
is a GBVM instruction used to return from a near call (a subroutine within the same memory bank) and simultaneously remove a specified number of arguments from the stack.
Purpose:
When you use VM_CALL
to jump to a subroutine, you often pass arguments to that subroutine by pushing them onto the stack. After the subroutine has completed its task, it needs to return control to the calling script and clean up the arguments it received from the stack. VM_RET_N
handles both of these actions:
VM_CALL
that initiated the jump.N
number of values from the stack. These N
values are typically the arguments that were passed to the subroutine.This instruction is crucial for proper function call conventions and stack management when dealing with subroutines within the same memory bank, ensuring that the stack remains balanced and that arguments are correctly removed after use.
Syntax:
VM_RET_N N
N
: The number of values (arguments) to be removed from the stack. This value should match the number of arguments that were pushed onto the stack before the VM_CALL
instruction.Usage Example: Reusable Function with Arguments
Let’s create a reusable function ADD_VALUES
that takes two numbers from the stack, adds them, and leaves the result on the stack. The function itself needs to clean up the two arguments it received.
; In your main script:
; Variables
VAR_NUM1:
.R_INT16 10
VAR_NUM2:
.R_INT16 20
VAR_SUM_RESULT:
.R_INT16 0
; Push arguments for the ADD_VALUES function
VM_PUSH_VALUE VAR_NUM1 ; Stack: [10]
VM_PUSH_VALUE VAR_NUM2 ; Stack: [10, 20]
; Call the ADD_VALUES function
VM_CALL ADD_VALUES
; After ADD_VALUES returns, the sum (30) is on the stack.
; Store the result into VAR_SUM_RESULT
VM_SET_INT16 VAR_SUM_RESULT, 0 ; The 0 is a placeholder, value taken from stack
; ... continue main script ...
; --- Subroutine Definition ---
ADD_VALUES:
; At this point, the stack contains: [return_address, VAR_NUM1_value, VAR_NUM2_value]
; We need to get the values for addition.
; Get the values from the stack (top-most first)
VM_GET_TLOCAL VAR_TEMP_B, 0 ; Get VAR_NUM2_value (20)
VM_GET_TLOCAL VAR_TEMP_A, 1 ; Get VAR_NUM1_value (10)
; Perform the addition
VM_RPN
.R_REF_MEM .R_INT16, VAR_TEMP_A
.R_REF_MEM .R_INT16, VAR_TEMP_B
.R_OPERATOR +
.R_INT16
VM_STOP
; The sum (30) is now on top of the stack.
; Return from the call and remove 2 arguments (VAR_NUM1_value, VAR_NUM2_value)
VM_RET_N 2
In this example, VM_CALL ADD_VALUES
pushes the return address and then the arguments. Inside ADD_VALUES
, the arguments are retrieved and used in the calculation. Finally, VM_RET_N 2
ensures that when the routine returns, the two arguments (10 and 20) are popped from the stack, leaving only the calculated sum (30) on top, which is then stored by the calling script.
Analogy to other programming languages:
This is analogous to a function returning in C/C++ where the calling convention dictates that the callee (the function being called) is responsible for cleaning up the arguments from the stack. For example, in __stdcall
calling convention on x86, the RET N
instruction (where N is the number of bytes of arguments) handles both returning and stack cleanup. It ensures that the stack is properly unwound after a function call.