In the section on subprograms we saw how to use a stack for storing
return values for procedures and functions. In this section, we
extend the use of the stack to parameter passing for
subprograms.
For this, we need two new instructions PUSH and POP. The PUSH
instruction pushes the contents of R1 on top of the stack, and the
POP instruction pops the top of the stack and puts it in R0. These
two instructions are possible to implement without any further
modifications to our architecture. Here is the microprogram for
push:
......: 0000000000000000000000010 (PUSH)
......: 0001000100000000000000001 (PUSH)
......: 0011000100000000000000001 (PUSH)
......: 1001000100000000000000001 (PUSH)
And here is the microprogram for POP:
......: 1010000000100000000000101 (POP)
With these two instructions, we can make a more complete
call/return protocol that contains rules for parameter passing as
well. Here is an example of such a protocol. It pushes the arguments
in reverse order (argument n first, argument 1 last). That is common
for the C language since it allows the subprogram to find the first
argument without knowing how many arguments have been passed:
Caller Callee
------ ------
compute argument n in R1
push R1
...
compute argument 1 in R1
push R1
jsr callee
compute return value in R0
ret
pop n arguments off the stack
While this way of passing paramenters works, it is not very
practical for the callee to access those parameters. The only
possibility currently available is to use the POP instruction. It
would be more practical if we had instructions that could use
addresses made up of the contents of the stack pointer plus a small
constant. If we had such instructions, we could access argument
number i by using address SP+(i+1), where SP is the
contents of the stack pointer.
What we need is thus to be able to add a constant to the stack
pointer. That constant will be stored as an argument to a new
instruction. We can do this by storing the constant in the address
register, and make it possible to add the contents of the address
register and the stack pointer to form an address for main memory.
The following modifications will allow that:
Notice the new MOP number 26 to communicate the sum to the
address bus.
We can now write a new instruction LDS (for load from stack) that
does what we want:
......: 00101010100000000000000000 (LDS)
......: 10100000001000000000000001 (LDS)
After the callee returns, the caller has to pop off hte arguments
that it pushed before the call. Currently, the only possibility is
to use POP as many times as there are arguments. An improvement
would be to the possibility to add a constant to the stack pointer.
For that, we can use the existing adder, but we need to be able to
store the result into the stack pointer. This requires additional
lines and an additional signal allowing a value to be loaded into
the stack pointer. Here is the modified architecture:
Notice the new MOP number 27 for loading a value into the stack
pointer. We can now write an instruction ADDSP that adds a constant
value to the stack pointer. Here is its implementation:
......: 001010101000000000000000000 (ADDSP)
......: 100000000000000000000000001 (ADDSP)
|