avr(at90...)的中断处理函数"注册"流程:
head.S中设置了默认中断处理(即:not_defined -> reset),同时注意到,这些位置的标记(symbol)都是弱的(.weak指明),也就是说,可以在程序中替换这些默认中断处理,也就是正常的方式,通过编译器定义好的方式写中断函数就可以了,编译器将我们自定义的中断处理函数做如下处理:
1. 保存现场(prologue);
2. 做真正的事;
3. 还原现场(epilogue);
4. reti从中断返回。
上面都是传统的方式,能够正常工作,也是大部分程序所采用的方法。 我们希望对其稍微改动,因为我们认为上面有几个不足:
1. 每个自定义中断处理函数,被编译器加上了头(prologue)和尾(epilogue),有点浪费code空间(,编译器加上naked参数能够跳过这些);
2. 不能为同一中断号注册多个处理函数,虽然一般不需要这样做(,当然也许你可以想到,把原来的中断处理例程中,改造为一个分发器也能实现这个,但我没有这样做);
3. 由1.引出的想法,中断处理的第一跳指令不是我们的指令,是不是不可控,作为新人类,我们要对我们的代码实行完全控制(代码控制控制欲),乱说的。。。
改造:
结合linux arm的还向量表构造来看,我们的难点将会是如果在我们所谓的“可控代码”中找到中断号(irq_nr):
1. 中断向量表处只能存放一条跳转指令,没有机会保存中断号;
2. 对这款芯片,各个中断标记分散在单独模块的寄存器中,如果做轮询的话,代码会很冗余;
取巧法:
hw_vect:
jmp reset
jmp sf_vect0
jmp sf_vect1
...
sf_vect0:
mov regX, 0
jmp prologue
sf_vect1:
mov regX, 1
jmp prologue
...
prologue:
do prologue
real_irq:
mov regY, regX ; 将irq_nr存入作为参数的寄存器
call do_IRQ ; 分发器,里面调用自定义的中断处理函数
epilogue:
do epilogue
reti
完成后,除了省了一些空间外,没发现有什么好的了,好玩而已?
补充(100506):用了这套东西,我们的串口无法输出爽快,输出几个字节就不动了,最后查找到问题在do_IRQ(int nr),我从内核里抄过来的原型,问题就出在这个int上,换成uint8_t它就爽了。