传统上,ADI和TI公司的DSP被业界广泛使用。其中TI公司的DSP分为C2000、C5000和C6000三个系列。对于TI公司的C6000而言,分为定点和浮点两种类型。一般,TMS320C64x和TMS320C62x属于定点DSP;TMS320C67x属于浮点DSP;TMS320C66x同时包含定点和浮点处理单元,属于多核DSP。
本节将以TI公司的TMS320C64x系列DSP为例,介绍DSP的架构和流水线。
1.DSP的结构和单元
TI公司的TMS320C64x DSP的内部结构如图2.2所示。尽管DSP的结构是固定的,但它是一个软件可编程(可以使用C语言对其编程)的结构,能够按顺序执行程序中的各种指令,但不允许并行实现。DSP通常由下面的单元组成。
图2.2 TMS320C64x DSP的内部结构
1 ) CPU
DSP的中央处理单元主要包含:①取出程序单元;②指令分派单元;③指令译码单元;④两个数据通道A和B,每个通道包含4个功能单元(.L、.S、.M和.D);⑤64个32位寄存器,寄存器A0~A31属于寄存器文件A,寄存器B0~B31属于寄存器文件B;⑥控制寄存器;⑦控制逻辑;⑧测试、仿真和中断逻辑。
(1)在每个CPU时钟周期内,取出程序单元、指令分派单元和指令译码单元可以将最多8条32位的指令发送给功能单元。
(2)每个寄存器组有4个功能单元(分别用.D1、.M1、.L1、.S1和.D2、.M2、.L2、.S2表示),不同单元的具体功能如下。
①.D单元。用于从存储器中加载或者将信息保存到存储器,并执行算术操作。该单元对存储器进行读写操作,并使用偏移量。此外,它也可执行32位的加减法运算。
②.M单元。用于乘法操作,在DSP中有两个乘法器单元.M1和.M2,可以实现32×32位的乘法运算。
③.L单元。用于逻辑和算术运算,该单元可以执行32/40位的算术运算、比较运算,以及32位的逻辑操作运算。
④.S单元。用于分支跳转、位操作和算术运算。它可执行32 位算术逻辑运算、位域操作,以及32/40位移位操作。此外,它也用于处理分支指令。
2 ) 总线
内部总线用于在DSP的不同功能单元之间传输数据和控制信息。内部总线提供了高度的并行性。对于TI公司的C6xxx系列而言,提供了3类总线:①指令总线;②数据总线;③直接存储器存取总线。这些总线的主要功能如下所示。
(1)一条用于提取指令的总线。
(2)两条用于分别从存储器中提取数据和滤波器系数的总线。
(3)用于在不同的外设和存储器之间进行直接存储器存取(Directive Memory Access,DMA)操作的总线。
3 ) 内部存储器
C64x系列的DSP提供32位可字节寻址的地址空间。内部(片上)存储器分为独立的数据和程序空间。当使用片外存储器时,通过外部存储器接口(External Memory Interface,EMIF),将外部存储器连接到DSP。
C64x系列的DSP提供了两个内部端口,用于访问内部数据存储器;提供了一个内部端口,用于访问内部程序存储器(取指宽度为256比特)。
4 ) 存储器和外设选项
C6000系列的DSP提供了不同的存储器和外设选项,包括:①大容量的片上RAM,最大容量为7Mb;②程序高速缓存;③两级高速缓存;④32位外部存储器接口,支持SDRAM、SBSRAM、SRAM,以及其他异步存储器。⑤扩展的直接存储器访问(Enhanced Direct Memory Access,EDMA)控制器;⑥以太网媒体访问控制器(Ethernet Media Access Controller,EMAC)和物理层设备管理数据输入/输出模块(Management Data Input/Output,MDIO);⑦主机接口(Host Port Interface,HPI);⑧内部集成电路总线(Inter-Integrated Circuit,I 2 C)模块;⑨多通道音频串行端口(Multichannel Audio Serial Port,McASP);⑩多通道缓冲串行端口 (Multichannel Buffered Serial Port,McBSP);⑪外设部件互联(Peripheral Component Interconnect,PCI) 端口;⑫232位通用定时器等。
2.DSP的流水线
DSP内的CPU通过流水线,相互重叠地实现连续取指、译码和执行操作。TI公司的C6000处理器使用超流水线结构,一个处理器周期由8个时钟周期组成,一个处理器周期不仅相互重叠地执行取指和译码,而且相互重叠地执行上一个和下一个指令。TI公司C6000系列DSP的流水线操作如图2.3所示。
图2.3 C6000系列DSP的流水线
注 :(1) 对于流水线的取指周期而言,细化为产生程序地址 (Program Address Generate) PG、发送程序地址 (Program Address Send) PS、程序访问准备等待 (Program Access Ready Wait) PW和接收程序取指包 (Program Fetch Packet Receive) PR阶段。
(2)对于指令的译码周期而言,细化为指令分派(Instruction Dispatch)DP和指令译码(Instruction Decode)DC阶段。
(3)对于指令的执行周期而言,细化为5个阶段,用E1~E5表示。
本节将从数字FIR滤波器与MAC操作、循环缓冲单元以及代码效率和编码功能几个方面,介绍使用DSP进行数字信号处理的性能方面的问题。
1.数字FIR滤波器与MAC操作
为了说明DSP对FIR滤波算法的处理过程,首先给出一个N抽头FIR滤波器的结构图,如图2.4所示。
图2.4 N抽头FIR滤波器的结构图
在第k时刻,N个权值FIR滤波器的输出可以表示为
其中:
从上式可知,对于长度为N的FIR滤波算法,需要执行N次MAC操作。使用DSP实现FIR滤波器算法的处理流程如图2.5所示。
从图2.5中可知,该FIR滤波算法包含一系列乘法和加法操作。在实际实现时,可以使用C语言或者汇编语言编程实现该FIR滤波算法。下面首先介绍使用C语言实现FIR滤波器的功能。
图2.5 FIR滤波器算法的原理
(1)可以通过C语言用一个for循环来实现。下面给出使用C语言代码实现FIR滤波器算法的代码:
其中,h_ptr指向权值参数h,x_ptr指向采样参数x。
(2)通过指针或者数组,存取存储器中所保存的输入数据和滤波器系数。为了节约所使用DSP的存储器资源,一般采用动态分配存储空间的方法。下面给出使用汇编语言实现FIR滤波器算法的代码:
2.循环缓冲单元
在MAC操作过程中,缓冲和更新数据的方法如图2.6所示。实现长度为N的FIR滤波器需要:
(1)每个采样周期,更新抽头延迟线x(k);
(2)不需要移动所有的数据,仅需要覆盖缓冲区中最早的数据。
图2.6 数据的更新
如果通过一个模N的操作实现指针x_ptr的增加或减少,则可以实现循环缓冲区,即指针循环到存储器阵列的任何一端。
循环缓冲区是一个非常有效的方法,它能够将存储器中需要移动的数据量最小化。当使用一个线性缓冲器时,加载一个新采样所需存储器移动操作的个数,如图2.7所示。
图2.7 线性循环缓冲器的实现过程
如果使用循环缓冲区,则可以将存储器所需要移动操作的次数减少,如图2.8所示。
3.代码效率和编码功能
使用DSP完成DSP算法,除了要求使用高性能的DSP外,软件设计人员还必须在代码效率和有效代码上进行深入研究。一方面,使用尽可能少的指令或者尽可能少的时钟周期实现DSP算法;另一方面,需要权衡代码效率和代码功能。不同优化级下的代码效率如表2.1所示。
图2.8 循环缓冲器的实现过程
表2.1 不同优化级下的代码效率
使用汇编语言编写的程序具有最优的处理器性能,当然代码的编写也是一种艺术(这主要是因为它可以充分使用DSP的流水线和并行结构)。
传统上,直接对C语言代码执行交叉汇编,但是以前这种方法产生的代码要比直接使用汇编语言编写的代码效率低。
TI开发工具内所集成的C编译器功能非常强大,并且针对DSP的内部结构进行了优化;与传统的使用最优汇编语言编写代码相比,可以达到80%的优化率。此外,还可以通过对部分代码使用C编程或者部分代码使用汇编编程来进一步改善算法性能。
一般的编程功能都允许C语言和汇编语言的混合编程。所以,与实时性处理要求密切相关的代码部分可以使用汇编语言编写,然后与剩余的C语言代码进行正确链接。
实际上,为了分析一个算法的行为和功能,通常从C语言开始编写代码。TI的Code Composer Studio(简称CCS)开发环境内集成了大量的分析工具,用于检查代码的时间要求和效率。通过使用这些工具,可以查找程序中耗时过多的代码,然后使用汇编来实现它。