Monday, 3 July 2017

[GSoC 2017 with RTEMS: Phase 2 Week 0] Working with interrupts on HiFive1

The purpose of this post is to show how interrupts in the HiFive1 board should be handled. I don't want here to describe a relation between RTEMS interrupt handling and  RISCV interrupt infrastructure. First of all, I want to describe FE310 SoC interrupt architecture and how interrupts can be initialized and handled on this architecture.

Interrupt initialization

There are two different types of interrupts in RISC-V architecture: local and global. Local interrupts have higher priorities. CLINT (Coreplex-Local Interrupts) module is responsible for interrupts in E31-Coreplex core (RISC-V Core in FE310 SoC). There are several local interrupts in CLINT:  Machine Software Interrupt, Machine Timer Interrupt, Machine External interrupt, Local Interrupts ID 0-15. 
Machine Software Interrupt can be generated by any hart - local or remote. Machine Timer interrupt is for timer interrupts and Machine External interrupt is for interrupts from global interrupts controller. In order to enable local interrupts, we should:
0 (optional). Set interrupt handlers vector address (aligned to 4) in mtvec register and set mtvec.MODE to 1 (mtvec.Mode is hardwired to zero in FE310-G000).

  1.  Set the required fields of mie register to 1.
  2.  Set mstatus register field mie to 1.
After this step, interrupts are enabled.

Interrupts handling

In order to handle interrupts you have to make several steps:
  1. Save context in stack
  2. Call interrupt handling routine 
  3. Read the value in mcause register
  4. Call an appropriate interrupt handler
    1. Turn off interrupts
    2. Make routine and clean* interrupt pending register
    3. Turn on interrupts
  5. Restore context
  6. Return to the state before entering to routine (with mret instruction).
In step 3 there is an mcause register that keeps the value of an occurred interrupt. If mcause[31]==0, then an exception took a place, otherwise - there was an interrupt. mcause[30:0] keeps the code of an occurred event. These codes can be found in [1, p.35].
In step 4.2 you have to clean interrupts pending bits in mip [1, p.28]. For each interrupt cause there are different ways to clean a pending bit [2]. For external interrupts, mip is cleaned by PLIC (external interrupt controller), for software interrupts, generated by writing '1' to address 0x02000000 - '0' should be written to the same address, and for timer interrupts, mtimecmp (memory mapped register, 0x02004000) should be written with a value greater than one in mtime (memory mapped register, 0x0200bff8).   
The description of mie register is provided in [1, p.28].


No comments:

Post a Comment