unsigned int recip(x)
unsigned int x;
/* binary search for reciprocal of x */
{
unsigned long int r = 0; /* approximation of reciprocal */
int i;
for (i = sizeof( int )-1; i>=0; i--) {
unsigned long int t = r | (1 << i); /* trial */
if (((t * x) >> sizeof( int )) == 0) {
r = t;
}
}
return (unsigned int) r;
}
MOV R5,(-SP) ; push old value of R5
... ; code to push n parameters
MOVE #(MARK n),R5 ; put mark on stack
JSR R5,PROC ; call proc.
The corresponding receiving and return sequences are:
PROC:
... ; code for body of procedure
JMP (SP) ; jump to mark instruction on stack
The mark instruction (sitting on the top word of the stack) takes care
of popping the parameters off the stack and finishing the return from
the procedure.
BAL R1,PROC ; R1 = PC; PC = PROC
W ARS ; size of caller's AR
Here is the corresponding receiving and return sequence:
PROC:
ADDS R2,R1 ; R2 = R2 + M[R1] -- add size of caller's AR
STS R1,R2 ; M[R2] = R1 -- store return address
... ; body of proc
LDS R1,R2 ; R1 = M[R2] -- recover return addr
SUBS R2,R1 ; R2 = R2 - M[R1] -- restore the AR pointer
INC R1 ; bump return address over inline param
JR R1 ; PC = R1
The above code assumes that, within the body of each procedure, R2 points
to the base of the activation record for that code. The first location in
each activation record is used to store the return address, and the size
of each function's activation record is passed as an inline parameter on the
call. There are no push or pop operations for individual words here!
There are, of course, many alternatives to the above suggested calling sequence.