Title: ENSC 150
1ENSC 150
27
- Exchanging Data Between Levels
2Subroutines
A subroutine is a collection of instructions that
performs some specific task. This task is usually
a common process that is used many times in a
single program or a common task that you may need
to include in some other program.
Examples HEATER ON HEATER OFF
The examples above are subroutines that do not
require any additional information when they are
called.
The Delay subroutine from the previous lecture
required that the calling level should send a
value to the subroutine EACH TIME that the
subroutine is called.
3Passing Parameters
We shall write the subroutine and top-level with
the convention that the value sent to the
subroutine shall be a 16-bit unsigned integer
passed on the stack.
Here are examples of both the calling procedure
and the subroutine.
ORG 0800 Main lds 0a00 ldd 10 pshd
jsr Wait puld Break bra
Wait pshx ldx 4,sp Here dbne x,Here pulx
rts
The Calling Sequence
The Subroutine
4The Stack Upon Entry
Here is the stack after the PSHD, before the JSR
in the main level.
Here is the stack after the JSR, on entry to the
subroutine.
Here is the stack after the PSHX, Before
accessing the parameter.
To access the parameter we used LDX 4,sp
5Receiving Results From the Subroutine
In many cases, subroutines not only receive input
parameters but also produce results after
execution that need to be returned up to the
calling level.
Usually the result is simple and can be encoded
into the 16-bit of Register D. When this is
possible, the two levels adopt the convention
that the result is to be returned in Register D.
Here is a simple example of a subroutine that
Multiplies two input 8-bit unsigned numbers and
returns an unsigned 16-bit result.
6Byte Multiply
ORG 0800 Main lds 0a00 ldaa 10 psha
ldaa 20 psha jsr ByteMultiply std Result
puld Break bra
ByteMultiply ldd 2,sp mul rts
ORG 0900 Res
ult dc.w 0
You should test this on the simulator by
yourself. Notice that the instruction PULD that
is used to restore the stack pointer after
returning from the subroutine will destroy the
result.
7Passing Pointers
In many cases a subroutine produces many results
or a result that cannot be encoded in 16-bits.
For example consider a subroutine that multiplies
two 16-bit unsigned integers and produces a
32-bit unsigned result.
One possible mechanism for returning the result
would be to have the subroutine place the result
in some memory location and then return the
address of this location to the calling level in
Register D.
WordMultiply pshy ldy 4,sp ldd 6,sp emul
sty Result std Result2 ldd Result puly
rts ORG
0900 Result dc.w 0, 0
8Calling The Subroutine
ORG 0800 Main lds 0a00 First
call ldd 10 pshd ldd 20 pshd jsr WordM
ultiply std Answer1 Second call ldd 30 ps
hd ldd 40 pshd jsr WordMultiply std Answe
r2 now try adding these two results Break bra
ORG 09
00 Answer1 dc.w 0 Answer2 dc.w 0
Here is an example of how a higher level routine
would call our multiply subroutine. Notice that
this will NOT work. Find the mistakes.
The memory location Result is a fixed location
that is known to the subroutine.
It is not sufficient for the higher level to
simply store the address of the result. Instead
the higher level must use the address to copy the
result before continuing onwards.
9Memory Allocation
A new result is produced each time the subroutine
is called. This result needs to be stored in
memory. Which level is responsible for keeping
track of the memory resources being used to store
these results?
The answer is clearly the level that executes the
JSRs since this is the level that knows how many
results will be created.
This gives rise to a commonly used convention for
returning results. The calling level is keeping
track of the memory being allocated for the
results. The calling level must supply to the
subroutine, the address of the location to store.
This address will appear to the subroutine as an
input parameter.
10Example Byte Multiplication
ORG 0800 Main lds 0a00 ldd 0202 psh
d ldy Result pshy jsr ByteMultiply puld
puld Break bra
ByteMultiply ldd 4,sp mul std 2,s
p rts
ORG 0900 Result dc.w 0,0,0,0
You can try this on the simulator and check that
the result is stored in location 0900.
This is an example of when we might use the
special INDIRECT INDEX ADDRESSING MODE.
11Local Variables
A subroutine may need to use memory locations to
store variables such as loop counters while it is
executing. These variables are transient in that
their values do not have any meaning while the
instruction on the calling level are executing.
In order to save memory, we can design the
subroutine so that it stores all of its internal
variables on the stack. When the subroutine exits
the stack is restored to its original position.
The memory that was being used for the internal
variables is again available.
Consider a subroutine that receives an 8-bit
input and reverses the bits from the left side to
the right side.
12The Flowchart
We begin by writing the subroutine with Global
Variables for the parameters and the Internal
Variables.
13 ORG 0800 Main jsr Reverse Break bra
Reverse ldaa
Input movb 0,Result movb 8,Count movb 1
,Left movb 80,Right Diamond tst Count beq
Finished NextDiamond tfr a,b andb Left beq
Over ldab Result orab Right stab Result Ov
er lsl Left lsr Right dec Count bra Diam
ond Finished rts
ORG 0900 Input dc.b 0 Result dc.b 0
Left dc.b 0 Right dc.b 0 Count dc.b 0