3D1-Microprocessor Systems 1

Lecture 13: subroutines - mechanisms

This lecture introduces a mechanism fundamental to the programmer: the subroutine. Suppose a particular sequence of operations is to be performed two or more times during the execution of a program. Writing out the same block of assembly language instructions multiple times would be tedious and memory inefficient. The subroutine provides a solution to this problem. In high-level languages the subroutine is frequently known as a procedure or function.

Learning Outcomes:

On completion of this lecture, you will be able to:

·  Discuss the need for subroutines;

·  Discuss the issue of returning from a subroutine call;

·  Describe the role and operation of the stack.

13.1 Subroutines

Functions, methods and procedures are mostly implemented at assembly language level as ‘subroutines’. A subroutine is simply a section of code designed to be called (branched or jumped to) from many places. The first problem with subroutines is the issue of returning to the place from where the call was made.

To solve the return problem, the BSR and JSR instructions store the address of the next sequential instruction just before they branch or jump to the subroutine. They store the ‘return address’ in The Stack.

A subroutine is called by executing the instruction BSR <label> or JSR <label>, for Branch to SubRoutine and Jump to SubRoutine. The difference between BSR and JSR is that BSR uses a relative address and JSR an absolute address. Remember that the programmer simply supplies the label of the subroutine and the assembler automatically calculates the appropriate relative or absolute address. The range of branching with BSR is -32K bytes to +32K bytes from the present instruction.

Example: The following subroutine called ABC calculates the value of 2x2 (where x is a 16-bit value passed in D0);

.

.

MOVE.W #4,D0 set up parameter in D0

BSR ABC subroutine call

. Return point (next instruction after the subroutine)

.

ABC MULU D0,D0 The subroutine

ASL.L #1,D0

RTS Return from subroutine

This subroutine is called by the instruction BSR ABC (Branch to SubRoutine), and a return from subroutine in made by an RTS (Return from SubRoutine) instruction. The value of the PC is saved on the stack before the branch to the subroutine. At the end of the subroutine, this returned address is pulled from the stack and loaded to the PC.

13.2 The 68000 Stack

The stack is a fundamental data structure that makes possible to call subroutines in both high-level and low-level languages with little difficulty.

The stack is a last in, first out (LIFO) queue with a single end, where items are always added or removed. When an item is added to the stack it is said to be pushed on to the stack, and when an item is removed from the stack it is said to be pulled (or popped) off the stack.

The 68000 stack is located in a region of the main memory and address register A7 is used as system stack pointer to point to the top of the stack.

Example:

6 / 7 / 8 / 9 / 10 / 11
01101001 / 10010100 / 11010100 / 01101101

(A7)

·  Stack contents: $69,$94,$D4,6D

·  Top of Stack pointed to by a stack pointer.

·  In the 68000, A7 is reserved for use as a stack pointer to ‘The Stack,’ hence, A7 is often called the Stack Pointer (SP).

·  You can have other stacks if you want; just don’t use A7.

13.2.1 Pushing [to] the Stack

6 / 7 / 8 / 9 / 10 / 11
11101111 / 00001010 / 01101001 / 10010100 / 11010100 / 01101101

(A7)

A word was pushed into the stack:

·  The stack grew downwards sufficiently to fit the item

·  Contents of the stack didn’t move in memory—instead, the top of the stack moved (pointed to by A7)

·  New contents: $EF,$0A,$69,$94,$D4,6D

13.2.2 Popping [from] the Stack

6 / 7 / 8 / 9 / 10 / 11
11101111 / 00001010 / 01101001 / 10010100 / 11010100 / 01101101

(A7)

A longword was pulled or popped from the stack:

·  The stack contracted upward

·  Contents of the stack didn’t move in memory—instead, the top of the stack moved (pointed to by A7)

·  New contents: $D4,6D

13.2.3 Frequent Stack Pointer Operations

Add Item --Adding an item to a stack consists of:

·  subtracting sufficient from the stack pointer to make room at the top of the stack for the item: (1:byte, 2:word, 4:longword, etc.)

·  moving the item to the location now pointed to by the stack pointer

New addressing mode: ‘Address Register Indirect with Pre-Decrement’ -Look like: -(An)

Pop Item -- Popping an item from a stack consists of:

·  moving the item from the location pointed to by the stack pointer

·  adding sufficient to the stack pointer to take up the space at the top of the stack formerly occupied by the item: (1:byte, 2:word, 4:longword, etc.)

New addressing mode: ‘Address Register Indirect with Post-Increment’ -- Look like:(An)+

13.3 Subroutines call and exit

13.3.1 Subroutines Calling…

When a subroutine is called, the address of the next instruction (the “return address”) is pushed onto the stack

$001010fe / 11
$001010fc / $FABB
(SP) / → / $001010fa / 6578
$001010f8 / $????
$001010f6 / $????

Example:

1040 moveq #0,d1

1042 jsr foo

1046 …

13.3.2 Subroutine Exiting…

When the subroutine finishes, it executes the RTS instruction, which pops a longword from the stack into the PC

$001010fe / 11
D0 / A0 / $001010fc / $FABB
D1 / A1 / $001010fa / 6578
D2 / A2 / $001010f8 / 1046
D3 / A3 / (SP) / → / $001010f6 / 0
D4 / / A4
D5 / A5
D6 / A6
D7 / A7 / $001010f6
PC
SR
68000

13.4 Example: Translation from binary to ASCII

Write a complete program to translate a signed binary word integer to a NUL-terminated sequence of ASCII characters denoting its decimal numeric form.
Define a sample number and reserve sufficient space to store the resulting character string where they can be examined with the debugger. Display the result on the top line of the LCD.

ORG $2000

num DC.W -30753

ORG $2002

RSLT DS.B 6

ORG $3000

LEA RSLT,A0

LEA num,A1

MOVE.W (A1),D0

JSR SUBRUT call subroutine SUBRUT

JSR DISPLAY call subroutine DISPLAY to LCD

TRAP #0 return control to the Monitor

ORG $4000

SUBRUT MOVEM.L D0-D7/A0-A6,-(A7) save contents of all registers on stack

BTST #15,D0 test if bit 15 is 1 (indicates neg. num in 2C)

BEQ NOTNEG if Z bit set, positive num then goto NOTNEG

MOVE.B #'-',(A0)+ else, negative num write ‘-‘ sign to memory

MOVEQ.L #0,D2 *

SUB.W D0,D2 * Get –[D0]

MOVE.W D2,D0 *

NOTNEG MOVE.W #10000,D7 Initialise D7 at 10000 (|num|<= 32768)

L1 DIVU D7,D0 D0 <- D0/D7 (quotient in LSW, reminder in MSW)

ADD.B #$30,D0 convert binary digit to ASCII code

MOVE.B D0,(A0)+ save to memory

MOVE.W #0,D0 Clear LSW of D0

SWAP D0

DIVU #10,D7 Divide D7 by 10

TST.W D7 Test if LSW of D7 is 0

BNE L1 If not zero, goto L1

MOVE.B #$0,(A0) else put NUL to memory

MOVEM.L (A7)+,D0-D7/A0-A6 Restore all registers

RTS

ORG $5000

DISPLAY MOVEM.L D0-D7/A0-A6,-(A7) save contents of all registers on stack

MOVE.L #RSLT,A0 load A0 with the result’s memory address

TRAP #7 displays the zero-terminated string pointed by

A0 on the top line of the LCD Display

MOVEM.L (A7)+,D0-D7/A0-A6 Restore all registers

RTS

END

Most programmers would employ a MOVEM instruction to save the contents of registers on the stack before they are used by a subroutine, and then restore them immediately before executing a return from subroutine. MOVEM stands for move multiple; it transfers the contents of a group of registers to or from memory with a single instruction. MOVEM operates only on words and longwords and does not affect the contents of the CCR.

The register list is defined as: Dp-Dq/Ai-Aj, where the hyphen indicates a sequence of contiguous registers and the back slash separates lists of registers. For example, the register list D0-D7/A0-A6 specifies data registers D0 to D7 and address registers A0 to A6.

MOVEM.L D0-D7/A0-A6,-(A7) pushes all the data registers and address registers A0 to A6 onto the system stack. MOVEM.L (A7)+,D0-D7/A0-A6 has the reverse effect of pulling the registers off the stack.

A7
4000 / 4000 / D0 / 4000
4004 / 4004 / D1
4008 / 4008 / D2
400C / 400C / D3
4010 / 4010 / D4
4014 / 4014 / D5
4018 / 4018 / D6
401C / 401C / D7
4020 / 4020 / A0
4024 / 4024 / A1
4028 / 4028 / A2
402C / 402C / A3
4030 / 4030 / A4
4034 / 4034 / A5
4038 / A7 / 4038 / A6
403C / / 403C / 403C

13.5  Conclusion

·  A subroutine is called by means of a BSR or a JSR instruction. A return from subroutine to the instruction immediately after the calling point is made by means of an RTS instruction.

·  The BSR instruction employs a relative address, calculated automatically by the assembler. If you know that the subroutine is situated within 128 bytes of the calling point, you can use the short form of the branch: BSR.S. If you use a JRS instruction, the address is absolute and the code is not position-independent.

·  The 68000’s stack pointed at by A7 automatically handles subroutine return addresses.

·  Although subroutines are primarily used to avoid rewriting bits of frequently used code, they can also be used to facilitate top-down design and to enhance program readability.

REFERENCES

·  A. Clements; Subroutines and Parameters, In: 68000 Family Assembly Language; pp.276-325; PWS Publishing Company; 1994.

·  Dr. Mike Brady, Microprocessor Systems 1, dept of Computer Science, Trinity College Dublin: http://www.tcd.ie/Engineering/Courses/BAI/JS_Subjects/3D1/.

·  Look on the Web at http://www.mee.tcd.ie/~assambc/3D1.

13-6