《嵌入式软件开发试验报告》
院 (系): 计算机科学与工程学院
专 业: 计算机科学与技术
班 级: 080602
学 生: 马珂
学 号: 080602128
汇编与 C 语言的相互调用
一。实验目的
阅读Embest Arm EduKit II 启动代码,观察处理器启动过程;
学会使用 Embest IDE 辅助信息窗口来分析判断调试过程和结果;
二.实验设备
硬件:PC 机。
软件:Embest IDE Pro 20## 集成开发环境,Windows 98/2000/NT/XP。
三。实验内容
使用汇编完成一个随机数产生函数,通过 C 语言调用该函数,产生一系列随机数,存放到数组里面。
四。实验原理
1. ARM过程调用ATPCS (ARM ),ATPCS 是一系列用于规定应用程序之间相互调用的基本规则,这此规则包括: ①支持数据栈限制检查; ②支持只读段位置无关(ROPI); ③支持可读/写段位置无关(RWPI); ④支持ARM 程序和Thumb 程序的混合使用; ⑤处理浮点运算。 使用以上规定的ATPCS 规则时,应用程序必须遵守如下:
①程序编写遵守ATPCS②变量传递以中间寄存器和数据栈完成;③汇编器使用-apcs 开关选项。
程序只要遵守ATPCS 相应规则,就可以使用不同的源代码编写程序。程序间的相互调用最主要的是解决参数传递问题。应用程序之间使用中间寄存器及数据栈来传递参数,其中,第一个到第四个参数使用 R0-R3,多于四个参数的使用数据栈进行传递。这样,接收参数的应用程序必须知道参数的个数 但是,在应用程序被调用时,一般无从知道所传递参数的个数。不同语言编写的应用程序在调用时可以自定义参数传递的约定,使用具有一定意义的形式来传递,可以很好地解决参数个数的问题。常用的方法是把第一个或最后一个参数作为参数个数 (包括个数本身)传递给应用程序。
ATPCS 中寄存器的对应关系
2. main() 函数与__gccmain()
当应用程序中包含了main()函数,将会引起对 C 运行时库的初始化。该初始化是通过
函数__gccmain()实现的,即在 main()函数入口处,编译器会首先调用__gccmain()函数,然后才是执行编写的代码。__gccmain()函数在gcc 的标准库里面实现。当应用程序中没有包含main()函数,将不会引起对 C 运行时库的初始化。这时,C 运行时库的很多功能在应用程序中是不能使用的。我们使用 main 函数作为应用程序的主函数,可以在源代码中加入一个空的__gccmain()函数(用C 语言或者汇编语言均可)。
五.实验操作步骤
1. 考本章其他实验,创建新的工程,工程名为:explasm;
2. 按照参考程序,重新编写源代码文件并分别保存为 randtest.c,init.s,random.s和 ldscript,并把它们加入工程里面;
3. 参照其他基础实验操作,按照编译 → 汇编器配置→链接器配置→调试器配置设置新工程,并编译、链接工程,如图 3-14 所示;
4. 下载调试文件,打开 memory/register/watch/variable/call stack 窗口,单步执行程序。通过以上窗口,跟踪程序运行,观察分析运行结果,通过实验学会使 用 Embest IDE 进行应用程序的开发与调试;
六。实验源代码
1. randtest.c参考源代码:
/***********************
* File: randtest.c
* Author: embest
* Desc: Random number generator demo program
* Calls assembler function 'randomnumber' defined in random.s
* History: y.y.wang 2005.2.24
**********************/
/*------------------------- extern function ----------------*/
extern unsigned int randomnumber( void );
/***********************
* name: Main
* func: c code entry
* para: none
* ret: none
* modify:
* comment:
***********************/
int Main()
{
unsigned int i,nTemp;
unsigned int unRandom[10];
for( i = 0; i < 10; i++ )
{
nTemp = randomnumber();
unRandom[i] = nTemp;
}
return(0);
}
2. init.s 参考源代码:
#********************
# File: init.s *
# Author: embest *
# Desc: C start up codes.Configure memory, Initialize ISR ,stacks, *
# initialize C-variables *
# Fill zeros into zero-initialized C-variables *
# History: *
#*********************
/*----------------- global symbol define --------------------*/
.global _start
.global __gccmain
/*------------------- code ---------------------*/
.text
_start:
# Set interrupt / exception vectors
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:
ldr sp, =0x00002000
#/*************************
# Branch on C code Main function (with interworking) *
# Branch must be performed by an interworking call as either an ARM or Thumb *
# main C function must be supported. This makes the code not position- *
# independant. A Branch with link would generate errors *
#/**************************
.extern Main
ldr r0, = Main
mov lr, pc
bx r0
#/*************************
# Loop for ever *
# End of application. Normally, never occur. *
# Could jump on Software Reset ( B 0x0 ). *
#/************************
End:
b End
__gccmain:
mov pc, lr
.end
实验二.C语言程序实验
一.实验目的
1..学会使用 Embest IDE 编写简单的 C 语言程序并进行调试;
2.学会编写和使用命令脚本文件;
3.掌握通过 memory/register/watch/variable 窗口分析判断运行结果。
二.实验设备
硬件:PC 机。
软件:Embest IDE Pro 20## 集成开发环境,Windows 98/2000/NT/XP。
三.实验内容
利用命令脚本初始化栈指针,并使用 c 语言完成延时函数。
四.实验原理
1. 命令脚本文件
用户在集成环境与目标板连接时、软件调试过程中以及复位目标板后,有时需要完成环境自动完成一些特定的功能,比如复位目标板、清除看门狗、屏蔽中断寄存器、存储区映射等,这些特定的功能可以通过执行一组命令序列完成,保存一组命令序列的文本文件称为命令脚本文件(EmbestIDE 使用.cs 作为命令脚本文件扩展名)。 命令脚本文件中各行以半角格式的 “;”号开始作为注释内容,分号前是一条命令。凡是可以在调试命令窗口使用的命令,都可以在脚本文件中使用,包括执行脚本文件命令 SCRIPT”。调试命令及详细参考请参照Embest IDE 所带的电子文档 UserGuide.chm中“调试命令列表”一节。命令脚本文件执行时按照命令在脚本文件中排列的先后顺序自动连续地执行。
2. 命令脚本文件的执行方法有两种执行方法: 在命令输入窗口,输入:script 脚本文件名,在项目设置对话框调试属性页指定连接后的行为(Action after connected), 此时,可选择命令脚本文件(Command script),并在编辑框中设定命令脚本文件名,则在 IDE 与目标系统连接后首先自动执行指定的脚本文件。
3. 常用命令介绍
1) GO –执行程序
语法: go
说明: 从当前 PC 执行目标程序。
参数: 无
选项: 无
2) MEMWRITE –存储区写
语法: memwrite [ –e] 地址 数值
说明: 向存储区指定地址写入数值。
参数: 地址 要写入数值的存储区地址
选项: -e 大印第安方式写入
3) REFRESH –刷新窗口
语法: refresh
说明: 刷新所有窗口命令,调试命令执行后,各窗口相关内容并不更新,用 户可以调用本命令刷新界面各窗口保持与实际内容一致。
参数: 无
选项: 无
4) REGWRITE – 寄存器写
语法: regwrite 寄存器名称 寄存器值
说明: 写寄存器
参数: 寄存器名称 待写入数值的寄存器名称
5) RESET – 复位目标设备
语法: reset
说明: 复位目标设备
参数: 无
选项: 无
6) STOP –停止执行程序
语法: stop
说明: 停止目标板运行
参数: 无
选项: 无
五 实验操作步骤
1 参考前面实验创建新的工程(工程名为 C1);
2 按照参考程序,编写源文件 C1.c 和 C1.cs,并把它们加入工程里面。C1.cs 加在
工程根目录即可。
3 参考前面例子进行标准的设置,其中需要注意的是,在调试 Debug 对话框设置的时
候,增加连接后自动执行脚本文件:
4 参考前面实验步骤进行编译;
5 下载,打开 Memory/Register/Watch/Variable 窗口,单步执行,通过memory/register/watch/variable 窗口分析判断结果,在watch 框中输入要观
察变量 I 和变量J 的值,并记录下来。特别注意在variable 窗口观察变量I 的变化
并记录下来;
6 结合实验内容和相关资料,观察程序运行,通过实验;
7 理解和掌握实验后,完成实验练习题。
六 实验源代码
1. c1.c参考源代码:
/********************************
* File: c1.c
* Author: embest
* Desc: c language example 1
* History:
******************************/
/*--------------- function declare ---------------------*/
void delay(int nTime);
/*************************
* name: _start
* func: entry point
* para: none
* ret: none
* modify:
* comment:
***********************/
_start()
{
int i = 5;
for( ; ; )
{
delay(i);
}
}
/**************************
* name: delay
* func: delay some time
* para: nTime -- input
* ret: none
* modify:
* comment:
**********************/
void delay(nTime)
{
int i, j = 0;
for(i = 0; i < nTime; i++)
{
for(j = 0; j < 10; j++)
{
}
}
}
2. C1.cs 参考源代码
stop ; stop target board
regwrite sp 0x1000 ; initialize the sp , sp = 0x1000
.ARM汇编指令实验
一.实验目的
1. 初步学会使用 Embest IDE for ARM 开发环境及ARM 软件模拟器;
2. 通过实验掌握简单ARM 汇编指令的使用方法。
二.实验设备
硬件:PC 机
软件:Embest IDE Pro 20## 集成开发环境,Windows 98/2000/NT/XP。
三. 实验内容
1.熟悉开发环境的使用并使用 ldr/str,mov 等指令访问寄存器或存储单元。
2.使用 add/sub/lsl/lsr/and/orr 等指令,完成基本数学/逻辑运算。
四. 实验原理
ARM 处理器共有 37 个寄存器:
31 个通用寄存器,包括程序计数器(PC)。这些寄存器都是32 位的。
6 个状态寄存器。这些寄存器也是 32 位的,但是只是使用了其中的12位。
<1> ARM 通用寄存器(R0~R15)可分为3 类
1) 不分组寄存器 R0~R7;
在所有处理器模式下,它们每一个都访问一样的 32 位寄存器。它们是真正的通用寄存器,没有体系结构所隐含的特殊用途。
2) 分组寄存器 R8~R14
它们每一个访问的物理寄存器取决于当前的处理器模式。若要访问特定的物理寄存器而不依赖当前的处理器模式,则要使用规定的名字。
寄存器 R8~R12 各有两组物理寄存器:一组为 FIQ 模式,另一组为除了 FIQ 以外的 所有模式。
寄存器 R8~R12 没有任何指定的特殊用途。只是使用 R8~R14 来简单地处理
中断。寄存器 R13,R14 各有 6 个分组的物理寄存器。1个用于用户模式和系统模式,其它 5 个分别用于 5 种异常模式。
寄存器 R13 通常用做堆栈指针,称为 SP。每种异常模式都自己的R13。
寄存器R14 用作子程序链接寄存器,也称为 LR。
3) 程序计数器 R15
寄存器 R15 用做程序计数器 (PC)。 在本实验中,我们认为ARM 核工作在用户模式 ,R0~R15 可用。
<2>ARM 存储器格式
ARM 体系结构将存储器看作是从零地址开始的字节的线性组合。
eg: 字节0到字节3放置第一个字(WORD),字节4到字节7存储第二个字,依此类推。
ARM 体系结构可以用两种方法存储字数据,分别称为大端格式和小端格式。
1) 大端格式
这种格式中,字数据的高位字节存储在低地址中,而字数据的低位字节则存放在高地址中
2) 小端格式
这种格式中,字数据的高位字节存储在高地址中,而字数据的低位字节则存放在低地址中
<3>GNU 基础知识
Embest IDE 集成了 GNU 汇编器 as,编译器gcc,链接器ld。
1) 程序默认入口点为“_start”,代码段默认起始地址为0x8000
2) as 常用伪操作符
.equ
.equ伪操作为数字常量、基于寄存器的值和程序中的标号定义一个字符名称。
语法格式
.equ symbol, expr
(expr 为基于寄存器的地址值、程序中的标号,32 位的地址常量或者 32 位的常量。Symbol 为.equ伪操作为 expr 定义的字符名称。
.global 及.globl
.global 声明一个符号可以被其他文件引用。相当于声明了一个全局变量,.globl与.global相同。
语法格式
.global symbol
symbol 为声明的符号的名称。它是区分大小写的。
.text
.text伪操作将操作符开始的代码编译到代码段或代码段子段(subsection)
语法格式
.text {subsection}
.end
标记汇编文件的结束行,即标号后的代码不作处理。
语法格式
.end
<4>Embest IDE开发环境的相关知识
五.实验操作步骤
1. 实验A
1) 新建工程:
运行 Embest IDE 集成开发环境,选择菜单项 File → New Workspace,系统弹出
一个对话框,点击OK 按钮,将创建一个新工程,并同时创建一个与工程名相同的工作区。此时在工 作区窗口将打开该工作区和工程。
2) 建立源文件:
点击菜单项 File → New,系统弹出一个新的、没有标题的文本编辑窗,编辑输入源文件代码。编辑完后,保存文件 asm1_a.s。
3) 添加源文件:
选择 Project → Add To Project → Files 命令,或单击工程管理窗口中的相应右键菜单命令,弹出文件选择对话框,在工程目录下选择刚才建立的源文件 asm1_a.s。
4) 基本配置:
选择菜单项 Project → Settings…或快捷键 Alt+F7,弹出工程设置对话框。在工程 设置对话框中,选择 Processor 设置对话框,进行目标板所用处理器的配置。
5) 生成目标代码:
选择菜单项 Build → Build asm_a 或快捷键 F7,生成目标代码。
6) 调试设置:
选择菜单项 Project → Settings…或快捷键 Alt+F7,弹出工程设置对话框。在工程 设置对话框中,选择 Remote 设置对话框。对调试设备模块进行设置。 选择 Debug 设置对话框,进行调试模块配置。
(b)下载相关配置
注意: Symbol file 与 Download file 设置应该相同,用户可以从 Linker 页面拷贝系 统默认的输出文件配置;且该实验输入下载地址为 0x8000,即为AS 默认的代码段起始地址。由于汇编和链接选项在本实验中没有进行配置,完全使用其默认选项,所以,代码段是从 0x8000 开始的,下载地址应该与它保持一致。
7) 选择 Debug 菜单 Remote Connect 进行连接软件仿真器,执行 Download 命令下载程序,并打开寄存器窗口。打开 memory 窗口,观察地址 0x8000~0x801f 的内容,与地址 0xff0~0xfff 的内容。
8) 单步执行程序并观察和记录寄存器与 memory 的值变化。
9) 结合实验内容和相关资料,观察程序运行,通过实验加深理解ARM 指令的使用。
10)理解和掌握实验后,完成实验练习题。
2. 实验 B
1) 在工作区窗口工作区名称上击右键鼠标, “Add New Project to Workspace…”。
2) 参照实验A 及相应的实验参考程序,建立工程 asm1_b。
3) 参照实验A 的步骤完成目标代码的生成与调试。
4) 理解和掌握实验后,完成实验练习题。
六,实验源代码
实验A
/******************************************************************/
#NAME: asm1_a.s # Author: Embest
#Desc: ARM instruction examples #History: shw.He 2005.02.22 /*******************************************************************/
/* constant define */
.equ x, 45 /* x=45 */
.equ y, 64 /* y=64 */
.equ stack_top, 0x1000 /* define the top address for stack*/
.global _start
/*------------- code start ----------*/
.text
_start:
mov sp, #stack_top
mov r0, #x
str r0, [sp]
mov r0, #y
ldr r1, [sp]
add r0, r0, r1
str r0, [sp]
stop:
b stop
.end
实验B:
/******************************/
# NAME: asm1_a.s
# Author: Embest
# Desc: ARM instruction examples
#History: shw.He 2005.02.22
/****************************/
/*----------------- constant define ----------------------------*/
.equ x, 45
.equ y, 64
.equ z, 87
.equ stack_top, 0x1000
.global _start
/*---------------- code -------------*/
.text
_start: mov r0, #x
mov r0, r0, lsl #8
mov r1, #y
add r2, r0, r1, lsr #1
mov sp, #0x1000
str r2, [sp]
mov r0, #z
mov r1, #y
add r2, r0, r1, lsr #1
ldr r0, [sp]
mov r1, #0x01
orr r0, r0, r1
mov r1, R2
add r2, r0, r1, lsr #1
stop:
b stop
.end