COE301 Lab 8 MIPS Exceptions and IO
COE301 Lab 8 MIPS Exceptions and IO
8.1 Objectives
Branches and jumps change the control flow in a program. Exceptions also change the control flow.
The MIPS architecture calls an exception any unexpected change in control flow, regardless of its
source.
An exception is said to be synchronous if it is caused by an instruction in the running program.
Examples of synchronous exceptions are arithmetic exceptions, invalid memory addresses
generated by load and store instructions, and trap instructions.
An exception is said to be asynchronous if it is caused by an I/O device requesting the processor.
This is also known as a hardware interrupt, which is not related to program execution. Interrupts
can be caused by a variety of I/O devices, such as the keyboard, timer, and disk controller.
When an exception happens, control is transferred to an exception handler, written specifically for
the purpose of dealing with exceptions. After executing the exception handler, control is returned
back to the program. The program continues as if nothing happened. The exception handler appears
as a procedure called suddenly in the program with no parameters and no return value.
The MIPS processor operates either in user or kernel mode. User programs (applications) run in
user mode. The CPU enters the kernel mode when an exception happens. The exception handling
mechanism is implemented by Coprocessor 0, which has several important registers, such as:
vaddr, status, cause, and EPC, which record information about an exception.
1. Vaddr ($8): Contains the invalid memory address caused by load, store, or fetch.
2. Status ($12): Contains the interrupt mask and enable bits (see below).
3. Cause ($13): Contains the type of exception and any pending bits (see below).
4. EPC ($14): Contains the address of the instruction when the exception occurred.
# Breakpoint Exception
# Caused by the break instruction
.text
. . .
break
15 14 13 12 11 10 9 8 6 5 4 3 2
15 14 13 12 11 10 9 8 1 0
EL IE
Interrupt Mask
Figure 8.5: The Status Register $12
Instruction Meaning
teq Rs, Rt Raise the trap exception if register Rs is equal to register Rt
tne Rs, Rt Raise the trap exception if register Rs is not equal to register Rt
tlt Rs, Rt Raise the trap exception if register Rs is less than register Rt
. . . There are other trap instructions not listed here (see Appendix B)
break code Raise the breakpoint exception. Code 1 is reserved for the debugger
syscall Raise the system call exception. Service number is specified in $v0
The trap instructions (teq, tne, … etc.) raise the TRAP exception code 13. The break instruction
raises the breakpoint exception code 9. However, the MARS simulator provides services for the
syscall instruction without raising an exception. On a real system, the syscall instruction raises
the system call exception code 8, which is serviced by the operating system.
When an exception occurs, the processor switches to kernel mode. Coprocessor 0 registers can be
accessed only when the processor is servicing an exception in kernel mode. Register values can be
transferred from and to coprocessor 0 using the following instructions. Load and store instructions
that transfer data between coprocessor 0 registers and memory are also available. These instructions
can be used when writing an exception handler.
After an exception is processed, the exception handler can return back and resume the execution of
a program. The eret instruction is used to return from an exception.
Instruction Meaning
mfc0 Rd, C0src Move from Coprocessor 0 register C0src into destination register Rd
mtc0 Rs, C0dst Move to Coprocessor 0 register C0dst the value of register Rs
lwc0 C0dst, addr Load a word from memory into Coprocessor 0 register C0dst
swc0 C0src, addr Store Coprocessor 0 register C0src in memory
eret Reset EL = 0 (back to user mode) and return: PC = EPC
0xffff0000
Memory-Mapped I/O
Dynamic Area
0x10040000 Data Segment
0x10000000 Static Area
Text Segment
0x00400000
0x00000000 Reserved
When a function is called using jal, control is transferred at the address provided by the instruction
and the return address is saved in register $ra. In the case of an exception there is no explicit call.
In MIPS, when an exception occurs, control is transferred at the fixed address 0x80000180. The
exception handler must be located at that address.
The exception return address cannot be saved in $ra since it will modify a return address that has
been placed in that register before the exception. The Exception Program Counter (EPC) register is
used to store the address of the instruction that was executing when the exception was generated.
An exception handler can be written in the same file as the regular program, or in a separate file.
The exception handler must start at the fixed address 0x80000180. This address is in the kernel
text segment. If there is no instruction at address 0x80000180, MARS will terminate the MIPS
program with an appropriate error message. An example of an exception handler that prints the
address of the instruction that caused the exception and the exception code is shown below:
Rather than writing the exception handler at the end of every MIPS program, it is better to write the
exception handler in a separate file, then open the “Exception Handler …” dialog box in the MARS
settings and include the exception handler file in all your MIPS programs.
The rate that characters are typed on the keyboard is very slow compared to the rate that the MIPS
processor can execute instructions. Typically, millions of instructions are executed until a key is
pressed. Register $t1 keeps track of the number of iterations in the wait_keyboard loop. The lw
instruction outside the loop gets the character from the keyboard data register, which also clears the
ready bit. A MIPS programmer can only read the keyboard data register. Writing to the keyboard
data register has no effect.
Communicating with the display controller can be done via polling in a similar way. The display
registers are mapped to addresses 0xffff0008 and 0xffff000c. As long as the ready bit is zero,
the processor keeps reading it in a loop. We must not store a character in the data register until the
display is ready to receive it. The display controller clears the ready bit when a character is stored in
the data register. It then sets the ready bit again after the character is displayed and it is ready to
receive the next character to display.
li $t0, 0xffff0008 # Address of display control register
wait_display:
lw $t2, ($t0) # Read the display control register
andi $t2, $t2, 1 # Extract ready bit
beqz $t2, wait_display # loop back while not ready
sw $a0, 4($t0) # Send character to display
Figure 8.9: Keyboard and Display MMIO Simulator under the MARS Tools
The main drawback of polling is that it keeps the processor busy, wasting millions of cycles before
the I/O device (such as the keyboard) becomes ready. An alternative to polling is to use interrupts.
Interrupts can be enabled for the keyboard by setting the Interrupt Enable bit in the keyboard
control register as follows:
li $t0, 0xffff0000 # Address of keyboard control register
li $t1, 2
sw $t1, ($t0) # Enable keyboard interrupt
When a key is pressed, the keyboard sends an interrupt signal to the MIPS processor and sets the
cause register $13 to the value 0x00000100. Bit 8 in the cause register is set to indicate that the
keyboard has interrupted the processor. An interrupt handler must be written to read the character
from the keyboard and returning its value to the running program. This requires modifying the code
of the exception handler shown in Figure 8.7 to deal with interrupts.
The Disk and Ethernet I/O device controllers use Direct Memory Access (DMA) to transfer blocks
of data directly between the device and memory. As controllers become more complex, more than
two registers are associated with each device controller. These devices are not part of the MARS
simulator. In general, the supplier of any I/O device must provide programmers with an explanation
of how to properly communicate with the I/O device controller.
7. If the keyboard interrupt enable bit is set then the keyboard will interrupt the processor each
time a key is pressed. Write a simple interrupt handler that returns the character pressed in
register $v0. Rewrite the main function of question 6 using keyboard interrupts.