这次我们介绍的功能是CLINT中断。
首先我们先看一下指令集《The RISC-V Instruction Set Manual Volume II: Privileged Architecture Privileged Architecture Version 1.10》是如何定义的。
文档链接:
https://riscv.org/specifications/privileged-isa/
再看看E3关于CLINT的说明。
红色箭头是一个软件中断位,配置为1会产生中断,配置为0清除中断。
蓝色箭头是timer比较数值的配置,当mtime的数值等于mtimecmp时,会产生timer中断,当然前提是打开了这个中断的开关。
绿色箭头是mtime的值,根据时钟每次+1。
需要注意的是mtime和mtimecmp都是64-bit的寄存器,所以32-bit总线系统需要操作两次。还有rocket-chip这边是没有单独引出rtc_toggle这个时钟输入端口的,它是直接采用core的时钟进行100分频,如果想像E3那样采用外部异步时钟的话,需要修改scala代码。而且需要保证rtc_toggle与core_clk有一定的倍数关系,例如:rtc_toggle≤core_clk/2。
还需要注意的是,mtime在复位后是会被清0的,但mtimecmp不会。
接下来直接看测试代码。
#include "encoding.h"
#define U32 *(volatile unsigned int *)
#define DEBUG_SIG 0x70000000
#define DEBUG_VAL 0x70000004
void handle_trap();
void csr_cfg();
void mtimecmp_cfg();
void msip_cfg();
//--------------------------------------------------------------------------
// handle_trap function
void handle_trap()
{
//enter handle_trap()
U32(DEBUG_SIG) = 0x5;
//clear msip interrupt
U32(0x2000000) = 0x0;
if((read_csr(mip) & 0x00000080) != 0x0)
{
//clear mtime register
U32(0x200BFF8) = 0x0;
U32(0x200BFFC) = 0x0;
U32(DEBUG_SIG) = 0xFF;
}
}
//--------------------------------------------------------------------------
// CSR interrupt configuration function
void csr_cfg()
{
unsigned int csr_tmp;
//mie.MEIE
csr_tmp = read_csr(mie);
U32(DEBUG_VAL) = csr_tmp;
//write_csr(mie,0x0);
write_csr(mie,(csr_tmp | 0xFFFF0888));
//mstatus.MIE
csr_tmp = read_csr(mstatus);
U32(DEBUG_VAL) = csr_tmp;
//write_csr(mstatus,0x0);
write_csr(mstatus,(csr_tmp | 0x8));
}
//--------------------------------------------------------------------------
// mtimecmp configuration function
void mtimecmp_cfg()
{
//mtiemcmp0 - low bit
U32(DEBUG_VAL) = U32(0x2004000);
U32(0x2004000) = 0x00000010;
//mtiemcmp1 - high bit
U32(DEBUG_VAL) = U32(0x2004004);
U32(0x2004004) = 0x00000000;
//clear mtime register
U32(0x200BFF8) = 0x0;
U32(0x200BFFC) = 0x0;
}
//--------------------------------------------------------------------------
// msip configuration function
void msip_cfg()
{
U32(0x2000000) = 0x1;
}
//--------------------------------------------------------------------------
// Main
void main()
{
unsigned int i;
//configuration
mtimecmp_cfg();
csr_cfg();
//delay
for(i=0;i<20;i++)
{
U32(0x70000008+i*4) = i;
}
//msip software interrupt
msip_cfg();
while(1) {asm volatile ("wfi");}
}
仿真波形如下。
测试代码一次完成了两个中断。第一次是在配置完寄存器后,延迟一小段时间,然后往msip写1产生软件中断,进入中断函数后往msip写0清除中断,此时并没有立刻结束仿真,还在等mtime的计数,当mtime计数值等于mtimecmp时,timer中断产生,进入中断函数,清除中断状态,最后结束仿真。