Department of Electrical and Computer Engineering
The University of Texas at Austin

EE 360N, Spring 2001
Y. N. Patt, Instructor
Kameswar Subramaniam, Onur Mutlu, TAs
Lab Assignment 3; Due April 8, 2001, 11.59pm


For lab 3, you will implement interrupts and exceptions for the LC-2 using your simulator from lab 2. The input to the simulator will be:

  1. A file entitled ucode which holds the expanded microcontrol store.

  3. A file holding an LC-2 program that gets loaded into memory location 0x0200.

  4. This will be the interrupt service routine.
  5. A file holding an LC-2 program that gets loaded into memory location 0x0300.

  6. This will be the memory exception handler.
  7. A file holding another LC-2 program that gets loaded into memory location 0x0400(memory page 2).
The simulator will start executing the LC-2 program loaded in memory page 2. When an interval timer interrupt occurs, the current value of the PC is pushed onto a stack, and control is passed to the interrupt service routine located at 0x0200. When the service routine finishes executing, the old PC is popped off the stack and control goes back to the original program.

The address space of the LC-2 is divided into pages of 512 locations (9 bits). Hence, page 0 is from 0x0000 to 0x01ff; page 1 is from 0x0200 to 0x03ff, and so on. Memory page 0 is a reserved section of memory. Any reference to a memory location in page 0 should generate a protection exception. When an exception occurs, 1 is subtracted from the PC, the value of the PC is pushed onto the stack, and control is passed to the exception handler located at 0x0300. The memory reference should not complete.

Interval Timer Interrupt

For this simulation, the interval timer interrupt will occur every 10 microseconds with a clock rate of 100MHz. The interval timer generates an interrupt, which is detected after the current instruction has finished executing. When the interrupt is detected, the current value of the PC is pushed onto a stack pointed to by R6, R6 is incremented before each push, and the PC is loaded with the contents of a register called the interrupt address register (IAR). IAR fits into the current LC-2 datapath as shown in the diagram at
This register should be initialized by the simulator. The IAR points to the beginning of the interrupt service routine (location 0x0200), which performs a task and returns to the interrupted procedure when it finishes. R6 should be loaded with the value 0x1FFF at the start of your program.

You will implement the mechanism to push the current PC onto the stack in microcode. The first step in this lab is to determine how the state diagram of the LC-2 can be modified to handle interrupts. You will have to augment the microsequencer with additional logic to sequence these new states, and extend the existing microinstructions with additional bits for both the microsequencer and the datapath. You may augment current microinstruction fields and add new fields. You are free to implement this as you wish, but you must document your method.

Next, you have to implement an instruction for returning from an interrupt. This will be used in the service routine to transfer control back to the interrupted program. This instruction, called RTI (return from interrupt), has the opcode 1000, and pops the old PC off the stack and loads them into the corresponding registers. In implementing this instruction, you need to decrement R6. (See the ISA reference for details on the RTI instruction)

Generating the interrupt will be left up to you. A feasible method would include a routine which counts cycles and sets the interval timer interrupt after a certain number of cycles have elapsed.

Protection Exceptions

Memory page 0 is reserved for various system information and cannot be referenced by an application program. Whenever an application program accesses a location in page 0, a protection exception occurs. An exception can occur during any execution cycle. When detected, an exception should cause the PC to decrement by one, the value of the PC is pushed onto a stack pointed by R6, R6 is incremented before each push, and the PC is loaded with the contents of a register called the memory exception address register (MEAR). This register should be initialized by the simulator. The exception handler is simply a program that halts the machine. Be sure the memory operation doesn't take place.

Again, you are to implement the exception detection in microcode. The exception condition must be generated in the memory phase of the simulation cycle. In the following microinstruction, the exception should be found by the logic in the microsequencer, which will trigger the execution of the exception handler. Hint: think about adding another mux to the microsequencer.

Testing the simulator

To test the simulator, you'll write a program to be loaded into memory location 0x0200, a program to be loaded into memory location 0x0300, and another program to be loaded into memory location 0x0400. The program in location 0x0400 will first load the value x0001 into memory location 0x3000, then proceed to increment it in a loop. Once the contents of 0x3000 reach x400, the program will save the contents of register 0 in memory location 0x0000 which will cause a protection exception, halting the program.

The program in memory location 0x0200 will be the interrupt service routine. It will simply increment a counter at memory location 0x3001 and then RTI to the interrupted program.

Useful Notes

  1. You will have to change the old simulator shell to initialize the IAR and MEAR registers.
  2. You'll also have to modify your assembler so that it can handle the RTI instruction. For this assignment (and the next one), RTI will use the opcode 1000. To ensure compatibility with any assembly programs that include the NOP instruction, your assembler should assemble it as 0x0000 (never branch, ie NOP)
  3. You will need to check for interrupts only at the end of every instruction, not in each state of the state machine. For example, if an interrupt occurs every x cycles, and an interrupt occurs when CYCLE_COUNT = x, and at that point the simulator is in some intermediate state of an instruction, you will detect & handle that interrupt only when the current instruction reaches its last state. The CYCLE_COUNT at that point might be say x+8 - that doesnt matter. The next interrupt will still be generated when CYCLE_COUNT reaches 2x.
  4. You do not need to worry about nested interrupts. In fact, in this assignment, since you are generating the interrupt yourself, you know that it occurs every x cycles, and x is much greater than the time for the interrupt service routine to execute, so it cant occur again during the interrupt service routine.
  5. You will need to check for memory exceptions (page 0 access) every time any value is fetched from memory - including state 1. However, an exception should not occur for the TRAP instruction (Since the interrupt service routine & exception handler are both in page 1, they will not cause an exception in state 1 - if they had been in page 0, you would have needed to turn off checking for memory exceptions in state 2 for them!)
  6. When an interrupt occurs, the PC is pushed onto the stack. The values of the registers and the condition codes are not saved. This gives rise to two issues:

    1. The interrupt service routine can change the values of the condition codes. After RTI, a BR instruction could use this incorrect value of CC - it should use the values of CC before the interrupt. Two possible solutions to this problem are:

      • Modify the datapath to provide capability to push & pop CC. Add more states to push & pop CC as required (for interrupt handling and RTI respectively)
      • In your interrupt service routine, you could save the condition codes and restore them (for example, store a number in a register depending on which of n,z,p are set; at the beginning of the interrupt service routine) and restore the flags at the end by loading 0, 1 or -1). This will not require any modifications to your datapath.
    2. The interrupt service routine should not change any register values which are being used by the main program. For the purpose of this assignment, if the main program uses say 4 registers, make sure your interrupt handler does not modify those 4 registers (or if it does, restore them to their original state before returning)


What To Submit

  1. Adequately documented source code of your simulator. Call this file "lc2sim2.c".

  3. The assembly code for the interrupt service routine, exception handler, and the counter program. Call these files "int.asm", "except.asm", and "count.asm" respectively.

  5. The new microcode called "ucode2".

  7. Simulate the LC-2 assembly programs. Dump the memory locations x0000, x3000, and x3001 after the protection exception occurs. Call this file "dumpsim".

  9. Include a text file called "readme" that explains how you implemented this lab assignment. Describe any new fields you added to the microcode. What changes did you make to the datapath? Include a picture similar to the state machine that shows the new states you added(only show your changes). Describe what occurs at each state. Draw a logic diagram of your new microsequencer. How many cycles pass between each interrupt?

    If you feel that a word document (or any other format) is more convenient, make sure that you convert it into a form which can be viewed on unix. An easy way of doing this is to print the word document, and choose the "print to file" option - this will create a postscript file which can be viewed on unix.