1. Classification of RISC-V interrupts
- Local interrupt Local
- Softirqs software interrupt
- Timer interruption timer-imterrupt rupt
- Global interrupt
- Peripheral interrupt externle interrupt
2. Registers involved in RISC-V interrupt programming
Last time, we learned:
- mtvec
- mepc
- mcause
- mtval
- mstatus
- mscratch
Mie and MIP are the only ones left out
-
Mie register: Previously the MIE of MStatus is the enable bit for global interrupts. If global interrupts are off, then all are off. If global interrupts are on, more refined interrupt management is performed by the MIE register.
-
Mip register: Records whether the current interrupt occurred, 1 indicates that it did
3. Risc-v interrupt processing flow
4. The PLIC is introduced
- External interrupts, that is, interrupts of peripherals – such as USB(mouse, keyboard), disk management, etc
- If all peripherals were handled with a single pin of the chip, it would be very cumbersome, so PLIC was introduced
- PLIC: Platform level interrupt controller
- Left there are many many peripherals connected to PLIC, right for a HART, only a pin, so the function is, as long as there is an interrupt, then trigger the CPU interrupt, and if there are multiple interrupts, the current moment will only let an interrupt in, to coordinate the interrupt on the left.
(The serial device UART is also an Interrupt Source, defined here as 10)
- PLIC itself is also a peripheral, we also use registers to manipulate this peripheral
Priority Priority:
Records whether a route interrupt source is Pending
Records whether an interrupt source is enabled :Enable
Set the Threshold for the occurrence of interrupts. If the priority of the interrupt source is less than = Threshold, :Threshold is masked
Get the interrupt currently processed/eliminate the interrupt: Cliam/Complete:
5. Input from UART in interrupt mode
How do you type on the console and see it on the screen?
Externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap = externel trap So you can go and display characters on the console.
Total interrupt handlers:
trap_vector:
# save context(registers).
csrrw t6, mscratch, t6 # swap t6 and mscratch
reg_save t6
csrw mscratch, t6
# call the C trap handler in trap.c
csrr a0, mepc
csrr a1, mcause
call trap_handler
# trap_handler will return the return address via a0.
csrw mepc, a0
# restore context(registers).
csrr t6, mscratch
reg_restore t6
# return to whatever we were doing before trap.
mret
Copy the code
As you can see here, when an interrupt occurs, the trap_handler function is called as follows:
reg_t trap_handler(reg_t epc, reg_t cause)
{
reg_t return_pc = epc;
reg_t cause_code = cause & 0xfff;
if (cause & 0x80000000) {
/* Asynchronous trap - interrupt */
switch (cause_code) {
case 3:
uart_puts("software interruption! \n");
break;
case 7:
uart_puts("timer interruption! \n");
break;
case 11:
uart_puts("external interruption! \n");
external_interrupt_handler(a);break;
default:
uart_puts("unknown async exception! \n");
break; }}else {
/* Synchronous trap - exception */
printf("Sync exceptions! , code = %d\n", cause_code);
panic("OOPS! What can I do!");
//return_pc += 4;
}
return return_pc;
}
Copy the code
11 is an external interrupt, so when we hit the keyboard, case11 is executed, so external_interrupt_handler is executed as follows:
void external_interrupt_handler(a)
{
int irq = plic_claim(); // Get the number of an interrupt source
if (irq == UART0_IRQ){ // If the interrupt is generated by the UART, write it to the UART
uart_isr();
} else if (irq) {
printf("unexpected interrupt irq = %d\n", irq);
}
if (irq) { // If it is an interrupt source, the interrupt is resolvedplic_complete(irq); }}Copy the code
Finally, let’s look at how uARt_ISr writes characters to uART.
/* * handle a uart interrupt, raised because input has arrived, called from trap.c. */
void uart_isr(void)
{
while (1) {
int c = uart_getc(); // Get the character typed from the keyboard from the UART
if (c == - 1) {
break;
} else {
uart_putc((char)c); // Print this character
uart_putc('\n'); }}}Copy the code
So, here we print out the typed character.