内容发布更新时间 : 2024/11/16 5:53:51星期一 下面是文章的全部内容请认真阅读。
21
Stop B Stop LTORG Src DCD 1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF,0x10
DCD 1,2,3,4,5,6,7,8,9,0xA,0xB,0xC,0xD,0xE,0xF,0x10 Dst DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DCD 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 END
6.将一个存放在【R1:R0】中的64位数据(其中R1中存放高32位)的高位和低位对称换位,如第0位与第63位调换,第1位与第62位调换,第2位与第61位调换,。。。。第31位与第32位调换。
答:解:程序设计思路:对于单个32位寄存器的对称换位操作,我们可以采用移位操作的方法,通过依次从低位取出目标寄存器的各个位,再将其放置到目标寄存器的最低位,然后通过移位操作,送入相应位。对于【R1:R0】到【R3:R2】的64位对称换位操作,我们可以采用R1-》R2和R0-》R3的两个32位的换位操作来完成。
在ARM集成开发环境下编程:
/*---------------------------------------------------------------------------------------- ********寄存器使用说明************************ ***R1,R0:源数据 ***R3,R2:目标数据
***R4:计数器,初值为32,递减至0
*---------------------------------------------------------------------------------------------*/ AREA Bit_Exch,CODE,READONLY ;声明代码段Bit_Exch ENTRY ;标识程序入口
CODE32 ;声明32位ARM指令
START LDR R0,=0x55555555 ;输入源数据
MOV R3,#0 ;目标数据 MOV R5,#0 ;数据临时缓冲区
MOV R4,#32 ;计数器 Bitex_H32 AND R5,R0,#1 ;取出源数据的最低位送R5
ORR R3,R5,R3,LSL #1 ;将目标数据左移一位,并将取出的数据
;送入其最低位
MOV R0,R0,LSR #1 ;源数据右移一位 SUBS R4,R4,#1 ;递减计数 BNE Bitex_L
LDR R1,=0x55555555 ;输入源数据
21
22
MOV MOV MOV
Bitex_L32 AND
ORR
R2,#0 R5,#0 R4,#32 ;目标数据
;数据临时缓冲区 ;计数器
;取出源数据的最低位送R5
;将目标数据左移一位,并将取出的数据 ;送入其最低位 ;源数据右移一位 ;递减计数
R5,R1,#1 R2,R5,R2,LSL #1
MOV R1,R1,LSR #1 SUBS R4,R4,#1 BNE Bitex_L Stop B Stop END
7.内存数据区定义如下: DataZone
DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45 DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45 DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45 DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45 DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45 DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45 DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45 DCD 0x12345678, 0x87654321, 0xABCDEF12, 0xCDEFAB45
以上可以看做一个8*4矩阵,请用ARM汇编语言在ARM集成开发环境下设计程序,实现对矩阵的转置操作。
如果改为在GNU ARM环境下编程,程序应如何修改。
答:解:使用R0指向源数据区,R1指向目标数据区。从源数据区中按列取数据(每次取8个),然后顺序存入目标数据区。 在ARM集成开发环境下编程:
/*---------------------------------------------------------------------------------------- ********寄存器使用说明************************ ***R0:源数据 ***R1:目标数据
***R2:行计数器,初值为8,递减至0 ***R3:列计数器,初值为4,递减至0
*---------------------------------------------------------------------------------------------*/ AREA Bit_Exch,CODE,READONLY ;声明代码段Bit_Exch ENTRY ;标识程序入口
CODE32 ;声明32位ARM指令
START LDR R0,=Src
22
23
COL ROW
LDR
MOV MOV LDR STR SUBS BNE
SUBS BNE
R1,=Dst R3,#4 R2,#8 R4,[R0],#16 R4,[R1],#4 R2,R2,#1 ROW R3,R3,#1 COL
;按列取数据 ;按行存数据 ;行计数递减
;列计数递减
Stop
B END
Stop
第8章 ARM汇编语言与嵌入式C混合编程
1.严格按照嵌入式C语言的编程规范,写一个C语言程序,实现将一个二维数组内的数据行和列进行排序。 答:略
2.嵌入式C程序设计中常用的移位操作有哪几种,请说明每种运算所对应的ARM指令实现。 答:移位操作分为左移操作与右移操作
左移运算符―<<‖实现将―<<‖左边的操作数的各个二进制位向左移动―<<‖右边操作数所指定的位数,高位丢弃,低位补0。其值相当于乘以:2―左移位数‖次方。
右移运算符―>>‖实现将―>>‖左边的操作数的各个二进制位向右移动―<<‖右边操作数所指定的位数。
? 对于空位的补齐方式,无符号数与有符号数是有区别的。
? 对无符号数进行右移时,低位丢弃,高位用0补齐,其值相当于除以:2―右移位数‖
次方
? 对有符号数进行右移时,根据处理器的不同选择逻辑右移或算术右移
3.volatile限制符在程序中起到什么作用。请举例说明。
答:volatile的本意为 ―暂态的‖或.―易变的‖,该说明符起到抑制编译器优化的作用。
如果在声明时用―volatile‖关键进行修饰,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供特殊地址的稳定访问。 ? 例:硬件端口寄存器读取 ? Char x=0,y=0,z=0;
? x=ReadChar(0x54000000);//读端口 ? y=x;
? x=ReadChar(0x54000000);//再读端口 ? z=x;
23
24
???????? 以上代码可能被编译器优化为 Char x=0,y=0,z=0;
x=ReadChar(0x54000000);//读端口 y=x; z=x;
为了确保x的值从真实端口获取,声明时应该为 Volatile char x; Char y,z;
4.请分析下列程序代码的执行结果。 #include
答:程序输出结果为:****p4=4081
5.分析宏定义#define POWER(x) x*x 是否合理,举例说明。如果不合理,应如何更改? 答:#define POWER(x) x*x 不合理;对于带参数的宏,其参数应该用括号括起来。 例:如果按照下边方式使用该宏
POWER(2+3) 则宏展开后为 2+3*2+3
该宏应修改为:#define POWER(x) (x)*(x)
6.条件编译在程序设计中有哪些用途?
答:条件编译包括了6条预处理指令#ifdef, #ifndef. ##if, #elif, #else, #endif.。条件编译的功能在于对源程序中的一部分内容只有满足某种条件的情况下才进行编译。
7.何为可重入函数?如果使程序具有可重入性,在程序设计中应该注意哪些问题?
答:如果某个函数可以被多个任务并发使用,而不会造成数据错误,我们就说这个函数具有可重入性(reentrant) 。
可重入函数可以使用局部变量,也可以使用全局变量。
如果使用全局变量,则应通过关中断、信号量(即P、V操作)等手段对其加以保护,若不加以保护,则此函数就不具有可重入性,即当多个进程调用此函数时,很有可能使得此全局变量变为不可知状态。
8.现有模块module_1, module_2, module_3, 要求在模块module_1中提供可供模块module_2, module_3使用的int型变量xx,请写出模块化程序设计框架。 答:首先在module_1的.c文件中定义 int xx; /*module_1.c*/
24
25
int xx=0;
然后在module_1的.h 文件中声明xx为外部变量 /*module_1.h*/ extern int xx;
接下来在module_2源文件中包括module_1的 .h 文件 /*module_2.c*/
#include \
在module_3源文件中包括module_1的 .h 文件 /*module_3.c*/
#include \
这样在module_2, module_3中就可以使用module_1中提供的int型变量xx了。
9.ATPCS 与 AAPCS的全称是是什么,它们有什么差别?掌握子程序调用过程中寄存器的使用规则,数据栈的使用规则及参数的传递规则,在具体的函数中能够熟练应用。
答:过程调用标准ATPCS(ARM-Thumb Produce Call Standard)规定了子程序间相互调用的基本规则, ATPCS规定子程序调用过程中寄存器的使用规则、数据栈的使用规则及参数的传递规则。
2007年,ARM公司推出了新的过程调用标准AAPCS(ARM Architecture Produce Call Standard),它只是改进了原有的ATPCS的二进制代码的兼容性。
10.内嵌式汇编有哪些局限性?编写一段代码采用C语言嵌入式汇编程序,在汇编程序中实现字符串的拷贝操作。 答:内嵌汇编的局限性
(1)操作数
? ARM开发工具编译环境下内嵌汇编语言,指令操作数可以是寄存器、常量或C语
言表达式。可以是char、short或int类型,而且是作为无符号数进行操作。 ? 当表达式过于复杂时需要使用较多的物理寄存器,有可能产生冲突。
? GNU ARM编译环境下内嵌汇编语言ARM开发工具稍有差别,不能直接引用C语
言中的变量。 (2)物理寄存器
不要直接向程序计数器PC赋值,程序的跳转只能通过B或BL指令实现。
一般将寄存器R0~R3、R12及R14用于子程序调用存放中间结果,因此在内嵌汇编指令中,一般不要将这些寄存器同时指定为指令中的物理寄存器。
在内嵌的汇编指令中使用物理寄存器时,如果有C语言变量使用了该物理寄存器,则编译器将在合适的时候保存并恢复该变量的值。需要注意的是,当寄存器SP、SL、FP以及SB用作特定的用途时,编译器不能恢复这些寄存器的值。
通常在内嵌汇编指令中不要指定物理寄存器,因为有可能会影响编译器分配寄存器,进而可能影响代码的效率。 (3)标号、常量及指令展开
? C语言程序中的标号可以被内嵌的汇编指令所使用。但是只有B指令可以使用C语
言程序中的标号,BL指令不能使用C语言程序中的标号。 (4)内存单元的分配
? 内嵌汇编器不支持汇编语言中用于内存分配的伪操作。所用的内存单元的分配都是
通过C语言程序完成的,分配的内存单元通过变量以供内嵌的汇编器使用。
25