Department of Electrical and Computer Engineering
The University of Texas at Austin
EE 360N, Fall 2005
Lab Assignment 4
Due: 30 October 2005, 11:59 pm
Yale N. Patt, Instructor
Aater Suleman, Linda Bigelow, Jose Joao, Veynu Narasiman, TAs
Introduction
The goal of this lab assignment is to extend the LC-3b simulator
you wrote in Lab 3 to handle interrupts and exceptions. You will
augment the existing LC-3b microarchitecture to support
detection and handling of timer interrupts and protection exceptions.
The input to this new simulator will be:
-
A file entitled ucode4 which holds the expanded microcontrol store.
-
A file holding an LC-3b user program that is loaded into memory starting at
memory location x3000.
-
A file holding data for the program starting at memory location x3000. This
data will be loaded into memory starting at memory location xC000.
-
A file holding the interrupt/exception vector table that is loaded
into memory starting at memory location x0200. You should form the
contents of this table based on the vector of each interrupt/exception
and starting address of the service routine for each interrupt/exception.
-
A file holding an LC-3b system program that is loaded into memory starting at
memory location x1200. This will be the timer interrupt service routine.
-
A file holding an LC-3b system program that is loaded into memory starting at
memory location x1600. This will be the protection exception handler.
The simulator will start executing the LC-3b program loaded at
x3000. The timer interrupt will occur at cycle 300. You are
supposed to provide microarchitectural support for interrupt
handling. The interrupt handler you write should increment location
x4000 by #1. You will also need to implement the RTI instruction so
that the interrupt handler can transfer control back to the user
program. If the user program accesses a memory location that can only
be accessed in supervisor mode, a protection exception will occur. You
are supposed to provide microarchitectural support for handling
exceptions. Most of this support is similar to the support you will
add for interrupts. The exception service routine you will write
should simply halt the machine. (Important note: we should be able to
swap out your exception routine with a routine that returns from an
exception. Therefore, make sure you implement the exceptions correctly
and do not rely on the machine halting.)
New shell code A modified shell code has been written for
you:
lc3bsim4.c
You will need to copy and paste the code you wrote for Lab 3
into this new shell code.
To run the simulator, type:
lc3bsim4 <micro_code_file> <program_file_1> <program_file_2> ...
The first parameter is the microcode file as before. The second
parameter is the user program you will write and will be executed by
the simulator. The rest of the parameters are program or data files
that will be loaded into memory.
Specifications
This Lab consists of 2 parts, which we will describe in detail:
1. Adding support for timer interrupts
2. Adding support for protection exceptions
- Adding support for timer interrupts
Timer
Interrupt
In this lab, 1 timer interrupt will occur - at
cycle 300. When the timer generates an interrupt, the
microarchitecture may be in the middle of executing an
instruction. You need to decide exactly when the interrupt is detected
and add the necessary microarchitectural support to handle
interrupts. This may involve augmenting the state diagram of the LC-3b with
additional states, augmenting the microsequencer with additional logic to
sequence these new states, and extending the existing microinstructions with
additional bits for both the microsequencer and the datapath.
When the interrupt is detected the following actions will
be taken by the processor:
- The privilege mode (most significant bit of the PSR, program
status register) is set to 0, which indicates supervisor-level
privilege. The interrupt service routine will be executed with
supervisor-level privilege.
- R6 is set to the supervisor stack pointer if that is not already
the case.
- The old PSR (PSR before PSR[15] is set to 0) and PC are pushed
onto the supervisor stack. On a push operation, the supervisor stack
pointer is decremented, and then the data is written (stored)
on the stack. Note that the supervisor stack is different from the user
stack. Interrupt service routines can access the supervisor stack
using R6. The shell code initializes the supervisor stack pointer to
address x3000. Note that R6 will refer to the user stack while your
program is running. It will refer to the supervisor stack while the
interrupt service routine is being executed. If the system is in user
mode when an interrupt is detected, the microarchitecture should
transparently switch R6 so that it points to the supervisor stack. You
need to implement this "stack switching" in microcode. You will need
to modify the datapath, add new states to the state machine, and
possibly add new control signals to support this operation. You may
add registers to the datapath to save and restore user and supervisor
stack pointers.
- The interrupting event supplies its 8-bit interrupt vector
(INTV). The interrupt vector for the timer interrupt is 0x01.
- The processor left-shifts the interrupt vector one bit, yielding
x02, and adds it to the base address of the interrupt/exception vector
table (x0200), yielding the address of the memory location (x0202)
that contains the starting address of the interrupt service routine.
- The contents of memory location x0202, which should be x1200 for
this assignment, are read and loaded into the PC.
- The processor begins execution of the interrupt service routine.
The first step in adding support for interrupts is to determine how
the state diagram of the LC-3b 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 may also add new logic to the datapath. You are free
to implement this as you wish, but you must document your method.
RTI Instruction
Next, you have to implement an instruction for returning from an
interrupt. This will be used in the interrupt 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 and
PSR off the supervisor stack. If the RTI transfers control back to a
user-level program, then the microcode should switch the stack pointer
back so that R6 points to the user stack (see
Appendix A for details on the RTI instruction).
- Adding support for exceptions
Protection Exception
Protection exceptions occur only when the machine is in user mode, and
a memory location in system space (locations x0000 - x2FFF) is
accessed by the user program. Exception handling for protection
exceptions is very similar to interrupt handling as described above
with an important difference: the exception-causing instruction should
not be allowed to complete before the exception is handled. Hence, the
memory access that causes the protection exception also should not be
allowed to complete. You will need to change the mode of the machine
to supervisor, switch to the supervisor stack, push the decremented PC
and the old PSR (PSR before PSR[15] is set to 0) on the supervisor
stack and load the PC with the address of
the exception service routine. The exception vector for a protection
exception is x02. You can store the exception vector in a separate
EXCV register and add this register left-shifted by
one to the interrupt/exception vector table base register to get
the address of the location that contains the starting address of the
exception service routine. You are free to implement this as you wish,
but keep in mind the possibility of combining the states used for
initiating the interrupt service routine and those used for initiating
the exception service routine.
You will also write the exception service routine for the
protection exception. This routine should start at memory location
x1600. For the purposes of this assignment, the exception service
routine will simply halt the machine. However, don't rely on this. We
can test your simulator by replacing your exception routine with our
routine which returns from the exception handler using the RTI
instruction instead of halting the machine. Upon return from the
exception handler, the instruction that caused the exception should be
re-executed.
Tips on getting started
When designing the mechanisms to support interrupts and exceptions
keep in mind that they are handled very similarly. In your microcode,
states for pushing the PSR and PC on stack and loading the address of
handler routines could be shared for both exception and interrupt
handling.
Writing Code
The user program loaded into x3000 should do the following: initialize
memory location x4000 to #1, calculate the sum of the first 20 bytes
stored in the memory locations beginning with xC000. This sum should
first be stored at xC014. Also, store the sum at x0000. This store
will cause a protection exception. The following numbers should be
stored at locations xC000:
x12, x11, x39, x23, x02,
xF6, x12, x23, x56, x89, xBC, xEF, x00, x01, x02,
x03, x04, x05, x06, x07.
The interrupt service routine
must increment memory location x4000.
The exception handlers you
will submit should simply halt the machine.
What To Submit Electronically
-
Adequately documented source code of your simulator called lc3bsim4.c.
-
The assembly code for the interrupt service routine, the
interrupt/exception vector table, the protection exception handler,
the user program, and the data for locations xC000-xC013, called int.asm,
vector_table.asm, except_prot.asm, add.asm, and
data.asm, respectively.
-
The machine code for the interrupt service routine, the
interrupt/exception vector table, the protection exception handler,
the user program, and the data for locations xC000-xC013, called
int.hex, vector_table.hex,
except_prot.hex, add.hex and data.hex,
respectively.
-
The new microcode called ucode4.
-
A file called dumpsim. To generate this file, simulate the
LC-3b assembly programs by following the instructions at the end of
this section.
-
A text file called readme that explains how you implemented
this lab assignment. This readme file should describe the following:
- Changes you made to the state diagram. Include a picture similar
to the state machine that shows the new states you added (only show
your changes or mark your changes in a new state diagram). This
picture should include the encodings of new states you added. Clearly
show where each state fits in the current state diagram. Describe what
happens in each new state.
- Changes you made to the datapath. Clearly show the new structures
added, along with the control signals controlling those
structures. Describe the purpose of each structure.
- New control signals you added to each microinstruction. Briefly
explain what each control signal is used for.
- Changes you made to the microsequencer. Draw a logic diagram of
your new microsequencer and describe why you made the changes.
- If you prefer to submit a hardcopy of your documentation (readme),
you can submit it before class on Monday October 30, 2005.
How to generate the dumpsim file
Dump memory location x4000 and the registers once before the 300th
cycle, once after the ISR is done, and finally after the protection
exception halts the execution of the program.
Things To Consider
The user stack should start at address xFE00 and the supervisor stack
should start at address x3000.
-
The microcode used for starting the exception service routine is very
similar to the microcode that is used for starting the interrupt
service routine. Are there any differences? With these differences
in mind perhaps you can combine the states used for interrupt and
exception handling.
-
The interrupt service routine should not change any register values
which are being used by the main program. We should be able to test
the service routine you wrote with a main program (and a simulator)
written by us and both programs should work correctly. Therefore, if
your interrupt service routine destroys any registers, it should save
the original values of those registers before destroying them and
restore those values before returning control to the main
program. Note that this saving/restoring of general purpose registers
could also be supported by microcode. Is this a good idea? A related
issue is the saving and restoring of condition codes. This has to be
done in microcode, it cannot be done by the interrupt service
routine. Why?
-
Make sure you check Appendix A for the description of PSR, the RTI
instruction, privilege mode, user stack, supervisor stack, and more
information on interrupt processing.
-
The functionality of your modifications to support interrupts and
exceptions should not depend on the interrupt and exception handlers
you write for this assignment. We should be able to replace your
interrupt and exception handlers with handlers written by us, and your
code should still work correctly. Conversely, the functionality of
your interrupt and exception handlers should not depend on the user
program you wrote for this assignment. We should be able to use your
exception and interrupt handlers in our simulator running a user
program different from what you wrote.
-
Basic LC-3b microarchitecture described in Appendix C makes use of 31
of the available 64 states. This leaves you with 33 states to
accomodate your changes to support interrupts and exceptions. Try to
avoid expanding the size of the control store. You can avoid this by
careful thinking and design before starting coding.
-
You do not need to worry about nested interrupts for this assignment.