1. Classification of RISC-V interrupts

  • Local interrupt Local
    1. Softirqs software interrupt
    2. Timer interruption timer-imterrupt rupt
  • Global interrupt
    1. 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.