You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

399 lines
10 KiB

// See LICENSE for license details.
#include <gd32vf103.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "riscv_encoding.h"
#include "n200_func.h"
// Configure PMP to make all the address space accesable and executable
void pmp_open_all_space(){
// Config entry0 addr to all 1s to make the range cover all space
asm volatile ("li x6, 0xffffffff":::"x6");
asm volatile ("csrw pmpaddr0, x6":::);
// Config entry0 cfg to make it NAPOT address mode, and R/W/X okay
asm volatile ("li x6, 0x7f":::"x6");
asm volatile ("csrw pmpcfg0, x6":::);
}
void switch_m2u_mode(){
clear_csr (mstatus,MSTATUS_MPP);
//printf("\nIn the m2u function, the mstatus is 0x%x\n", read_csr(mstatus));
//printf("\nIn the m2u function, the mepc is 0x%x\n", read_csr(mepc));
asm volatile ("la x6, 1f ":::"x6");
asm volatile ("csrw mepc, x6":::);
asm volatile ("mret":::);
asm volatile ("1:":::);
}
uint32_t mtime_lo(void)
{
return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME);
}
uint32_t mtime_hi(void)
{
return *(volatile uint32_t *)(TIMER_CTRL_ADDR + TIMER_MTIME + 4);
}
uint64_t get_timer_value()
{
while (1) {
uint32_t hi = mtime_hi();
uint32_t lo = mtime_lo();
if (hi == mtime_hi())
return ((uint64_t)hi << 32) | lo;
}
}
uint32_t get_timer_freq()
{
return TIMER_FREQ;
}
uint64_t get_instret_value()
{
while (1) {
uint32_t hi = read_csr(minstreth);
uint32_t lo = read_csr(minstret);
if (hi == read_csr(minstreth))
return ((uint64_t)hi << 32) | lo;
}
}
uint64_t get_cycle_value()
{
while (1) {
uint32_t hi = read_csr(mcycleh);
uint32_t lo = read_csr(mcycle);
if (hi == read_csr(mcycleh))
return ((uint64_t)hi << 32) | lo;
}
}
uint32_t __attribute__((noinline)) measure_cpu_freq(size_t n)
{
uint32_t start_mtime, delta_mtime;
uint32_t mtime_freq = get_timer_freq();
// Don't start measuruing until we see an mtime tick
uint32_t tmp = mtime_lo();
do {
start_mtime = mtime_lo();
} while (start_mtime == tmp);
uint32_t start_mcycle = read_csr(mcycle);
do {
delta_mtime = mtime_lo() - start_mtime;
} while (delta_mtime < n);
uint32_t delta_mcycle = read_csr(mcycle) - start_mcycle;
return (delta_mcycle / delta_mtime) * mtime_freq
+ ((delta_mcycle % delta_mtime) * mtime_freq) / delta_mtime;
}
uint32_t get_cpu_freq()
{
uint32_t cpu_freq;
// warm up
measure_cpu_freq(1);
// measure for real
cpu_freq = measure_cpu_freq(100);
return cpu_freq;
}
// Note that there are no assertions or bounds checking on these
// parameter values.
void eclic_init ( uint32_t num_irq )
{
typedef volatile uint32_t vuint32_t;
//clear cfg register
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_CFG_OFFSET)=0;
//clear minthresh register
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_MTH_OFFSET)=0;
//clear all IP/IE/ATTR/CTRL bits for all interrupt sources
vuint32_t * ptr;
vuint32_t * base = (vuint32_t*)(ECLIC_ADDR_BASE + ECLIC_INT_IP_OFFSET);
vuint32_t * upper = (vuint32_t*)(base + num_irq*4);
for (ptr = base; ptr < upper; ptr=ptr+4){
*ptr = 0;
}
}
void eclic_enable_interrupt (uint32_t source) {
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IE_OFFSET+source*4) = 1;
}
void eclic_disable_interrupt (uint32_t source){
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IE_OFFSET+source*4) = 0;
}
void eclic_set_pending(uint32_t source){
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IP_OFFSET+source*4) = 1;
}
void eclic_clear_pending(uint32_t source){
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_IP_OFFSET+source*4) = 0;
}
void eclic_set_intctrl (uint32_t source, uint8_t intctrl){
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_CTRL_OFFSET+source*4) = intctrl;
}
uint8_t eclic_get_intctrl (uint32_t source){
return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_CTRL_OFFSET+source*4);
}
void eclic_set_intattr (uint32_t source, uint8_t intattr){
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_ATTR_OFFSET+source*4) = intattr;
}
uint8_t eclic_get_intattr (uint32_t source){
return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_INT_ATTR_OFFSET+source*4);
}
void eclic_set_cliccfg (uint8_t cliccfg){
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_CFG_OFFSET) = cliccfg;
}
uint8_t eclic_get_cliccfg (){
return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_CFG_OFFSET);
}
void eclic_set_mth (uint8_t mth){
*(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_MTH_OFFSET) = mth;
}
uint8_t eclic_get_mth (){
return *(volatile uint8_t*)(ECLIC_ADDR_BASE+ECLIC_MTH_OFFSET);
}
//sets nlbits
void eclic_set_nlbits(uint8_t nlbits) {
//shift nlbits to correct position
uint8_t nlbits_shifted = nlbits << ECLIC_CFG_NLBITS_LSB;
//read the current cliccfg
uint8_t old_cliccfg = eclic_get_cliccfg();
uint8_t new_cliccfg = (old_cliccfg & (~ECLIC_CFG_NLBITS_MASK)) | (ECLIC_CFG_NLBITS_MASK & nlbits_shifted);
eclic_set_cliccfg(new_cliccfg);
}
//get nlbits
uint8_t eclic_get_nlbits(void) {
//extract nlbits
uint8_t nlbits = eclic_get_cliccfg();
nlbits = (nlbits & ECLIC_CFG_NLBITS_MASK) >> ECLIC_CFG_NLBITS_LSB;
return nlbits;
}
//sets an interrupt level based encoding of nlbits and ECLICINTCTLBITS
void eclic_set_irq_lvl(uint32_t source, uint8_t lvl) {
//extract nlbits
uint8_t nlbits = eclic_get_nlbits();
if (nlbits > ECLICINTCTLBITS) {
nlbits = ECLICINTCTLBITS;
}
//shift lvl right to mask off unused bits
lvl = lvl >> (8-nlbits);
//shift lvl into correct bit position
lvl = lvl << (8-nlbits);
//write to clicintctrl
uint8_t current_intctrl = eclic_get_intctrl(source);
//shift intctrl left to mask off unused bits
current_intctrl = current_intctrl << nlbits;
//shift intctrl into correct bit position
current_intctrl = current_intctrl >> nlbits;
eclic_set_intctrl(source, (current_intctrl | lvl));
}
//gets an interrupt level based encoding of nlbits
uint8_t eclic_get_irq_lvl(uint32_t source) {
//extract nlbits
uint8_t nlbits = eclic_get_nlbits();
if (nlbits > ECLICINTCTLBITS) {
nlbits = ECLICINTCTLBITS;
}
uint8_t intctrl = eclic_get_intctrl(source);
//shift intctrl
intctrl = intctrl >> (8-nlbits);
//shift intctrl
uint8_t lvl = intctrl << (8-nlbits);
return lvl;
}
void eclic_set_irq_lvl_abs(uint32_t source, uint8_t lvl_abs) {
//extract nlbits
uint8_t nlbits = eclic_get_nlbits();
if (nlbits > ECLICINTCTLBITS) {
nlbits = ECLICINTCTLBITS;
}
//shift lvl_abs into correct bit position
uint8_t lvl = lvl_abs << (8-nlbits);
//write to clicintctrl
uint8_t current_intctrl = eclic_get_intctrl(source);
//shift intctrl left to mask off unused bits
current_intctrl = current_intctrl << nlbits;
//shift intctrl into correct bit position
current_intctrl = current_intctrl >> nlbits;
eclic_set_intctrl(source, (current_intctrl | lvl));
}
uint8_t eclic_get_irq_lvl_abs(uint32_t source) {
//extract nlbits
uint8_t nlbits = eclic_get_nlbits();
if (nlbits > ECLICINTCTLBITS) {
nlbits = ECLICINTCTLBITS;
}
uint8_t intctrl = eclic_get_intctrl(source);
//shift intctrl
intctrl = intctrl >> (8-nlbits);
//shift intctrl
uint8_t lvl_abs = intctrl;
return lvl_abs;
}
//sets an interrupt priority based encoding of nlbits and ECLICINTCTLBITS
uint8_t eclic_set_irq_priority(uint32_t source, uint8_t priority) {
//extract nlbits
uint8_t nlbits = eclic_get_nlbits();
if (nlbits >= ECLICINTCTLBITS) {
nlbits = ECLICINTCTLBITS;
return 0;
}
//shift priority into correct bit position
priority = priority << (8 - ECLICINTCTLBITS);
//write to eclicintctrl
uint8_t current_intctrl = eclic_get_intctrl(source);
//shift intctrl right to mask off unused bits
current_intctrl = current_intctrl >> (8-nlbits);
//shift intctrl into correct bit position
current_intctrl = current_intctrl << (8-nlbits);
eclic_set_intctrl(source, (current_intctrl | priority));
return priority;
}
//gets an interrupt priority based encoding of nlbits
uint8_t eclic_get_irq_priority(uint32_t source) {
//extract nlbits
uint8_t nlbits = eclic_get_nlbits();
if (nlbits > ECLICINTCTLBITS) {
nlbits = ECLICINTCTLBITS;
}
uint8_t intctrl = eclic_get_intctrl(source);
//shift intctrl
intctrl = intctrl << nlbits;
//shift intctrl
uint8_t priority = intctrl >> (nlbits+(8 - ECLICINTCTLBITS));
return priority;
}
void eclic_mode_enable() {
uint32_t mtvec_value = read_csr(mtvec);
mtvec_value = mtvec_value & 0xFFFFFFC0;
mtvec_value = mtvec_value | 0x00000003;
write_csr(mtvec,mtvec_value);
}
//sets vector-mode or non-vector mode
void eclic_set_vmode(uint32_t source) {
//read the current attr
uint8_t old_intattr = eclic_get_intattr(source);
// Keep other bits unchanged and only set the LSB bit
uint8_t new_intattr = (old_intattr | 0x1);
eclic_set_intattr(source,new_intattr);
}
void eclic_set_nonvmode(uint32_t source) {
//read the current attr
uint8_t old_intattr = eclic_get_intattr(source);
// Keep other bits unchanged and only clear the LSB bit
uint8_t new_intattr = (old_intattr & (~0x1));
eclic_set_intattr(source,new_intattr);
}
//sets interrupt as level sensitive
//Bit 1, trig[0], is defined as "edge-triggered" (0: level-triggered, 1: edge-triggered);
//Bit 2, trig[1], is defined as "negative-edge" (0: positive-edge, 1: negative-edge).
void eclic_set_level_trig(uint32_t source) {
//read the current attr
uint8_t old_intattr = eclic_get_intattr(source);
// Keep other bits unchanged and only clear the bit 1
uint8_t new_intattr = (old_intattr & (~0x2));
eclic_set_intattr(source,new_intattr);
}
void eclic_set_posedge_trig(uint32_t source) {
//read the current attr
uint8_t old_intattr = eclic_get_intattr(source);
// Keep other bits unchanged and only set the bit 1
uint8_t new_intattr = (old_intattr | 0x2);
// Keep other bits unchanged and only clear the bit 2
new_intattr = (old_intattr & (~0x4));
eclic_set_intattr(source,new_intattr);
}
void eclic_set_negedge_trig(uint32_t source) {
//read the current attr
uint8_t old_intattr = eclic_get_intattr(source);
// Keep other bits unchanged and only set the bit 1
uint8_t new_intattr = (old_intattr | 0x2);
// Keep other bits unchanged and only set the bit 2
new_intattr = (old_intattr | 0x4);
eclic_set_intattr(source,new_intattr);
}
//void wfe() {
// core_wfe();
//}