1. PLIC software design
Related reference articles:
RISC-V teaching plan
1.4. plic_driver.c
#include "platform.h" #include "plic.h" #include "plic_driver.h" #include "encoding.h" #include <string.h> //Initialize the value in the interval to 0, volatile means that the variable does not need to be optimized and can be changed at any time void volatile_memzero(u8_t * base, unsigned int size) { volatile u8_t *ptr; for (ptr = base; ptr < (base + size); ptr++){ *ptr = 0; } } //initialization void PLIC_init ( plic_instance_t * this_plic, uintptr_t base_addr, u32_t num_sources, u32_t num_priorities ) { //Access variables in this_plic_struct this_plic->base_addr = base_addr; this_plic->num_sources = num_sources; this_plic->num_priorities = num_priorities; // disable all interrupts unsigned long hart_id = read_csr(mhartid); //Applicable to multi-core systems volatile_memzero( (u8_t*) (this_plic->base_addr + PLIC_ENABLE_OFFSET + (hart_id << PLIC_ENABLE_SHIFT_PER_TARGET)), //The unit of address range is 1byte/8 bit, +8 is because the division of integers is rounded up, where num_sources = 64 (num_sources + 8) / 8); // Set the priority of all interrupts to 0 volatile_memzero ( (u8_t *)(this_plic->base_addr + PLIC_PRIORITY_OFFSET), (num_sources + 1) << PLIC_PRIORITY_SHIFT_PER_SOURCE); // Initialize the priority threshold to 0, volatile means that the variable does not need to be optimized and can be changed at any time volatile plic_threshold* threshold = (plic_threshold*) (this_plic->base_addr + PLIC_THRESHOLD_OFFSET + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); *threshold = 0; //The threshold pointed to by the pointer is set to 0 } //Set the priority threshold void PLIC_set_threshold (plic_instance_t * this_plic,plic_threshold threshold) { unsigned long hart_id = read_csr(mhartid); //Applicable to multi-core systems //pointer value volatile plic_threshold* threshold_ptr = (plic_threshold*) (this_plic->base_addr + PLIC_THRESHOLD_OFFSET + (hart_id << PLIC_THRESHOLD_SHIFT_PER_TARGET)); *threshold_ptr = threshold;//address } //set priority void PLIC_set_priority (plic_instance_t * this_plic, plic_source source, plic_priority priority) { if (this_plic->num_priorities > 0) { volatile plic_priority * priority_ptr = (volatile plic_priority *) (this_plic->base_addr + PLIC_PRIORITY_OFFSET + /*The unit of address range is 1byte */ (source << PLIC_PRIORITY_SHIFT_PER_SOURCE)); *priority_ptr = priority; } } //read interrupt declaration register plic_source PLIC_claim_interrupt(plic_instance_t * this_plic){ unsigned long hart_id = read_csr(mhartid); //Applicable to multi-core systems volatile plic_source * claim_addr = (volatile plic_source * ) (this_plic->base_addr + PLIC_CLAIM_OFFSET + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); return *claim_addr; } // interrupt complete void PLIC_complete_interrupt(plic_instance_t * this_plic, plic_source source){ unsigned long hart_id = read_csr(mhartid); //Applicable to multi-core systems volatile plic_source * claim_addr = (volatile plic_source *) (this_plic->base_addr + PLIC_CLAIM_OFFSET + (hart_id << PLIC_CLAIM_SHIFT_PER_TARGET)); *claim_addr = source; }
1.5. main.c
Only the functions related to PLIC in the main function are listed here, and other detailed parts of the main function will be introduced in the project related to PLIC.
//PLIC enable static void enable_plic_int(u8_t int_src) { u8_t reg_off = 0; u8_t reg_val = 0; reg_off = (int_src / 32) * 4; //by definition reg_val = int_src & 0x1f; //Only 31 bits are reserved, 1F(16)=31(10) PLIC_REG(PLIC_ENABLE_OFFSET + reg_off) |= 1 << reg_val; //Set up the corresponding bit return; } //PLIC prohibited static void disable_plic_int(u8_t int_src) { u8_t reg_off = 0; u8_t reg_val = 0; reg_off = (int_src / 32) * 4; //by definition reg_val = int_src & 0x1f; //Only 31 bits are reserved, 1F(16)=31(10) PLIC_REG(PLIC_ENABLE_OFFSET + reg_off) &= ~(1 << reg_val); //Clear the corresponding bit return; }