This file can be included to 16bit programs written in EuroAssembler.
The library contains OS-independent macroinstructions
Procedure, EndProcedure, Invoke
which extend generic pseudoinstructions
PROC, ENDPROC, CALL
.
Macroinstructions Procedure
and EndProcedure
hide the prologue and epilogue of
standard call calling convention
, where the arguments are pushed backwards and they are removed by the called procedure.
All GP registers are calee-saved by the Procedure. Result value of the invokation can be returned
from procedure by copying the value to stack-variables, such as
%ReturnAX
, which is defined by %StdCall16 as BP+14
.
Macroinstructions in this library comunicate with one another
at assembly time using the preprocessing %variables
%LvSize_ProcName
(total size of all stack-variables) and
ArgC_ProcName
(number of procedure parameters).
Individualization of global %variable names allows to nest procedure definitions in one another.
stdcal16 HEAD
Implementation of standard call convention in €ASM uses formal %names for accessing Procedure parameters, local stack-memory variables and all eight general-purpose registers saved on stack.
The following example shows the stack frame created by invoking Procedure with the name
MyFn which has three parameters and uses two local stack variables
with sizes 2 and 4. Prologue of MyFn Procedure Param1, Param2, Param3
will assign "global" %variables
%ArgC_MyFn %SETA 3
and %LvSize_MyFn %SETA 2+4
, they can be used in macros LocalVar,
ClearLocalVar and by epilogue in
EndProcedure MyFn
during
Invoke MyFn, Param1, Param2, Param3
.
; Formal %names assignment: %Par8 %SET BP+32 %Par7 %SET BP+30 %Par6 %SET BP+28 %Par5 %SET BP+26 %Par4 %SET BP+24 %Par3 %SET BP+22 %Par2 %SET BP+20 %Par1 %SET BP+18 %ReturnAX %SET BP+14 %ReturnCX %SET BP+12 %ReturnDX %SET BP+10 %ReturnBX %SET BP+08 %ReturnSP %SET BP+06 %ReturnBP %SET BP+04 %ReturnSI %SET BP+02 %ReturnDI %SET BP+00
PUSHAW
and
MOV BP,SP
as the procedure prolog.Procedure %MACRO Operands ; Prologue of standard calling convention procedure. LblCheck %IF "%:" === "" %ERROR ID=5921, 'Macro "Procedure" requires a label.' %EXITMACRO Procedure %ENDIF LblCheck %%ArgC_%: %SETX %# %%LvSize_%: %SETX 0 ArgNr %FOR 1..%#, STEP= +1 %%%*{%ArgNr} %SETX BP+(16+%ArgNr*2) %ENDFOR ArgNr %::: PROC %=*, NESTINGCHECK=OFF PUSHAW MOV BP,SP %ENDMACRO Procedure
BP-2
Block LocalVar Size=1K ; %Block is now BP-1026
.
ClearLocalVar ; Fill Block and BlockSize with 0.
MOV [%BlockSize],1K, DATA=WORD
LEA DI,[%Block] ; DI is now offset of Block in segment SS.
...
EndProcedure ProcNameSUB SP,%Size
to reserve room on the machine stack.
%LvSize_ProcName
which was initialized in macro Procedure
.LocalVar %MACRO Size=2 LblCheck %IF "%:"=="" %ERROR ID=5922, 'Macro "LocalVar" requires a label.' %EXITMACRO LocalVar %ENDIF LblCheck SizeCheck %IF %# %ERROR ID=5923, 'Macro "LocalVar" does not expect ordinal parameters.' %EXITMACRO LocalVar %ENDIF SizeCheck %: %COMMENT ; This makes the label of macro invocation void %ENDCOMMENT %: ; so it does not declare a symbol. %ThisLvSize %SETA (%Size + 1) & ~1 ; Round up to WORD. %GlbLvSize %SET2 %%LvSize_%^PROC+%ThisLvSize ; Accumulate total size of all LocalVar. %%LvSize_%^PROC %SETX %GlbLvSize ; Update the "global" variable. SUB SP, %ThisLvSize ; Allocate room on stack. %%%: %SETX BP-(%GlbLvSize) ; Assign formal %name to the id specified with LocalVar label. %ENDMACRO LocalVar
We could as well decide to initialize each local variable individually, in this case the macro ClearLocalVar will not be used in the Procedure body at all.
SS:SP
, cleared size is specified with "global" variable
%LvSize_ProcName
.ClearLocalVar %MACRO %GlbLvSize %SET2 %%LvSize_%^PROC %IF %GlbLvSize MOV DI,SP MOV CX,(%GlbLvSize) / 2 PUSH ES,SS POP ES XOR AX,AX CLD REP STOSW POP ES %ENDIF %ENDMACRO ClearLocalVar
Macro EndProcedure terminates context of the previously opened
Procedure
. This epilogue of StdCall convention will discard local variables defined with
LocalVar (using machine instruction
MOV SP,BP
), restore all GP registers (using
POPAW
) and then return to the parent code
which the Procedure was Invoked from (using RET 2*%ArgC_ProcName
).
Operands pushed on stack in the Invoke statement
will be discarded here by this EndProcedure macro.
All registers are preserved throughout the procedure invocation
unless the procedure changed their stored value
on the stack frame (writing to [%ReturnAX]
for instance).
CPU flags are not preserved, EndProcedure returns
with the same flag values which were set at the
EndProcedure entry.
Programmer should never use explicit machine instructionRET
to return from the block defined withProcedure .. EndProcedure
. If premature return is required, jump to the label ofEndProcedure
statement instead.
Procedure
statement.Invoke
statement.EndProcedure %MACRO ProcName OpCheck %IF "%ProcName" === "" %ERROR ID=5924, 'Macro "EndProcedure" requires one operand.' %EXITMACRO EndProcedure %ENDIF OpCheck %NameStrip %SET %ProcName %WHILE "%ProcNameStrip[%&]" === ":" %ProcNameStrip %SET %ProcNameStrip[1..%&-1] ; Get rid of trailing colons. %ENDWHILE %ArgC %SET2 %%ArgC_%NameStrip NestChck %IF "%ArgC" === "" %ERROR ID=5925, '"%ProcName Procedure" statement missing.' %EXITMACRO EndProcedure %ENDIF NestChck MOV SP,BP POPAW RET 2 * (%ArgC) ENDP %ProcName, NESTINGCHECK=OFF %ENDMACRO EndProcedure
Invoke %MACRO ProcName, Arguments ArgCheck %IF "%ProcName" === "" %ERROR ID=5926, 'Macro "Invoke" requires the name of called Procedure.' %EXITMACRO Invoke %ENDIF ArgCheck ArgNr %FOR %#..2, STEP= -1 PUSHW %*{%ArgNr} %ENDFOR ArgNr CALL %ProcName %ENDMACRO Invoke
ENDHEAD stdcal16