Synchronous Exceptions

<aside> đź’ˇ Note: Synchronous Exceptions are synchronous with the instruction stream (the sequence of instructions being executed). They occur due to an instruction being executed.

Note: mret will not contain the return address of the next instruction for Synchronous Exceptions as the program should be killed after an unclear instruction has executed (whether that be an Access Fault Exception or an Illegal Instruction Exception). mepc is going to refer to the instruction that caused the exception.

</aside>

<aside> đź’ˇ Access Fault Exceptions

Access Fault Exceptions are when you access memory that can’t be accessed in the way it is being accessed.

Examples Storing to ROM (writing to ROM) Reading to/writing from a memory address that doesn’t exist

</aside>

<aside> đź’ˇ How Exceptions Are Handled (Example Using Access Fault Exception)

In this example, there is an access fault exception during the execution of lw a1, 0(a0) because 0x71000000 is an invalid address and this code attempts to access this invalid address in lw a1, 0(a0).

As a result of this exception, the code goes to an exception handler. The exception handler’s starting address is contained in the control status register (CSR), mtvec.

In order for mtvec to contain the starting address of the exception handler, the csrw instruction is needed to change mtvec’s value to that address.

</aside>

Screen Shot 2022-03-14 at 11.16.12 AM.png

Wait-Loop I/O

<aside> đź’ˇ Definition: Wait-Loop I/O involves a loop that will continuously run and check if a button has been pressed. And it will react to a button press.

</aside>

Multi-Button Controller Status Register (0x40000018)

Screen Shot 2022-03-14 at 12.02.45 PM.png

<aside> 💡 Know how to use Wait-Loop I/O to wait for a user to press any of the WADX buttons and how to check which of the four buttons was pressed. Given a specific layout of the multi-button controller status register saying which bits correspond to W, A, D, and X, you should be able to determine which button was pressed if the given layout were the register’s actual layout.

In the above image, the following bits correspond to the following buttons:

Bit #3: Right Button (D key) Bit #2: Down Button (X key) Bit #1: Up Key (W key) Bit #0: Left Key (A key)

To determine which button was pressed, Bitwise AND (&) can be used to check which of the bits are set. For instance, controller & LEFT would check if the bit that corresponds to the left key being pressed is set to 1. Meaning that the entire 32-bit sequence is being ANDed with 1 (since 1 would be the least significant bit that corresponds to the left button being pressed). If it’s set to 1, that is a button pressed. Otherwise, the left key was not pressed.

</aside>

Screen Shot 2022-03-14 at 12.41.52 PM.png

Interrupts

Note: Interrupts are asynchronous with the instruction stream meaning that they are caused by outside sources (input/output such as pressing a key). Thus, interrupts can occur in between lines of instructions not during the instruction cycle.

Interrupt-Driven I/O is more efficient than Wait-Loop I/O as with wait-loop I/O it’s repeatedly checking the multi-button CSR which results in instructions being eaten up. With Interrupt-Driven I/O, when a button is pressed, an interrupt will occur as a result of that button press (interrupting the instruction stream), and the program will respond to that button press.

<aside> đź’ˇ Setting Up/Understanding The Role of mtvec

The first step of setting up Interrupt-Driven I/O is setting the value of mtvec to the address of the exception handler’s first instruction. Setting mtvec’s value must be done in RISC-V Assembly!

</aside>

Screen Shot 2022-03-14 at 1.01.30 PM.png

<aside> đź’ˇ Why does an interrupt handler preserve registers?

An interrupt handler preserves all registers because it can randomly modify values in registers in instructions meaning that a register can have a random value as a result of the interrupt handler modifying that register’s value and not preserving it.

Register preservation for an interrupt handler does not follow the calling convention! This register preservation also must be done in RISC-V Assembly! It is unknown when an interrupt happens, so registers can’t be preserved before an interrupt occurs. Another reason register preservation can’t be done beforehand, is that the interrupt handler could mess up the register preservation.

Note: In the following image, s0 and s1 are already preserved. The complier will know that c_interrupt_handler will need to follow the calling convention. The calling convention requires that the callee preserves s0 and s1 . Thus, the Assembly code for that function will preserve s0 and s1.

Note: When an interrupt occurs, ****the return address is stored in a CSR called mepc. Therefore, mret gets the return address from mepc.

</aside>