热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[嵌入式]Cortex-A8处理器编程(下)

第3章Cortex-A8处理器编程3.6指令系统ARM伪指令不属于ARM指令集中的指令,是为了编程方便而定义的。伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。A

第3章 Cortex-A8处理器编程

3.6  指令系统

ARM伪指令不属于ARM指令集中的指令,是为了编程方便而定义的。伪指令可以像其它ARM指令一样使用,但在编译时这些指令将被等效的ARM指令代替。ARM伪指令有四条,分别为ADR伪指令、ADRL伪指令、LDR伪指令、NOP伪指令。

ARM伪指令——小范围的地址读取

ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。在汇编编译器编译源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或SUB指令来实现该ADR伪指令的功能,若不能用一条指令实现,则产生错误,编译失败。

 

地址表达式expr的取指范围:

当地址值不是字对齐时,其取值范围为-255~255;

当地址值是字对齐时,其取值范围为-1020~1020;

当地址值是16字节对齐时,其取值范围将更大。

应用示例(源程序):

  ...

    ADR     R0,Delay    

    ...

Delay

    MOV     R0,r14

    ...

使用伪指令将程序标号Delay的地址存入R0

ARM伪指令——中等范围的地址读取

ADRL伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中,比ADR伪指令可以读取更大范围的地址 。在汇编编译器编译源程序时,ADRL伪指令被编译器替换成两条合适的指令。若不能用两条指令实现,则产生错误,编译失败。

 

地址表达式expr的取指范围:

当地址值不是字对齐时,其取址范围为-64K~64K;

当地址值是字对齐时,其取址范围为-256K~256K;

当地址值是16字节对齐时,其取址范围将更大。

应用示例(源程序):

...

    ADRL    R0,Delay    

    ...

Delay

    MOV     R0,r14

    ...

使用伪指令将程序标号Delay的地址存入R0

ARM伪指令——大范围的地址读取

LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器。在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV或MVN的范围,则使用MOV或MVN指令代替该LDR伪指令,否则汇编器将常量放入文字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。

 

应用示例(源程序):

   ...

    LDR     R1,=InitStack

    ...

InitStack    

    MOV     R0, LR

    ...

使用伪指令将程序标号InitStack的地址存入R1

注意:

1.从指令位置到文字池的偏移量必须小于4KB;

2.与ARM指令的LDR相比,伪指令的LDR的参数有“=”号。

ARM伪指令——空操作伪指令

NOP伪指令在汇编时将会被代替成ARM中的空操作,比如可能是“MOV  R0,R0”指令等。NOP可用于延时操作。

 

应用示例(延时子程序):

    Delay

    NOP;空操作

    NOP

    NOP

    SUBS    R1,R1,#1  ;循环次数减一

    BNE     Delay      ;如果循环没有结束,跳转Delay继续

    MOV     PC,LR       ;子程序返回

3.7 ARM汇编程序规范

     在只关心系统所具有功能的设计中,采用高级编程语言编写程序更合适,由于其隐藏了CPU执行指令的许多细节。但是,CPU执行指令的细节差异会反应在系统的非功能特性上,例如系统程序的规模和运行速度。因此,掌握汇编语言程序设计对于嵌入式系统的设计者来说是非常必要的。

ARM汇编程序中每一行的通用格式为:

{标号} {指令|指示符|伪指令} {;注解}

     在ARM汇编语言源程序中,除了标号和注释外,指令、伪指令和指示符都必须有前导空格,而不能顶格书写。如果每一行的代码太长,可以使用字符“\”将其分行书写,并允许有空行。指令助记符、指示符和寄存器名既可以用大写字母,也可以用小写字母,但不能混用。注释从“;”开始,到该行结束为止。

 

标号

标号代表一个地址,段内标号的地址值在汇编时确定,段外标号的地址值在链接时确定。在此要区别程序相对寻址和寄存器相对寻址。在程序段中,标号代表其所在位置与段首地址的偏移量,根据程序计数器PC和偏移量计算地址称为程序相对寻址。在映像中定义的标号代表标号到映像首地址的偏移量,映像的首地址通常被赋予一个寄存器,根据该寄存器值与偏移量计算地址称为寄存器相对寻址。

指示符

 

 

 

 

 

预定义变量

ARM汇编器对ARM的寄存器进行了预定义,所有的寄存器和协处理器名都是大小写敏感的。预定义的寄存器如下:

·R0~R15或r0~r15;

·a1~a4(参数、结果或临时寄存器,与r0~r3同义);

·v1~v8(变量寄存器,与r4~r11同义);

·sb和SB(静态基址寄存器,与r9同义);

·sl和SL(堆栈限制寄存器,与r10同义);

·fp和FP(帧指针,与r11同义);

·ip和IP(过程调用中间临时寄存器,与r12同义);

·sp和SP(堆栈指针,与r13同义);

·lr和LR(链接寄存器,与r14同义);

·pc和PC(程序计数器,与r15同义);

·cpsr和CPSR(程序状态寄存器);

·spsr和SPSR(程序状态寄存器);

·f0~f7和F0~F7(FPA寄存器);

·s0~s31和S0~S31(VFP单精度寄存器);

·d0~d15和D0~D15(VFP双精度寄存器);

·p0~p15(协处理器0~15);

·c0~c15(协处理器寄存器0~15)。

内置变量

ARM汇编器所定义的内置变量如表所示。值得注意的是内置变量的设置不能用SETA、SETL或SETS等指示符来设置,只能用表达式或条件来设置。例如:

IF  {ARCHITECTURE} = “4T”

 

 

子程序调用规则

ARM9处理器的子程序调用指令有别于Intel X86的子程序调用指令CALL,此小节再对这一特点进行归纳。另外,本小节还将介绍C或C++语言编写的程序与汇编语言编写的程序之间相互调用的规则。

汇编子程序调用

程序设计时,通常会把完成某个特定功能的一段程序代码编写成子程序,在需要的地方进行调用。ARM汇编程序中,使用下面语句调用子程序。

    BL  next

    其中,next为子程序中的第一条指令代码的标号。

    任何一个子程序进入前,处理器需要保存主程序中的现场,即需要保存当前工作寄存器(注意:当采用了子程序嵌套调用时,应该保存LR寄存器)。汇编指令BL的功能是将BL指令的下一条指令地址放到LR寄存器中,作为返回地址。并将子程序的第一条指令地址赋予PC寄存器,实现程序转移,即进入子程序执行。子程序执行完后,通过把LR寄存器值赋予PC寄存器,实现返回。

C、C++语言程序中内嵌汇编

C、C++语言编写的程序要比汇编语言编写的程序易读性、移植性好,因此,在嵌入式系统开发时,编写系统程序大多还是采用C、C++语言。但是在某些场合有时需要采用汇编指令编写程序,以实现一些高级语言没有的功能,并提高执行效率。ARM汇编工具支持在C、C++语言程序中嵌入汇编编写的程序段,其语法格式如下:

    __asm{“指令[;指令]”}

 

汇编程序序实例--系统引导程序

掌握汇编语言程序设计对于嵌入式系统的设计者来说是非常必要的。大多数嵌入式系统加电后运行的第一段程序(在此称为系统引导程序,有时也称启动代码),往往是采用汇编语言编写的。

    系统引导程序是依赖于具体硬件环境的,除了依赖于CPU的体系结构外,还依赖于具体的板级硬件配置。

·关看门狗定时器,关中断。

·有时需要设置系统CPU的速度和时钟频率。

·设置好堆栈。系统堆栈初始化取决于用户使用哪些异常,以及系统需要处理哪些错误类型。

  一般情况下,管理模式堆栈必须设置;若使用了IRQ中断,则IRQ中断堆栈必须设置。

·如果系统应用程序是运行在用户模式下,可在系统引导程序中将系统改为用户模式并初始

  化用户堆栈指针。

·若系统使用了DRAM或其他外设,需要设置相关寄存器,以确定其刷新频率、总线宽度

  等信息。

·初始化所需的存储器空间。将系统需要读写的数据和变量从ROM拷贝到RAM里;要求快

  速响应的程序,如中断程序,也需要在RAM中运行;对Flash的擦除和写入操作也一定

  要在RAM里运行。

·跳转到C程序的入口点。

系统上电或复位后,首先执行的是“b reset”指令,系统跳转到标号为reset处接着执行,在完成了关中断、使能管理模式、初始化各模式的堆栈等功能后,执行指令“b main”跳转到C语言的主函数处执行。

 


推荐阅读
  • C语言是计算机科学和编程领域的基石,许多初学者在学习过程中会感到困惑。本文将详细介绍C语言的基本概念、关键语法和实用示例,帮助你快速上手C语言。 ... [详细]
  • 本文介绍了如何在Linux和Windows环境中使用C语言中的beep函数来生成不同频率的声音,并提供了详细的代码示例和解释。 ... [详细]
  • 【妙】bug称它为数组越界的妙用
    1、聊一聊首先跟大家推荐一首非常温柔的歌曲,跑步的常听。本文主要把自己对C语言中柔性数组、零数组等等的理解分享给大家,并聊聊如何构建一种统一化的学习思想 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 单片机入门指南:基础理论与实践
    本文介绍了单片机的基础知识及其应用。单片机是一种将微处理器(类似于CPU)、存储器(类似硬盘和内存)以及多种输入输出接口集成在一块硅片上的微型计算机系统。通过详细解析其内部结构和功能,帮助初学者快速掌握单片机的基本原理和实际操作方法。 ... [详细]
  • 深入解析C语言中结构体的内存对齐机制及其优化方法
    为了提高CPU访问效率,C语言中的结构体成员在内存中遵循特定的对齐规则。本文详细解析了这些对齐机制,并探讨了如何通过合理的布局和编译器选项来优化结构体的内存使用,从而提升程序性能。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 线程能否先以安全方式获取对象,再进行非安全发布? ... [详细]
  • iOS 不定参数 详解 ... [详细]
  • 兆芯X86 CPU架构的演进与现状(国产CPU系列)
    本文详细介绍了兆芯X86 CPU架构的发展历程,从公司成立背景到关键技术授权,再到具体芯片架构的演进,全面解析了兆芯在国产CPU领域的贡献与挑战。 ... [详细]
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • C语言中全部可用的数学函数有哪些?2.longlabs(longn);求长整型数的绝对值。3.doublefabs(doublex);求实数的绝对值。4.doublefloor(d ... [详细]
  • 本文是Java并发编程系列的开篇之作,将详细解析Java 1.5及以上版本中提供的并发工具。文章假设读者已经具备同步和易失性关键字的基本知识,重点介绍信号量机制的内部工作原理及其在实际开发中的应用。 ... [详细]
  • 你的问题在于:1. 代码格式混乱,缺乏必要的缩进,导致可读性极低;2. 使用 `strlen()` 和 `malloc()` 函数时,必须包含相应的头文件;3. `write()` 函数的返回值处理不当,建议检查并处理其返回值以确保程序的健壮性。此外,建议在编写代码时遵循良好的编程规范,增加代码的可维护性和可读性。 ... [详细]
  • 本文探讨了如何通过编程手段在Linux系统中禁用硬件预取功能。基于Intel® Core™微架构的应用性能优化需求,文章详细介绍了相关配置方法和代码实现,旨在帮助开发人员有效控制硬件预取行为,提升应用程序的运行效率。 ... [详细]
author-avatar
行侠客人生_983
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有