\input{myLectHead}

\setcounter{lecture}{4}

% Oct 10, 2007
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lecture{Toy Hardware and Operating System}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lectpart{Introduction}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

For use in our OS projects,
we introduce ``THE Machine'' where ``THE'' is an acronym\footnote{
	THE is the namesake of a multi-tasking OS designed in 1965--6
        by the pioneer Dutch Computer Scientist, Edsger Dijkstra.
        "THE" is an abbreviation of "Technische Hogeschool Eindhoven",
        now the Eindhoven University of Technology.
}
for \dt{Toy HardwarE}.  We also introduce
an associated \dt{Toy Operating System} (TOS).
Both THE Machine and Toy OS are implemented as C programs.
The assembly language for THE Machine is called
\dt{Simulated Toy Machine Language} (STML).

The Toy OS executes a single STML program at a time.
Sample STML programs will be provided.
All our OS projects are based on THE/TOS.
One of your first assignment is to modify the Toy OS is
to introduce multi-programming.

The source files for THE/TOS are found in a CVS repository
which you can get access to.
You are to store your projects in the CVS repository,
which will be team-based.
In order to carry out these projects, you
will learn need to learn about using the CVS tool 
for developing software projects.

% are found in \dt{the.c} and \dt{tos.c}, respectively.
% There are associated header files \dt{the.h} and \dt{tos.h}.

%We provide some sample STML programs:
%\ttt{primes.stm}, \ttt{sort.stm}, \ttt{fraction.stm}, \ttt{gcd.stm}

History.  THE/TOS originated as a unified program
by Professor E.~Davis in his OS courses.  
The stark simplicity of his machine made it
a great pedagogical tool.  
In Fall 2006, we decided to
split the OS part from the hardware, to permit
independent development of the hardware and software.
Various OS projects can be defined over 
this barebones framework.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lectpart{THE Machine}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%\bitem
%\item
Hardware Specification:
THE Machine has 1 MB of RAM,
and this is divided up into 256K of words
where each word is 4 bytes.
We can address individual words in the RAM.
Hence, the physical address space is 18 bits.

There are 16 registers, named R0, R1,..., R15.
The register R0 is the PC (program counter).

There are three special registers to support multiprogramming:
a base register, a limit register, and an program status word
(a.k.a.~error status flag).

%\item
There are 16 machine instructions.
Thus each instruction can be represented
by a 4-bit number.  These 4-bit numbers are
called \dt{OpCodes}.  The operands
of each instruction consists of at most one address (AD),
and up to four registers (RA, RB, RC, RD).
Here, AD is an 18-bit number while RA, RB, RC, RD
are all 4-bit numbers.

%\item
The following table describes these 16 instructions.

{\small
\bcen
\begin{tabular}{|l | l | l | l |}
\multicolumn{4}{c}{Table of STML Instructions} \\
\hline
OpCode	& Operation & Operands	& Meaning \\\hline\hline
0	& LOA	& RA, AD &	Loads contents at location AD to RA \\
1	& STO	& RA, AD &	Stores contents of RA to location AD \\
2  	& CPR 	& RA, RB &	 Copies RB into RA\\
3  	& LOI 	& RA, RB &	 RB holds the address of AD. Loads the
				value of AD into RA.\\\hline
4  	& STI 	& RA, RB &	 RB holds the address of AD. Stores the
				value in RA to AD.\\
5  	& ADD 	& RA, RB, RC &	 RC = RA + RB\\
6  	& SUB 	& RA, RB, RC &	 RC = RA - RB\\
7  	& MUL 	& RA, RB, RC &	 RC = RA * RB\\\hline
8  	& DIV 	& RA, RB, RC, RD &	 RC = RA / RB, and RD = RA \% RB.\\
9  	& ICR 	& RA &	 RA\mathpp\\
10 	& DCR 	& RA &	 RA\mathmm\\
11 	& GTR 	& RA, RB, RC &	 RC = (RA $>$ RB)\\\hline
12 	& JMP 	& RA, AD &	 Jumps to AD. (RA is unused).\\
13 	& IFZ 	& RA, AD &	 If (RA == 0) then goto AD.\\
14 	& JMI 	& RA &	 RA holds the address of AD. Jump to AD.\\
15 	& TRP 	& &	 Traps to the kernel. \\\hline
\end{tabular}
\ecen
}%small

%\item
Remark: the ``I'' in the instruction names \ttt{LOI/STI/JMI}
suggests \ul{I}ndirect Addressing, i.e., when the address
is stored in a register or location, rather than explicitly given.
But the ``I'' in \ttt{ICR} and \ttt{IFZ} is just coincidence.

%\item
Each STML instruction can fit into a machine word:
the OpCode is laid out in the lowest order $4$ bits,
followed by the arguments.
This layout is illustrated in \refFig{stml}.
Here, bit 0 is the lowest-order bit and bit 31 is the highest-order bit.

\myfignew{stml}{Formats for STML instructions}{stml}{.4}

%\item
For instance, in \refFig{stml}(a), we see that
the instruction
	$$\ttt{LOA\ RA,\ AD}$$
uses bits 0--3 to specify the OpCode,
bits 4--7 to specify the registor RA,
and bits 8--25 to specify the address AD.
This uses up 4+4+18=26 bits.  
The remaining bits 26--31 are unused.

Let us suppose that \ttt{RA=3} and \ttt{AD=10}.
Then the bit pattern for this instruction would be

\beql{load}
	\ttt{(0000,0000,0000,0000,0000,1010,0011,0000)}.
\eeql

%\item
There are 6 distinct instruction formats,
depending on OpCode.  These formats use
at most 26 bits, and as few as 4 bits.
Besides the four formats in \refFig{stml},
there are two others. 
(What are they?)

%\item
We must discuss the TRAP instruction.
Registers 15 and possibly 14 and 13 will be used.
The value in R15 indicates the nature of the system call.
So we refer to the instruction as ``TRAP $n$''
if the value of R15 is $n$.

	\bitem
	\item R15 = 0.
		Terminate. The process halts.
	\item R15 = 1.
		Integer Input. Read an integer from standard input.
		The value of the integer read is
		returned to the process in register R14.
		R13 is returned as 1 if an integer
		has been read and 0 if the end-of-file is reached.
		Any non-integer value in standard input causes an error.
	\item R15 = 2.
		Integer Output.
		Print on a new line to standard output in decimal 
		the value of the integer held in register R14.
	\item R15 $>$ 2.
		Future projects will involve defining other trap codes,
		for forking and for manipulating semaphores, etc.
	\eitem 

%\item
HISTORICAL NOTE:
In the Store Indirect Operation, \ttt{STI RA, RB},
we copy the contents of RA to the address found in RB.
This is consistent with the \ttt{STO RA, RB} command.
Prior to Version STM1.4, the arguments of STI would
be reversed, given as \ttt{STI RB, RA} instead.

%\eitem

\myPara{Enhanced I/O Traps.}
The above I/O traps for THE Machine handle
only integers.   We would like to be able to
handle general string I/O.  To do this, we enhance
the original TRAP 1 and TRAP 2 instructions.
As before, R15 stores the TRAP code,
R14 indicates what or where to input or output,
R13 is the return value.
But we now use R12 to indicate the length of the input/output
string.  When R12=0, it indicates an integer input/output
whose behavior is identical to the original TRAP instruction.

Thus, the new TRAP instruction is fully compatible with
the original one: to convert old STML programs to our
new spec, we just have to set R12 to zero before calling
TRAP 0 or TRAP 1.

	\bitem
	\item R15 = 1.  Input.

		If R12=0, the behavior is as before.
		Namely, we attempt to read an integer from standard input.
		The value of the read integer will be stored in R14.
		R13 is set to 1 if an integer
		has been read, to 0 if the end-of-file is reached,
		and to a negative number if a non-integer value is read.

		If R12$>$0, then we read a line of characters from the standard
		input.  If R12 has the value $n$, we read up to $n$ characters
		and store their ASCII code in consecutive memory locations,
		starting at the address stored in R14.  
		If the input line has more than $n$ characters, they are
		discarded.  The actual number of characters stored in
		memory is stored in R13.  A negative value in R13
		would indicate failure (e.g., the input string is longer than
		$n$ characters).  By convention, the TRAP instruction
		stores a NULL character (=$0$) after the last stored
		ASCII character.  So the caller of this TRAP must allocate
		at least $n+1$ memory locations for this instruction.

	\item R15 = 2.  Output.

		If R12=0, the behavior is as before.
		Namely we print on the standard output
		the value of the integer in R14.

		if R12$>$0, then we will print a string on the standard
		output.  If R12 has the value $n$, we output up to $n$ ASCII
		characters which are stored in consecutive memory locations,
		starting at the address stored in R14.  The end of the
		output string is indicated by the NULL character ($=0$).
		Again, the actual number of characters that is printed
		is stored in R13.  This number is negative in case of
		error conditions (e.g.,  attempting to print
		an non-ASCII code).
		
	\eitem 
NOTE:  For output, if R2=$-1$, the printed integer will not be followed
by a newline (the default behavior).  
If R2=$-2$, the printed integer will be followed by a space.  
If R2=$-3$, the printed integer will be followed by a comma.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lectpart{The Assembly Language STML}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\bitem
\item
STML (Simulated Toy Machine Language)
is the name of assembly language for THE Machine.

\item
An STML source file is a text (ASCII) file
that normally has the ".stm" extension.
It has the following structure:
	\bitem
	\item Line 1: name of process
	\item Line 2: an integer, specifying the
		size of memory (in number of words) for this process.
		This size includes space for code, data, variables, etc.
	\item Line 3 onwards: 
		1 instruction or data item per line.
		Any line not beginning with a number is ignored.
		Any item beyond the first number in a line is ignored.
	\eitem

\item
Let us discuss the ASCII encoding for STML instructions.
We view an STML instruction an 32-bit word, which
can be intepreted as an integer. 
By convention, we set the unused bits to zero.
With this convention, each instruction is uniquely
associated with a 32-bit integer.
It is best to write this integer in hexadecimal notation,
using the 16 ``hexadecimal digits''
	$$\ttt{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F}$$
We normally prefix a hexadecimal notation with the sequence $\ttt{0x}$,
to distinguish it from the standard decimal notation
(which is unadorned).
Thus, \ttt{0xA} is $10$ (in decimal) while \ttt{0x10} is $16$.
Again, \ttt{0xF} is $15$ is decimal, and \ttt{0x1F} is $16+15=31$.

Our main use of hexadecimal notation is, however, to denote
STML instructions in a convenient way.  For instance, the
bit pattern in \refeq{load} can now be simply written as
\ttt{0xA30}.  The following table gives more illustrations:

	\bcen
	\begin{tabular}{|l | l | l |}\hline
	Hexadecimal Notation & Instruction & Comments \\\hline\hline
	\ttt{0xF} & TRP & Trap instruction, no explicit arguments\\
	\ttt{0xA9} & \ttt{INC R10} & Increment register 10 \\
	\ttt{0xE22} & \ttt{CPR R2 R14} & Copy into register 2 the contents of register 14\\
	\hline
	\end{tabular}
	\ecen
\item
Let us go through a sample stm code, "fraction.stm".
	\begin{verbatim}
        fraction 
        33
        
        % This program reads four integers A,B,C,D from standard input
        % where A < B != 0.  It prints in the standard output,
        % successively, the first D "digits" of A/B in base C.
        % E.g., if (A,B,C,D)=(1,3,10,5), it prints out "3 3 3 3 3"
        % This code is from Professor Davies.
        
        0x1CF0     0  LOA R15 ONE
        0xF        1  TRP           --- Read A
        0xE12      2  CPR R1 R14    ---   and save in R1
        0xF        3  TRP           --- Read B
        0xE22      4  CPR R2 R14    ---   and save in R2
        0xF        5  TRP           --- Read C
        0xE32      6  CPR R3 R14    ---   and save in R3
        0xF        7  TRP           --- Read D
        0xE42      8  CPR R4 R14    ---   and save in R4
        0x512B     9  GTR R2 R1 R5  --- If A > B then fail. 
        0x195D     A  IFZ R5 EXIT
        0x192D     B  IFZ R2 EXIT   --- If B == 0 then fail.
        0x1BA0     C  LOA R10 ZERO  --- R10 is the counter for the number of digits.
        0x5A3B     D  GTR R3 R10 R5 --- If C <= 0 then fail.
        0x195D     D  IFZ R5 EXIT
        0x1DF0     E  LOA R15 TWO   --- The next series of traps will be prints.
                 LOOP 
        0x5137    10  MUL R3 R1 R5  --- print (A*C)/B;
        0x76258   11  DIV R5 R2 R6 R7
        0x6E2     12  CPR R14 R6
        0xF       13  TRP
        0x712     14  CPR R1 R7     --- A := (A*C) % B;
        0xA9      15  INC R10       --- Increment digit counter and compare to D.
        0x5A46    16  SUB R4 R10 R5
        0x195D    17  IFZ R5 EXIT
        0x100C    18  JMP LOOP
                 EXIT 
        0x1BF0    19  LOA R15 ZERO
        0xF       1A  TRP
        0         1B  ZERO          --- this is essentially the beginning of the
        1         1C  ONE           --- data segment!
        2         1D  TWO           --- 1D (=29 in decimal) is last address
	\end{verbatim}

\item
	Remarks about this code:
	\bitem
	\item Although all the instructions are in hexadecimal
		notation (indicated by the prefix \ttt{0x}),
		we also enter decimal numbers when convenient.

		For instance, line 2 indicates that the program
		memory size is $33$ in decimal.  Also,
		the last three lines of program contains
		just constants
		(ZERO, ONE, TWO) written in decimal notation.

	\item Following each STML instructions, on the same line, we
		enter three items of information in human-readable form.
		E.g., \ttt{0xF	3	TRP	--- Read B}.
		\bitem
		\item   STML instruction --- \ttt{0xF}.
		\item	Line number --- this is in hexadecimal notation,
			even though we omit the \ttt{0x} prefix.
		\item	The corresponding instructions in ``assembly language''
			--- TRP
		\item	Any comments --- this trap corresponds to 
			reading input B.
		\eitem

	\item Note that lines \ttt{1B, 1C, 1D} are data sections
		(storing the constants $0, 1, 2$).

	\item Can you see why we use 33 words for this process?

	\eitem

\item
	Another convention for data: in the above code, we
	see that constants such as ZERO, ONE, TWO, etc,
	are needed, and these are placed at the end of the 
	executable code.  An alternative convention is
	as follows: our first instruction is to jump
	to some relative starting address for
	our executable code, say \ttt{0x20}.
	The first 31 memory locations can be used for
	data and constants.  E.g., we can conventionally
	let \ttt{0x1}--\ttt{0xB} store the constants
	$0,1\dd 9$.   It is easier to remember the
	addresses of these constants (and it does not
	depend on the length of the STML program.

% construct an example!!!  This should be easy...

\eitem

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lectpart{The Toy OS (TOS)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

We now describe the Toy OS for THE machine.

\bitem

\item
The basic operation of THE/TOS is simply this: 

	\bitem
	\item It reads a STML file and loads the program
		into memory (sequentially).
	\item All addresses are \dt{relative}: the physical
		address is equal to the base register plus the
		relative address.
	\item It starts execution of the program starting at relative
		address 0.
	\eitem

\item
The compiled version the THE/TOS is called \ttt{tos}.
To invoke \ttt{tos}, you must give it a STML program to execute.
Three other optional arguments can be given under the following
flags:
	\bitem
	\item
		\ttt{-b} $n$:
	Here $n$ is a non-negative integer.
	This means that the program will be loaded starting
	at the base address of $n$.  Default value is $n=0$.
	\item
		\ttt{-d} $n$:
	Here $n$ is $0$, $1$ or $2$.
	It indicates the debugging level.  The default level is $n=0$,
	indicating no debugging messages.  At higher levels, the
	Toy OS is increasingly verbose, printing out various diagnostic
	messages.
	\item
		\ttt{-m} $n$:
	Here $m$ is a positive integer, indicating the maximum
	number of instructions in the STML program to be executed.
	This might be useful to avoid infinite loops while you
	are still debugging a STML program.
	\eitem

	Example: to run a program called \ttt{primes.stm} for at most
	99 instructions, and at debugging level $1$, you type

	\myprogtt{\> \% tos -b 1 -m 99 primes.stm}


\item
Program Status Word (PSW) and Error Status:
	THE Machine does not implement a PSW but
	has a simpler error flag for the following conditions:

	\bitem
	\item Arithmetic errors:
		divide by 0 (\ttt{ERR\_DIV\_BY\_0}) or
		overflow (\ttt{ERR\_OVERFLOW}).
	\item Address errors (\ttt{ERR\_ADDR}):
			address not in partition.
	\item PC increment error (\ttt{ERR\_PC}):
			incrementing the PC goes outside the partition.
	\item I/O error:
			non-integer in input (\ttt{ERR\_INPUT}),
			or reading past End-of-File (\ttt{ERR\_OUTPUT}).
	\eitem

\item
THE/TOS is useful as a pedagogical artifact.
Nevertheless, it can be made more realistic in several ways.

	\bitem
	\item There is no multiprogramming in the basic TOS.
	\item There is hardware support for multiprogramming.
	\item Having hardware support for a stack pointer would
		make it easily to implement recursion.
	\item THE Machine does not model I/O devices which
		operates asynchronously from the CPU.
		Thus timing is unrealistic.  We would need
		to simulate I/O blocking and interrupts.
	\item The OS is not resident in memory.  
		This seems hardest to overcome.
	\eitem

	Some of these shortcomings can be overcome in
	class projects.
\eitem

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lectpart{Stack Pointer and Procedure Call}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

We want to extend TOS to support function
calls.  The standard way to do this is
to exploit a stack.  We will need a new register
SP (stack pointer) to point to the top of this stack.  

We can modify THE Machine to have this new register, and
modify in our current STML instruction set to support
access to this register.  Alternatively, we can make
our modifications at the TOS level:
we add the SP as another TOS register
and implement new traps to access this register.

We will introduce six basic traps which are named
	\myprogtt{
	\>\>\>\> CALL, RET, PUSH, POP, GETSP, SETSP.
	}
These traps are grouped into three pairs:
CALL/RET are for calling 
and returning from procedures.
PUSH/POP are for adding and removing
an entry from the stack.  Finally,
GETSP/SETSP are for moving information from memory
to the stack, or vice-versa.
The reason why GETSP/SETSP are necessary is
because SP is an implicit register which
we can only manipulate through traps.

These traps are viewed as user services, and we
would like to distinguish them from traps that
perform system services.  By definition, system traps
will automatically cause a context switch, but user traps do not.
So we introduce a convention for our trap vector.
Traps 0 to 19 will be considered system traps.
Traps 20 and higher will be considered user traps.

In order to understand the way the stack works below,
we recall a convention about how stacks
are organize in the memory allocated to a process.

FIGURE: mem[0]... mem[LIMIT-1]


We think of the process memory as starting from address 0
to some upper limit.  Let mem[0.. LIMIT-1] denote
this sequence of memory location.
The executable code of the
process is loaded starting at mem[0].
After this, we allocate memory for static
variables, and also space for the heap (used
in dynamic memory allocation).
The stack, however, begins at the mem[LIMIT-1],
and grows towards mem[0].  In the above figure,
we draw mem[0] at the top, and mem[LIMIT-1] at the bottom.
In this sense, the stack is growing upwards.

When we load a process, we assume that SP is initialized
to the value LIMIT.  To push a value X on the stack,
we first \dt{decrement} SP and then set mem[SP]=X.
Now, we are ready to describe the four new traps:

\bitem
\item	TRAP 20:
	As usual, R15 contains the constant 20 but
	R14 will contain either the number of a register
	(0-13) or an address ($>$13).
	In case of a register, we assume that the
	register contains an address.  In either case, let the address
	be denoted ADDR.  We expect ADDR to be the address
	or entry point into a procedure.
	We will refer to this trap call as
		
		\ttt{CALL ADDR}.

	In fact, our assembler can easily be
	extended to accept this new syntax.
	The result of this trap is that:

	\bitem
	\item Increment register R0 (the PC).
		Note this incremented value of R0 is the
		return address after the procedure call.
	\item Decrement the stack pointer SP.
	\item Store the value of R0 into mem[SP].
	\item Set R0 to the value ADDR.
		This means we jumped to ADDR for our
		next instruction.
	\eitem


\item	TRAP 21:
	R15 contains the constant 21 and R14 contains
	some (small) non-negative integer N.
	We will refer to this trap as
		
		\ttt{RET N}.

	The result of this trap is the sequence of actions:
	
	\bitem
	\item Set register R0 to the mem[SP].
		Recall that mem[SP] holds the
		return address after the procedure call.
	\item Increment the stack pointer SP.
	\item Further, add \ttt{N} to SP.
	\eitem

	For now, assume \ttt{N} is $0$.
	We will shortly why it is useful to have
	positive values for \ttt{N}.

\item TRAP 22:
	R15 contains the constant 22 but
	R14 will contain an address ADDR.
	%In order for this trap to be refer to registers
	%we make a convention: when ADDR is in the range 0-13,
	%then it is actually referring to a register!
	We will refer to this trap as
		
		\ttt{PUSH ADDR}.

	The result of this trap is the following actions:

	\bitem
	\item Decrement the stack pointer SP.
	\item Set mem[SP] to ADDR. 
	\eitem

\item TRAP 23:
	R15 contains the constant 23.
	R14 will contain an address ADDR.
	%Again, if ADDR is in the range 0-13, it
	%refers to a register.
	We refer to this trap as
		
		\ttt{POP ADDR}.

	The result of this trap is the following actions:

	\bitem
	\item Set reg[ADDR] to mem[SP].
	\item Increment the stack pointer SP.
	\eitem

\item TRAP 24:
	R15 contains constant 24.
	R14 contains an offset N.
	This trap is known as

		\ttt{GETSP N}

	and its effect is to set \ttt{R13=mem[SP+N]}.

\item TRAP 25:
	R15 contains constant 25.
	R14 contains an offset N.
	R13 contains some user data.
	This trap is known as

		\ttt{SETSP N}

	and its effect is to set \ttt{mem[SP+N] = R13}.

\eitem

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\myPara{Using stack pointer traps.}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
We assume that the program loader will
now initialize SP to the
last location in the process image.

Suppose your procedure uses local variables.
We allocate space for these local variables,
on the stack.  First assume that the procedure
takes it arguments in registers.

	\bitem
	\item	Invoke the procedure by executing CALL ADDR.
	\item	Save on the stack the
		values of any registers that might be used.
		Use PUSH to do this.
	\item 	Allocate space for local variables by decrementing SP.
	\item	Initiatize these local variables.
	\item	Start executing the procedure.

		In this procedure, whenever you need to
		refer to local variables, use mem[SP+n]
		for suitable values of n.

	\item	Cleaning up.
		First, deallocate the space for local variables
		(increment SP)
	\item
		Restore values of registers from the stack.
		Use POP to do this.
	\item	Return to the caller by executing RET 0.
	\eitem

Passing arguments using registers is fine for most
purposes.  But there are situations where
we want to pass arguments to a procedure
``directly'', by giving the address of the argument.
Another reason might be that we need to pass
more arguments than there are registers.

The method is as follows: the caller will push the address of the
arguments directly onto the stack before calling the procedure.
Upon return, the procedure will do the courtesy of
popping the arguments off the stack by calling \ttt{RET N}
for some positive value of \ttt{N}.

APPLICATIONS:
Using these function calls, we can now implement
libraries.  The OS can provide a list of standard libraries.
We can keep all library files in a special directory
that the OS knows about.  When called, it searches
this library and loads it.  Such libraries are
loaded in System space.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\myPara{Enhancing the STML Loader.}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
To fully exploit function calls, we need to add
some user-friendly features to the STML program loader.
Specically, we introduce \dt{STML directives} which
are instructions to modify the behavior of the loader.
Directives are indicated by keywords
that begin with a \ttt{\#} symbol.  We now describe some of them.

The loader keeps track of a \dt{current relative address}.
Each non-comment input line is read into the current relative address
in memory, then the current relative address is incremented.
Sometimes we want to reserve a large blocks of space
(for instance, for a large array), and it would
be convenient to be able to directly increment 
current relative address.  We will achieve this by
introducing an \dt{loader directive} of the following type:
	$$\ttt{\#SKIP\ ARGN}$$
where \ttt{ARGN} is either \ttt{=N} or \ttt{+N}
for some natural number \ttt{N}.
If \ttt{=N}, the loader makes \ttt{N} the next 
relative address; if \ttt{+N}, 
the loader adds \ttt{N} to the current relative address.

Instead of reserving space, we may want to initialize the
memory with data, typically a long string.
A convenient way to do this is
	$$\ttt{\#DATA\ ARGS}$$
where $ARGS$ is a sequence of comma separated
strings or numbers (hex or decimal).  E.g.,
	$$\ttt{\#DATA\ "Hello\ World!",\ 0xA,\ 0xD,\ 8, 512, "Bye", 0}$$
will load the ASCII code for the characters in
the string "Hello World!", followed by the hex code \ttt{0xA}
and \ttt{0xD} (corresponding to $10$ and $13$ in decimal)
followed by the decimal values $8$ and $512$, and finally
the characters "Bye", then $0$.  This final $0$ is useful,
as it is the NULL character that ends a string.  Note that
"Hello World!" and "Bye" were not NULL terminated automatically.
Entering $10$ and $13$ is useful for
strings since these are the ASCII code for
carriage return and line feed, respectively.
Another useful ASCII code is $44$, corresponding to a comma.
Note that commas cannot be directly placed in strings
because of our convention that the individual tokens in \ttt{ARGS}
are comma separated.  E.g., to enter the string "Hello, World!",
you would use:
	$$\ttt{\#DATA\ "Hello", 44 "\ World!", 0}$$
Note that this string is NULL-terminated.

% other features...
Another useful directive is
	$$\ttt{\#SYMB LABEL [ARG]}$$

The argument \ttt{LABEL} is any identifier
and \ttt{ARG} is optional.
If \ttt{ARG} is given, it is an integer (could
be negative), and this directive makes the identifier have the
value of the constant \ttt{ARG}.  If \ttt{ARG} is omitted,
the identifier has the value of the current relative address.
Subsequent STML instructions can refer to this value using:
	$$\ttt{\#LOAD RB, LABEL}$$
where \ttt{RB} is in the range $0-15$, indicating a register.
The effect of this instruction is to
store the value of \ttt{LABEL} into register \ttt{RB}.
For instance, the next STML instruction might be
	\ttt{JMP RB} or \ttt{LOI RA, RB}.

We want the ability to include another STML file:
	$$\ttt{\#INCL FILE}$$

Typically, this file contains a single function
which we want to call as a subroutine.
If \ttt{FILE} is \ttt{gcd}, then the file
\ttt{gcd.stm} will be found from the current
directory or another known system directory,
and loaded into the current relative address in
the process image.  The name of this function
will be taken from the first line of \ttt{gcd.stm},
and we may assume that there is an implicit
call to \ttt{\#SYMB gcd}.  Thus we can subsequently
call this subroutine as follows:
	\ttt{\#LOAD 14, gcd}
and we can invoke \ttt{CALL gcd} appropriately.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lectpart{Files}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

To extend TOS to support file I/O, we introduce new traps.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\beginExer
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\bexer
What not allow TRAP's to take arguments?
Design a trap instruction of the form
\ttt{TRAP R, ADDR} where R is a register and ADDR an address.
\eexer

\bexer
Write a STML program that takes as input
three numbers $a, b, n$ and it prints the 
Fibonacci number $f_n$ where
the Fibonacci sequence $\set{f_i: i\ge 0}$ is defined by
$f_0=a, f_1=b$ and $f_{i+1}=f_{i-1}+f_i$.
\eexer

\bexer
Implement the following six new \dt{user} traps to support function calls,
based on the (hidden) register SP or Stack Pointer.
\eexer

\bexer
(a) Re-write the STML programs in our collection (sort.stm, primes.stm, etc)
so that these programs can be called a subroutines.
\\(b)
We want to implement a library system using the function call traps.
Modify TOS to support this. 
\eexer
\bexer
Write a recursive version of fib.stm using these new function
call traps.
% check up on C language calling convention... I looked at the
%	Bell Labs report of S.C. Johnson and B.Kernighan from 1970's...
\eexer


\bexer
Introduce a rudimentary file system for
TOS.  There are no directories, i.e., there
is only one giant directory in which all files
are kept.  There should be traps to create,
open and close files.  Currently opened
files are kept in a per-process table, and
indexes into this table are called \dt{file descriptors}
as in UNIX.  The standard input, standard output
and standard error are initially given to every
process (with file descriptors $0, 1, 2$ respectively).
We provide traps to change the default input and output
file descriptors from $0, 1, 2$ to any opened file.
In this way, our original
I/O Traps can be used to read/write into files.
\eexer

\bexer
The OS should be able to run a batch system.
We place jobs in files in a special directory,
which the system checks.
Certain jobs can be run periodically, or can
be specified to start at a particular time.
For batch jobs, we need to arrange I/O to be
done through files
(via redirection of the standard I/O).
\eexer

\bexer
Discuss what it would take to implement TOS so
that it is directly stored in the TOS memory or disk.
\eexer

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\doneExer
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\myTail
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newpage

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\lectpart{PROGRAM LISTING}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The basic hardware is given by the following 2 files:

{\scriptsize
\begin{verbatim}
/* file: the.h
 *
 * Code for the Toy HardwarE (THE), 
 * a simulated architecture supporting variable-length partitions.
 * We refer to this hardware as ``THE machine''.
 *
 * THIS CODE IS derived from the original stm.c code,
 * 	with permission from Professor Ernie Davis 
 * 	The original stm.c file is split into a hardware
 * 	part and an OS part, represented by the four files
 * 	
 * 		the.h,  the.c, tos.h, tos.c.
 *
 * Fall 2006, Fall 2007: Operating Systems Class, Professor Yap
 *
 ***************************************************/

#ifndef _THE_H_
#define _THE_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define RAMSIZE 262144	// 2**18 address space
#define NUMREGS 16

/****************************************************
 * Error Codes 
 ****************************************************/

#define ERR_DIV_BY_0 0
#define ERR_OVERFLOW 1
#define ERR_ADDR 2
#define ERR_PC 3
#define ERR_INPUT 4
#define ERR_OUTPUT 5

/****************************************************
 * Global variables for the simulated architecture
 ****************************************************/

extern int
      mem[RAMSIZE],	    // Core memory
      regs[NUMREGS],	    // general registers
      base,         	    // Base register
      limit,        	    // limit register
      error; 		    // Error status flag (or register)
      
extern char codes[16][4];   // Op codes 
     
/****************************************************
 * Other global variables 
 ****************************************************/

#define MAXBUF 128	    // Buffer size for string I/O traps

extern int
     debug,                 // Level of debugging
     terminate,		    // Termination flag
     maxinst;  		    // Maximum number of instructions

// N.B. The following logically belongs to tos.h.
// But for debugging purposes, we put it here:

#define NAMESIZE 32	// maximum size of process name
extern int     procindex;      /* Index of process */
extern char procname[NAMESIZE];  /* name of process */

/****************************************************
 * int the_err(char msg[])
 * 	Print an error message (msg) with error code e
 ****************************************************/

extern int the_err(int e, char msg[]);

/****************************************************
 * phys_address(...)
 * 	Convert a relative address to a physical address.
 *	Check that it lies within bounds 
 ****************************************************/

extern int phys_address(int reladd);

/****************************************************
 * show_inst(...)
 *	Display STM instruction for level-2 debugging 
 ****************************************************/

extern void show_inst(int op, int ra, int ad, int rb, int rc, int rd);

/****************************************************
 * get_inst(...)
 *	Decompose an STM instruction into its components
 ****************************************************/

extern void get_inst(int inst,
	int* pop, int* pra, int* pad, int* prb, int* prc, int* prd);

/****************************************************
 * exec_inst(...)
 *	Executes an STM instruction.
 *	This does the actual work of the STM code
 ****************************************************/

extern int exec_inst(int op, int ra, int ad, int rb, int rc, int rd);

/****************************************************
 * void exec_trap();
 * 	Execute a trap
 ****************************************************/

extern void exec_trap();
 
/****************************************************
 * void exec_stm();
 * 	The main loop of THE machine:
 * 	infinite loop to execute each instruction of STM code
 ****************************************************/

extern void exec_stm();

#endif
\end{verbatim}
}

{\scriptsize
\begin{verbatim}
/*  file: the.c
 *
 *  Code for the simulated toy machine (STM),
 *  a simulated architecture supporting variable-length partitions.
 *
 *  HISTORY:
 *  	-- Fall 2006: this code was derived from the stm.c code of
 *		Professor Ernie Davis with permission.
 *	-- Fall 2007: introduce enhanced I/O traps
 ***************************************************/

#include "the.h"

/* MIN macro, used in trap_exec */
#define MIN(x,y)  ((x) < (y) ? : (x) : (y))

/* Global variables for the simulated architecture --- DO NOT CHANGE */
int   mem[RAMSIZE],  /* Core memory */
      regs[NUMREGS], /* Number of registers */
      base,          /* Base register */
      limit;         /* limit register */
      
char codes[16][4] =  /* Abbreviations for opcodes */
   { "LOA", "STO", "CPR", "LOI", "STI", "ADD", "SUB", "MUL", 
     "DIV", "ICR", "DCR", "GTR", "JMP", "IFZ", "JMI", "TRP" };
     

/****************************************************
 * Other global variables  
 ****************************************************/
int  debug = 0,          /* Level of debugging */
     error = 0,          /* Error flag */
     terminate = 0,      /* Termination flag */
     maxinst = -1;       /* Maximum number of instructions */

// N.B. Logically, this ought to be in tos.c, but for debugging purposes
// we put it here for convenience:

int  procindex = 0;      /* Index of process */
char procname[NAMESIZE];  /* name of process */

/****************************************************
 * int the_err(int e, char msg[])
 *
 *      Print an error message (msg) with error code e
 ****************************************************/

int the_err(int e, char msg[])
{
	printf("Error %d: error value=%d, %s\n", e, error, msg);
}


/***************************************************
 * Convert a relative address to a physical address.
 * Check that it lies within bounds 
 * Note: This is considered part of the "hardware" of the virtual machine.
 * You may not change it in any of the projects. 
 ***************************************************/

int phys_address(int reladd)

{ if ((reladd >= 0) && (reladd < limit)) return(reladd+base);
  else { error = 1;
         printf("Error: Address out of bounds\n");
         return(0);
       }
}

/***************************************************
 * Display STM instruction for level-2 debugging 
 ***************************************************/

void show_inst(op, ra, ad, rb, rc, rd)
	int op, ra, ad, rb, rc, rd;
{ 
  printf("Process %i  %s instruction 0x%X : %3s", 
                           procindex, procname, regs[0], codes[op]);
  switch(op) {
     case 0: case 1:  case 13: 
         printf(" R%i Address 0x%X", ra, ad); break;
     case 12: printf(" Address 0x%X", ad); break;
     case 2: case 3: case 4: 
         printf(" R%i R%i", ra, rb); break;
     case 5: case 6: case 7: case 11:
         printf(" R%i R%i R%i", ra, rb, rc); break;
     case 8: 
         printf(" R%i R%i R%i R%i", ra, rb, rc, rd); break;
     case 9: case 10: case 14: 
         printf(" R%i ", ra); break;
    }
  printf("\n");
}

/***************************************************
 * Decompose an STM instruction into its components
 ***************************************************/

void get_inst(inst, pop, pra, pad, prb, prc, prd)
	int inst, *pop, *pra, *pad, *prb, *prc, *prd;

{ *pop = inst % 16;
  inst = inst / 16;
  *pra = inst % 16;
  inst = inst / 16;
  *pad = inst % RAMSIZE;
  *prb = inst % 16;
  inst = inst / 16;
  *prc = inst % 16;
  inst = inst / 16;
  *prd = inst % 16;
  if (debug == 2) show_inst(*pop, *pra, *pad, *prb, *prc, *prd);
}

/***************************************************
/* Execute an STM instruction.
 * This is what does the actual work of carrying out the STM code 
 ***************************************************/

int exec_inst(op, ra, ad, rb, rc, rd)
	int op, ra, ad, rb, rc, rd;
{ int regrep = 0; /* Flag for repeated registers */
  int trap = 0;
 
  switch (op) {
    case 0: regs[ra] = mem[phys_address(ad)]; break;
    case 1: mem[phys_address(ad)] = regs[ra]; break;
    case 2: regs[ra] = regs[rb]; break;
    case 3: regs[ra] = mem[phys_address(regs[rb])]; break;
    case 4: mem[phys_address(regs[ra])] = regs[rb]; break;
    case 5: regs[rc] = regs[ra] + regs[rb]; break; 
    case 6: regs[rc] = regs[ra] - regs[rb]; break; 
    case 7: regs[rc] = regs[ra] * regs[rb]; break; 
    case 8: if (regs[rb] == 0) 
                 { printf("Arithmetic error: Divide by zero\n");
                   error = 1; }
            else { regs[rc] = regs[ra] / regs[rb]; 
                   regs[rd] = regs[ra] % regs[rb]; }
            break;
    case 9: regs[ra]++; break;
    case 10: regs[ra]--; break;
    case 11: regs[rc] = (regs[ra] > regs[rb]); break;
    case 12: regs[0] = ad; break;
    case 13: if (regs[ra] == 0) regs[0] = ad; break;
    case 14: regs[0] = regs[ra]; break;
    case 15: trap = 1; break;
  }
  return(trap);
}


/***************************************************
 * Execute a trap 
 ***************************************************/

void exec_trap()
{ int iread, i, n;
  char buffer[MAXBUF];	// input buffer

  if (debug) printf("Process %s, index %i, ", procname, procindex);
  switch(regs[15]) {
    case 0:	// TERMINATE
	    terminate=1;
            if (debug) printf(" TRP 0 -- Terminate\n");
            break;
    case 1:	// READ INPUT
	    if (regs[12] == 0){		// READ INTEGER
	    	if (debug) printf(" TRP 1 -- Read int: ");
            	iread = scanf("%i",&regs[14]);
            	if (iread ==1) {	// input is integer
			regs[13]=0;
	    		if (debug) printf("%d\n", regs[14]);
		} else {		// input is non-integer
			regs[13]=-1;
			error=1; 	
	    		if (debug) printf("input error\n");
		}
	    } else if (regs[12]>0){	// READ STRING
	    	if (debug) printf(" TRP 1 -- Read string: ");
            	iread = scanf("%i", &buffer); // no check for buffer overflow!
            	if (iread ==1) {
			n=strlen(buffer);
			for (i=0; i< min(regs[12],n); i++) 
    			    mem[phys_address(regs[14]+i)] = buffer[i];
    			mem[phys_address(regs[14]+1+min(regs[12],n))] = 0;
	    		if (debug)
			    printf("%s\n", mem[phys_address(regs[14])]);
		} else {
			regs[13]=-2;
			error=1; 
	    		if (debug) printf("input error\n");
		}
	    }
            break;
    case 2:	// WRITE OUTPUT
	    if (regs[12] <= 0){		// WRITE INTEGER
	        if (debug) printf(" TRP 2 -- Write int: ");
                printf("%i", regs[14]);
		if (regs[12]==0) printf("\n");	// add newline if regs[12]=0
		if (regs[12]==-1) ; 		// add nothing if regs[12]=-1
		if (regs[12]==-2) printf(" ");  // add space if regs[12]=-2
		if (regs[12]==-3) printf(",");  // add comma if regs[12]=-3
		regs[13]=0;
	    } else if ((regs[12]>0)&(regs[12]<MAXBUF)){	// WRITE STRING
		if (debug) printf(" TRP 2 -- Write string: ");
		for (i=0; i< min(regs[12],MAXBUF); i++)
			buffer[i] = mem[phys_address(regs[14]+i)];
		buffer[1+min(regs[12],MAXBUF)] = 0;
		printf("%s", buffer);
		regs[13]=0;
	    } else {
	    	regs[13]=-1;
		error=1;
	    }
	    break;
   default: printf("Invalid trap code\n");
            error=1;
            break;
    }
 }
 

/***************************************************
 * fetch and execute an instruction of STM code 
 ***************************************************/


extern void exec_stm()
{ int opcode, rega, ad, regb, regc, regd; /* Components of STML instruction */
  int trap;  /* flag that code executes a trap */
  int padd;  /* physical address */
  int i; 

      
  padd=phys_address(regs[0]);
  if (debug == 2) {
      printf("Registers: ");
      for (i=0; i<16; i++) printf(" %3i", regs[i]);
      printf("\n");
      printf("address 0x%X instruction 0x%X\n", regs[0], mem[padd]);
     }
  get_inst(mem[padd], &opcode, &rega, &ad, &regb, &regc, &regd);
                              /* fetch instruction */
  if (!error) { 
      regs[0]++;               /* increment PC */
      if (regs[0] >= limit) error=1;
      else { trap = exec_inst(opcode, rega, ad, regb, regc, regd); /*execute*/
             if (trap) exec_trap();                          /* handle trap */
           }
    }
}
  

\end{verbatim}
}

\myTail


