University of Wisconsin Computer Sciences Header Map (repeated with 
textual links if page includes departmental footer) Useful Resources Research at UW-Madison CS Dept UW-Madison CS Undergraduate Program UW-Madison CS Graduate Program UW-Madison CS People Useful Information Current Seminars in the CS Department Search Our Site UW-Madison CS Computer Systems Laboratory UW-Madison Computer Sciences Department Home Page UW-Madison Home Page

Lecture Notes for Chapter 2 -- SAL

CS/ECE 354: Machine Organization and Programming

Mark D. Hill's Section 4 for Fall 2001




*******************************************************************
*  Students should read UPDATED Chapter 2 handout from web page,  *
*  which is more up to date than Chapter 2 in the textbook.       *
*******************************************************************

MOTIVATION for SAL:
     hiding the details of MAL, MIPS asm. lang. (on purpose!)
     SAL code will look more like HLL code -- to make student's transition
	  easier.
     Introducing one more level of abstraction in order to postpone
	  discussion of several topics.


     HLL           SAL         assembly          machine code


     each HLL statement maps into 1 or MORE SAL instructions
     each SAL instruction maps into 1 or MORE MAL instructions

     for this course, there is actually one more layer that
     students will be given

     HLL        SAL     MAL       TAL      MIPS RISC machine code




SAL

A subset of the functionality of most high level languages --
     no records/structures
     no formal arrays (see chapter 7 for their implementation)

What is required by a programming language?
  declarations
  arithmetic operations
  conditional execution (if then else)
  looping control structures
  communication w/user. . .(write statement)


About SAL:
 -- one instruction, declaration per line
 -- comments are anything on a line following `#'
    (comments may not span lines)




DECLARATIONS
------------

  - they give information about how much memory space is needed
  - they assign a name to the memory space

  SAL has 3 basic types: integer, float (real), character
  can build other types out of these,
       for example, boolean is really an integer with only 2 defined values.
  
  Pascal:
       var        variablename:  type;

  C:
       type     variablename;

  SAL:
       variablename:  type value


     type is       .word      if integer
		   .byte      if character
		   .float     if real (floating point)

     value is optional -- it gives the variable an initial value

  examples:
       flag:  .word   0

       counter:   .word   0

       variable3: .word

       e:  .float   2.71828

       uservalue:    .byte

       letter:    .byte 'a'



other useful rules:
  -- one declaration per line.
  -- default initial value is 0.



DIRECTIVES
----------
  a way to give information to the assembler.

  - all directives start with `.' (period)

    examples:

	 .byte
	 .word
	 .float

	 .data       # identifies the start of the declaration section
		     #   there can be more than 1 .data section in
		     #   a program


	 .text       # identifies where instructions are
		     #   there can be more than 1 .text section in
		     #   a program

	 .asciiz  "a string.\n"  # places a string into memory
				 # and null terminates the string.

	 .ascii  "new string."   # places a string into memory
				 # WITHOUT null termination.





ARITHMETIC operations
----------------------

     SAL             Pascal             C

     move x, y       x := y;           x = y;
     add x, y, z     x := y + z;       x = y + z;
     sub x, y, z     x := y - z;       x = y - z;
     mul x, y, z     x := y * z;       x = y * z;
     div x, y, z     x := y div z;     x = y / z;
     rem x, y, z     x := y mod z;     x = y % z;

   NOTES: 1. the operation result depends on the type of the variables.
	  2. cannot increase the number of operands.
	  3. y and/or z can be IMMEDIATES


   examples:

      move  count, 0

      mul   product, mult1, mult2

      add   sum, 2, addend


NOTE:  there are other instructions that implement boolean functions,
       but we don't cover them yet.


GO OVER SIMPLE PROGRAM modified from REVISED Chapter 2 Figure 1 page 7
(and note that (20+13+82)/3 = 38.333...)


-------------------------------------------
avg3.c
-------------------------------------------

/* a simple C program to average 3 integers */

#include <stdio.h> 

void main()
{
   int avg;
   int i1 = 20;
   int i2 = 13;
   int i3 = 82;

   avg = (i1 + i2 + i3) / 3;

   printf("%d\n", avg);
}

-------------------------------------------
avg3.s
-------------------------------------------

# a simple SAL program to average 3 integers

        .data
avg:    .word
i1:     .word 20
i2:     .word 13
i3:     .word 82

        .text

__start: add avg, i1, i2
         add avg, avg, i3
	 div avg, avg, 3
	 put avg
	 put '\n'
	 done

-------------------------------------------

        Show assembly code
        Assembler translates to executable -- machine language
        (multiple source files need "linker" -- much later)

        To Run
                loader puts executable into memory and makes
                CPU jump to first instruction or __start:
                execute
                executing done returns control to OS

        Repeat last step to run again -- usually with different data

        simp combines all of the above

Explain
        # comment follows and end at end of line
        .data   # data follows
        .text   # instructions follow

        __start:        label to start program
        done            syscall to end program



CONDITIONAL EXECUTION
---------------------
  sometimes an instruction (or a set of instructions) should
  be executed, and sometimes it (they) shouldn't.

  HLL -- simplest form is a go-to.  (Always discouraged.)


Pascal if-then-else
  (a conditional go-to!)

   if (condition) then
       statement
   else
       statement;


C if-then-else

   if (condition)
       statement;
   else
       statement;


SAL 'ifs' and 'gotos'
--------------------------------
    SAL                  Pascal

    b label             goto label;
    bltz x, label       if x < 0 then goto label;
    bgtz x, label       if x > 0 then goto label;
    blez x, label       if x <= 0 then goto label;
    bgez x, label       if x >= 0 then goto label;
    beqz x, label       if x = 0 then goto label;
    bnez x, label       if x <> 0 then goto label;
    beq x, y, label     if x = y then goto label;
    bne x, y, label     if x <> y then goto label;
    blt x, y, label     if x < y then goto label;
    bgt x, y, label     if x > y then goto label;
    ble x, y, label     if x <= y then goto label;
    bge x, y, label     if x >= y then goto label;




EXAMPLE:
--------
  Pascal if-then-else:

       if (count < 0) then
       begin
	   count := count + 1;
       end;

  C equivalent:

       if (count < 0)
	   count = count + 1;


SAL equiv to if-then-else:

                bltz count, ifstuff
	        b endif
      ifstuff:  add count, count, 1
      endif:      # next program instruction goes here

	 -- OR --

                bgez count, endif
	        add count, count, 1
      endif:      # next program instruction goes here


    WHICH ONE OF THESE IS BETTER?



Structured loops can be built out of IF's and GOTO's
                                  (test and branch)

EXAMPLES:
---------

while loop example

  Pascal:

       while ( count > 0 ) do
       begin
	   a := a mod count;
	   count := count - 1;
       end;

  BAD STYLE Pascal:

       while: if  (count <= 0) then goto endwhile;
	      a := a mod count;
	      count := count - 1;
	      goto while;
       endwhile:

  C:

       while (count > 0) {
	   a = a % count;
	   count --;
       }

  SAL:

      while: blez  count, endwhile
             rem a, a, count
             sub count, count, 1
             b while
      endwhile:    # next program instruction goes here




repeat loop example

  Pascal:

       /* do statement until expression is TRUE */
       repeat
	   if (a < b) then
	      a := a + 1;
	   if (a > b) then
	      a := a - 1;
       until a = b;


  C:
       /* do statement while expression is TRUE */
       /*   when expression is FALSE, exit loop */
       do {
	   if (a < b)
	       a++;
	   if (a > b)
	       a--;
       } while( a != b);


  SAL:

      repeat:    bge a, b, secondif
                 add a, a, 1
      secondif:  ble a, b, until
	         sub a, a, 1
      until:     bne a, b, repeat



while loop example
  Pascal:

           while (count < limit) and (c = d) do
	   begin
	      /* loop's code goes here */
	   end;

  C:

           while ( (count < limit) && (c==d) )
           {
	      /* loop's code goes here */
           }
  SAL:

        while:   bge count, limit, endwhile
                 bne c, d, endwhile
        
                 # loop's code goes here

                 b while
        endwhile:







for loop example

  Pascal:

           for i:= 3 to 8 do
           begin
               a := a + i;
           end;


  C:

	   for ( i = 3; i <= 8; i++)
	   {
	       a = a + i;
	   }

  SAL:

                 move i, 3
        for:     bgt  i, 8, endfor
                 add  a, a, i
                 add  i, i, 1
		 b for
        endfor:



COMMUNICATION WITH THE USER (I/O operations)
--------------------------------------------
     SAL              Pascal

     put x           write(x);
     get x           readln(x);
     puts 'string'   write('string');

SAL doesn't have any oddities about
testing for eoln or eof.  A carriage return is just another
character to be read or written.  It is '\n'

get  has the most irregularities!
---
  get intvariable
    places  first integer variable it "finds" into intvariable,
    then throws away the rest of the line.

    if the first value read does not match the type requested, then
    the value 0 is placed in variable intvariable.
    
  get charvariable
    placed the first character variable it has into charvariable

EXAMPLES:

  INPUT:

  23 abc
   -13
  1234fgh!

  SAL CODE:

     get int1        # int1 <- 23
     get int2        # int2 <- -13
     get int3        # int3 <- 1234

  OR:

     get char1       # char1 <- '2'
     get int1        # int1 <- 3, and throw away rest of line
     get char2       # char2 <- ' ', there is a space character before
		     #    the -13

  OR:

     get char1       # char1 <- '2'
     get char2       # char2 <- '3'
     get int1        # int1 <- 0, because the first value read (ignoring
		     #   the white space) is not a digit, so the type does
		     #   not match.

So, if you want to get more than one non-character value from
a single line, you must read in character by character, and
convert to whatever form is desired.  More about this in
chapter 4.




PROGRAM EXAMPLE:
----------------

# this simple program adds up 2 integers and prints their sum and products.

   .data

 prompt1:  .asciiz "Enter an integer: "
 prompt2:  .asciiz "Enter a second integer: "
 linefeed: .byte '\n'
 msg1:     .asciiz "The sum of "
 msg2:     .asciiz " and "
 msg3:     .asciiz " is "
 msg4:     .asciiz "The product of "
 int1:     .word  0
 int2:     .word  0
 sum:      .word
 product:  .word

   .text

      # get the 2 integers from user
           puts prompt1
           get int1
           put linefeed
           puts prompt2
           get int2
           put linefeed

      # calculate the sum and products
           add sum, int1, int2
           mul product, int1, int2
	
      # print out the sum and products
           puts msg1
           put int1
           puts msg2
           put int2
           puts msg3
           put sum
           put linefeed

           puts msg4
           put int1
           puts msg2
           put int2
           puts msg3
           put product
           put linefeed
           done



Another simple SAL example program (optional)
----------------------------------

# A SAL program to print out a multiplication table

 .data
start:    .word 0  # entered by user
finish:   .word 0  # entered by user
ii:       .word    # loop induction variable
jj:       .word    # loop induction variable
product:  .word
prompt1:  .asciiz "Enter starting value: "
prompt2:  .asciiz "Enter ending value: "
newline:  .byte '\n'
x_symbol: .byte 'X'
equals:   .byte '='
space:    .byte ' '

 .text

__start:    puts prompt1                # get user input
            get  start
            puts prompt2
            get  finish


            move ii, start
for:        bgt  ii, finish, all_done   # nested for loop to print out
            move jj, start              # the table
nested:     bgt  jj, finish, next_iter
            mul  product, ii, jj

            # print one line of table
            put  ii
            put  space
            put  x_symbol
            put  space
            put  jj
            put  space
            put  equals
            put  space
            put  product
            put  newline

            add  jj, jj, 1
            b    nested
next_iter:  add ii, ii, 1
            put  newline
            b    for

all_done:   done



PROCEDURES 101
--------------

In main program:

	...
	y = abs(x);	<--call--need a branch
	y = y + 1;	<--return point/address
	...



	int abs (x);
	int x, y;
	{
	    if (x < 0) {
		y = -x;
	    }
	    else {
		y = x;
	    }
	return(y);
	};	<-- return -- branch back


Ignore parameters, simplest SAL:
	
	...
	b abs
return:	add y,y,1
	...

abs:	bgez x, nonnegative
	sub y, 0, x
	b endabs
nonnegative: move y, x
endabs:	b return


But what about (add to HLL):

	...
	... = abs(y,x)
	y = y + 1;
	x = y*x;	<-- new
	... = abs(y,x)	<-- new
	y = y + 2;	<-- new
	...



Needed:  an ADDRESS to return to!

       la  var1, label

       The address implied by label is placed into var1.
       Notice difference between address and contents of
       the address.
       NOTE:  var1 must be declared as integer (.word)

       label       address      contents
        aa:          103           6
        bb:          104           'a'
        cc:          105          2001


       The SAL instruction
	 la cc, bb
       changes the table above to be:

       label       address      contents
        aa:          103           6
        bb:          104           'a'
        cc:          105       **  104  **

	
Change SAL again
	
returnhere:	.word			<-- add

	...
	la returnhere, return		<-- add
	b abs
return:	add y,y,1
	mul x,y,x
	la returnhere, return2		<-- add
	b abs
return2: ...

Change SAL procedure:

abs:	bgez x, nonnegative
	sub y, 0, x
	b endabs
nonnegative: move y, x
endabs:	b returnhere		<-- change, NOT!

Must be:

endabs:	b (returnhere)	<-- Parentheses are important


Key ideas
	assembly vs execution
	SAL language
		declatations
		arithmetic
		conditional
		looping
		I/O
		procedures