COUNT EQU 100 则COUNT就表示常数100. (2)符号表示指令助记符.例:
MOV EQU MOV则MOVE就表示指令MOV
(3)符号表示寄存器,例:COUNT EQU CX则COUNT就代表寄存器CX.
(4)符号作为段名,例: DATA SEGMENT - - - - - - - DATA ENDS
DATA 是段名,引用DATA表示段地址. (5)符号作为过程名,例:SUBR PROC NEAR/- - - - - - - SUB ENDP
SUB为过程名,它同样具有段、偏移量和距离类型三个属性 .(6)符号作为宏指令名
宏定义格式宏指令名 MACRO [形式参数] - - - - - - - ENDM 宏调用格式: 宏指令名 [实参数]
每当引用宏指令名则汇编程序对宏调用作宏展开,就是用宏定义体取代源程序中的宏指令并用实参数取代宏定义中的形式参数
36
汇编语言是各种计算机语言中与硬件关系最为密切、最直接的语言,是时空效率最高的语言,它能够利用计算机所有硬件特性并能直接控制硬件,所以在计算机应用系统设计和过程控制中是必不可少的.目前教学中采用8086/8088汇编语言系统组织教学仍是最佳选择.其中子程序技术是一种解决重复性问题的重要设计方法,采用子程序结构可以简化源程序书写、提高程序存储效率、减少出错率、增加程序的易读性和可维护性,并且有利用子程序资源的组织和使用.设计子程序时,除了必需要考虑的程序调用、返回和完成特定功能的指令序列外,还必须注意解决子程序设计中带有的共性的一些问题,即:现场保护、参数传递、子程序的嵌套与递归调用、编写子程序说明文档等.
1 现场保护
现场保护的目的是调用子程序之后,能够返回主程序继续执行.因此要对子程序中用到的寄存器,堆栈进行必要的保护.
1 1 寄存器保护因为汇编语言程序中的主要操作对象是CPU中的各寄存器,对那些主程序和子程序中都会用到的一些寄存器要在子程序使用之前进行保护.寄存器保护最好是在子程序中进行,并且在子程序中进行恢复,这样子程序显得更完整.其方法是使用堆栈,由于指令系统中制定了规范的进栈指令PUSH和出栈指令POP,并会自动修改堆栈指针,只要在程序设计中注意8086/8088的堆栈是否按 后进先出 的原则组织的.
1 2 堆栈保护子程序是利用调用(CALL)指令和返回(RET)指令来实现正确的调用和返回的.因为CALL命令执行时压入堆栈
37
的断点地址就是供子程序返回主程序时的地址,编程时一定要注意子程序的类型属性,即是段内调用还是段间调用.段内调用和返回为NEAR属性,段间调 王艳玲,等谈谈汇编语言中子程序的设计方法37用和返回为FAR属性.8086/8088的汇编程序用子程序定义PROC的类型属性来确定CALL和RET指令的属性.如果所定义的子程序是FAR属性,那么对它的调用和返回一定都是FAR属性;如果所定义的子程序是NEAR属性,那么对它的调用和返回也一定是NEAR属性.这样用户只是在定义子程序时考虑它的属性,而CALL和RET指令的属性就可以由汇编程序来确定了.另外,进入子程序后再使用堆栈时也必须保证压入和弹出字节数一致,如果在这里堆栈存取出错,必然会导致返回地址的错误.
2 参数传递
主程序在调用子程序时,经常要向子程序传递一些参数或控制信息,子程序执行后,也常需要把运行的结果返回调用程序.这种信息传递称为参数传递,其常用的方法有寄存器传递、内存固定单元传递、堆栈传递.
2 1 寄存器传递由主程序将要传递的参数装入事先约定的寄存器中,转入子程序后再取出进行处理,这种方法受CPU内部寄存器数量限制,因此只适于传递少量参数的场合,如一些常见的软件延时子程序,均是利用某寄存器传递循环计数器初值.
2 2 通过内存固定单元的传递此方法适于大量传递参数时使用,它是在内存中开辟特定的一片区域用于传递参数.主程序和子程序都
38
按事先约定在指定的存储单元中进行数据交换,这种方法要占用一定数量的存储单元.不足之处是信息易被修改,不利于模块化设计.
2 3 通过堆栈实现参数传递这种方法是先在主程序中把参数和参数地址压入堆栈,在子程序中取出使用,由于堆栈操作不占用寄存器,并且堆栈单元使用后可自动释放,反复使用,便于实现数据隔离和模块化设计.使用这种方法时,当子程序返回后,这些参数就不在有用了,应当丢弃.这时可以利用带立即数的返回指令修改指针,使其指向参数入栈以前的值.
3 子程序嵌套与递归调用
汇编语言中子程序的嵌套只要堆栈空间允许,一般不受嵌套层次限制.嵌套子程序设计中,应注意寄存器的保护和恢复,避免各层子程序之间寄存器冲突.递归子程序的设计必须保证每次调用都不破坏以前调用时所用的参数和中间结果.为保证每次调用的正确,一般把每次调用的参数、有关寄存器的内容以及中间结果进栈保存.
4 子程序说明文档
一般来说子程序是要反复使用或提供用户使用,所以编写子程序时应尽量采用较好的算法,使子程序运行速度比较快,又节省内存.同时还应最大限度地满足今后程序维护与使用的需要.在设计子程序的同时就应当建立相应的说明文档,清楚地描述子程序的功能和调用方法.通常子程序说明文档应包括:子程序名称、子程序功能、入口参数、出口参数、工作寄存器、工作单元及最后修改日期等
ARM中C和汇编混合编程及示例
39
在嵌入式系统开发中,目前使用的主要编程语言是C和汇编,C++已经有相应的编译器,但是现在使用还是比较少的。在稍大规模的嵌入式软件中,例如含 有OS,大部分的代码都是用C 编写的,主要是因为C 语言的结构比较好,便于人的理解,而且有大量的支持库。尽管如此,很多地方还是要用到汇编语言,例如开机时硬件系统的初始化,包括CPU 状态的设定,中断的使能,主频的设定,以及RAM的控制参数及初始化,一些中断处理方面也可能涉及汇编。另外一个使用汇编的地方就是一些对性能非常敏感的 代码块,这是不能依靠C编译器的生成代码,而要手工编写汇编,达到优化的目的。而且,汇编语言是和CPU 的指令集紧密相连的,作为涉及底层的嵌入式系统开发,熟练对应
汇编语言的使用也是必须的。
单纯的C 或者汇编编程请参考相关的书籍或者手册,这里主要讨论C 和汇编的混合编程,包括相互之间的函数调用。下面分四种情况来进行讨论,暂不涉及C++。
1. 在C 语言中内嵌汇编
在C 中内嵌的汇编指令包含大部分的ARM 和Thumb 指令,不过其使用与汇编文件中的指令有些不同,存在一些限制,主要有下面几个方面:
不能直接向PC寄存器赋值,程序跳转要使用B或者BL指令 在使用物理寄存器时,不要使用过于复杂的C 表达式,避免物理寄存器冲突
40