六、实验参考程序
;ARM 微控制器工作模式实验的参考程序如下: ;定义堆栈的大小
USR_STACK_LEGTH EQU 64 SVC_STACK_LEGTH EQU 0 FIQ_STACK_LEGTH EQU 16 IRQ_STACK_LEGTH EQU 64 ABT_STACK_LEGTH EQU 0 UND_STACK_LEGTH EQU 0
AREA Example3,CODE,READONLY ;声明代码段Example3 ENTRY ;标识程序入口 CODE32 ;声明32 位ARM 指令
START MOV R0,#0
MOV R1,#1 MOV R2,#2 MOV R3,#3 MOV R4,#4 MOV R5,#5 MOV R6,#6 MOV R7,#7 MOV R8,#8 MOV R9,#9
MOV R10,#10 MOV R11,#11 MOV R12,#12
BL InitStack
;初始化各模式下的堆栈指针
;打开IRQ 中断(将CPSR 寄存器的1 位清零)
MRS R0,CPSR BIC R0,R0,#0X80 MSR CPSR_cxsf,R0
;切换到用户模式 MSR CPSR_c,#0xd0 MRS R0,CPSR
;切换到管理模式 MSR CPSR_c,#0xd0 MRS R0,CPSR
HALT B HALT
;R0 <-CPSR ;CPSR <-R0
;名称:InitStack
;功能:堆栈初始化,即初始化各模式下下的堆栈指针。 ;入口参数:无 ;出口参数:无
;说明:在特权模式下调用此子程序,比如复位后的管理模式 InitStack
MOV R0,LR ;设置管理模式堆栈
MSR CPSR_c,#0xd3 LDR SP,StackSvc ;设置中断模式堆栈 MSR CPSR_c,#0xd2 LDR SP,StackIrq
;设置快速中断模式堆栈 MSR CPSR_c,#0xd1 LDR SP,StackFiq
;设置中止模式堆栈 MSR CPSR_c,#0xd7 LDR SP,StackAbt
;设置为定义模式堆栈 MSR CPSR_c,#0xdb LDR SP,StackUnd ;设置系统模式堆栈 MSR CPSR_c,#0xdf LDR SP,StackUsr MOV PC,R0
StackUsr DCD UsrStackSpace+(USR_STACK_LEGTH-1)*4 StackSvc DCD SvcStackSpace+(SVC_STACK_LEGTH-1)*4 StackIrq DCD IrqStackSpace+(IRQ_STACK_LEGTH-1)*4 StackFiq DCD FiqStackSpace+(FIQ_STACK_LEGTH-1)*4 StackAbt DCD AbtStackSpace+(ABT_STACK_LEGTH-1)*4 StackUnd DCD UndStackSpace+(UND_STACK_LEGTH-1)*4
;分配堆栈空间
AREA MyStacks, DATA, NOINIT, ALIGN=2
UsrStackSpace SPACE USR_STACK_LEGTH*4 SvcStackSpace SPACE SVC_STACK_LEGTH*4 IrqStackSpace SPACE IRQ_STACK_LEGTH*4
FiqStackSpace SPACE FIQ_STACK_LEGTH*4 AbtStackSpace SPACE ABT_STACK_LEGTH*4
;R0 <-LR ,因为各种模式下R0 是相同的
UndStackSpace SPACE UND_STACK_LEGTH*4
七、练习题
参考本节实验例子,把其中系统模式程序更改为用户模式程序,编译调试,观察运行结果,检查是否正确。如果有错误,分析其原因。
提示:不能从用户模式直接切换到其他模式,可以先使用SWI 指令切换到管理模式。
实验五、C语言程序和C调用汇编程序实验
一、实验目的
了解ARM7 启动过程,学会使用ADS 编写简单的C 语言程序 掌握C 语言调用汇编程序,并进行调试的方法
二、实验设备
硬件:嵌入式实验平台一套、仿真器一个、PC机一台。
软件:Windows 98/2000/NT/XP 操作系统、仿真器驱动程序、ADS开发软件一套。 三、实验内容
在C 语言程序中调用汇编子程序,实现计算1+2+3+?+(N-1)+N 的值(N>0)的加法运算。汇编子程序实现两个数的加法运算,其原型为:uint32 Add(uint32 x,uint32 y),其中uint32 已定义为unsigned int 。
四、实验原理
(1)作为最基本的编程语言之一,汇编语言虽然应用的范围不算很广,但重要性却勿 庸置疑,因为它能够完成许多其它语言所无法完成的功能。就拿 Linux 内核来讲,虽然绝 大部分代码是用 C 语言编写的,但仍然不可避免地在某些关键地方使用了汇编代码,其中 主要是在 Linux 的启动部分。由于这部分代码与硬件的关系非常密切,即使是 C 语言也会有些力不从心,而汇编语言则能够很好扬长避短,最大限度地发挥硬件的性能。大多数情况下 Linux 程序员不需要使用汇编语言,因为即便是硬件驱动这样的底层程序在 Linux 操作系统中也可以用完全用 C 语言来实现,再加上 GCC 这一优秀的编译器目前已经能够对最终生成的代码进行很好的优化,的确有足够的理由让我们可以暂时将汇编语言抛在一边了。但实现情况是 Linux 程序员有时还是需要使用汇编,或者不得不使用汇编,理由很简单:精简、高效和 libc 无关性。假设要移植 Linux 到某一特定的嵌入式硬件环境下,首先必然面临如何减少系统大小、提高执行效率等问题,此时或许只有汇编语言能帮上忙了。
汇编语言直接同计算机的底层软件甚至硬件进行交互,它具有如下一些优点: 能够直接访问与硬件相关的存储器或 I/O 端口;
能够不受编译器的限制,对生成的二进制代码进行完全的控制;
能够对关键代码进行更准确的控制,避免因线程共同访问或者硬件设备共享引起的死锁;
能够根据特定的应用对代码做最佳的优化,提高运行速度,能够最大限度地发挥硬件的功能。
同时还应该认识到,汇编语言是一种层次非常低的语言,它仅仅高于直接手工编写二进制的机器指令码,因此不可避免地存在一些缺点:
编写的代码非常难懂,不好维护;
很容易产生 bug,难于调试;
只能针对特定的体系结构和处理器进行优化;
开发效率很低,时间长且单调。
(2)混合编程的一般方法有三种:一是对C 程序编译后形成的汇编程序进行手工的修改与优化。二是直接在C 语言程序中嵌入汇编语句。三是分别编写C 程序和汇编程序,再独立编译成目标代码模块,再进行链接。
第一种编程方式要求对汇编与C 语言都极其熟悉,并且这样的编程方式对程序的可读
性和扩展性的负面影响比较大。
第二种方法适用于语句执行频率非常高,并且C 编程与汇编编程效率差异较大的情况,例如进入中断的通用中断子程序等。
第三种方式是混合编程最常用的方式之一。在这种方式下,C 程序与汇编程序均可使用另一方定义的函数与变量。变量定义是混合编程的基本问题。C 程序与汇编程序定义的变量相互之间可以进行访问。在汇编程序中定义时,需要在变量前加下划线“_”,然后再用.global定义为全局变量。在C 程序中则需要说明为extern变量。
五、实验操作步骤
1.启动ADS1.2,使用ARM Execuatable Image 工程模板新建一个工程; 2.添加两个组INC 和SRC;
3.将INC 文件夹下所有文件添加到组INC 中; 4.将SRC 文件夹下所有文件添加到组SRC 中;
5.建立源文件test4.C 和ADD.S,编写实验程序,添加到工程中; 6.编译链接选项的设置同前面实验;
7.编译链接工程,点击Debug 按钮,启动AXD 进行调试;
8.在test4.C 的“sum=Add(sum,i)”处设置断点,然后全速运行程序;
9.程序在断点处停止。单步运行程序,判断程序是否跳转到Add.S 汇编程序中运行; 10.选择【Processor Views】->【Variables】打开变量观察窗口,观察全局变量sum 的值,单步/全速运行程序,判断程序的运行结果是否正确。
11. 理解并掌握本实验原理及程序,完成练习题
六、实验参考程序
C 语言实验的参考程序见程序清单1。
//-------------------------------------------------------------- //程序清单1 C 语言实验参考程序 #include \ #include \ #include \ #include \ #define uint8 unsigned char #define uint32 unsigned int
#define N 100
extern uint32 Add(uint32 x,uint32 y); uint32 sum; void Main(void) { uint32 i; sum=0;
for(i=0;i<=N;i++)
{
sum=Add(sum,i);