Using jump for conditional branching


jmp cond ads

cond = EQ, NEQ, LT, LE, GT, GE, ALWAYS

There are four flags in the processor: Sign, Zero, Carry, Overflow (S,Z,C,O).  Each flag is one bit.  They are like global variables.  Flags are set by ALU intructions such as, add, sub, mul, div, and, xor etc.  The ld/st instructions do not change flags.  The condition is decided by flags.  Flags are set by the previous ALU instruction.   To compare two variables, subtract instruction is used and flags S,Z will be affected.  Let two variables be in r1 and r2, "sub r0 r1 r2" will compare these variables and set the Sign and Zero flags without altering any register (because r0 is always zero). For example, EQ is true when Z = 1. LT is true when S = 1.  LE is true when S = 1 or Z = 1.  Subsequently, jump instruction can test the condition to affect the control flow.

Example of using jump to do if...then...else

if a > b then1
  if b < c then2 e1 else2 e2
else1
  e3

let r1 = a, r2 = b, r3 = c
 

     ld r1 a
     ld r2 b
     ld r3 c
     sub r0 r1 r2 ;; compare a b
     jmp GT then1 ;; if a > b then1
     e3           ;; else1
     jmp always exit
:then1
     sub r0 r2 r3 ;; compare b c
     jmp LT then2
     e2           ;; else2
     jmp always exit
:then2
     e1
:exit

Function call

The part of program that is reused is made into a function.  When a main program calls a function, the body of that function is executed and then the flow goes back to the main program at the location "after" the line that call that function.  This transfer of flow requires saving of the program counter (PC) which at the time of call pointed to the next instruction.  The return from a function call requires restoring PC.  There are two instructions for implementing a function call:
jump and link, jump register.

jal rx ads

jump and link save PC to rx and jump to ads.  rx = PC; PC = ads.

jr rx

restore PC from rx.  PC = rx.

rx is called a link register.  It stores PC which is called "the return address" for the function call.  It is complicate when the function is recursive because rx must then be save/restore properly.  We will concern here only the non-recursive call.

What is not mentioned here is the passing of parameters of a function call.   It involves a data structure called "activation record".  This data structure is the topic related to compiler contruction.  For simplicity, the parameters can be passed through registers, assuming that the programmer takes responsibility to allocate registers appropriately.

Example of function call.

main(){
  a = 2
  b = sq(a)
}

sq(x){
  return x * x
}

let r1 = a, r2 = b, r3 = x, r4 = retads, r5 = retvalue.
 

:main
     ld r1 #2
     st a r1          ;; a = 2
     add r3 r1 r0     ;;  x = a
     jal r4 sq        ;; call sq()
     add r2 r5 r0     ;; b = sq(a)
     st b r2
     trap print r2
     trap stop r0
:sq
     mul r5 r3 r3
     jr r4            ;; return


Note we use "add rx ry r0"  to do rx = ry (moving a value between two registers)

r4 is used as a link register to store the return address.  The passing of a parameter is done by assigning x = a ("add r3 r1 r0").  The return value is stored in r5.

12 June 2003