乐趣区

关于arm:嵌入式ARM设计编程四-ARM启动过程控制

文章和代码已归档至【Github 仓库:hardware-tutorial】,须要的敌人们自取。或者关注公众号【AIShareLab】,回复 嵌入式 也可获取。

一、试验目标

(1)把握建设根本残缺的 ARM 工程,蕴含启动代码,C 语言程序等;

(2)理解 ARM 启动过程,学会编写简略的 C 语言程序和汇编启动代码并进行调试;

(3)把握如何指定代码入口地址与入口点;

(4)把握通过 memory/register/watch/variable 窗口分析判断后果。

二、试验环境

硬件:PC 机。

软件:ADS1.2 集成开发环境

三、试验内容

应用汇编语言编写初始化程序,并疏导至 C 语言 main 函数,用汇编语言编写延时函数实现毫秒级的延时,在 C 语言中调用延时函数, 实现 1s 钟定时。

四、试验要求

(1) 在 ADS 下创立一个工程 armasmc,编写 3 个文件,如下图所示:

其中一个初始化汇编语言文件 Init.s,该文件中次要实现异样矢量表的建设,模式堆栈初始化,并将程序疏导至 C 语言的 main 函数。

C 语言程序保留为 armasmc.c。C 语言中调用汇编语言文件 delay.s 中的毫秒延时程序 delayxms,C 语言将延时的毫秒数通过参数传递到汇编语言,汇编语言实现延时,而后返回 C 语言函数。

通过 AXD 使用单步执行形式调试程序。察看程序执行过程中的寄存器及存储器的变动状况。

(2)试验过程中请记录并思考以下内容:

1)如何建设异样矢量入口表?

2)如何在汇编语言中切换至 C 语言的 main 函数?。

3)如何在 C 语言中调用汇编语言函数,并实现参数传递?

4)汇编语言函数中用到的寄存器如何爱护与复原,为什么要爱护参考程序中的 R11?

5)将 delay.s 中的 R11 改成 R4,并将两条 R11 的爱护与复原语句 stmfd sp!,{r11} 和 ldmfd sp!,{r11} 删掉,在 C 语言程序中的语句 i – 处设置端点,察看运行过程中变量 i 的变动状况,并解释其中的起因。

五、试验状况:

1、试验源代码(含正文):

Init.s 代码:

;************************ entry.s ****************************
 IMPORT Main  ; 在汇编程序调用该 c 程序前要在汇编语言程序中应用 IMPORT 伪操作来申明该 c 程序

  area Init,code,readonly   ; 定义 CODE 片段 Init 只读 
  entry     ; 设置程序入口伪指令
  code32   ; 以下为 32 位的 ARM 程序
; *********** Setup interrupt/exception vector *******************
start              b Reset_Handler        ; 异样矢量表,依据异样矢量表进入不同模式的中断程序      
Undefined_Handler  b Undefined_Handler
SWI_Handler        b SWI_Handler
Prefetch_handler   b Prefetch_handler
Abort_Handler      b Abort_Handler
                   nop   ;Reserved vector
IRQ_Handler        b IRQ_Handler
FIQ_Handler        b FIQ_Handler

Reset_Handler     ;Reset 中断,为整个中断的理论入口点        
             bl initstack    ; 初始化各模式下的堆栈指针
                             
             ; 切换至用户模式堆    
             msr cpsr_c,#0xd0    ;110  10000
                 
             bl Main

halt  b halt

initstack    mov r0,lr   ;r0<--lr, 因为各种模式下 r0 是雷同的而各个模式?                            
                                   
             ; 设置管理模式堆栈
             msr cpsr_c,#0xd3    ;110  10011  
             ldr sp,stacksvc
               
             ; 设置中断模式堆栈
             msr cpsr_c,#0xd2    ;110  10010
             ldr sp,stackirq  
             
             ; 设置疾速中断模式堆栈
             msr cpsr_c,#0xd1    ;110  10001
             ldr sp,stackfiq
                                
             ; 设置停止模式堆栈      
             msr cpsr_c,#0xd7    ;110  10111
             ldr sp,stackabt
                                    
            ; 设置未定义模式堆栈   
             msr cpsr_c,#0xdb    ;110  11011
             ldr sp,stackund
   
             ; 设置零碎模式堆栈    
             msr cpsr_c,#0xdf    ;110  11111
             ldr sp,stackusr
             
             mov pc,r0 ; 返回
         
  LTORG      

stackusr     dcd  usrstackspace+128
stacksvc     dcd  svcstackspace+128
stackirq     dcd  irqstackspace+128
stackfiq     dcd  fiqstackspace+128
stackabt     dcd  abtstackspace+128
stackund     dcd  undstackspace+128

  area Interrupt,data,READWRITE  ; 调配堆栈空间
usrstackspace space 128
svcstackspace space 128
irqstackspace space 128
fiqstackspace space 128
abtstackspace space 128
undstackspace space 128
     
       end

delay.s 代码:

;************************* delay.s *****************************
  EXPORT delayxms;EXPORT 伪指令用于在程序中申明一个全局的标号,该标号可在其余的文件中援用
  area delay,code,readonly  ; 定义 code 片段 delay 只读
  code32  ; 以下为 32 位的 ARM 程序
  
; 上面是延时若干 ms 的子程序      
delayxms
     stmfd sp!,{r11} ; 寄存器入栈
     sub r0,r0,#1 ;r0=r0-1
     ldr r11,=1000;加载至 r11 中
loop2
     sub r11,r11,#1;每次将 r11 自减一
     cmp r11,#0x0 ; 将 r11 与 0 比拟
     bne loop2  ; 比拟的后果不为 0,则持续调用 loop2  
     cmp r0,#0x0    ; 将 r0 与 0 比拟
     bne delayxms   ; 比拟的后果不为 0,则持续调用 delayxms
     ldmfd sp!,{r11};
     mov pc,lr; 返回
     
     end

armasmc.c 代码:

//*************************armasmc.c******************************
#include <stdio.h>
int Main()
{extern void delayxms(int xms);  // 在 C 程序调用汇编程序之前须要在 C 语言程序中应用 extern 关键词来申明该汇编程序
  
  int i=100;
  
  while(1)
  {delayxms(1000); // 调用 delayxms 汇编程序
     i--;
     if(i==0)
       i=100;
  }
  return 0;
}

2、试验过程(含后果截图及相应文字解释):

1. 如何建设异样矢量入口表?

答:建设异样矢量入口表须要设置中断类型号,并且要设置中断服务子程序段地址,以依据异样矢量表进入不同模式的中断程序。在试验程序中也有定义:

2. 如何在汇编语言中切换至 C 语言的 main 函数?

答:由上代码可知,为保障程序调用时参数的正确传递,汇编程序设计要恪守 ATPCS(ARM-Thumb Produce Call Standard), 它是 ARM 程序和 Thumb 程序中子程序调用的根本规定,目标是为了使独自编译的 C 语言程序和汇编程序之间可能互相调用。这些根本规定包含子程序调用过程中寄存器的应用规定、数据栈的应用规定和参数的传递规定。在 C 程序中不须要任何关键字来申明将被汇编语言调用的 C 程序,但须要在汇编语言程序之前应用 IMPORT 伪操作来申明该 C 程序。在汇编程序中通过 BL 指令来调用子程序。同时,汇编程序能够通过地址间接拜访在 C 语言程序中申明的全局变量。通过应用 IMPORT 关键词引入全局变量,并利用 LDR 和 STR 指令依据全局变量的地址能够拜访它们。

3. 如何在 C 语言中调用汇编语言函数,并实现参数传递?

答:为了保障程序调用时参数的正确传递,汇编程序设计要恪守 ATPCS。在汇编程序中须要应用 EXPORT 伪操作来申明,同时,在 C 程序中调用该汇编程序之前须要在 C 语言程序中应用 extern 关键词来申明该汇编程序。

4. 汇编语言函数中用到的寄存器如何爱护与复原,为什么要爱护参考程序中的 R11?

答:汇编语言函数中用到的寄存器通过压栈来爱护,出栈来复原。依据 ATPCS 规定,R11 对应 ARM 状态局部变量寄存器 8,R11 中含有循环次数的重要参量,因而要爱护 R11 防止在程序运行与调用过程中受到影响而导致程序异样。

5. 将 delay.s 中的 R11 改成 R4,并将两条 R11 的爱护与复原语句 stmfd sp!,{r11} 和 ldmfd sp!,{r11} 删掉,在 C 语言程序中的语句 i – 处设置端点,察看运行过程中变量 i 的变动状况,并解释其中的起因。

批改程序如下:

答:由上可知 R4 对应局部变量寄存器 1,即变量 i,因而在子程序 delay.s 中,R4 的值减为 0,若不进行爱护,则返回 C 程序后自减 -1,导致变量 i 的值变为 -1,此时将无奈满足 0 的条件,也就无奈执行 if,导致 i 会始终递加上来,最终无奈进行。

六、总结

本次无关汇编与 C 语言互相调用的局部,建设异样矢量入口表的办法,即须要设置中断类型号,并且要设置中断服务子程序段地址,以依据异样矢量表进入不同模式的中断程序。此外,还有 ARM 程序和 Thumb 程序中子程序调用的根本规定 ATPCS(ARM-Thumb Produce Call Standard),目标是为了使独自编译的 C 语言程序和汇编程序之间可能互相调用。这些根本规定包含子程序调用过程中寄存器的应用规定、数据栈的应用规定和参数的传递规定,为调用提供了相干的标准。其中汇编程序拜访全局 C 变量的办法是:汇编程序能够通过地址间接拜访在 C 语言程序中申明的全局变量。通过应用 IMPORT 关键词引入全局变量,并利用 LDR 和 STR 指令依据全局变量的地址能够拜访它们。在 C 语言程序中调用汇编程序的办法是:在汇编程序中须要应用 EXPORT 伪操作来申明,使得本程序能够被其它程序调用。同时,在 C 程序调用该汇编程序之前须要在 C 语言程序中应用 extern 关键词来申明该汇编程序。而在汇编程序中调用 C 语言程序的办法是:在 C 程序中不须要应用任何关键字来申明将被汇编语言调用的 C 程序,然而在汇编程序调用该 C 程序之前须要在汇编语言程序中应用 IMPORT 伪操作来申明该 C 程序。在汇编程序中通过 BL 指令来调用子程序。


欢送关注公众号【AIShareLab】,一起交换更多相干常识,前沿算法,Paper 解读,我的项目源码,面经总结。

退出移动版