首页
社区
课程
招聘
[求助]ARM7TDMI SWI指令的用法
发表于: 2009-3-9 19:32 11951

[求助]ARM7TDMI SWI指令的用法

2009-3-9 19:32
11951
这两天在看SWI的用法,但始终不能得到其中的玄机,这里问问朋友们。
MSR     CPSR_c, #0xd0               ;切换到用户模式
MRS    R0,CPSR
SWI    1                           ;*****1
SWI_Hander
    STMFD    SP!,{R0-R3,R12,LR}  ;保存各寄存器
    MRS    R0,SPSR             ;保存SPSR
    STMFD    SP!,{R0}
    TST    R0,#T_bit           ;测试是Thumb还是ARM
    LDRNEH    R0,[LR,#-2]         
    BICNE    R0,R0,#0xFF00
    LDREQ    R0,[LR,#-4]
    BICEQ    R0,R0,#0xFF000000
    LDR    PC,[PC,R0,LSL #2]
    MOVS    PC,LR
SWI_function
    DCD    ChangeMode
            
ChangeMode
    MRS    R0,CPSR

这段程序的不完整的,我的目的是想看看SWI是如何在用户模式下工作,并切换到系统模式,SWI_Hander这段代码的意思我理解,就是得到SWI的编号,然后通过LDR  PC,[PC,R0,LSL #2]来跳转到相应的子程序,但我现在不明白的是SWI 后的立即数是如何工作的,像我上面这样写运行时走到SWI 1报告Undefined instruction的错误,各位大大能否告诉该如何做,我网上也找了,还没看懂,大大能不能举个例子教教我,谢谢了

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (25)
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
2
SWI指令用于产生软件中断,以便用户程序能调用操作系统的系统例程。操作系统在SWI的异常处理程序中提供相应的系统服务,指令中24位的立即数指定用户程序调用系统例程的类型,相关参数通过通用寄存器传递,当指令中24位的立即数被忽略时,用户程序调用系统例程的类型由通用寄存器R0的内容决定,同时,参数通过其他通用寄存器传递。

SWI         0x02                    ;该指令调用操作系统编号位02的系统例程。
2009-3-9 19:51
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
3
另外不知道你的构建系统是什么?比如ADS等。建议可以看看ADS提供的示例代码可以降低学习的难度。
2009-3-9 19:59
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
楼上的意思就是SWI后面的立即数是系统内自己定义好的,是固定的?
2009-3-9 22:12
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
5
我认为应该是这样的。我记得以前用ADS做过一些试验,反汇编后可以发现使用了SWI和一些特殊的编号。

我个人的理解是:SWI指令的使用和过去DOS下INT中断类似。

你可以再查查,欢迎把结果发布回来。呵呵。
2009-3-9 22:17
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我看了Semihosting这份文档,里面说道SWI后跟的立即数是系统确定的,比如0x123456表示的软件终端,他会跳转到0x08这个地址,我还看了其他资料上说这个地址上一般放一条跳转指令,用来跳转到终端后的程序,我修改的程序如下:
MOV                R1,#0x08
LDR                R1,TestMode
SWI                0x123456
TestMode
                                 ..........
当结果依然不对,无法跳转到TestMode这里,并且始终停留在SWI这段,大大还请指教下,谢谢了
2009-3-12 15:15
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
7
MOV    R1,#0x08
这条指令运行后,r1寄存器中的数据为0x08.

LDR    R1,TestMode
这条指令可能有问题。如果你想把TestMode标号处的内存地址保存到r1中应该使用:
ldr      r1, = TestMode
按照你的写法很可能是把TestMode标号后的一条指令编码保存到r1中了。你可以调试的时候注意一下r1中的数据。
2009-3-12 17:16
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
8
你所说“终端后的程序”应该是“中断后的程序”吧?

按照你提供的资料我估计应该这样写这几条指令:


mov r1,#0x08 ;r1中保存地址
ldr r0,=TestMode ;r0中保存标号TestMode地址。或者说让r0指向TestMode
str r0,[r1] ;将r0中保存的TestMode地址写入0x08位置。
SWI 0x123456

TestMode


你先试试看,有问题大家再讨论。
2009-3-12 17:22
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
SWI 后面的立即数是自己定的,你可以通过指令中的立即数传递,如
swi  1;调用1号软中断
也可以通过寄存器传递,如
mov r0, #1;调用1号软中断
swi 0;忽略指令中的24位立即数
功能号在这里定义,每个功能号对应一个子程序,子程序的地址用DCD伪指令放于内存中。
SWI_function
    DCD    ChangeMode;0号功能
   DCD   function1;  1号功能
   DCD   function2;  2号功能
     .          .
       .           .
       .          .
当遇到SWI指令时,CPU就将处理器模式切换到管理模式,并产生中断,然后PC会跳到预先定义好的swi异常向量入口处,然后跳到swi中断服务程序,比如就是这里
SWI_Hander
    STMFD    SP!,{R0-R3,R12,LR}  ;保存各寄存器
    MRS    R0,SPSR             ;保存SPSR
    STMFD    SP!,{R0}
    TST    R0,#T_bit           ;测试是Thumb还是ARM
    LDRNEH    R0,[LR,#-2]   ;如果是    Thumb指令,就读取指16位令码
    BICNE    R0,R0,#0xFF00;取得Thumb指令中的8位立即数
    LDREQ    R0,[LR,#-4]    ;如果是    ARM指令,就读取指32位令码
    BICEQ    R0,R0,#0xFF000000; 取得ARM指令中的24位立即数读到的24位立即数保存在R0中(就是对应的功能号)
    LDR    PC,[PC,R0,LSL #2] ;PC+R0*4->PC,这里实现跳转到对应的swi功能号去,
    MOVS    PC,LR
SWI_function
    DCD    ChangeMode
2009-3-12 19:34
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
回复"加百力":
     按你的方法无法运行到SWI时无法切换到系统模式,而且感觉的PC也没跑到0x08那里
回复"guetcw"
       你这段我在很多文章上都看到,但不明SWI如何和SWI_Hander联系起来,能否给个完完整整的简单代码,谢谢

谢谢大家的关心
2009-3-12 21:15
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
11
我只是顺着你的代码修改一下,一般0x08这样的地址应该处于系统保护的。恐怕一般不容易访问到。呵呵。

ADS开发系统中应该附带有代码的。在初学阶段多用可靠代码可以降低难度,也可以用Google搜搜。
2009-3-12 21:25
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
12
特别是你的程序本身不复杂,应该注意使用调试工具逐步跟踪,看看是哪个地方的错误?
调试技术是一项非常重要的基本功,自己写的代码调试起来还是比较容易的。
2009-3-12 21:35
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
我下的是盗版的ADS,安装教程上说这些帮助文件不能装,所以比较郁闷,我自己也做了好多试验,我在网上找了N久了,都是片段,我片段是懂的,但是我不知道SWI如何跳转到中断处理程序,这段详细的代码,网上都没有
2009-3-12 22:44
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
14
昨晚我练跆拳道的时候突然想到一个办法,也是我刚入门的时候经常使用的招数:

对于不熟悉的汇编语法可以写一个最简单的有等效功能的C语言程序,构建成功之后调试查看其汇编代码。

Xarm的语法也是用这种方法整理出来的。建议你试试。
2009-3-13 08:48
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
难道你不理解中断的含义啊,我上面说了的

当遇到SWI指令时,CPU就将处理器模式切换到管理模式,并产生中断,然后PC会跳到预先定义好的swi异常向量入口处,然后跳到swi中断服务程序

执行swi指令的时候CPU产生中断,然后CPU会自动的跳到中断向量地址上去,在ARM7中,共有8个中断向量,每个中断向量的地址都是固定的,比如lswi软件中断向量的地址是0x00000008,当发生swi中断的时候,CPU就肯定会跳到0x00000008这个地址上,除非你让ARM公司不这么做。而0x00000008这个地址上我们通常会放一条跳转指令,让CPU跳到我们的中断服务程序上来。在ARM的地址映射中0x00000000-0x0000001C这个地址范围对应的是ARM的8个中断异常入口,你可以去看看ARM中断的的一些资料。通常我们会在这几地址上构建一个中断向量表,当CPU发生中断后就可以跳到对应的中断服务上。
你这样做
mov    r1,#0x08           ;r1中保存地址
   ldr      r0,=TestMode    ;r0中保存标号TestMode地址。或者说让r0指向TestMode
    str      r0,[r1]                ;将r0中保存的TestMode地址写入0x08位置。
   SWI    0x123456

TestMode
是没有一点用的,你把TestMode 的地址装载到0x00000008这个地址上,产生swi中断后,PC指到这里,但它不是一条跳转指令,你放到0x00000008这个地址的数据(就是TestMode 的地址) 也许CPU根本就无法识别。

完整的测试代码一会贴上来。
2009-3-13 19:17
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
测试代码
startup.s 中的代码
;引入的外部标号在这声明
    IMPORT  __main                          ;C语言主程序入口(这个__main()是编译器提供的)
    IMPORT  SWI_Exception                                        ;SWI软件中断散转函数

;给外部使用的标号在这声明
    EXPORT  Reset

    CODE32

    AREA    vectors,CODE,READONLY
        ENTRY
;中断向量表
Reset
        LDR     PC, ResetAddr
        LDR     PC, UndefinedAddr
        LDR     PC, SWI_Addr
        LDR     PC, PrefetchAddr
        LDR     PC, DataAbortAddr
        DCD     0
        LDR     PC, IRQ_Addr
        LDR     PC, FIQ_Addr

ResetAddr           DCD     ResetInit
UndefinedAddr       DCD     0
SWI_Addr            DCD     SoftwareInterrupt
PrefetchAddr        DCD     0
DataAbortAddr       DCD     0
Nouse               DCD     0
IRQ_Addr            DCD     0
FIQ_Addr            DCD     0

;软件中断
SoftwareInterrupt
        LDR     SP, StackSvc            ; 重新设置堆栈指针
        STMFD   SP!, {R0-R3, R12, LR}

        MRS     R3, SPSR
        TST     R3, #0x20                      ; 中断前是否是Thumb状态
        LDRNEH  R0, [LR,#-2]            ; 是: 读取Thumb状态SWI号
        BICNE   R0, R0, #0xff00
        LDREQ   R0, [LR,#-4]            ; 否: 读取arm状态SWI号
        BICEQ   R0, R0, #0xFF000000
                                       
        BL      SWI_Exception                        ; r0 = SWI号,调用C语言SWI_Exception()函数
                                                                        ;参数通过r0传递
        
        LDMFD   SP!, {R0-R3, R12, PC}^  
        

;/* 复位入口*/
ResetInit      
                ;设置系统模式堆栈
        MSR     CPSR_c, #0xdf
        LDR     SP, StackSys
        
        B       __main                        ;跳转到c语言入口, __main()由编译器提供

StackSys           DCD     SysStackSpace +         31* 4
StackSvc           DCD     SvcStackSpace +  31* 4

;/* 分配堆栈空间 */
        AREA    MyStacks, DATA, NOINIT, ALIGN=2
SysStackSpace           SPACE   32 * 4  ;系统模式堆栈
SvcStackSpace                      SPACE   32 * 4  ;管理模式堆栈空间

  END
2009-3-13 19:35
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
main.c 中的代码
int SWI_Function1()
{
        return 1;
}

int SWI_Function2()
{
        return 2;
}

int Test()
{
        return 0x12345;
}

void SWI_Exception(int SWI_Nu)
{//处于管理模式,可切换到其它模式。
        switch(SWI_Nu)
        {
                case 0x1:
                        SWI_Function1();
                break;
                case 0x2:
                        SWI_Function2();
                break;
                case 0x12345:
                        Test();
                break;
        }
}

int main()
{
        __asm
        {
                SWI 0x1;//调用1号功能
                SWI 0x2;//调用2号功能
                SWI 0x12345;//调用0x12345号功能
        }
       
        while(1);
       
        return 0;
}
2009-3-13 19:36
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
我把整个项目文件上传给你,是在ADS下写的代码,你可以用ADS的DEBUG工具AXD进行仿真。
上传的附件:
2009-3-13 19:38
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
19
用C写程序再反汇编分析是个不错的办法。现在应该可以解决问题了。
2009-3-13 19:45
0
雪    币: 2604
活跃值: (64)
能力值: (RANK:510 )
在线值:
发帖
回帖
粉丝
20
以后ADS的问题就可以多找找:guetcw了。
2009-3-13 20:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
SWI是ARM的软件中断,找到软件中断子程序
2009-3-14 16:30
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
回复"guetcw"
      谢谢你的代码,我用你的程序运行到SWI 0x1时ADS会保存,"Process ARM7TDMI raised an exception. Cause: Undefined instruction"
2009-3-16 16:46
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
是你自己新建的工程吗,我在ADS里仿真是没有问题的,你按我建的工程设计,特别是ARM Linker /Layout 那里
2009-3-17 13:02
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
咦,按照你的工程设置就对了,但又多了些问题,大大能否给我个你的QQ号或者MSN我想当面请教,谢谢了,我的邮箱是taowenyin@tom.com或者Wenyin.tao@tpvaoc.com这两个都可以
2009-3-17 22:55
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
感谢"guetcw",感谢"加百力"今天晚上把你的代码理解了下,我终于知道中断是怎么操作的,所以来说下我的理解,有什么不对的地方还请朋友们指出来,谢谢

首先看一下工程设置在RO里面设置的是0x0000,可是为什么要设为0x0000呢,而不设为0x40000000,因为0x40000000是片内RAM的地址,他用于在线调试,而一般程序运行,都是从0x0000开始的,这里我有个猜测,应为LPC2210的FLash起始地址是0x80000000,而这里设置的0x0000是相对于0x80000000,即0x80000000=0x0000,0x80000001=0x0001.其次来说说LayOut里面的Object/Symbol和Section,前者设置的是工程的启动代码.o文件,即把startup.s改为startup.o,而后者表示启动代码的开始域名称。
说完工程设置来说说中断的操作,应为汇编是顺序执行的,所以把代码反汇编后在Disassembly最左边的一排指的是指令地址,由于ARM定位在0x00000008处指软中断的地址,所以在汇编程序开始的第三行必须写一个LDR     PC, SWI_Addr这样的跳转指令对软件中断进行初始化,当产生中断后就可以直接跳到这里进行操作。这也就是一直困扰我的跳转指令是如何到0x00000008处的。
OVER
2009-3-19 23:04
0
游客
登录 | 注册 方可回帖
返回
//