Saturday, November 2, 2013

LOOPS AND SUBROUTINES IN ASSEMBLEY LANGUAGE

The LOOPS and SUBROUTINES are two of the most important constructs which are at the heart of all programming paradigms. The IBM's BAL (360) provides support for creating efficient LOOPS and SUBROUTINE calls with help of a rich inventory of the instructions at hand.

CREATING LOOP STRUCTURES

The LOOPS are essentially the chunks of code which are executed repeatedly subject to certain control condition. Two types of looping structures are most frequently encountered:
  • Type1: Loop with known number of cycles
  • Type2: Loop with unknown number of cycles
The Type 1 loops are often created either of following instructions:
         BCT    r1,D(X,B)
         BCTR   r1,r2
   

The effect of executing either of these is shown in following pseudocode:
BCT:
   |r1| = |r1|-1
   if(|r1|!=0) take branch to D(X,B)
   else go to next instruction
       1. Condition code remains unaltered.
BCTR:
   |r1| = |r1|-1
   if((|r1|!=0)&&(|r2|!=R0)) take branch to |r2|
   else go to next instruction.
       1. Condition code remains unaltered.

The type 2 loops are created using either of following:
         BXLE  r1,r2,D(B)
         BXH   r1,r2,D(B)
           1. Note the absence of X in address.
   


Both of these are examples of type RS instructions that are coded as follows.
   h_{0}h_{0}h_{r1}h_{r2}h_{b}h_{D}h_{D}h_{D}
   Where:
     h_{0}h_{0} : Machine code of the instruction
     h_{r1}: Register r1
     h_{r2}: Register r2
     h_{B} : Base Register
     h_{D} : 3 Byte displacement
   


Whenever either of these are present, following are assigned:
  • Index Register (INDR)
  • Increment Register (INCR)
  • Limit Register (LIMR)
This is done according to following pseudocode:
     INDR  = r1
     if (r2 == Even Numbered) :
           INCR = r2
           LIMR = r2+1
     else if (r2 == Odd Numbered):
           INCR = r2
           LIMR = r2
  

Once these three are identified, working of both these instructions can be understood below:
BXLE:
    |INDR| = |INDR|+|INCR|
    if (|INDR| <= |LIMR|) take a branch to D(B)
    else go to next instruction
        1. Condition code remains unaltered.
BXH:
   |INDR| = |INDR|+|INCR|
   if (|INDR| >  |LIMR|) take a branch to D(B)
   else go to next instruction
       1. Condition code remains unaltered.
  

CREATING INTERNAL SUBROUTINES

Succession of logical steps for calling a subroutine is summarised below:
   1. Store the address of next instruction in some register.
   2. Take a branch to the address where subroutine begins.
   3. Once there, store all the registers to an area in memmory
   4. Perform the tasks coded into the subroutine
   5. At the end, restore all registers from area in Step:3
   6. Take a branch to main program using information stored in Step:1 
  

The Steps 1,2 can be implemented using either of following instructions:
          BAL   r,D(X,B)
          BALR  r1,r2
Pseudocode:

BAL:
   |r| = |PSW (right 32 bits)|
   take a branch to D(X,B)

BALR:
  |r1| = |PSW (right 32 bits)|
  if (r2 != R0) take a branch to |r2|
  else go to next instruction 
  

The BAL instruction cause right 32 bits of PSW which contain the address of next instruction, to be stored in 'r' register. Then a branch is taken to the address D(X,B), which in current context is the address of subroutine we wish to call. The BALR instruction is similar to BAL, except that the branching takes place into the address contained in r2 and that if r2 is R0, branching does not take place.

Upon being called, a subroutine needs to store caller's data before using any of the registers, so that they may be restored upon exit. This constitute steps 3 and 5, and may be implemented with following instructions:

          STM   r1,r2,D(B)   :STORE TO MEMMORY
          LM    r1,r2,D(B)   :LOAD FROM MEMMORY

Pseudocode:

STM:
   Store registers r1 through r2 into 1 FW each
   of the contiguous memmory starting D(B). 

LM :
   Restore registers r1 through r2 from contiguous 
   memmory starting at D(B), reading 1 FW into each.
  
*NOTE: Note address is coded as D(B): X not allowed !!
  

Here we show a pseudocode to demonstrate the call to an internal subroutine:
***********************************************************
*MAIN FUNCTION: CALLER DEMO                               *
*R6: CONTAINS ADDRESS OF NEXT TO CALLER                   *
***********************************************************
MAIN     CSECT                   :CONTROL SECT
         USING MAIN,15           :ESTABLISH BASE REG
         BAL   R6,SUBR           :STORE NEXT INSTR,
*                                 AND BRANCH TO A(SUBR)
         BR    R14               :EXIT 
***********************************************************
*SUBROUTINE SUBR: DEMO SKELETON                           *
*R6: CONTAINS ADDRESS OF NEXT TO CALLER                   *
***********************************************************
SUBR     STM   R0,R15,SUBSAFE    :STORE REGS INTO MEMMORY
         ...   ..............    :DO STUFF
         ...   ..............    :DO STUFF
         LM    R0,R15,SUBSAFE    :RESTORE REFS FROM MEMMORY
         BR    R6                :BRANCH BACK TO CALLER
         LTORG                   :LITERALS STORAGE
SUBSAFE  DS   18F                :RESERVE REG STORAGE
         END   MAIN              :END MAIN
   

Its time to finish the current post here, please take time to post your comments or suggestions below. If you have any example code, feel free to share that as well.