封装龙芯1c上常见外设接口,便于在裸机程序或实时操作系统中使用,类似于STM32库,正在不断添加中。Git地址是https://gitee.com/caogos/OpenLoongsonLib1c
龙芯1c中断结构分析
异常和中断的区别
在MIPS体系结构中,中断、自陷、系统调用以及其它打断程序正常执行流程的事件称为异常,
即异常包括中断,中断是一种特定类型的异常。
龙芯1c的异常分为四级
第一级: 各种情况下异常的总入口
第二级:各个异常的入口,其中ExcCode=0的异常为外设中断的总入口
第三级: 外设中断的每组的总入口(龙芯1c将所有外设分为五组)
第四级: 每个外设中断的入口
第一级——各种情况下异常的总入口
异常向量间的距离缺省为128字节(0x80)。
上表中,龙芯1C的BASE为0x80000000。
异常地址BASE+0x180对应的所有其它异常(包括我们关心的中断),在linux中的源码为
void __init trap_init(void)
{
……
set_handler(0x180, &except_vec3_generic, 0x80);
……
}
函数set_handler()的源码为
/* Install CPU exception handler */
void __init set_handler(unsigned long offset, void *addr, unsigned long size)
{
memcpy((void *)(ebase + offset), addr, size);
local_flush_icache_range(ebase + offset, ebase + offset + size);
}
简单来说,就是把函数except_vec3_generic()复制到BASE+0x180开始的长度为0x80的空间内,并且还有个刷cache的操作。这和其它单片机的中断处理函数名是在汇编中指定不太一样,但实现的功能是一样的。
函数except_vec3_generic()位于genex.S中,使用汇编实现的,如下
/*
* General exception vector for all other CPUs.
*
* Be careful when changing this, it has to be at most 128 bytes
* to fit into space reserved for the exception handler.
*/
NESTED(except_vec3_generic, 0, sp)
.set push
.set noat
#if R5432_CP0_INTERRUPT_WAR
mfc0 k0, CP0_INDEX
#endif
mfc0 k1, CP0_CAUSE
andi k1, k1, 0x7c
#ifdef CONFIG_64BIT
dsll k1, k1, 1
#endif
PTR_L k0, exception_handlers(k1)
jr k0
.set pop
END(except_vec3_generic)
其中,命令
mfc0 k1, CP0_CAUSE
andi k1, k1, 0x7c
取协处理器0的cause寄存器中[2,6]位,即ExcCode,如下
并将ExcCode作为索引,命令
PTR_L k0, exception_handlers(k1)
jr k0
跳转到对应的异常处理函数中。
exception_handlers的注册在traps.c中用函数set_except_vector()实现
void __init *set_except_vector(int n, void *addr)
{
unsigned long handler = (unsigned long) addr;
unsigned long old_handler = exception_handlers[n];
exception_handlers[n] = handler;
if (n