dsp复习详解Word格式文档下载.docx
《dsp复习详解Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《dsp复习详解Word格式文档下载.docx(27页珍藏版)》请在冰豆网上搜索。
DAB
DAR
dmad
算术逻辑单元
辅助寄存器,通用
某一指定的辅助寄存器(0£
x£
7)
被测试位(0£
BITC£
15)
2位的条件码(0£
CC£
3)
条件执行指令中的操作数
延迟选项
D地址总线
DAB的地址寄存器
16位数据存储器立即地址
Dmem
dst
dst_
EAB
EAR
extpmad
hi(A)
K
k3
k5
数据存储器操作数
目的累加器(A或B)
相对目的累加器的另一个累加器
E地址总线
EAB的地址寄存器
23位程序存储器的立即地址
累加器A中的高位部分(位32~16)
少于9位的短立即数
3位立即数(0£
k3£
5位立即数(-16£
k5£
实现16位定点减法:
‘C54X中提供了多条用于减法的指令,如SUB,SUBB,SUBC和SUBS。
其中SUBS用于无符号数的减法运算,SUBB用于带借位的减法运算(如32位扩展精度的减法),而SUBC为带条件的移位减,DSP中的除法就是用该指令来实现的。
SUB指令与ADD指令一样,有许多的寻址方式
减法指令使用举例
SUB*AR1+,14,A
❑SUBA,-8,B
❑SUBB5,A
❑SUBB*AR1+,B
利用SUBC实现除法
在‘C54X中没有提供专门的除法指令,一般有两种方法来完成除法。
一种是用乘法来代替,除以某个数相当于乘以其倒数,所以先求出其倒数,然后相乘。
这种方法对于除以常数特别适用。
另一种方法是使用SUBC指令,重复16次减法完成除法运算。
利用SUBC完成Temp1/Temp2
LDtemp1,B;
将被除数temp1装入B寄存器的低16位
RPT#15;
重复SUBC指令16次
SUBCtemp2,B;
使用SUBC指令完成除法
STLB,temp3;
将商(B寄存器的低16位)存入变量temp3
STHB,temp4;
将余数(B寄存器的高16位)存入变量temp4
注:
实际上是完成整数除法
3、乘法指令
实现16定点整数乘法
在‘C54X中提供了大量的乘法运算指令,其结果都是32位,放在A或B寄存器中。
乘数在‘C54X的乘法指令很灵活,可以是T寄存器、立即数、存贮单元和A或B寄存器的高16位。
如果是无符号数乘时,请使用MPYU指令。
这是一条专用于无符号数乘法运算的指令,而其它指令都是有符号数的乘法。
整数乘法举例:
RSBXFRCT;
清FRCT标志,准备整数乘
LDtemp1,T;
将变量temp1装入T寄存器
MPYtemp2,A;
完成temp2*temp1,结果放入A寄存器(32位)
FRCT标志为小数方式标志位
实现小数乘法
在‘C54X中,小数的乘法与整数乘法基本一致,只是由于两个有符号的小数相乘,其结果的小数点的位置在次高的后面,所以必须左移一位,才能得到正确的结果。
‘C54X中提供了一个状态位FRCT,将其设置为1时,系统自动将乘积结果左移移位。
两个小数(16位)相乘后结果为32位,如果精度允许的话,可以只存高16位,将低16位丢弃,这样仍可得到16位的结果。
小数乘法举例
SSBXFRCT;
FRCT=1,准备小数乘法
LDtemp1,16,A;
将变量temp1装入寄存器A的高16位
MPYAtemp2;
完成temp2乘寄存器A的高16位,结
果在B中,同时将temp2装入T寄存器
STHB,temp3;
将乘积结果的高16位存入变量temp3
如:
0.1(0x0ccd)*0.7(0x599a)
=0.06997680664063(0x08f5F0A4)
4、乘加与乘减指令:
5、双精度/双数操作指令
6、特殊指令
数据归一化相关指令EXP、NORM
归一化一个数是先求其指数,然后把它调整到最大精度格式。
实现方法如下:
二、逻辑运算指令
逻辑指令包括与、或、异或、移位和测试指令
1、与指令(AND)
2、或、异或指令
3、移位和测试指令
三、程序控制指令
程序控制指令包括:
分支指令、调用指令、中断指令、返回指令、重复指令、堆栈操作指令、混合程序控制指令
四、装入和存储指令
装入和存储指令包括:
一般的装入和存储指令
2、存贮指令
5、并行存储和加、减、乘法指令
6、并行装入和乘法指令
7、混合装入和存储指令
同一条指令在不同存储器中可能有不同执行时间
操作数在双寻址空间、单寻址空间和外部
程序代码在双寻址、单寻址和外部空间
操作数和代码在相同存储器块中
数据空间插入了等待周期
程序空间插入了等待周期
特殊指令使用说明
FIRS指令
FIRS指令用于线性相位滤波器的处理。
一个如下图的8阶线性相位滤波器的输出表达式:
FIR滤波的两指令MAC、FIRS
数据块移动MVDD、MVDP、MVPD
在C54x系列DSP,数据与数据存储器、数据与程序存储器之间可以方便的进行数据传输,结合单指令循环可实现数据块移动。
如16个系数的移动:
最小均方运算LMS
在进行自适应滤波等操作中经常会使用LMS算法,C54x提供的LMS指令方便了编程。
如下图所示的自适应滤波器设计中,滤波器系数修正公式为:
基于LMS的自适应滤波编程
数据块移动指令MVDD、MVDP、MVPD
4、C语言DSP程序设计
一、存储器模式二、寄存器规则三、函数调用规则四、中断函数五、表达式分析
一、存储器模式
(5.5.1节)
TMS320C2X/C5X定点处理器:
程序存储器:
可执行的程序代码;
数据存储器:
外部变量、静态变量和系统堆栈。
由C程序生成的每一块程序或数据存放于存储空间的一个连续段中。
(一)C编译器生成的块
由C5X编译器编译生成5个初始化段,3个未初始化段和1个.data段(表5.5.1)
(二)C系统堆栈
定点C编译器采用1个寄存器来管理这个堆栈:
AR1——作为堆栈指针(SP被保护起来),它指向堆栈的顶部。
激活每个函数时,都在堆栈中建立一个新的帧,以用于分配局部变量和临时变量。
C环境能够自动管理这些寄存器。
如果需要编写操作堆栈的汇编程序,必须注意这些寄存器的正确使用。
定点C编译器的堆栈长度由链接器确定,全局符号_STACK_SIZE的值等于堆栈长度,单位为字节,缺省值为1K字节。
同样,需要改变堆栈长度时,在链接时用-stack选项,并在其后指定一个数值。
(三)动态存储器分配
在运行支持库中,有几个允许在运行时进行动态存储器分配的函数,如malloc、calloc、realloc,动态存储器分配的目标一般采用指针进行寻址。
(四)静态和全局变量的存储器分配
在C程序中说明的每一个外部或静态变量被分配给一个唯一的连续空间。
空间的地址由链接器确定。
编译器保证这些变量的空间分配在多个字中以使每个变量按字边界对准。
(五)域/结构的对准
编译器为结构分配空间时,它分配足够的字以包含所有的结构成员,在一组结构中,每个结构开始于字边界。
所有的非域类型对准于字的边界。
对域分配足够多的比特,相邻域组装进一个字的相邻比特,但不跨越两个字。
如果一个域要跨越两个字,则整个域分配到下一个字中。
二、寄存器规则
(5.5.3节)
在定点c编译器中定义了严格的寄存器使用规则。
这些规则对于编写汇编语言与C语言的接口非常重要。
如果编写的汇编程序不符合寄存器使用规则,则C环境将被破坏。
C编译器使用寄存器的方法在使用和不使用优化器时是不一样的。
因为优化器需要使用额外的寄存器作为寄存器变量以提高程序的运行效率。
但函数调用时保护寄存器的规则在使用和不使用优化器时是一样的。
下面我们来介绍定点C编译器使用寄存器的规则。
函数采用汇编编写时,可以使用辅助寄存器、T寄存器和SP寄存器、各种状态寄存器,在使用时必须符合下列规则:
1.
辅助寄存器(ARP和AR0~AR7)
AR2、AR3、AR4和AR5可以自由使用,也就是说,在函数执行过程中可以修改,被调用函数不会保护这些寄存器,如果要保护的话需要调用者来进行。
AR6和AR7用作寄存器变量。
分别分配给第一个和第二个寄存器变量
2.
状态寄存器
在C编译器中,ARP、ASM、C、OVA、OVB、OVM、SMUL、SXM和TC可以修改。
其他位域不可修改。
3.
其它寄存器
累加器A/B可以自由使用,不必保护和恢复。
SP、BRC和T寄存器也可以自由使用。
(三)寄存器变量
在一个函数中,定点C编译器可以自由使用多至两个寄存器变量。
如果要在函数中使用寄存器变量,则应在函数的参数表或函数的第一块中定义。
否则,作为一般的变量处理。
编译器用AR6和AR7作为寄存器变量,其中AR6分配给第一个寄存器变量,AR7分配给第二个寄存器变量。
由于在运行时建立一个寄存器变量约需4个指令周期,因此,只有当一个变量访问2次以上,使用寄存器变量的效果才能明显地体现出来。
三、函数调用规则
(5.5.4节)
C编译器规定了一组严格的函数调用规则。
除了特殊函数的运行支持外,任何调用C函数或被C函数所调用的函数都必须遵循这些规则,否则就会破坏C环境。
(一)参数传递
将参数传递给一个C函数时,必须遵循下列规则:
(1)函数调用前,将参数压入运行堆栈。
(2)以逆序传递参数。
也就是说:
第一个参数(最左边)最后压栈,而最后一个参数(最右边)最先压。
(3)若参数是浮点数或长整型数,则低位字先压栈,高位字后压栈。
(4)传递结构时,采用多字方式。
(二)局部帧的产生
函数被调用时,编译器在运行栈中建立一个帧以存储信息。
当前函数帧称为局部帧。
C环境利用局部帧来保护调用者的有关信息、传递参数和生成局部变量。
每调用一个函数,就建立一个新的帧。
(三)函数调用过程
1、父函数将第一个参数(左)置入A,其他参数逆序压栈;
SP传给AR1;
2、如果函数返回的是一个结构,则父函数为该结构分配空间,并将返回空间的地址通过A传递给子函数;
3、函数调用的7个工作;
四、中断函数
在定点C编译器中,中断可以用C函数直接处理。
每个中断采用固定的程序名。
如下所示:
c_int0系统复位中断
c_int1外部中断0
c_int2外部中断1
c_int3外部中断2
c_int4内部定时器中断
c_int5串行口接收中断
c_int6串行口发送中断
c_int7TDM口接收中断
c_int8TDM口发送中断
c_int9外部中断3
用C语言编写中断程序时,必须注意以下几点:
(1)对由SP(AR1)指向的字,编译器可能正在使用,必须加以保护。
(2)中断的屏蔽和使能必须由程序员设置,设置的方法是用嵌入汇编语句的方法修改IMR寄存器。
这样修改不会破坏C环境或C指针。
(3)中断程序没有参数传递,即使说明,也将被忽略。
(4)由于用C编写中断程序时,需要保护所有的寄存器,因此效率不高。
(5)将一个程序与某个中断关联时,必须在相应的中断矢量处放置一条跳转指令。
(6)在汇编语言中,注意必须在中断程序名前加一下划杠。
例如,c语言中的c_int1,在汇编语言中为_c_int1。
(7)中断程序或在中断程序中需要调用的程序都不能用_oe选项进行优化编译。
五、表达式分析
当C程序中需要计算整型表达式时,必须注意到以下几点:
1.
算术上溢和下溢。
即使采用16位操作数,TMS320C5X也会产生32位结果。
因此,算术溢出是不能以一种可预测的方式进行处理的。
2.
整除和取模。
TMS320C5X没有直接提供整除指令,因此,所有的整除和取模运算都需要调用库函数来实现。
这些函数将运算表达式的右操作数压入堆栈,将左操作数放入累加器的低16位。
函数的计算结果在累加器中返回。
表达式分析。
下面的一些运算在函数调用时并不遵循标准的C调用规则,目的在于提高程序运行速度和减少程序代码空间。
1)变量的左移;
2)变量的右移;
3)除法;
4)取模(5)乘法
4.
C代码访问16位乘法结果的高16位。
DSP中增加的C关键字p280
Const:
定义常量,保证不被改变
例:
int*constp=&
x;
constint*q=&
Volatile:
定义一个变量,保证其不被优化掉
unsignedint*ctrl
while(*ctrl!
=0xFF)
volatileunsignedint*ctrl
Ioport:
定义端口
例子:
ioportunsignedport10
Interrupt:
定义一个中断服务函数
interruptvoidint_handler()
Near/far:
定义函数的调用方式
nearfoo()——用call来调用
farintfoo()——用fcall远程调用
定点DSP芯片C程序的开发过程主要分以下几个步骤:
用编辑器(如EDIT、ccs等)编辑一个或多个C程序,如example1.c,example2.c。
编译C程序,形成目标文件,如example1.obj,example2.obj:
dspcl_v25_g_mn_o2example1.c
dspc_v50_g_mn_o2example1.c
命令选项中的_v25表示是TMS320C2X,若是TMS320C5X,则选项为_v50。
根据实际应用编辑一个链接命令文件,如example.cmd。
MEMORY
{
PAGE0:
VECS:
origin=0h
len=30h
PAGE0:
PROG:
orgin=30h
len=0EFDOh
/*程序空间*/
PAGE1:
DATA:
origin=800h
len=OE800h
/*数据空间*/
}
SECTIONS
.vectors:
{}>
VECS
/*中断矢量*/
.text:
PROGPAGE0
/*代码*/
.cinit:
PROGPAGE0
/*C初始化表*/
.switch:
/*switch语句表*/
.bss:
DATAPAGE1
/*变量*/
.const:
/*常数变量*/
.stack:
/*系统堆栈*/
.cio:
{}>
DATAPAGE1/printf和有关函数
使用的缓存*/
.system:
/*动态存储器*/
}
链接形成example.out:
dsplnkexample.cmd
5.
用C源码调试器进行调试(模拟器、硬件仿真器等)。
(1)C程序的结构及组成
//#include包含语句定义程序中使用的函数库对应的.h头文件
#include“函数库1”
#include<
函数库2>
#include“函数库3”
…
//#define定义程序中所有的宏替换
#define宏替换名替换内容
//本程序的内部函数声明,这些函数一般放在main()函数的后面
函数类型函数名(函数参数列表);
//中断服务程序(函数)的声明
interruptvoidfunction_name(void);
//全局变量声明
变量类型全局变量名;
//主函数main()
voidmain(void)
{//局部变量定义
…
for(;
;
)
{
//调用子函数来处理数据
//完成数据的输入和输出功能
}
}
//本程序的内部函数
函数类型函数名(函数参数列表)
{
//本函数的局部变量定义
//本函数中的算法
}
…
//程序结束
(2)C54xx相关的头文件
54xx硬件专用头文件位于C:
\ti\c5400\dsk5402\include目录下。
可以分为两类:
一类头文件对DSP本身及外部接口电路所拥有的硬件资源进行描述定义,如Regs.h、Regs54xx.h。
另一类头文件对这些资源的设置和使用的接口函数库进行了描述,使用户可以不关心底层的驱动程序,直接调用库函数即可实现对硬件的控制,这些往往都是硬件开发人员所完成的,如CCS中的board.h和mcbsp54.h.
c5400\dsk5402\include目录中的部分头文件与dsk板库文件drv5402.lib和dsk5402.lib相关联。
drv5402.lib和dsk5402.lib函数库在c5400\dsk5402\lib目录下,dsk5402.lib是一个主要的库函数,内部使用了drv5402.lib。
c5400\cgtools\include目录下的头文件是5000系列DSP的通用头文件,与硬件无关,它们与运行时支持库rts.lib相关联,
(3)头文件中存储器映射寄存器
(MMR)的定义和访问
54XDSP的片内寄存器资源是通过两个头文件Regs.h和Regs54x.h进行定义的,这些头文件位于c:
\ti\c5400\dsk5402\include目录下,在这两个文件中定义了C54xDSP中涉及到的所有寄存器及其所包含的控制和状态比特,这些定义是使用宏替换定义#define进行的。
MMR的定义和访问
例如:
串口控制寄存器中接收移位寄存器满标志位的比特域定义:
#defineRSRFULL13//RSRFULL标志比特位于寄存器的bit13位置
#defineRSRFULL_SZ1//此标志的长度为1个比特
(4)DSPI/O空间的访问
方式1:
在C语言中访问DSP的I/O空间借助于关键字ioport来进行,注意,此关键字只为DSP54xx的编译器所识别和使用。
例如:
当访问I/O空间在200H地址时,可以采取以下定义形式:
ioportunsignedintport200;
unsignedinttest;
test=port200;
//读I/O端口,port200作为一个变量使用
port200=test;
//写I/O端口,port200作为一个变量使用
DSPI/O空间的访问
方式2:
借助于库函数portRead(port)和portWrite(port)对一段连续I/O端口进行读写。
在portio.h头中定义了portRead()、portWrite()函数。
#includeportio.h//所需要的函数包含在portio.h中
#defineportA0x00//使用宏替换定义I/O端口的地址
#defineportB0x01
或
typedefenum//使用枚举定义I/O端口的地址
portA=0x00;
portB=0x01;
}cpldReg,*pcpldReg.
Variable=portRead(portA);
//读I/O端口
portwrite(portB)=Value;
//写I/O端口