Machine Code Execution of Functions / Procedures

The Branch Unit is the part of the CPU which allows the program to make decisions, and also to perform jumps (changes to the PC) and procedure calls. The branch unit operates under the control of the Dispatch Unit.

A function call or procedure call from a high level language usually compiles to a "call" or "JSR" instruction. Usually the compiler also inserts data marshalling intructions before and after the call. the purpose of the extra instructions is to modify the stack so that it is ready to execute the function/procedure.

CALL/JSR instructions

These are similar to JMP instructions, in that the Program Counter is loaded with a new value from the instruction, and the next instruction is executed from that new address. However, in addition to this, the address of the instruction immediately following the CALL/JSR instruction is put onto the stack. So, if the following addresses contain instructions as follows: (shown in hex form)

address code assembly language

020 2030 JSR 030
021 0086 MOV r0,r1

When the instruction JSR 030 is executed, the program counter is loaded with the value 030; but the value 021 is stored on the stack. This means that at a later stage, the operation of the program can return to the next instruction. This is usually done by the instruction RET, which simply loads the program counter with the top value on the stack.

Most CPUs set aside a special part of memory, to act as a stack. So suppose the stack had the following values on it already before the JSR 030 instruction:

010
03E

Then after the JSR 030 instruction, the stack would contain

021
010
03E

A RET instruction would load the Program Counter to load 021, and pop a value from the stack, leaving the stack as

010
03E

If another RET instruction was executed, the program counter would be loaded with 010, and the stack would just contain 03E.

Procedures/Functions and the stack

A stack is normally a part of the ordinary memory; CPUs use a register called a stack pointer to hold the address of the top of the stack; and every time to write to the stack, you change the address by one. Either way, the effect is to produce what is called a LIFO data structure "Last In, First Out".

The clever thing about this stack system is that you can call subroutines - special bits of code - which can themselves call subroutines. Consider the following example as follows:

JSR INIT ;initialisation
BEGIN: JSR DISPLAY ;read and display
JMP BEGIN

This illustrates one important feature of the use of calling procedures; it allows the writing of clear and understandable code. It is clear that in this program, after the initialisation process, the program enters and endless loop, where it repeatedly reads and displays data.

However, the procedure DISPLAY may also contain a call to a procedure (it simply suspends execution of DISPLAY, in favour of the next specified procedure).

JSR S_SEG ;find seven-segment pattern
;corresponding to value in W

The stack allows procedures to be "nested" that is: a procedure could call a procedure, which could call a procedure, etc ...

Procedures have several advantages:

They allow the writing of clear and structured code, which is easy to understand, and easy to modify: e.g.

JSR INIT ;initialisation routines
INIT: JSR INITPORTS ;initialize I/O ports
JSR INITAD ;initialise A to D converter
JSR INIT-TIME ;initialize timers
JSR INIT-INTS ;initialise interrupts
RET

Procedures also allow the use of the same code in different parts of the program. For example, you may have written a delay procedure, which causes a delay whose length is proportional to the value of r0. Then in quite different parts of the program. you could write

MOV r0, #1 ;delay constant 1
JSR DELAY ;delay proportional to r0

Some procedures are quite complex; for example, you could write a procedure called LMULU which does a multiplication of two 16 bit numbers by each other, to give a 32 bit answer; you could then just write JSR LMULU at various different points in the program, to perform this operation. For long routines which have to be performed many times at different points in the program, the use of procedures like this makes the code much shorter. You can also keep a library of such procedures, and use them when writing programs, so that you save time writing programs as well.


See also:

EG2069 Home Page


Authot: Gorry Fairhurst (Email: G.Fairhurst@eng.abdn.ac.uk)