第6章 C语言和汇编语言混合编程
6.1 C语言和汇编语言混合编程中参数传递和寄存器使用
在很多DSP应用中使用C语言和汇编语言进行混合编程。C语言具有可读性高、便于维护和可移植性好等优点,然而汇编语言具有实时运行效率高和代码效率高的优点。使用汇编语言可以更充分地利用DSP的硬件资源,例如乘累加单元、单指令重复、块重复和块移动等等。某些程序使用汇编语言编写实时运行效率是C语言的几十倍或更多,运算量越大,汇编语言编写的程序实时运行效率越明显。C函数调用汇编子程序和C函数一样有参数传递和返回,以下我们给出C函数如何调用C55x汇编子程序。
6.1.1名称转换
C函数调用汇编子程序时,汇编程序所有变量名和子函数名加前缀下划线“ _ ”,例如使用_sum作为汇编语言程序子函数名。如果汇编程序中定义了变量,必须加前缀下划线C函数才能使用该变量。前缀“ _ ”只在C编译时使用,当我们用C函数调用汇编子函数和变量时,不需要加前缀“ _ ”。以下是C程序调用汇编子函数例子。
C程序:
extern int sum(int *);//参考一个汇编函数
int x[4]={0x1223,0x345,0x2345,0x3444};//定义全局变量并初始化
int s;//定义全局变量
void main()
{
s=sum(x);//
while(1);//
}
汇编程序:
.global _sum ;
_sum ;
rptz ac0,#3 ;
add *ar0+,ac0;
mov ac0,t0 ;
ret ;
_sum ;
rptz ac0,#3 ;
add *ar0+,ac0;
mov ac0,t0 ;
ret ;
2.变量定义
当C和汇编子程序使用同一变量时,在汇编程序中必须使用.global,.def 或.ref定义成全局变量。
3.编译模式
使用C编译器,C55x的CPL(编译模式位)自动被置1,在进入汇编程序时,相对寻址模式使用堆栈指针SP。如果在汇编程序中我们需要使用相对直接寻址模式访问数据存储器,必须改成数据页DP直接寻址模式,可以通过清CPL位实现,在返回C调用程序前,CPL位必须重新置1。
4.参数传递
从C函数传递参数到汇编子程序,必须严格遵守C调用转换规则。传递一个参数,C编译器安排它一个特定的数据类型,并把它放到相应数据类型的寄存器里,C55x的C编译器使用以下三种典型的数据类型:
⏹ 数据指针:int *或long *
⏹ 16位数据:char、short或 int
⏹ 32位数据:long、float、double或函数入口
如果参数指向数据内存,它们作为数据指针;如果参数能放到一个16位的寄存器里,它作为16位数据,例如数据类型为int和char,否则作为32位数据;参数也可以是结构体,一个结构体是两个字(32位)或少于两个字将作为32位参数,并使用32位寄存器传递,超过两个字的结构体,使用参考点传递参数,C编译器将使用指针来传递结构体的地址,这个指针作为一数据参数。
在子程序调用中,函数中的参数顺序地安排到寄存器中,参数存放寄存器和其数据类型相对应,表6-1是参数类型和寄存器安排顺序表。
表6-1参数类型和寄存器安排顺序表
参数类型 | 寄存器安排顺序 |
16位数据指针 | AR0,AR1,AR2,AR3,AR4 |
23位数据指针 | XAR0,XAR1,XAR2,XAR3,XAR4 |
16位数据 | T0,T1,AR0,AR1,AR2,AR3,AR4 |
32位数据 | AC0,AC1,AC2 |
从表6-1中看到辅助寄存器既可作为数据指针又可以作为16位数据寄存器,例如T0和T1保存了16位数据参数,并且AR0已经保存了一个数据指针参数,那么第三个16位参数数据将放到AR1。
5.参数返回值
从被调用的子程序返回值,当返回一个16位数据使用T0;当返回一个32位数据使用AC 0;当返回一个数据指针使用XAR0;当返回一个结构体,这个结构体在当前的堆栈里。
以下是几个参数传递和返回值使用寄存器的例子:
例1:返回值存放于T0,参数传递16位数据i使用T0,16位数据指针*k使用AR0,32位数据p使用AC0;
例2:返回值存放于AC0,参数传递16位数据i使用T0,16位数据指针*k使用AR0,16位数据p使用T1,16位数据n使用AR1;
例3:返回值存放于AC0,参数传递16位数据i使用T0,16位数据指针*k使用AR0,32位数
据p使用AC0,16位数据n使用T1。
6.寄存器的使用和保存
当使用一个函数调用,调用函数和被调用函数之间寄存器安排和保存被严格定义。被调用函数需使用这些寄存器:T2,T3,AR5,AR6,AR7,AC3时,在使用之前必须先将其内容保存之后再使用,可以使用压栈来保存这些寄存器,在返回前按照先入后出顺序弹栈,将其内容恢复;被调用函数可以自由使用这些寄存器:AC0—AC2,T0,T1和AR0—AR4,不需要预先保存和恢复。调用函数如果需要使用AC0—AC2,T0,T1和AR0—AR4这些寄存器的内容,在进入被调用函数之前,需要先将其内容压栈保存。
6.2 C55x DSP C语言和汇编语言混合编程实验
6.2.1实验目的
⏹ 学习C语言和汇编语言混合编程的编写方法;
⏹ 掌握C语言调用汇编程序;
⏹ 学习C语言和汇编语言之间参数的传递和返回。
6.2.2 实验设备
⏹ PC兼容机一台;操作系统为Windows2000 (或WindowsNT、Windows98、WindowsXP);
⏹ 计算机安装CCS 5000或CCS 3.1。
6.2.3实验内容
使用C语言和汇编语言进行混合编程,使用C程序调用汇编子程序,使用汇编语言编写一个两个数组乘累加运算公式程序,C程序将两个数组首地址和长度传递给汇编程序,汇编程序将运算结果返回给C程序。乘累加公式:
6.2.4实验步骤
1. 实验准备
参照第1章的内容,将CCS设置成C55x 软件仿真,启动CCS;
2. 建一个工程;
3. 建一个C文件,把C语言程序输入到文件中,把该文件添加到工程;
4. 建一个汇编asm文件,把汇编程序输入到文件中,把该文件添加到工程;
5. 建一个命令cmd文件,把命令输入到文件中,把该文件添加到工程;
6. 编译工程,装载输出文件;
7. 打开CPU寄存器观察窗;
8. 从菜单View—>Watch Window打开变量观察窗口,如图6-1所示;
在Watch 1窗口Name栏输入全局变量的名称,可以在Type栏看到该变量的所定义的类型,在对应变量Radix栏点击鼠标左键,将弹出数据显示类型选择条,可以选择相应的数据类型,将变量s3数据类型选择Q15格式。
图6-1变量观察窗口
9. 将程序运行到sum( )子程序;
可以在Watch Locals观察窗口看到局部变量k,l,s的值,如图6-2所示。
图6-2 局部变量观察窗口
10. 继续运行程序,直到while( )处;
可以在变量观察窗口Watch 1处观察变量s1,s2,s3的变化,如图6-2所示。
图6-3 局部变量观察窗口
在运行程序时,注意观察寄存器:AC0,T0,XAR0,XAR1,XAR2,XAR3等的变化,在
参数传递和返回中使用了这些寄存器。
6.2.5 程序清单参考
1. C语言程序
extern int mac1(int *,int *,int );
extern long mac2(int *,int *,int );
extern int mac3(int *,int *,int );//all data are Q15
int x[4]={0x1223,0x345,0x2345,0x3444};
c语言中文网汇编语言int a[4]={0x4567,0x345,0x786,0x4332};
int n=4; int s1; long s2; int s3;
int sum();
void main()
{
int s4;
s4=sum();
extern long mac2(int *,int *,int );
extern int mac3(int *,int *,int );//all data are Q15
int x[4]={0x1223,0x345,0x2345,0x3444};
c语言中文网汇编语言int a[4]={0x4567,0x345,0x786,0x4332};
int n=4; int s1; long s2; int s3;
int sum();
void main()
{
int s4;
s4=sum();
s1=mac1(x,a,n);//*ar0=x[0],*ar1=a[0],t0=n,return is stored in t0
s2=mac2(x,a,n);//*ar0=x[0],*ar1=a[0],t0=n,return is stored in ac0
s3=mac3(x,a,n);//*ar0=x[0],*ar1=a[0],t0=n,return is stored in t0
while(1);
}
int sum()
{
int s;int k=3; int l=9; s=k+l;
return(s);
}
s2=mac2(x,a,n);//*ar0=x[0],*ar1=a[0],t0=n,return is stored in ac0
s3=mac3(x,a,n);//*ar0=x[0],*ar1=a[0],t0=n,return is stored in t0
while(1);
}
int sum()
{
int s;int k=3; int l=9; s=k+l;
return(s);
}
2. 汇编程序
.global _mac1,_mac2,_mac3
_mac1 ; int mac1(int *, int *, int )
; first data second data window length
; return value is 16bit and storing t0
sub #1,t0
mov t0,mmap(csr)
mov #0,ac0
rpt csr
mac *ar0+,*ar1+,ac0
mov ac0,t0
ret
sub #1,t0
mov t0,mmap(csr)
mov #0,ac0
rpt csr
mac *ar0+,*ar1+,ac0
mov ac0,t0
ret
_mac2 ; long mac2(int *, int *, int )
;first data second data window length
; return value is 32bit and storing ac0
sub #1,t0
mov t0,mmap(csr)
mov #0,ac0
rpt csr
;first data second data window length
; return value is 32bit and storing ac0
sub #1,t0
mov t0,mmap(csr)
mov #0,ac0
rpt csr
mac *ar0+,*ar1+,ac0
ret
ret
_mac3 ; int mac3(int *, int *, int )
; first data second data window length
;all data is Q15
; return value is 16bit and storing ac0
bset frct
sub #1,t0
mov t0,mmap(csr)
mov #0,ac0
rpt csr
mac *ar0+,*ar1+,ac0
mov hi(ac0),t0
bclr frct
ret
;all data is Q15
; return value is 16bit and storing ac0
bset frct
sub #1,t0
mov t0,mmap(csr)
mov #0,ac0
rpt csr
mac *ar0+,*ar1+,ac0
mov hi(ac0),t0
bclr frct
ret
3. 命令文件
-stack 0x500 /* Primary stack size */
-sysstack 0x500 /* Secondary stack size */
-c /* Use C linking conventions: auto-init vars at runtime */
-u _Reset /* Force load of reset interrupt handler */
/* SPECIFY THE SYSTEM MEMORY MAP */
MEMORY
{
PAGE 0: /* ---- Unified Program/Data Address Space ---- */
RAM (RWIX) : origin = 0x000100, length = 0x01ff00 /* 128Kb page of RAM */
ROM (RIX) : origin = 0x020100, length = 0x01ff00 /* 128Kb page of ROM */
VECS (RIX) : origin = 0xffff00, length = 0x000100 /* 256-byte int vector */
-sysstack 0x500 /* Secondary stack size */
-c /* Use C linking conventions: auto-init vars at runtime */
-u _Reset /* Force load of reset interrupt handler */
/* SPECIFY THE SYSTEM MEMORY MAP */
MEMORY
{
PAGE 0: /* ---- Unified Program/Data Address Space ---- */
RAM (RWIX) : origin = 0x000100, length = 0x01ff00 /* 128Kb page of RAM */
ROM (RIX) : origin = 0x020100, length = 0x01ff00 /* 128Kb page of ROM */
VECS (RIX) : origin = 0xffff00, length = 0x000100 /* 256-byte int vector */
PAGE 2: /* -------- 64K-word I/O Address Space -------- */
IOPORT (RWI) : origin = 0x000000, length = 0x020000
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论