Runtime environment
Runtime stack (activation record)
      In this lecture we will discuss how a high level language being compiled
      into assembly language. One of the necessary supports for function call in
      high level language is the runtime environment.  It is simply called
      "stack frame" or "frame" in short.  Sequences of assembly code must
      be added to the main code to "create" this frame when "entering" the
      function body and "delete" it when the function call is ended.  A
      frame  is stored in the main memory, with a global register "FP"
      (frame pointer) points to it.  The frame is used to save values of
      registers of the caller when entering the function body and restore them
      when ending (return). The registers that need to be saved/restored are the
      ones use by the function. This includes the link register that holds
      "return address" because function call can be nested (call another
      function).
      
      Let us see the simplest program compiled into assembly
      
      main()
          a = 0
the output is:  (ignore the symbol/data section)
      
      ...
        .code 0
         mov fp #3500
         mov sp #3000
         jal rads main    ;  *** call main
         trap r0 #0        
        ;   *** stop
        
        :main
          st r1 @1 fp
          add fp fp #2
          st rads @0 fp
          mov r1 #0        ; <<<
        *** a = 0
        :L101
          ld rads @0 fp
          sub fp fp #2
          ld r1 @1 fp
          ret rads
        
        .end
      
      Note:  to access frame, we use addressing with offset (disp)
      
      ld r1 @d r2      R[r1] = M[ R[r2] + d]
        st r1 @d r2      M[ R[r2] + d] = R[r1]
      
      The runtime stack is created.
      
      :main
          st r1 @1 fp
          add fp fp #2
          st rads @0 fp     ;  ***  create
        frame
        
          <body>
        
          ld rads @0 fp
          sub fp fp #2
          ld r1 @1 fp        
        ;  ***  delete frame
          ret rads
      
      
      when a function is called, it creates a "frame" to store the "return
      point" and local variables.

Figure 1 Picture of stack frame when main() call A() and A() call B().
in the above example, fp points to the current frame, the return point
      (rads) is stored at the slot 0. local var r1 ("a") is stored at the slot
      1. 
      
      a frame looks like this
      
      memory
      stack grows downward
      
        ----           
        <- fp'
        r1       
        fp-1        (main)
        retads    fp+0  <- fp    
        -----
           
      let us see a call to a user defined function
      
      double(x)
          return x + x
        
        main()
          a = double(2)
      
      its assembly language is:
      
      .code 0
        
        :double
        st r1 @1 fp
        st r2 @2 fp
        add fp fp #3
        st rads @0 fp
        pop sp r1       ; *** get actual parameter
        x
        add r2 r1 r1    ; *** tmp = x + x
        mov retval r2   ; *** return tmp
        ...
        ld rads @0 fp
        sub fp fp #3
        ld r2 @2 fp
        ld r1 @1 fp      ; *** delete frame
        ret rads
      
      :main
        ...
        mov r2 #2
        push sp r2       ; *** pass x to double
        jal rads double
        ....
        ret rads
        
        .end
      
      double() has two local vars r1 (x) and r2 (tmp). it accepts the passing
      value (x) from parameter stack. The parameter stack is a separate stack
      used to keep the passing parameters when doing a function call. A global
      register ("SP", for stack pointer) points to this region.  The values
      of FP and SP must be initialized when main() starts.
      
      frames look like this:
      
        ----
        r1                    
        (main)
        retads 
        -----
        r1       
        fp-2         (double)
        r2        fp-1
        retads    fp+0  <- fp  
        -----
      
      Now let us see how to access an array
      
      ax[10]
        
        main()
          ax[1] = 22
      
      its assembly is:
      
      .symbol
          ax 1100        ; *** compiler
        allocate ax at 1100
        .code 0
        :main
        ...
          mov r1 #22
          mov r2 #1
          st r1 @ax r2   ; ***  ax[1] = 22
        ...
        .end
      
      You can use my compiler "rz36" to compile a high level language file (Rz)
      into S2 assembly language and inspect the output file.
test(x)
        if( x == 0 ) 
           b = 1
        else
           b = 2
         while( b < 10 )
           b = b + 1
        return b
      
      main()
        test(x)
    use the command in a console :
> rz36 test.txt > out.txt
out.txt contains the assembly file. You can assemble and run it.
> as21 out.txt 
this will produce two files: "out.lis" and "out.obj". You run "out.obj" using the simulator
> sim21 out.obj
end
last update 31 Mar 2020