Lecture 11
Exceptions and Interrupts.
Lecture
Outline
- Exceptions and interrupts
Examples:
Workshop
Outline
- Control and Status Registers
- System instructions
- Exceptions
- Exception handling
- Interrupts
Exceptions and Interrupts
Exception is an an unscheduled event that disrupts program execution. Interrupt is an exception that comes from outside of the processor. (Some architectures use the term interrupt for all exceptions.) Exceptions require dealing with special system instructions and registers.
Control and Status Registers (CSRs)
The Control and Status Registers (CSRs) are system registers provided by RISC-V to control monitor system states. CSR’s can be read, written and bits can be set/cleared. Each CSR has a special name and is assigned a unique function. In this course, we focus on the user privilege level. We will use user-level CSRs to handle user-level exceptions.
User-level CSRs:
Number | Priviledge | Name | Description |
User Trap Setup | |||
0x000 | URW | ustatus | User status register. |
0x004 | URW | uie | User interrupt-enable register. |
0x005 | URW | utvec | User trap handler base address. |
User Trap Handling | |||
0x040 | URW | uscratch | Scratch register for user trap handlers. |
0x041 | URW | uepc | User exception program counter. |
0x042 | URW | ucause | User trap cause. |
0x043 | URW | utval | User bad address or instruction. |
0x044 | URW | uip | User interrupt pending. |
User Floating-Point CSRs | |||
0x001 | URW | fflags | Floating-Point Accrued Exceptions. |
0x002 | URW | frm | Floating-Point Dynamic Rounding Mode. |
0x003 | URW | fcsr | Floating-Point Control and Status Register. |
User Counter/Timers | |||
0xC00 | URO | cycle | Cycle counter for RDCYCLE instruction. |
0xC01 | URO | time | Timer for RDTIME instruction. |
0xC02 | URO | instret | Instructions-retired counter for RDINSTRET instruction. |
0xC80 | URO | cycleh | Upper 32 bits of cycle, RV32 only. |
0xC81 | URO | timeh | Upper 32 bits of time, RV32 only. |
0xC82 | URO | instreth | Upper 32 bits of instret, RV32 only. |
System Instructions
CSR Instructions:
Read/Clear CSR: read from the CSR into t0 and clear bits of the CSR according to t1 | |
Read/Clear CSR Immediate: read from the CSR into t0 and clear bits of the CSR according to a constant | |
Read/Set CSR: read from the CSR into t0 and logical or t1 into the CSR | |
Read/Set CSR Immediate: read from the CSR into t0 and logical or a constant into the CSR | |
Read/Write CSR: read from the CSR into t0 and write t1 into the CSR | |
Read/Write CSR Immediate: read from the CSR into t0 and write a constant into the CSR |
CSR Pseudo Instructions:
Clear bits in control and status register | |
Clear bits in control and status register | |
Read control and status register | |
Set bits in control and status register | |
Set bits in control and status register | |
Write control and status register | |
Write control and status register |
System Instructions:
ebreak | Pause execution (at a breakpoint) |
ecall | Issue a system call : Execute the system call specified by value in a7 |
uret | Return from handling an interrupt or exception (to uepc) |
wfi | Wait for interrupt |
Exceptions
When an exception occurs the PC is written to the uepc
register and
the exception cause code is written to the ucause
.
Exceptions Supported in RARS:
-
INSTRUCTION_ADDR_MISALIGNED (
ucause
= 0)Code:
j main end: li a7, 10 ecall main: la t0, end addi t0, t0, 2 jr t0
Result:
Error in : Instruction load alignment error ucause = 0x0 uepc = 0x00400006
-
INSTRUCTION_ACCESS_FAULT (
ucause
= 1)Code:
.data data: .word 99 .word 100 .text la t0, data jr t0
Result:
Error in : Instruction load access error ucause = 0x00000001 uepc = 0x10010000
-
ILLEGAL_INSTRUCTION (
ucause
= 2)Code:
.text main: li t0, 8 csrrs zero, cycle, t0
Result:
Error in : Runtime exception at 0x00400004: Attempt to write to read-only CSR ucause = 0x00000002 uepc = 0x00400004
-
LOAD_ADDRESS_MISALIGNED (
ucause
= 4)Code:
.data .space 2 .align 0 data: .word 0xDEADBEEF .text main: la t0, data lw t1, 0(t0)
Result:
Error in: Load address not aligned to word boundary 0x10010002 ucause = 0x00000004 uepc = 0x00400008 utval = 0x10010002
-
LOAD_ACCESS_FAULT (
ucause
= 5)Code:
.text main: la t0, main lw t1, 0(t0)
Result:
Error in: Runtime exception at 0x00400008: Cannot read directly from text segment!0x00400000 ucause = 0x00000005 uepc = 0x00400008 utval = 0x00400000
-
STORE_ADDRESS_MISALIGNED (
ucause
= 6)Code:
.data .space 2 .align 0 data: .word 0 .text main: la t0, data li t1, 0xDEADBEEF sw t1, 0(t0)
Result:
Error in: Runtime exception at 0x00400010: Store address not aligned to word boundary 0x10010002 ucause = 0x00000006 uepc = 0x00400010 utval = 0x10010002
-
STORE_ACCESS_FAULT (
ucause
= 7)Code:
.text main: la t0, main li t1, 0xDEADBEEF sw t1, 0(t0)
Result:
Error in: Runtime exception at 0x00400010: Cannot write directly to text segment!0x00400000 ucause = 0x00000007 uepc = 0x00400010 utval = 0x00400000
-
ENVIRONMENT_CALL (
ucause
= 8)Code:
.text main: li a7, 100 ecall
Result:
Error in: Runtime exception at 0x00400008: invalid or unimplemented syscall service: 100 ucause = 0x00000004 uepc = 0x00400008
Exception Handling
When an exception occurs the following actions are performed:
- the
uie
(interrupt enable) bit in the status word is set to0
; - the
ucause
register is set to indicate which event has occurred; - the
uepc
is set to the last instruction that was executing when system trapped; - the PC is set to
utvec
value; in case of vectored exception handling, the PC is setutvec
base address + 4 *utcause
.
In order to have a working exception handler, the program must:
- set
utvec
to the address of the handler code (the lowest two bits are special); - set the bits corresponding to the handled interrupts in
uie
; - set the interrupt enable (lowest) bit in
ustatus
to enable the handler.
The simplest user-level exception handler that just returns control to the next (PC+4) instruction:
handler:
# Just ignore it by moving uepc to the next instruction
csrrw t0, uepc, zero
addi t0, t0, 4
csrrw zero, uepc, t0
uret
The user-level handler can be registered in the following way:
la t0, handler # load handler address to t0
csrrw zero, utvec, t0 # set utvec to the handlers address
csrrsi zero, ustatus, 1 # set interrupt enable bit in ustatus
Interrupts are exceptions that come from external devices such as I/O devices.
These events can be handled. To do this, an interrupt must be enabled in the device and
a corresponding bit must be set in uie
. See the examples to learn how this works.
Tasks
-
Study the theory and examples on the current workshop.
-
Implement an exception handler that prints a message that explains the reason of an exception (the list of exceptions with descriptions is above).
-
Image how the try-catch construct is implemented in high-level languages. Then write a program that implements a simple function with an exception handler. The function takes an argument that specifies what exception it will raise (
0
- no exception,1
- some exception from list above,2
- some other exception from the list). The function must return exception cause or 0 if no exception has occurred. The program prints the exception cause.
Homework
Study the theory and the examples and finish the tasks.
-
Write a program that waits for timer interrupts and counts them. Input data:
m
is the limit on number of interrupts to process,t
is the interval between interrupts in milliseconds. The program exits when the number of handler interrupts reaches the limit.Hint: Use the “Tools | Timer Tool” RARS extension. See its help. The MMIO address to get the current time
0xFFFF0018
; the MMIO address the set the time for the next interrupt is0xFFFF0020
. To set up the cycle of processing interrupts, the following must be done:- The address of your interrupt handler must be stored in the
utvec
CSR. - The fourth bit of the
uie
CSR must be set to1
(i.e.ori uie, uie, 0x10
). - The zeroth bit of the
ustatus
CSR must be set to1
(i.e.ori ustatus, ustatus, 0x1
). - The time for the next interrupt must be written to
0xFFFF0020
. - When an interrupt is handled the time for the next interrupt must be updated.
- The address of your interrupt handler must be stored in the
-
Bonus task (2 bonus points):
How would you simulate multitasking using interrupts and timer? Write a program that contains two for-loops running in a semi-parallel mode. The first prints messages
Thread1: 0
..Thread1: N
and the second prints messagesThread2: 0
..Thread2: N
. The program must use timer to switch between the threads.Hint: Each thread stores in memory (
.data
section) its PC and values of register it uses. When a timer interrupt occurs, the handler saves current register values, loads the new register values, and return control to the PC of the next thread.
Commit the programs to your private GitHub account. Place them into the folder ca/lab10
.
References
- Chapter 6: “N” Standard Extension for User-Level Interrupts in The RISC-V Instruction Set Manual Volume II: Privileged Architecture.
- RISC-V Assembly Programmer’s Manual.
- The Processor. Chapter 4 in [CODR].
- Pipelining: Basic and Intermediate Concepts. Appendix C in [CAQA].
- Instruction-Level Parallelism and Its Exploitation. Chapter 3 in [CAQA].
- RISC-V Assembly Language Programmer Manual. Part I.
- Interrupt (Wikipedia).
- Superscalar processor (Wikipedia).
- Out-of-order execution (Wikipedia).
- Ripes - graphical processor simulator and assembly editor for the RISC-V ISA.