第四章编译连接工具的使用一,C54X汇编工具的使用
C54X的源程序可以使用汇编或 C语言编写。使用汇编语言是可以使用助记符指令集( Mnemonic Instruction Set)
或代数指令集( Algebraic
Instruction Set),但两种不能混用。
两种指令的汇编语言比较
low_pass_mac:
push(st1) ; pshm st1
push(st0) ; pshm st0
push(ar0) ; pshm ar0
push(bk) ; pshm bk
ar2 = data(#t_ar2) ; mvdm #t_ar2,ar2
ar3= data(#t_ar3) ; mvdm #t_ar3,ar3
ar0 = #1 ; stm #1,ar0
bk = #N ; stm #N,bk
*ar3+% = a ; stl a,*ar3+%
repeat(#(N-1)),a=0 ; rptz a,#(N-1)
a+= *ar2+0% * *ar3+0% ; mac
*ar2+0%,*ar3+0%,a
ASM500命令格式如下:
asm500 [ input file [ object file [ listing file] ] ] [ -
options]
input file,汇编源文件名,缺省后缀为,asm
object file,编译输出的 OBJ文件名,缺省后缀为,obj
listing file,产生的列表文件名,缺省后缀为,lst
options,编译器使用的各种选择。常用选项有:
-c,若使用该选项,编译器忽略字母的大小写。例如
abc与 ABC是一样的。系统缺省为区分大小写。
-i,设置搜索路径。通知编译器在指定的搜索路径中去查找,copy,.include中的文件。 用法举例,-ic:\c54x。
-l,(小写的 L)在编译时产生列表文件,缺省后缀为,lst
-mg,汇编源程序使用代数指令集 或在源代码中使用,Algebraic
-s,将所有的符号都放入符号表。若不使用该选项,编译器仅将全局变量放入符号表。
-v,指定版本。特别是需要使用
BOOTLOADER时,应加 -v548开关 。
先看两个汇编源程序:
file1.asm
.global test
loop:
call test
bc loop,ageq
.end
file2.asm file3.asm
.global
test,global test
test,
test:
mar *ar3+
mar(*ar3+)
add #1,a
a=a+#1
汇编工具 ASM500的使用举例
asm500 file1.asm <enter>
asm500 file2 -l <enter>
asm500 file3 -mg -l <enter>
TMS320C54x COFF Assembler Version 1.20 Sun Jul
30 12:11:25 2000
Copyright (c) 1997 Texas Instruments Incorporated
file2.asm PAGE 1
1,global test
2
3 000000 test:
4 000000 6D93 mar *ar3+
5 000001 F000 add #1,a
000002 0001
6 000003 FC00 ret
7
8,end
No Errors,No Warnings
TMS320C54x COFF Assembler Version 1.20 Sun Jul 30 12:21:26 2000
Copyright (c) 1997 Texas Instruments Incorporated
file3.asm PAGE 1
1,global test
2
3 000000 test:
4 000000 6D93 mar(*ar3+)
5 000001 F000 a=a+#1
000002 0001
6 000003 FC00 return
7
8,end
No Errors,No Warnings
C54X汇编语言书写规范
语法,[label][:] 指令 [操作数 ] [;注释 ]
#前缀表示立即数或直接地址
后缀 B或 b表示二进制常数例如,LD #1000B,A
后缀 Q或 q表示八进制常数,或以 0开始的常数例如,LD #10Q,A ( 010,A)
十二进制常数例如,LD #1000,A
C54X汇编语言书写规范
后缀 H或 h表示十六进制常数
例如,LD #1000H,A
使用,set定义一个符号的值例如 addr,set 1000h
stm #addr,ar0
标号的使用
例如 b loop
loop,ssbx intm
使用,global 定义全局标号
C54X汇编语言书写规范
使用符号 $表示当前 PC值
例如 B $
可以使用结构
例如 item,struct,int
value,int deltat
_len,endstruct,
array,tag item
,bss array,i_len
C54X汇编语言书写规范
可以定义宏例如 mypush,macro
pshm ah
pshm al
pshm bh
pshm bl
endm
二,C54X连接工具的使用
使用 LNK500命令可以将一个或多个 OBJ
文件连接为一个,OUT文件。在连接时,
可以通过段定位控制命令将不同的代码、
数据写入不同的内存单元。 注意:
LNK500生成的 OUT文件不是纯二进制代码文件,而是包含代码、符号表、代码定位信息的复合文件。
LNK500的使用格式:
lnk500 [ -options] filename 1,,.,filename
n
使用举例,lnk500 file1.obj file2.obj -o file.out
LNK500命令常用的选项有:
-e global_symbol,定义程序的进入点。
global_symbol必须在源程序中使用,global命令说明。
-c,使用 C编译器的 ROM初始化模式。
-cr,使用 C编译器的 RAM初始化模式 。
-i dir,指定库文件的路径。
-l filename,指定连接时使用的库文件名。
-m filename,生成 MAP文件 。
-o filename,指定生成的 OUT文件名。系统缺省为
a.out。
将文件 file1.asm和 file2.asm连接成 OUT文件:
lnk500 file1 file2 -m file.map -o file.out
通过查看 MAP文件可以获得变量、子程序等符号的具体地址。注意,MAP文件只列出全局变量的地址。(用,global说明的符号)
三,汇编连接工具对段的处理
为了灵活使用 C54X的内存,可以将不同的代码段放入不同的内存中。在汇编源程序中可以使用下列指令,
,bss 该指令表示在,bss段中保留空间。 用法,.bss symbol,size
,usect 该指令表示在指定的段中保留空间。用法,symbol,usect,section name”,size
,text 将代码或数据放入,text段中
,data 将数据放入,data段中
,sect 将代码或数据放入指定的段中。
用法,symbol,sect,section name”,size
在连接时使用相应的控制命令以确定具体的内存地址。下面给出其中一种方法:
其中,.bss,.text,.data 三个段是标准定义,而,vect,.buffer是自定义的。 (t.cmd)
MEMORY
{
PAGE 0,PROG,origin = 1800h,length = 800h
PAGE 4,PROG,origin = 0200h,length = 100h
PAGE 1,DATA,origin = 0c00h,length = 100h
PAGE 2,DATA,origin = 0d00h,length = 200h
PAGE 3,DATA,origin = 0f00h,length = 100h
}
SECTIONS
{
.text > PROG PAGE 0
.vect > PROG PAGE 4
.bss > DATA PAGE 1
.data > DATA PAGE 2
.buffer > DATA PAGE 3
}
下面是例子程序 t.asm的一部分,其中红色部分为段的定义
.bss temp,1
buf,usect ".buffer",10
.sect ".vect"
start:
b mainstart
nop
nop
b $
.text
mainstart:
ssbx intm ; disable all interrupt !
编译连接程序 exer.asm,通过 MAP文件检查各个段是否装入指定的内存地址。
LNK500的选项可以放入内存定位文件中。
如 user.cmd,这时使用连接命令可以简化为:
lnk500 user.cmd
四,C编译器
C54X的 C编译器有两个部分组成:先剖系 C源代码并完成优化,然后将其转化为汇编源代码。
另一部分就是前面介绍过的汇编语言工具。所以当使用 CL500命令对 C语言进行编译时,它实际上调用:
ac500 —— C 剖析器
opt500 —— 优化器
cg500 —— 汇编语言生成器
asm500 —— 汇编编译器
若在 CL500命令中使用了 -z选项,C编译器还可以自动调用 LNK500完成连接操作。
下面是一些常用的选项:
-g,允许使用 C代码级的调试。
-k,保留生成的汇编源程序。
-ss,产生 C的注释汇编源程序 。
-z,允许调用连接程序。
-o,完成优化
CL500还有许多有关 C剖析,优化的选项。
请参考,TMS320C54x Optimizing C
Compiler User Guide,
我们举一个例子:
/**************************************/
/* function.c */
/* (Sample file for walkthrough) */
/**************************************/
int main(i)
int i;
{
return(i < 0? -i,i );
}
cl500 -o function <enter>
cl500 -k -o function <enter> (保留汇编)
cl500 -ss -o funtion <enter>
lnk500 -c function.obj lnk.cmd -o function.out
-l rts.lib 或 cl500 function.c -z lnk.cmd
-o function.out -l rts.lib
C代码的程序入口地址符号为 _c_int00。
LNK500时使用的 -c和 -cr是对 C语言中常量(放在,cinit段中)的处理不同。 -c
表示在运行时处理,而 -cr则在装入时处理。
_main:;* A assigned to _i
FRAME #-1
nop
STL A,*SP(0) ; |2|;------------------------------------------------------------------------------; 3 | return(i<0? -i:i);;------------------------------------------------------------------------------
SSBX SXM
nop
LD *SP(0),A ; |3|
BC L3,AGEQ ; |3|; branch occurs ; |3|
BD L4 ; |3|
LD *SP(0),A ; |3|
NEG A,A ; |3|; branch occurs ; |3|
L3,
LD *SP(0),A ; |3|
L4,
FRAME #1 ; |4|
RET ; |4|; return occurs ; |4|;
_main:;* A assigned to _i;* A assigned to _i; 3 | return(i<0? -i:i);;-------------------------------------------------------------------------
-----
SSBX SXM
LD *(AL),A ; |3|
ABS A,A ; |3|
RET ; |4|; return occurs ; |4|
优化后的结果
C语言编写说明
使用 Interrupt关键字说明函数的返回使用 RETE,例如
interrupt void int_handle()
{ int
j,flag; …
… }
汇编完成后,使用开中断 RETE返回。
C语言编写说明
使用 volatile关键字。优化器会尽量减少存储器的访问,所以有时必须禁止优化,
特别是循环控制变量。参见下面的例子
unsigned int *ctrl;
while(*ctrl !=
0xff); ……
L2,;--------------------------------------------------------------
----------------; 4 | while(*ctrl != 0xff);;--------------------------------------------------------------
----------------
MVDK *SP(0),*(AR1) ; |4|
CMPM *AR1,#255 ; |4|
BC L2,NTC ; |4|; branch occurs ; |4|
未优化的结果优化后的结果
…..,
MVDK *AR1,*(AR1)
L2,;** -----------------------g2:;** 4 ----------------------- if ( U$1 != 255 ) goto g2;
BANZ L2,*AR1(-255) ; |4|; branch occurs ; |4|;** ----------------------- return;
…...
增加了 volatile关键字后,再优化
L2,;** -----------------------g2:;** 4 ----------------------- if ( *ctrl != 255 ) goto g2;
CMPM *AR1,#255 ; |4|
BC L2,NTC ; |4|; branch occurs ; |4|;** ----------------------- return;
C语言编写说明
使用 register关键字说明寄存器变量。
在 C代码中插入汇编代码,……
i++;
asm(,assembler text”); /* 如
asm(,nop”);
例子,标准的连接定位文件 lnk.cmd
rts.lib
-stack 0x2000
-heap 0x2000
MEMORY
{
PAGE 0,PROG,origin = 3000h,length = 0D000h
PAGE 1,DATA,origin = 0800h,length = 0E800h
}
SECTIONS {
.text > PROG PAGE 0
.cinit > PROG PAGE 0
.switch > PROG PAGE 0
.data > DATA PAGE 1
.bss > DATA PAGE 1
.const > DATA PAGE 1
.sysmem > DATA PAGE 1
.stack > DATA PAGE 1
}
C语言编写说明
C代码的程序入口地址符号为 _c_int00。
LNK500时使用的 -c和 -cr是对 C语言中常量(放在,cinit段中)的处理不同。 -c
表示在运行时处理,而 -cr则在装入时处理。
例子 cl500 -g a.c -z lnk.cmd -c or
-cr,使用 SIM54X,查看 -c 和 -cr 区别。
C语言调用汇编的例子
<C program:>
extern int asmfunc();
int gvar;
main()
{ int i;
i = asmfunc(i);
}
< Assembly program:>
_asmfunc:
add *(_gvar),A
stl a,*(_gval);
ret
C语言与汇编相互调用的考虑
参数的传递
返回值的约定
全局变量的使用
汇编中所有符号前面的加 _
C程序的进入点,_c_int00