目录
一、MPIS CPU Core与32个异常exception
1.1 龙芯1B的MIPS CPU IP Core
1.2 MIP32指令系统
1.3 MIPS CPU寄存器
1.4 龙芯异常exception与中断interrupt的区别
1.5 向量中断与非向量中断
1.6 MIPS CPU的异常向量与异常向量号:向量中断的支持
二、协议处理器CP0的中断控制与8个中断
2.1 CP0概述
2.2 协处理器支持的32个寄存器与CP0寄存器操作指令
2.3 CPU协处理器CP0支持的指令执行异常:32个异常编辑
2.4 CPU协处理器CP0支持的中断:8个中断
2.4.1 默认的中断号定义
2.4.2 中断号的配置与控制
2.5 协处理器CP0的中断服务程序
三、4个外部中断控制器与128个外部中断
3.1 外部中断源与4个中断控制器:INT0、INT1、INT2、INT3
3.2 如何配置外部中断源
3.3 四个中断控制器控制的所有外部中断的中断向量表
3.2.1 软件中断向量表结构定义:ls1b_irq.c
3.2.2 软件中断向量表定义:ls1b_irq.c和ls1b_irq.h
3.3.3 默认的中断处理或中断服务程序:ls1b_irq.c
3.3.4 中断向量表的初始化
3.3.5 安装用户自定义的中断服务程序的安装与移除
3.4 4个中断控制器的中断相关的寄存器
3.4.1 中断相关的寄存器列表(每个中断控制器有一套寄存器)
3.4.2 32bit 中断寄存器含义
3.4.3 32bits如何与中断源对应起来
3.4.5 如何根据中断原因寄存器挨个、逐一分发中断服务程序
2.4.6 四个中断控制器对应的中断服务程序
2.4.7 CPU协处理器是如何调用4个中断控制器对应的中断服务器程序
一、MPIS CPU Core与32个异常exception
1.1 龙芯1B的MIPS CPU IP Core
1.2 MIP32指令系统
1.3 MIPS CPU寄存器
1.4 龙芯异常exception与中断interrupt的区别
龙芯处理器中的异常(exception)和中断(interrupt)在概念上是有区别的,它们分别代表了不同类型的事件和处理机制:
-
异常(Exception):异常是指在程序执行过程中出现的一种非正常事件,通常是由指令执行时产生的,可以看作是处理器内部的问题。异常可以是因为错误的操作码、内存访问冲突、算术错误等原因导致的,需要处理器暂停当前指令的执行并执行相应的异常处理程序。异常通常由处理器本身或者处理器内部逻辑主动触发,它跳转到异常处理程序,处理完异常后再恢复到正常指令流程。
-
中断(Interrupt):中断是指来自外部设备的一种请求,要求处理器暂停当前正在执行的程序,转而执行与中断相关的处理程序。中断是处理器响应外部事件的一种方式,可以是来自设备的信号或者时钟,需要处理器打断当前执行的指令流程,执行相应的中断服务程序,处理完中断后再返回到被中断的程序继续执行。
在龙芯处理器中,异常和中断的区别在于触发原因和处理方式上:异常通常是由指令执行过程中的内部错误或意外情况引发,需要处理器内部去处理;而中断是由外部事件触发,需要处理器响应外部设备的请求。处理器在接收到异常或中断信号后,会根据具体情况执行相应的处理程序,保证系统的稳定运行和正确性。
1.5 同步中断与非同步中断
同步中断和异步中断是计算机中两种不同类型的中断处理方式。
-
同步中断:
- 在同步中断中,中断事件的发生和处理是同步发生的,也就是说,处理器会立即响应中断请求,并在当前执行的指令之后立即处理中断。
- 这种中断处理方式通常用于一些特定的同步事件,例如硬件错误、系统调用等。在这种情况下,处理器需要立即响应并处理中断,以保证系统的正确性和稳定性。
-
异步中断:
- 异步中断是指中断事件的发生和处理是异步的,处理器不会立即响应中断请求,而是在当前执行的指令结束后,再由中断控制器通知处理器发生了中断事件,然后才开始处理中断。
- 典型的异步中断包括外部设备的输入输出请求、定时器中断等。这些中断事件的发生不受处理器当前指令的影响,因此称为异步中断。
总的来说,同步中断是指中断事件和处理是同步发生的,而异步中断则是指中断事件和处理是异步的,处理器会在适当的时候才响应和处理中断请求。
1.6 向量中断与非向量中断
向量中断与非向量中断是处理器中处理中断的两种主要方式。
-
向量中断(Vectored Interrupts):
- 在向量中断系统中,每个中断都有一个唯一的向量号。
- 处理器硬件可以根据中断向量号直接访问/调用中断服务程序的入口地址。
- 当中断发生时,处理器硬件会自动跳转到相应中断服务程序的入口地址。
- 向量中断系统通常能够提供更快的中断响应时间,因为处理器软件不需要额外的逻辑来确定中断服务程序的入口地址。
-
非向量中断(Non-Vectored Interrupts):
- 在非向量中断系统中,中断服务程序的入口地址不是由中断向量表直接确定的。
- 处理器收到中断后,需要通过硬件设计或软件配置来确定统一的中断服务程序的入口地址。如在龙芯1B中为c_exception_handler。
- 通常需要额外的逻辑来确定中断服务程序的入口地址,因此可能导致较长的中断响应时间。包括额外的硬件逻辑和额外的软件逻辑,硬件逻辑包括控制器和原因寄存器,软件包括读取中断原因寄存器,并根据中断原因寄存器执行中断,此时的中断向量表是通过软件数组来维护的。
- 非向量中断系统在处理不同类型的中断时可能需要更多的处理逻辑。
1.7 MIPS CPU的异常向量与异常向量号:向量中断的支持
龙芯1B GS232处理器支持向量中断(Non-Vectored Interrupts)和非向量中断
如下是1B GS232处理器支持的异常向量表:
实际上,龙芯1B也支持非向量中断,非向量中断更加的灵活,大部分场景下,采用的是非向量中断,下面就阐述龙芯1B对非向量中断的支持。
二、协议处理器CP0的中断控制与8个中断
2.1 CP0概述
龙芯1B协处理器CP0(Coprocessor 0)是龙芯处理器(Loongson)中的一个重要组成部分,主要用于管理处理器的系统级行为和状态信息。CP0是一个与主处理器CPU紧密集成的协处理器,它的功能主要有以下几个方面:
-
地址转换和虚拟存储管理MMU:CP0可以实现物理地址的解析和转换,支持虚拟存储管理,使得应用程序可以像访问物理内存一样方便地访问虚拟内存区域。
-
异常和中断处理(本文要深入讨论的部分):CP0是处理器内部异常exception和外部中断Interrupt处理的核心,它存储了异常和中断向量表、错误状态码等信息,并负责中断的响应和异常处理程序的执行。
-
性能计数器和性能分析:CP0中还包括可编程的性能计数器和时钟戳记寄存器,可以用于对程序的性能分析和调优,并支持操作系统的性能监控功能。
-
系统控制寄存器:CP0中还包含了一些系统级别的控制寄存器,可以用于修改处理器的运行状态,如设置缓存策略、开/关写缓冲等。
总之,龙芯1B协处理器CP0是Loongson处理器的重要组成部分,它管理和控制处理器中的系统级行为和状态信息,为操作系统和应用程序提供了重要的支持和保障。
2.2 协处理器支持的32个寄存器与CP0寄存器操作指令
协处理器支持32个寄存器,其中部分寄存器用于中断控制!!!
2.3 CPU协处理器CP0支持的指令执行异常:32个异常
备注:
- 异常代码0:代表8个中断异常,在异常编码中,编码最小,优先级最低。
- 上述指令异常,部分需要软件处理,大部分是不需要软件处理的,而是有硬件电路进行处理
- Cause寄存器中的代码,不需要提供中断服务程序,提供个软件记录和现实异常的原因,辅助定位,大部分的异常处理,是由硬件完成纠错和处理,不需要软件参与。软件只需要把这些异常的原因记录和现实下来。
/*
* Define the name of the CPU family.
*/
#define CPU_NAME "MIPS"
/*
* MIPS Vector numbers for exception conditions. This is a direct map to the causes.
*/
#define MIPS_EXCEPTION_BASE 0
#define MIPS_EXCEPTION_INT MIPS_EXCEPTION_BASE+0
#define MIPS_EXCEPTION_MOD MIPS_EXCEPTION_BASE+1
#define MIPS_EXCEPTION_TLBL MIPS_EXCEPTION_BASE+2
#define MIPS_EXCEPTION_TLBS MIPS_EXCEPTION_BASE+3
#define MIPS_EXCEPTION_ADEL MIPS_EXCEPTION_BASE+4
#define MIPS_EXCEPTION_ADES MIPS_EXCEPTION_BASE+5
#define MIPS_EXCEPTION_IBE MIPS_EXCEPTION_BASE+6
#define MIPS_EXCEPTION_DBE MIPS_EXCEPTION_BASE+7
#define MIPS_EXCEPTION_SYSCALL MIPS_EXCEPTION_BASE+8
#define MIPS_EXCEPTION_BREAK MIPS_EXCEPTION_BASE+9
#define MIPS_EXCEPTION_RI MIPS_EXCEPTION_BASE+10
#define MIPS_EXCEPTION_CPU MIPS_EXCEPTION_BASE+11
#define MIPS_EXCEPTION_OVERFLOW MIPS_EXCEPTION_BASE+12
#define MIPS_EXCEPTION_TRAP MIPS_EXCEPTION_BASE+13
#define MIPS_EXCEPTION_VCEI MIPS_EXCEPTION_BASE+14
/* FPE only on mips2 and higher */
#define MIPS_EXCEPTION_FPE MIPS_EXCEPTION_BASE+15
#define MIPS_EXCEPTION_C2E MIPS_EXCEPTION_BASE+16
/* 17-22 reserved */
#define MIPS_EXCEPTION_WATCH MIPS_EXCEPTION_BASE+23
/* 24-30 reserved */
#define MIPS_EXCEPTION_VCED MIPS_EXCEPTION_BASE+31
#define MIPS_INTERRUPT_BASE MIPS_EXCEPTION_BASE+32
#define MIPS_EXCEPTION_BASE 0
#define MIPS_EXCEPTION_INT MIPS_EXCEPTION_BASE+0 # 中断异常
#define MIPS_EXCEPTION_WATCH MIPS_EXCEPTION_BASE+23
#define MIPS_EXCEPTION_VCED MIPS_EXCEPTION_BASE+31
#define MIPS_INTERRUPT_BASE MIPS_EXCEPTION_BASE+32 //中断控制器的中断服务程序入口
2.4 CPU协处理器CP0支持的中断:8个中断
2.4.1 默认的中断号定义
/*
* CP0 Cause ($12) IP bit(15:8)=IP[7:0], IP[1:0] is soft-interrupt
* Status($13) IM bit(15:8) if mask interrupts
*
*/
#define LS1B_IRQ_SW0 (MIPS_INTERRUPT_BASE + 0) //软件触发的中断SW0
#define LS1B_IRQ_SW1 (MIPS_INTERRUPT_BASE + 1) //软件触发的中断SW1
#define LS1B_IRQ0_REQ (MIPS_INTERRUPT_BASE + 2) //来自SOC芯片的中断控制器0
#define LS1B_IRQ1_REQ (MIPS_INTERRUPT_BASE + 3) //来自SOC芯片的中断控制器1
#define LS1B_IRQ2_REQ (MIPS_INTERRUPT_BASE + 4) //来自SOC芯片的中断控制器2
#define LS1B_IRQ3_REQ (MIPS_INTERRUPT_BASE + 5)//来自SOC芯片的中断控制器3
#define LS1B_IRQ_PERF (MIPS_INTERRUPT_BASE + 6) //来自CP0的性能统计
#define LS1B_IRQ_CNT (MIPS_INTERRUPT_BASE + 7) //来自CP0的Tick计数,用于操作系统tick调度// 备注:
//中断号越大,优先级越高
//中断号越小,优先级越低
2.4.2 中断号的配置与控制
默认情况下,性能统计和Tick计数的中断,其中断号是6和7,龙芯1B允许对该中断号进行修改,以降低其优先级,默认情况下,数值越大,优先级越高。
- IPTI:自定义Tick计数器中断的中断号
- IPPCI:自定义性能统计计数器中断的中断号
- VS:定义中断向量表的地址间隔,0表示相邻,1表示相隔32字节.....
2.5 协处理器CP0的中断服务程序
void c_interrupt_handler(void *p)
{
unsigned int sr;
unsigned int cause;
mips_get_sr(sr);
mips_get_cause(cause);
cause &= (sr & SR_IMASK);
cause >>= CAUSE_IPSHIFT;
/******************************************************************
* XXX use as bsp system tick generator.
*/
if (cause & 0x80) /* count/compare interrupt */
{
bsp_irq_handler_dispatch(LS1x_IRQ_CNT);
}
if (cause & 0x04) /* Interrupt controller 0 */
{
call_vectored_isr(p, cause, (void *)LS1x_INTC0_BASE);
}
if (cause & 0x08) /* Interrupt controller 1 */
{
call_vectored_isr(p, cause, (void *)LS1x_INTC1_BASE);
}
if (cause & 0x10) /* Interrupt controller 2 */
{
call_vectored_isr(p, cause, (void *)LS1x_INTC2_BASE);
}
if (cause & 0x20) /* Interrupt controller 3 */
{
call_vectored_isr(p, cause, (void *)LS1x_INTC3_BASE);
}
#if defined(LS1B)
if (cause & 0x40) /* Performance counter */
{
bsp_irq_handler_dispatch(LS1x_IRQ_PERF);
}
#elif defined(LS1C)
if (cause & 0x40) /* Interrupt controller 4 */
{
call_vectored_isr(p, cause, (void *)LS1x_INTC4_BASE);
}
#endif
if (cause & 0x02) /* Soft Interrupt SW[1] */
{
bsp_irq_handler_dispatch(LS1x_IRQ_SW1);
}
if (cause & 0x01) /* Soft Interrupt SW[0] */
{
bsp_irq_handler_dispatch(LS1x_IRQ_SW0);
}
// mips_set_cause(0);
}
三、4个外部中断控制器与128个外部中断
3.1 外部中断源与4个中断控制器:INT0、INT1、INT2、INT3
龙芯1B SOC芯片内置了4个简单、灵活的中断控制器,即INT0、INT1、INT2、INT3,用于管理SOC芯片外设和GPIO的中断。每个中断控制器最大管辖32个中断。
1B芯片的中断控制器除了管理 GPIO输入的中断信号外,中断控制器还处理内部设备引起的中断。所有的中断寄存器的位域安排相同,一个中断源对应其中一位。
SOC的中断控制器共四个中断线输出连接到CPU模块,分别对应 INT0, INT1, INT2, INT3。
SOC芯片中断控制器本身能够支持 64个内部中断和 64个 GPIO的中断,最大一共128个硬件外部中断源,这128个中断源分为四组,每组最大支持32个中断源,分别归组为:INT0, INT1, INT2, INT3。
其中 INT0和 INT1分别对应于 64个内部中断的前后 32位,INT2和 INT3对应于 64个外部 GPIO中断。但龙芯1B的实现过程中,并非所有的中断源都被使用,部分中断源是保留未使用,
具体中断源如下表所示:
从上图可以看出:
(1)GPIO31、GPIO62、GPIO63都未使用,属于保留位,因此一个64-3=61个GPIO中断源。
(2)并非所有的INT0和INT1的外设中断都被使用上,实际上,龙芯1B SOC芯片,并没有那么多外设,因此,大量的位都是闲置的,属于保留为,未定义其行为。
3.2 如何配置外部中断源
3.3 四个中断控制器控制的所有外部中断的中断向量表
3.2.1 软件中断向量表结构定义:ls1b_irq.c
/* 中断向量表 */
typedef struct isr_tbl
{
void (*handler)(int, void *); // 中断句柄
unsigned int arg; // 参数
} isr_tbl_t;
3.2.2 软件中断向量表定义:ls1b_irq.c和ls1b_irq.h
定义龙芯1B实际支持的中断源(去除保留位)
/******************************************************************************
* Interrupt Vector Numbers
* MIPS_INTERRUPT_BASE should be 32 (0x20)
******************************************************************************/
/*
* CP0 Cause ($12) IP bit(15:8)=IP[7:0],
* IP[1:0] is soft-interrupt
* Status($13) IM bit(15:8) if mask interrupts
*
*/
#define LS1B_IRQ_SW0 (MIPS_INTERRUPT_BASE + 0) # 协处理器的软中断
#define LS1B_IRQ_SW1 (MIPS_INTERRUPT_BASE + 1) # 协处理器的软中断
#define LS1B_IRQ0_REQ (MIPS_INTERRUPT_BASE + 2) # 协处理器的中断请求0
#define LS1B_IRQ1_REQ (MIPS_INTERRUPT_BASE + 3) # 协处理器的中断请求1
#define LS1B_IRQ2_REQ (MIPS_INTERRUPT_BASE + 4) # 协处理器的中断请求2
#define LS1B_IRQ3_REQ (MIPS_INTERRUPT_BASE + 5) # 协处理器的中断请求3
#define LS1B_IRQ_PERF (MIPS_INTERRUPT_BASE + 6) # 协处理器的性能统计中断
#define LS1B_IRQ_CNT (MIPS_INTERRUPT_BASE + 7) # 协处理器的计数或tick中断,操作系统调度使用
/*
* Interrupt Control 0 Interrupts: 中断控制器0支持的外设中断数量:29个
*/
#define LS1B_IRQ0_BASE (MIPS_INTERRUPT_BASE + 8)
#define LS1B_UART0_IRQ (LS1B_IRQ0_BASE + 2)
#define LS1B_UART1_IRQ (LS1B_IRQ0_BASE + 3)
#define LS1B_UART2_IRQ (LS1B_IRQ0_BASE + 4)
#define LS1B_UART3_IRQ (LS1B_IRQ0_BASE + 5)
#define LS1B_CAN0_IRQ (LS1B_IRQ0_BASE + 6)
#define LS1B_CAN1_IRQ (LS1B_IRQ0_BASE + 7)
#define LS1B_SPI0_IRQ (LS1B_IRQ0_BASE + 8)
#define LS1B_SPI1_IRQ (LS1B_IRQ0_BASE + 9)
#define LS1B_AC97_IRQ (LS1B_IRQ0_BASE + 10)
#define LS1B_DMA0_IRQ (LS1B_IRQ0_BASE + 13)
#define LS1B_DMA1_IRQ (LS1B_IRQ0_BASE + 14)
#define LS1B_DMA2_IRQ (LS1B_IRQ0_BASE + 15)
#define LS1B_PWM0_IRQ (LS1B_IRQ0_BASE + 17)
#define LS1B_PWM1_IRQ (LS1B_IRQ0_BASE + 18)
#define LS1B_PWM2_IRQ (LS1B_IRQ0_BASE + 19)
#define LS1B_PWM3_IRQ (LS1B_IRQ0_BASE + 20)
#define LS1B_RTC0_IRQ (LS1B_IRQ0_BASE + 21)
#define LS1B_RTC1_IRQ (LS1B_IRQ0_BASE + 22)
#define LS1B_RTC2_IRQ (LS1B_IRQ0_BASE + 23)
#define LS1B_TOY0_IRQ (LS1B_IRQ0_BASE + 24)
#define LS1B_TOY1_IRQ (LS1B_IRQ0_BASE + 25)
#define LS1B_TOY2_IRQ (LS1B_IRQ0_BASE + 26)
#define LS1B_RTC_IRQ (LS1B_IRQ0_BASE + 27)
#define LS1B_TOY_IRQ (LS1B_IRQ0_BASE + 28)
#define LS1B_UART4_IRQ (LS1B_IRQ0_BASE + 29)
#define LS1B_UART5_IRQ (LS1B_IRQ0_BASE + 30)
/*
* Interrupt Control 1 interrupts:中断控制器1支持的外设中断:4个
*/
#define LS1B_IRQ1_BASE (MIPS_INTERRUPT_BASE + 40)
#define LS1B_EHCI_IRQ (LS1B_IRQ1_BASE + 0)
#define LS1B_OHCI_IRQ (LS1B_IRQ1_BASE + 1)
#define LS1B_GMAC0_IRQ (LS1B_IRQ1_BASE + 2)
#define LS1B_GMAC1_IRQ (LS1B_IRQ1_BASE + 3)
/*
* Interrupt Control 2 interrupts (GPIO):中断控制器2支持的GPIO中断数:31个
*/
#define LS1B_IRQ2_BASE (MIPS_INTERRUPT_BASE + 72)
#define LS1B_GPIO0_IRQ (LS1B_IRQ2_BASE + 0)
#define LS1B_GPIO1_IRQ (LS1B_IRQ2_BASE + 1)
#define LS1B_GPIO2_IRQ (LS1B_IRQ2_BASE + 2)
#define LS1B_GPIO3_IRQ (LS1B_IRQ2_BASE + 3)
#define LS1B_GPIO4_IRQ (LS1B_IRQ2_BASE + 4)
#define LS1B_GPIO5_IRQ (LS1B_IRQ2_BASE + 5)
#define LS1B_GPIO6_IRQ (LS1B_IRQ2_BASE + 6)
#define LS1B_GPIO7_IRQ (LS1B_IRQ2_BASE + 7)
#define LS1B_GPIO8_IRQ (LS1B_IRQ2_BASE + 8)
#define LS1B_GPIO9_IRQ (LS1B_IRQ2_BASE + 9)
#define LS1B_GPIO10_IRQ (LS1B_IRQ2_BASE + 10)
#define LS1B_GPIO11_IRQ (LS1B_IRQ2_BASE + 11)
#define LS1B_GPIO12_IRQ (LS1B_IRQ2_BASE + 12)
#define LS1B_GPIO13_IRQ (LS1B_IRQ2_BASE + 13)
#define LS1B_GPIO14_IRQ (LS1B_IRQ2_BASE + 14)
#define LS1B_GPIO15_IRQ (LS1B_IRQ2_BASE + 15)
#define LS1B_GPIO16_IRQ (LS1B_IRQ2_BASE + 16)
#define LS1B_GPIO17_IRQ (LS1B_IRQ2_BASE + 17)
#define LS1B_GPIO18_IRQ (LS1B_IRQ2_BASE + 18)
#define LS1B_GPIO19_IRQ (LS1B_IRQ2_BASE + 19)
#define LS1B_GPIO20_IRQ (LS1B_IRQ2_BASE + 20)
#define LS1B_GPIO21_IRQ (LS1B_IRQ2_BASE + 21)
#define LS1B_GPIO22_IRQ (LS1B_IRQ2_BASE + 22)
#define LS1B_GPIO23_IRQ (LS1B_IRQ2_BASE + 23)
#define LS1B_GPIO24_IRQ (LS1B_IRQ2_BASE + 24)
#define LS1B_GPIO25_IRQ (LS1B_IRQ2_BASE + 25)
#define LS1B_GPIO26_IRQ (LS1B_IRQ2_BASE + 26)
#define LS1B_GPIO27_IRQ (LS1B_IRQ2_BASE + 27)
#define LS1B_GPIO28_IRQ (LS1B_IRQ2_BASE + 28)
#define LS1B_GPIO29_IRQ (LS1B_IRQ2_BASE + 29)
#define LS1B_GPIO30_IRQ (LS1B_IRQ2_BASE + 30)
/*
* Interrupt Control 3 source bit (GPIO):中断控制器3支持的GPIO中断数:30个。
*/
#define LS1B_IRQ3_BASE (MIPS_INTERRUPT_BASE + 104)
#define LS1B_GPIO32_IRQ (LS1B_IRQ3_BASE + 0)
#define LS1B_GPIO33_IRQ (LS1B_IRQ3_BASE + 1)
#define LS1B_GPIO34_IRQ (LS1B_IRQ3_BASE + 2)
#define LS1B_GPIO35_IRQ (LS1B_IRQ3_BASE + 3)
#define LS1B_GPIO36_IRQ (LS1B_IRQ3_BASE + 4)
#define LS1B_GPIO37_IRQ (LS1B_IRQ3_BASE + 5)
#define LS1B_GPIO38_IRQ (LS1B_IRQ3_BASE + 6)
#define LS1B_GPIO39_IRQ (LS1B_IRQ3_BASE + 7)
#define LS1B_GPIO40_IRQ (LS1B_IRQ3_BASE + 8)
#define LS1B_GPIO41_IRQ (LS1B_IRQ3_BASE + 9)
#define LS1B_GPIO42_IRQ (LS1B_IRQ3_BASE + 10)
#define LS1B_GPIO43_IRQ (LS1B_IRQ3_BASE + 11)
#define LS1B_GPIO44_IRQ (LS1B_IRQ3_BASE + 12)
#define LS1B_GPIO45_IRQ (LS1B_IRQ3_BASE + 13)
#define LS1B_GPIO46_IRQ (LS1B_IRQ3_BASE + 14)
#define LS1B_GPIO47_IRQ (LS1B_IRQ3_BASE + 15)
#define LS1B_GPIO48_IRQ (LS1B_IRQ3_BASE + 16)
#define LS1B_GPIO49_IRQ (LS1B_IRQ3_BASE + 17)
#define LS1B_GPIO50_IRQ (LS1B_IRQ3_BASE + 18)
#define LS1B_GPIO51_IRQ (LS1B_IRQ3_BASE + 19)
#define LS1B_GPIO52_IRQ (LS1B_IRQ3_BASE + 20)
#define LS1B_GPIO53_IRQ (LS1B_IRQ3_BASE + 21)
#define LS1B_GPIO54_IRQ (LS1B_IRQ3_BASE + 22)
#define LS1B_GPIO55_IRQ (LS1B_IRQ3_BASE + 23)
#define LS1B_GPIO56_IRQ (LS1B_IRQ3_BASE + 24)
#define LS1B_GPIO57_IRQ (LS1B_IRQ3_BASE + 25)
#define LS1B_GPIO58_IRQ (LS1B_IRQ3_BASE + 26)
#define LS1B_GPIO59_IRQ (LS1B_IRQ3_BASE + 27)
#define LS1B_GPIO60_IRQ (LS1B_IRQ3_BASE + 28)
#define LS1B_GPIO61_IRQ (LS1B_IRQ3_BASE + 29)
#define LS1B_MAXIMUM_VECTORS (LS1B_GPIO61_IRQ+1)
#define BSP_INTERRUPT_VECTOR_MIN 0
#define BSP_INTERRUPT_VECTOR_MAX LS1B_MAXIMUM_VECTORS
备注:中断向量表中一共支持8 + 29 + 4 + 31 + 30 = 8 + 33 + 61 = 102个中断。
中断向量表:
static isr_tbl_t isr_table[BSP_INTERRUPT_VECTOR_MAX];
3.3.3 默认的中断处理或中断服务程序:ls1b_irq.c
/*
* 默认中断
*/
static void mips_default_isr(int vector, void *arg)
{
unsigned int sr;
unsigned int cause;
mips_get_sr(sr);
mips_get_cause(cause);
printf("Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n",
vector, cause, sr);
while (1)
;
}
3.3.4 中断向量表的初始化
/*
* 初始化
*/
void mips_init_isr_table(void)
{
unsigned int i;
for (i=0; i<BSP_INTERRUPT_VECTOR_MAX; i++)
{
isr_table[i].handler = mips_default_isr;
isr_table[i].arg = i;
}
}
使用默认的中断服务程序mips_default_isr初始化中断向量表。
3.3.5 安装用户自定义的中断服务程序的安装与移除
void ls1x_install_irq_handler(int vector, void (*isr)(int, void *), void *arg)
{
if ((vector >= 0) && (vector < BSP_INTERRUPT_VECTOR_MAX))
{
mips_interrupt_disable();
isr_table[vector].handler = isr;
isr_table[vector].arg = (unsigned int)arg;
mips_interrupt_enable();
}
}
void ls1x_remove_irq_handler(int vector)
{
if ((vector >= 0) && (vector < BSP_INTERRUPT_VECTOR_MAX))
{
mips_interrupt_disable();
isr_table[vector].handler = mips_default_isr;
isr_table[vector].arg = vector;
mips_interrupt_enable();
}
}
3.4 4个中断控制器的中断相关的寄存器
3.4.1 中断相关的寄存器列表(每个中断控制器有一套寄存器)
/*
* Interrupt Control register
*/
#define LS1B_INTC0_BASE 0xBFD01040 #中断控制器0对应的寄存器的基地址
#define LS1B_INTC1_BASE 0xBFD01058 #中断控制器1对应的寄存器的基地址
#define LS1B_INTC2_BASE 0xBFD01070 #中断控制器2对应的寄存器的基地址
#define LS1B_INTC3_BASE 0xBFD01088 #中断控制器3对应的寄存器的基地址
#define LS1B_INTC_ISR(base) (*(volatile unsigned int*)(base + 0x00)) /* 中断控制状态寄存器 */
#define LS1B_INTC_IEN(base) (*(volatile unsigned int*)(base + 0x04)) /* 中断控制使能寄存器 */
#define LS1B_INTC_SET(base) (*(volatile unsigned int*)(base + 0x08)) /* 中断置位寄存器 */
#define LS1B_INTC_CLR(base) (*(volatile unsigned int*)(base + 0x0C)) /* 中断清空寄存器 */
#define LS1B_INTC_POL(base) (*(volatile unsigned int*)(base + 0x10)) /* 高电平触发中断使能寄存器 */
/* EDGE 电平触发时: 1=高电平触发, 0=低电平触发
EDGE 边沿触发时: 1=上升沿触发, 0=下降沿触发 */
#define LS1B_INTC_EDGE(base) (*(volatile unsigned int*)(base + 0x14)) /* 边沿触发中断使能寄存器; 1:边沿触发, 0: 电平触发 */
3.4.2 32bit 中断寄存器含义
(1)中断控制状态寄存器:表面是否有某种中断发生
(2)中断控制使能寄存器:使能某个中断控制器的某个中断
(3)中断置位寄存器:强制置位对应bits的中断
(4)中断清空寄存器:强制清空对应bit的中断
(5)高电平触发中断使能寄存器:中断使能
3.4.3 32bits如何与中断源对应起来
四个中断控制器对应的bits有各自的含义
/*
* Interrupt Control 0 source bit:中断控制器0的中断源
*/
#define INTC0_UART5_BIT bit(30)
#define INTC0_UART4_BIT bit(29)
#define INTC0_TOY_BIT bit(28)
#define INTC0_RTC_BIT bit(27)
#define INTC0_TOY2_BIT bit(26)
#define INTC0_TOY1_BIT bit(25)
#define INTC0_TOY0_BIT bit(24)
#define INTC0_RTC2_BIT bit(23)
#define INTC0_RTC1_BIT bit(22)
#define INTC0_RTC0_BIT bit(21)
#define INTC0_PWM3_BIT bit(20)
#define INTC0_PWM2_BIT bit(19)
#define INTC0_PWM1_BIT bit(18)
#define INTC0_PWM0_BIT bit(17)
#define INTC0_DMA2_BIT bit(15)
#define INTC0_DMA1_BIT bit(14)
#define INTC0_DMA0_BIT bit(13)
#define INTC0_AC97_BIT bit(10)
#define INTC0_SPI1_BIT bit(9)
#define INTC0_SPI0_BIT bit(8)
#define INTC0_CAN1_BIT bit(7)
#define INTC0_CAN0_BIT bit(6)
#define INTC0_UART3_BIT bit(5)
#define INTC0_UART2_BIT bit(4)
#define INTC0_UART1_BIT bit(3)
#define INTC0_UART0_BIT bit(2)
/*
* Interrupt Control 1 source bit:中断控制器1的中断源
*/
#define INTC1_GMAC1_BIT bit(3)
#define INTC1_GMAC0_BIT bit(2)
#define INTC1_OHCI_BIT bit(1)
#define INTC1_EHCI_BIT bit(0)
/*
* Interrupt Control 2 source bit (GPIO) :中断控制器2对应的中断源
*/
#define INTC2_GPIO30_BIT bit(30)
#define INTC2_GPIO29_BIT bit(29)
#define INTC2_GPIO28_BIT bit(28)
#define INTC2_GPIO27_BIT bit(27)
#define INTC2_GPIO26_BIT bit(26)
#define INTC2_GPIO25_BIT bit(25)
#define INTC2_GPIO24_BIT bit(24)
#define INTC2_GPIO23_BIT bit(23)
#define INTC2_GPIO22_BIT bit(22)
#define INTC2_GPIO21_BIT bit(21)
#define INTC2_GPIO20_BIT bit(20)
#define INTC2_GPIO19_BIT bit(19)
#define INTC2_GPIO18_BIT bit(18)
#define INTC2_GPIO17_BIT bit(17)
#define INTC2_GPIO16_BIT bit(16)
#define INTC2_GPIO15_BIT bit(15)
#define INTC2_GPIO14_BIT bit(14)
#define INTC2_GPIO13_BIT bit(13)
#define INTC2_GPIO12_BIT bit(12)
#define INTC2_GPIO11_BIT bit(11)
#define INTC2_GPIO10_BIT bit(10)
#define INTC2_GPIO9_BIT bit(9)
#define INTC2_GPIO8_BIT bit(8)
#define INTC2_GPIO7_BIT bit(7)
#define INTC2_GPIO6_BIT bit(6)
#define INTC2_GPIO5_BIT bit(5)
#define INTC2_GPIO4_BIT bit(4)
#define INTC2_GPIO3_BIT bit(3)
#define INTC2_GPIO2_BIT bit(2)
#define INTC2_GPIO1_BIT bit(1)
#define INTC2_GPIO0_BIT bit(0)
/*
* Interrupt Control 3 source bit (GPIO):中断控制器3对应的中断源
*/
#define INTC3_GPIO61_BIT bit(29)
#define INTC3_GPIO60_BIT bit(28)
#define INTC3_GPIO59_BIT bit(27)
#define INTC3_GPIO58_BIT bit(26)
#define INTC3_GPIO57_BIT bit(25)
#define INTC3_GPIO56_BIT bit(24)
#define INTC3_GPIO55_BIT bit(23)
#define INTC3_GPIO54_BIT bit(22)
#define INTC3_GPIO53_BIT bit(21)
#define INTC3_GPIO52_BIT bit(20)
#define INTC3_GPIO51_BIT bit(19)
#define INTC3_GPIO50_BIT bit(18)
#define INTC3_GPIO49_BIT bit(17)
#define INTC3_GPIO48_BIT bit(16)
#define INTC3_GPIO47_BIT bit(15)
#define INTC3_GPIO46_BIT bit(14)
#define INTC3_GPIO45_BIT bit(13)
#define INTC3_GPIO44_BIT bit(12)
#define INTC3_GPIO43_BIT bit(11)
#define INTC3_GPIO42_BIT bit(10)
#define INTC3_GPIO41_BIT bit(9)
#define INTC3_GPIO40_BIT bit(8)
#define INTC3_GPIO39_BIT bit(7)
#define INTC3_GPIO38_BIT bit(6)
#define INTC3_GPIO37_BIT bit(5)
#define INTC3_GPIO36_BIT bit(4)
#define INTC3_GPIO35_BIT bit(3)
#define INTC3_GPIO34_BIT bit(2)
#define INTC3_GPIO33_BIT bit(1)
#define INTC3_GPIO32_BIT bit(0)
3.4.5 如何根据中断原因寄存器挨个、逐一分发中断服务程序
(1)读取中断原因寄存器
#define LS1B_INTC_ISR(base) (*(volatile unsigned int*)(base + 0x00)) /* 中断控制状态寄存器 */
#define LS1x_INTC_ISR(base) LS1B_INTC_ISR(base)
(2)逐一检查原因寄存器
//-----------------------------------------------------------------------------
static void call_vectored_isr(void *p, unsigned int cause, void *ctrlr)
{
unsigned int src;
int index;
/* check request */
src = LS1x_INTC_ISR((unsigned int)ctrlr);
index = 0;
while (src) //挨个检查所有的中断源
{
/* check LSB */
if (src & 1)
{
/* clear */
LS1x_INTC_CLR((unsigned int)ctrlr) = (1 << index);
asm volatile ("sync");
if ((unsigned int)ctrlr == LS1x_INTC0_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ0_BASE + index);
}
else if ((unsigned int)ctrlr == LS1x_INTC1_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ1_BASE + index);
}
else if ((unsigned int)ctrlr == LS1x_INTC2_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ2_BASE + index);
}
else if ((unsigned int)ctrlr == LS1x_INTC3_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ3_BASE + index);
}
#if defined(LS1C)
else if ((unsigned int)ctrlr == LS1x_INTC4_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ4_BASE + index);
}
#endif
}
index++;
/* shift, and make sure MSB is clear */
src = (src >> 1) & 0x7fffffff; //挨个检查所有的中断源
}
}
(3)根据中断向量表执行中断服务器程序
//-----------------------------------------------------------------------------
// 中断分发
//-----------------------------------------------------------------------------
static void bsp_irq_handler_dispatch(int vector)
{
if ((vector >= 0) && (vector < BSP_INTERRUPT_VECTOR_MAX))
{
if (isr_table[vector].handler)
{
/*
* 关中断由中断程序自己处理
*/
isr_table[vector].handler(vector, (void *)isr_table[vector].arg);
/*
* 开中断由中断程序自己处理
*/
}
else
{
mips_default_isr(vector, NULL);
}
}
else
{
mips_default_isr(vector, NULL);
}
}
2.4.6 四个中断控制器对应的中断服务程序
static void call_vectored_isr(void *p, unsigned int cause, void *ctrlr)
{
unsigned int src;
int index;
/* check request */
src = LS1x_INTC_ISR((unsigned int)ctrlr);
index = 0;
while (src)
{
/* check LSB */
if (src & 1)
{
/* clear */
LS1x_INTC_CLR((unsigned int)ctrlr) = (1 << index);
asm volatile ("sync");
if ((unsigned int)ctrlr == LS1x_INTC0_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ0_BASE + index);
}
else if ((unsigned int)ctrlr == LS1x_INTC1_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ1_BASE + index);
}
else if ((unsigned int)ctrlr == LS1x_INTC2_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ2_BASE + index);
}
else if ((unsigned int)ctrlr == LS1x_INTC3_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ3_BASE + index);
}
#if defined(LS1C)
else if ((unsigned int)ctrlr == LS1x_INTC4_BASE)
{
bsp_irq_handler_dispatch(LS1x_IRQ4_BASE + index);
}
#endif
}
index++;
/* shift, and make sure MSB is clear */
src = (src >> 1) & 0x7fffffff;
}
}
2.4.7 CPU协处理器是如何调用4个中断控制器对应的中断服务器程序
void c_interrupt_handler(void *p)
{
unsigned int sr;
unsigned int cause;
mips_get_sr(sr);
mips_get_cause(cause);
cause &= (sr & SR_IMASK);
cause >>= CAUSE_IPSHIFT;
/******************************************************************
* XXX use as bsp system tick generator.
*/
if (cause & 0x80) /* count/compare interrupt */
{
bsp_irq_handler_dispatch(LS1x_IRQ_CNT);
}
if (cause & 0x04) /* Interrupt controller 0 中断控制器0对应的中断服务程序 */
{
call_vectored_isr(p, cause, (void *)LS1x_INTC0_BASE);
}
if (cause & 0x08) /* Interrupt controller 1 中断控制器1对应的中断服务程序*/
{
call_vectored_isr(p, cause, (void *)LS1x_INTC1_BASE);
}
if (cause & 0x10) /* Interrupt controller 2 中断控制器2对应的中断服务程序*/
{
call_vectored_isr(p, cause, (void *)LS1x_INTC2_BASE);
}
if (cause & 0x20) /* Interrupt controller 3 中断控制器3对应的中断服务程序*/
{
call_vectored_isr(p, cause, (void *)LS1x_INTC3_BASE);
}
#if defined(LS1B)
if (cause & 0x40) /* Performance counter */
{
bsp_irq_handler_dispatch(LS1x_IRQ_PERF);
}
#elif defined(LS1C)
if (cause & 0x40) /* Interrupt controller 4 */
{
call_vectored_isr(p, cause, (void *)LS1x_INTC4_BASE);
}
#endif
if (cause & 0x02) /* Soft Interrupt SW[1] */
{
bsp_irq_handler_dispatch(LS1x_IRQ_SW1);
}
if (cause & 0x01) /* Soft Interrupt SW[0] */
{
bsp_irq_handler_dispatch(LS1x_IRQ_SW0);
}
// mips_set_cause(0);
}