Program 3 -- CS 473.


This program is to help you understand pipelining and the need
to delay certain instructions due to a previous instruction's
values.

Pipelining is used to improve the time it takes to execute instructions.
If you recall, the basic process of an instruction execution is to
do the following:
 LOOP
   Use the PC to select an instruction from Memory
   Place the instruction into a register I.
   Execute "I"
    (check for interrupts)
   Increment the PC
 Repeat LOOP


In about 50% of the time (or more), it is possible to separate the
Fetch from the decode from the execute.  This means that we can do the following

   T0  Fetch I1
   T1  Decode I1    Fetch I2
   T2  Execute I1    Decode I2  Fetch I3
   T4               Execute I2  Decode I3   Fetch I4 
   .....


This only works IFF I2 does not depend on the values of I1.  If
I2 depends on the values of I1, we have to "stall" I2 to allow I1
to execute.

This programming assignment is to take a list of instructions from the SCOOPY's
famous process (see data sheet below) and indicate which instructions
should be stalled.

We will define a stall IFF the registers in Instruction_K have their
values set in Instruction_(K-1).  In this case, you are to INSERT
a new instruction called STALL between instructions K-1 and K.

In other words, if a register is used in I_K and it is set in I_K-1,
you must STALL (please keep in mind that several of the instructions
set a value to R0 or R1 even though they are not explicited listed
in the Assembly Line).

There are a number of instructions that need not be stalled.
For example
  LI does not depend on any values from the previous instruction
  IK does not depend on any previous values

Others 
  LD MAY depend on previous values if Rk is changes in the previous
      instruction
  JMP implicitly depends on R1
  
  JMPNE depends on both R1 and R0 -- so if either is affected, you have to stall



You *MUST* write your program in C.  You must document your code with the following
standards:

  1) you must have your name, date, program title, program purpose, assumptions
     on data input, etc as part of the header of the program (10 pt)


  2)  for every subroutine/function, you must have at least a description on
      what that function is suppose to do and how it is used (5pt per instance)

  3)  for every "while", "for", or complicated "if" statement, I expect to see
      at least one line explaining what that structure is doing.  Statements
      like "this is a while loop" are not considered documentation.  A statement
      like "cruise through the memory loading up values from STDIN"  are good. 
      (5 pt per instance)

I believe programs should have decent, "high level", documentation in them.  If
you choose to not document, your performance will suffer.


The input to your program will be a lines of Assembly language instructions.
Your output will be the same set with STALL inserted between the instructions
that need to be stalled.



SCOOPY's INFAMOUS PROCESSOR DATASHEET

16 bit word, 4 registers (R0- R3)


The instruction format  (in general) is as follows:

bits
| 15 - 12 | 11 - 9 | 8 - 6 | 5 - 0
  OP CODE    Ri       Rj     Data

bits (LI only)
| 15 - 12 | 11 - 0 
  OP CODE    Data


--control--

0000 LI        -- Load R0 with the value from the last 12 bits of the instruction word
0001 LD  Ri Rk -- Load Ri with the contents of Rk
0010 LM  Ri    -- Load R0 with the memory value refenced by Ri

0011 STO Ri    -- Store R0 into the memory refence of Ri

0100 JMP       -- Jump to the value stored in R1
0101 JMPNE     -- Jump to the address in R1 if R0 is equal to zero


-- I/O --

0110 IK  Ri          -- input from keyboard a decimal number and place it into 
                   Register i

0111 OM Ri           -- output to the standard output the contents of Register i
                   in decimal format


-- datapath --

1000 CMP       Compare R0 to R1.  R0=1 if the same, R0=0 if not the same
1001 ADD  Ri   Add Ri to R0.  The result goes into R0.  Ie, R0=R0+Ri
1010 SUB  Ri   Subtract Ri from R0.  The Result goes into R0.  R0=R0-Ri
1011 INC  Ri   Ri=Ri + 1
1100 MULT Ri   R0=R0*Ri
1101 DIV  Ri   R0=R0 div Ri
1110 MOD  Ri   R0=R0 mod Ri

-- extra --


Here is an example input and output.

Input

LI 20 
LD R1 R0 
LD R2 R0 
LD R3 R0 
INC R1   
INC R2   
INC R3   
OM R0    
OM R1    
OM R2    
OM R3   
PC      
HALT    

Should Turn into


LI R0 20 
STALL
LD R1 R0 
LD R2 R0 
LD R3 R0 
INC R1   
INC R2   
INC R3   
OM R0    
OM R1    
OM R2    
OM R3   
PC      
HALT    


Another example is

LI  20
LD R1 R0
LD R2 R1
LD R3 R1
HALT

Would be

LI 20
STALL
LD R1 R0
STALL
LD R2 R1
LD R3 R1
HALT




Example 3:

LI 20
LD R1 R0
JMP

Turns into

LI 20
STALL
LD R1 R0
STALL
JMP     /node JMP depends on R1, which is set in the previous I/


Example 4:
LI 20
LD R1 R0
LD R2 R0
JMP


Turns into 
LI 20
STALL
LD R1 R0
LD R2 R1
JMP          /note the JMP depends on R1, but it is not SET in the previous I/