#include
#include
#include
#define EINT0 0
#define IRQNUMBER 32
static void (*irq_handlers[IRQNUMBER])(void);
void irq_init(void)
{
struct interrupt *const irq = get_base_interrupt();
irq->INTMSK = ~0;
/* 修改cpsr,开启中断 */
__asm__ __volatile__ (
"mrs r0, cpsr\n\t"
"bic r0, r0, #0x80\n\t"
"msr cpsr, r0\n\t"
:
:
:"r0"
);
}
void request_irq(int num, void (*handler)(void))
{
struct interrupt *const irq = get_base_interrupt();
if(num >= 0 && num < IRQNUMBER && irq_handlers[num] == 0)
{
irq_handlers[num] = handler;
/* 启用中断服务 */
set0(irq->INTMSK, num);
}
}
void do_irq(void)
{
struct interrupt *const irq = get_base_interrupt();
const int num = irq->INTOFFSET & 0x1f;
if(irq_handlers[num])
irq_handlers[num]();
/* 中断处理完后或无中断处理函数,清中断 */
irq->SRCPND = irq->INTPND;
irq->INTPND = irq->INTPND;
}
void key(void)
{
puts("hello key");
}
int do_key(int argc, char *argv[])
{
struct gpio *const gpio = get_base_gpio();
/* 配置GPF0为EINT0中断模式,启用上拉 */
setval(gpio->GPFCON, 0x2, 2, 0);
set1(gpio->GPFUP, 0);
request_irq(EINT0, key);
return 0;
}
G_BOOT_CMD(key, do_key);
//==========================================================
以下汇编的启动代码:
.text
.global _start
_start:
ldr pc, _start_code
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
b _start
ldr pc, _irq
ldr pc, _fiq
_start_code:
.word start_code
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_irq:
.word irq
_fiq:
.word fiq
start_code:
/* 将r4-r14和cpsr的值保存到预留的80byte空间里 */
ldr r0, =u_boot_reg
stmia r0!, {r4-r14}
mrs r1, cpsr
str r1, [r0]
/* =============== 切换svc模式 ============ */
mov r0, #0xd3
msr cpsr, r0
/* ========== 设置栈的起始地址 ============ */
mov sp, #0x33800000
/* =================== 自拷贝 ============= */
/*
* 从0x30000000地址处拷贝64byte到0x0的地址处
* 就是开头line4 - line32的这段代码
*/
mov r0, #0x30000000
mov r1, #0
mov r2, #4*16
1:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r1, r2
blt 1b
/* ============ 自拷贝完 64byte =========== */
/* ============== 初始 sp 为0 ========== */
ldr r0, bss_start
ldr r1, bss_end
mov r2, #0
2:
str r2, [r0], #4
cmp r0, r1
blt 2b
/* =========== 初始化 sp 完 ============ */
bl clock_init
bl console_init
bl irq_init
mov lr, pc
ldr pc, _shell
3:
b 3b
_shell:
.word shell
bss_start:
.word __bss_start
bss_end:
.word __bss_end
.global exit
exit:
ldr r2, =u_boot_reg
ldmia r2!, {r4-r14}
ldr r3, [r2] /* 取出最后一个cpsr的值 */
msr cpsr, r3 /* 恢复cpsr的值 */
bx lr /* 恢复pc的值 */
/* ========== 保留80byte的空间 ========= */
u_boot_reg:
.space 4*20
//================================================
进入中断的处理函数
.text
.global undefined_instruction
undefined_instruction:
mov sp, #0x33c00000
@r0传参:
@r0的值传给do_interrupt函数的第一个参数
mov r0, #1
b do_interrupt
.global software_interrupt
software_interrupt:
stmfd sp!, {lr}
mov sp, #0x33c00000
mov r0, #2
@读取出swi的中断号,主要过程如下:
@需了解swi的功能:并了解执行swi的时候,它所做的一些事情是
@由硬件完成的.
@1. 取出执行swi时所保存的pc地址-4,就是swi指令的地址.
@2. bic一行的指令是屏蔽掉swi本身指令码,取出数据保存在r1寄存器
@3. r1的数据传给do_interrupt函数,作为其第二个参数.
ldr r1, [lr, #-4]
bic r1, #0xff000000
b do_interrupt
ldmfd sp!, {lr}
movs pc, lr @mov带上s,将spsr的值自动恢复给cpsr
.global prefetch_abort
prefetch_abort:
mov sp, #0x33c00000
mov r0, #3
b do_interrupt
.global data_abort
data_abort:
mov sp, #0x33c00000
mov r0, #4
b do_interrupt
.global irq
irq:
mov sp, #0x33c00000
stmfd sp!, {r0-r12, lr}
@因为执行bl时会改变pc的地址,所以需要将
@通用寄存器进栈保护,才能恢复到原来状态
bl do_irq
ldmfd sp!, {r0-r12, lr}
subs pc, lr, #4
.global fiq
fiq:
mov sp, #0x33c00000
mov r0, #6
b do_interrupt