Notes N24

Math 10 -- D. C. Smolarski, S.J.
Santa Clara University, Department of Mathematics and Computer Science

[Return to Math 10 Homepage | Return to Notes Listing Page]

Contents


Machine Level Programming

It has already been mentioned that machines don't really understand higher level languages directly, i.e., BASIC, FORTRAN, COBOL, Pascal, C, C++. Computers only "understand" what is called "Machine Language."

MACHINE LANGUAGE is the binary numeric code that can be directly interpreted by the hardware when loaded into the proper "register."

There is a shorthand way of writing machine language instructions in which alphabetic code is used instead of a string of zeroes and ones. This is called ASSEMBLY LANGUAGE and is the mnemonic code that people usually write in -- it has a 1-1 correspondence (more or less) with machine code.

Both "machine language" and "assembly" are often used interchangeably and referred to as "machine level" programming.

What a computer (i.e., program language compiler) does is translate a higher level language (e.g., Pascal, C/C++, FORTRAN) into assembly code. (On many machines it is possible to see the assembly translation of source code.)

A compiler gives "compiler errors" when it cannot understand the higher level code and therefore cannot continue translating the code into assembly.

Machine Types

In general there are four types of machines, classified by how many memory addresses (or locations) are needed in each instruction.
0-address  stack	rpn prog'ble calculator
1-address  accumulator	"Kosmos"
2-address  --		DEC
3-address  --		--
Let's look at the first two types a bit more.

0 - Address or "Stack" Machine

The simplest type of machine language to look at is the 0-address paradigm, which is the type of machine that many programmable calculators are like.

SOME BACKGROUND:

A STACK is a data structure such that the FIRST information put INTO is the LAST information OUT (called FILO). Information is enterred and removed from the stack at its TOP. One visualization is the dish stack dispenser in a cafeteria.

The major operations associated with stacks are:

-- PUSH (also called STACK) -- inserts new information into the stack.

-- POP (also called UNSTACK) -- removes information from the stack.

-- PEEK (also called VIEW or TOP) -- examine the next element that could be popped.

A stack contains space to store the information as well as a TOP-OF-STACK pointer that indicates the location of the TOP. The PEEK operations looks at what the TOP-OF-STACK points to.

SIMPLE EXAMPLE. INPUT STREAM: 1 2 3 4 5
COMMANDS: Pu Pu Pu POP POP Pu POP Pu POP POP
(this can also be written as S S S U U S U S U U)

|    |
|    |
|    |
|    |	OUTPUT STREAM: ___ ___ ___ ___ ___
|    |
|    |
|____|

One can use stacks for evaluating arithmetic expressions.

There are at least two possible options: using 1 stack or 2.

1 stack

Each arithmetic operation operates on the top two elements of the stack, replacing them with a new element.

For simplicity of notation, we can modify our basic stack commands to include an argument. E.g.

	PUSH(n)  -- push  n  onto the stack
	POP(A)   -- pop from Top-of-stack into variable A.

E.g.
	5*3 ==> PUSH(5)
		PUSH(3)
		MULT
		POP(output)	==> 15


	C = A + B*C ==>	PUSH(A)
			PUSH(B)
			PUSH(C)
			MULT
			ADD
			POP(C)
NOTE: The order of stack operations is the same as RPN, i.e., tree traversal in post order: A B C * +

2 stack

This is arrangement is sometimes used by small calculators that operate with "algebraic" notation.

In this situation, one stack is used for operands (i.e., numbers) and the other for the operators.

Each operator is associated with a "precedence" number. If you try to push a "smaller" operator on top of a "larger" one already at the top of the stack, you first must "reduce" the operAND stack with the already existing operatOR at the top of the stack.

This has the advantage of not having to save operators from the input list and can be adapted for parentheses in expressions (in this case, each open-parenthesis changes the precedence number by +4 and each close-parenthesis changes the precedence number by -4).

	OPERATOR:		+ - * /
	PRECEDENCE NUMBER:	0 1 3 4

	3 + 2 * 5 + 6

	|    |    |    |
	|    |    |    |
	|____|    |____|
	op'rand	  op'tor

REDUCE

	|    |    |    |
	|    |    |    |
	|____|    |____|
	op'rand	  op'tor

REDUCE

	|    |    |    |
	|    |    |    |
	|____|    |____|
	op'rand	  op'tor

REDUCE

	|    |    |    |
	|    |    |    |
	|____|    |____|
	op'rand	  op'tor

1 - Register Machine

One register machines are also called "accumulator" machines because of a register which "accumulates" the values similar to the display on a pocket calculator. In the simplest form of such a machine, all arithmetic work is done in the accumulator and all storage passes through it.

To clarify this, we refer to an imaginery 1-register machine called KOSMOS. (There is actually a program simulating KOSMOS written in FORTRAN -- unfortunately, it has not been updated for the Alpha as yet.) KOSMOS is a paradigm of a typical machine with similar commands. (A list of KOSMOS commands can be seen via this link.)

For the convenience of humans to read its commands, KOSMOS is a decimal machine. Each word has 10 digits plus a sign. Memory consists of 1000 words.

When a word is used as an instruction, it is subdivided into three sections.

First two digits are the operation code.

Next four digits are for modification of the address.

Last four digits comprise the memory address.

We refer to the sheet for the complete list of numerical commands and mnemonic abbreviations.

FOR EXAMPLE

Suppose we want to code C= A+B for KOSMOS.

Suppose A corresponds to memory location 20, B to 21 and C to 22.

To translate C = A+B for KOSMOS we want to:

  1. load A into the accumulator
  2. add B to what is in the accumulator (i.e., to A)
  3. store what is in the accumulator into C
I.e.,
	40 0000 0020	(load from A)
	20 0000 0021	(add B)
	42 0000 0022	(store in C)
This is what "machine language programming" consists of.

There is a problem: it is difficult to read and decipher, particularly if written in binary.

The solution: use mnemonic and symbolic codes and address. This become "assembly language programming."

We can translate the 3 line code above into:

	LD	A
	ADD	B
	ST	C

Fibonacci Example

C/C++ code
	a = 1;
	b = 1;
	cout << a << endl;
	while (a < MAXIMUM) 
	{
	  c = b + a;
	  a = b;
	  b = c;
	  cout << a << endl;
	}
KOSMOS Assembly
	HI	WRP	A
		BOV	BYE
		LD	B
		ADD	A
		ST	C
		LD	B
		ST	A
		LD	C
		ST	B
		BU	HI
	BYE	EXT
	A	DC	1
	B	DC	1
	C	DS	1
		END

2 - Register Machine

The commands for this machine are similar to those of a 1-register machine, with the difference that TWO ADDRESSES may be given in some commands.

For example,

   ADD	A,C  <==> ADD A + C and store in A         
	     <==> A = A+C
   SUB	B,D  <==> SUBTRACT D from B and store in B 
 	     <==> B = B-D

Many DEC machines, like the VAX, are 2-register machines. One can see the translation by the compiler into assembly by requesting the machine code to be printed.

3 - Register Machine

In these machines, THREE ADDRESSES may be given in some commands.

For example,

	ADD	A,B,C	<==>	C=A+B
	SUB	B,D,E	<==>	E=B-D


This page is maintained by Dennis C. Smolarski, S.J. dsmolarski@math.scu.edu
© Copyright 1997, 1998, 1999 Dennis C. Smolarski, SJ, All rights reserved. Last changed: 5 March 1999.