免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1367 | 回复: 0
打印 上一主题 下一主题

arm中软中断的实现 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-21 09:56 |只看该作者 |倒序浏览
进过一天的奋战,终于搞好了软中断,其中的错误原来还是对代码存储的地址映射没搞清楚,错误的将向量表给覆盖了。结果可想而知了.......
    第一步:
先从root.s文件开始吧,这个文件就是系统启动代码,相当于有操作系统下的bootloader这里就是初始化向量表,寄存器,等等....废话少说还是看看源码吧
IMPORT postDelay
IMPORT osStack
IMPORT init_Stack
IMPORT post_initGpio
IMPORT init_Memory
IMPORT post_initKey
IMPORT dummyOs
IMPORT IRQ_Handler
IMPORT SWI_Handler
IMPORT ICMR
IMPORT init_ICMR
IMPORT PSSR
AREA boot ,CODE ,READONLY
ENTRY
B Reset_Handler
B Undefined_Handler
B SWI_Handler1
B Prefetch_Handler
B DataAbort_Handler
NOP
B IRQ_Handler
B FIQ_Handler
Undefined_Handler
B Undefined_Handler
SWI_Handler1
B   
SWI_Handler

Prefetch_Handler
B Prefetch_Handler
DataAbort_Handler
B DataAbort_Handler
FIQ_Handler
B FIQ_Handler    ;Defined by yourself
Reset_Handler
;*************************
;Check if run in the SDRAM
;*************************
MOV R0,PC
CMP R0,#0x0000003C
BNE Stack
  
..........下面的代码就略了呵呵,如果需要跟我qq 275911170
这里就在中断向量表中注册了我们函数的地址函数就是绿色字体的哪个,一开始我遇到的问题就是这个了,我看着下面红色的代码纯属浪费就在entry 下面的B SWI_Handler1 直接写成B SWI_Handler ,问题就出来了软硬中断都不响应了,在这里具体是怎么样的还没分析清楚,待分析清楚了再写下来。
第二步:
实现软中断程序,主要就是寄存器,程序状态寄存器,等的备份,。也就是软中断程序(软中断发生后执行的代码,和软中断推出执行的代码。
SWI_Handler.s
;;; Copyright ARM Ltd 1998. All rights reserved.
    AREA SWI_Area, CODE, READONLY
    EXPORT SWI_Handler
    IMPORT C_SWI_Handler

T_bit EQU 0x20
SWI_Handler
    STMFD   sp!, {r0-r3, r12, lr} ; Store registers
    MOV     r1, sp                 ; Set pointer to parameters
    MRS     r0, spsr               ; Get spsr
    STMFD   sp!, {r0}              ; Store spsr onto stack
    TST     r0, #T_bit             ; Occurred in Thumb state?
    LDRNEH r0, [lr,#-2]           ; Yes: Load halfword and...
    BICNE   r0, r0, #0xFF00        ; ...extract comment field
    LDREQ   r0, [lr,#-4]           ; No: Load word and...
    BICEQ   r0, r0, #0xFF000000    ; ...extract comment field

        ; r0 now contains SWI number
        ; r1 now contains pointer to stacked registers

    BL      C_SWI_Handler          ; Call main part of handler
    LDMFD   sp!, {r0}              ; Get spsr from stack
    MSR     spsr_cf, r0            ; Restore spsr
    LDMFD   sp!, {r0-r3, r12, pc}^ ; Restore registers and return
    END
这段代码直接从ads1.2自带的代码中copy过来,稍微加了些修改的。
我们来分析下:
可以看出软中入口子程序中lr的数值是不需要减的(现在什么情况减什么时候不减也不很清楚,流水线这东西复杂呵呵)
这段程序是中断处理程序的一部分,由它调用中断处理程序的主要处理部分,主要处理部分是用c语言写的chandle.c。下面分析一下这段程序。从下面几条语句开始
                STMFD   sp!, {r0-r3, r12, lr} ; Store registers


    MOV     r1, sp                 ; Set pointer to parameters
    MRS     r0, spsr               ; Get spsr
    STMFD   sp!, {r0}              ; Store spsr onto stack
第一条语句是把c语言中函数调用时的参数保存到堆栈中(如果不知道c和汇编互相传递参数机制就看看书吧) 在c语言的中断处理程序中读出这些参数。保存lr是因为一会要调用别的函数,所以防止lr丢失。为什么要保存r12这个我有点不太明白,因为这段程序运行根本就没用到它。第二条是把堆栈的地址保存到r1中,因为一会要把它传到c语言的中断处理函数中。
MRS     r0, spsr               ; Get spsr
STMFD   sp!, {r0}
这两句是把spsr保存到堆栈中,这是一般中断函数必要做的,不管用没用,保存是个习惯。
TST     r0, #T_bit             ; Occurred in Thumb state?
    LDRNEH r0, [lr,#-2]           ; Yes: Load halfword and...
    BICNE   r0, r0, #0xFF00        ; ...extract comment field
    LDREQ   r0, [lr,#-4]           ; No: Load word and...
    BICEQ   r0, r0, #0xFF000000    ; ...extract comment field
这一小段的代码主要作用是判断现在arm是thumb状态还是arm状态,根据不同的状态取半字还是字,然后得到用户要调用几号软中断,把这个号放到r0中。这里为什么会是lr-4呢,因为当main.c中执行中执行h文件中声明的方法时,就是调用了swi * 指令,当执行 swi * 这条指令时,编译器同时把这条指令的下一条指令的地址放到lr中,我们要得到swi * 这条指令,并得到 * (就是用户要调多少号软中断的号)是多少时,就得用lr-4了。
    BL      C_SWI_Handler          ; Call main part of handler
    LDMFD   sp!, {r0}              ; Get spsr from stack
    MSR     spsr_cf, r0            ; Restore spsr
    LDMFD   sp!, {r0-r3, r12, pc}^ ; Restore registers and return
一切准备工作都做完后,就调用c语言编写的具体的处理函数。函数返回后,恢复保存的寄存器。
这段代码的红色字体部分就是我们要实现的函数了,下面给出源码:
#define LED_CS   (*((volatile unsigned short int *)(0x10300000))) //LED1 and LED2
void C_SWI_Handler(int swi_num,int *regs)
{
switch(swi_num)
{
   case 0:
    //show number a,b
    LED_CS = 0x2479;
    break;
   case 1:
    //show number c,d
    LED_CS = 0x1930;
    break;
   
}
}
这里只做了个简单的测试,如果用户调用0号中断则在数码管上面显示12,如果用户调用1号中断则显示34
看到函数的参数第一个是swi_num就是中断号了,这个在上一个文件中已经保存在寄存器r0中了,编译器会自动把参数赋值给此函数的第一个参数,第二个参数是一个指针,用户在调用的时候传递的其他参数就可以用这个指针来获取。如第一个参数 reg[0] ..
根据不同的参数就作不同的处理了。
现在你一定很关心,用户的功能调用函数怎么编写呢?请看下面的代码:
__swi(0) int showNumber1(int, int); //中断服务函数申明,注意参数
__swi(1) int showNumber2(int, int);
//__swi(2) int add_multiply_two(int, int, int, int);
//struct four_results
//{
//    int a;
//    int c;
//    int d;
//};
//__swi(3) __value_in_regs struct four_results                 
//
看到了吗,其实就这么简单,我们知道在汇编中调用软中断是用命令swi * 当我们写了这个之后就可以在c中调用中断了,像使用普通的函数一样,某种意义上增加了系统的多任务能力。至于软中断的用处,还是google下比较好。这里只是简单的实现,现在比较忙,就没具体写具体的用法,在后续文章中会补上的。
万事具备只欠东风了,下面我们就写我们的主函数:
#include
#include "swi.h" //include the serice header
extern void SWI_Handler(void);
#define LED_CS2   (*((volatile unsigned short int *)(0x10300000))) //LED1 and LED2
#define LED_CS3   (*((volatile unsigned short int *)(0x10400000))) //LED3 and LED4
#define KPDK_VALUE (*((volatile unsigned char *)(0x41500008)))   //Direct Keypad
#define KPAS_VALUE (*((volatile unsigned char *)(0x41500020)))   //Matrix Keypad
unsigned *swi_vec = (unsigned*)0x08; //中断向量表入口地址
unsigned Install_Handler( unsigned routine, unsigned *vector )   //注册向量表,这段断码是通用的,不过还有其他的多种方法。
{
    unsigned vec, old_vec;
    vec = (routine - (unsigned)vector - 8) >> 2;
    if (vec & 0xff000000)
    {
        printf("Handler greater than 32MBytes from vector");
    }
    vec = 0xea000000 | vec;     /* OR in 'branch always' code */
    old_vec = *vector;
    *vector = vec;
    return (old_vec);
}
void delay(unsigned int x)
{
unsigned int i, j, k;
for (i =0; i

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93893/showart_1870570.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP