3.1 寻址方式
指令的寻址方式是指硬件寻找指令指定的参与运算的操作数的方法。根据程序的要求采用不同的寻址方式,可以大大缩短程序的运行时间和提高代码效率。TMS320C54x芯片的寻址方式可以分为数据寻址和程序寻址两种。由于程序代码和数据都要存放在DSP存储器里,因此只有对程序存储器和数据存储器的准确寻址和访问,才能保证程序的正确运行。
TMS320C54x有7种基本的数据寻址方式:立即寻址、绝对寻址、累加器寻址、直接寻址、间接寻址、存储器映像寄存器寻址和堆栈寻址。表3.1.1列出了寻址方式中用到的一些缩略语名称及其含义。
表3.1.1 部分寻址缩略语

3.1.1 立即寻址
立即寻址主要用于初始化,其特点是指令中包含有一个固定的立即数,因此没有寻找数据地址的过程。在一条指令中的立即数有短立即数和长立即数两类。短立即数长度为3,5,8或9位,可以放在一个字长的指令(单字指令)中;长立即数长度为16位,应该放在两个字长的指令(双字指令)中。立即数的长度由使用的指令类型决定。表3.1.2列出了可以包含立即数的指令,并指出了立即数的位数。
表3.1.2 支持立即数的指令

在立即寻址方式指令中,应在数值或符号前面加一个“#”,表示是一个立即数,以区别于地址。例如,将一个十六进制数80H,装入累加器A的指令为
LD # 80H,A
3.1.2 绝对寻址
绝对寻址利用 16 位地址寻址存储单元,其特点是指令中包含一个固定地址。16 位地址可以用其地址标号或程序中定义的符号常数来表示。由于绝对地址代码的位数为16位,所以绝对地址寻址的指令至少应为2个字长。绝对寻址有以下4种类型。
1.数据存储器地址(dmad)寻址
该寻址类型用于确定操作数存于数据存储单元的地址。语法是使用一个程序标号或一个数字来指定数据空间的一个地址。例如,将数据存储器EXAM1地址单元中的数据复制到AR5寄存器所指向的数据存储单元中去,即:
MVKD EXAM1,*AR5
其中,EXAM1是16位地址dmad值。
2.程序存储器地址(pmad)寻址
该寻址类型用于确定程序存储器中的一个地址。语法是使用一个符号或具体的数字来指定程序空间的一个地址。例如,将程序存储器TABLE地址单元中的内容复制到AR2寄存器所指向的数据存储单元中去,即:
MVPD TABLE,*AR2
其中,TABLE标注的是16位地址pmad值。
3.端口(PA)寻址
该寻址类型是用一个符号或一个数字来确定外部I/O端口的地址。例如,把一个数从端口为FIFO的I/O口复制到AR5寄存器所指向的数据存储单元中,即:
PORTR FIFO,*AR5
其中,FIFO是I/O端口地址PA。
4.*(1k)寻址
该寻址类型是使用一个指定数据空间的地址来确定数据存储器中的一个地址。例如,把地址为PN的数据单元中的数据装到累加器A中,即:
LD *(PN),A
*(1k)寻址的语法允许所有使用单数据存储器(Smem)寻址的指令去访问数据空间的任意单元,而不改变 DP的值,也不用对 AR 进行初始化。这种寻址可用于支持单数据存储器操作数的指令。当采用绝对寻址方式时,指令长度将在原来的基础上增加一个字。值得注意的是,使用*(1k)寻址方式的指令不能与循环指令(RPT,RPTZ)一起使用。
3.1.3 累加器寻址
累加器寻址是将累加器的内容作为地址去访问程序存储器单元,即将累加器中的数作为地址,用来对存放数据的程序存储器寻址。有两条指令可以采用累加器寻址。
(1)READA Smem
把累加器 A 所确定的程序存储器单元中的一个字,传送到单数据存储单元(Smem)所确定的数据存储单元中去。
(2)WRITA Smem
把Smem所确定的数据存储单元中的一个字,传送到累加器A所确定的程序存储器单元中。
以上两条指令,在重复方式下执行,可以用来每次对累加器A的内容增加1。注意:对不同的TMS320C54x芯片,有的使用累加器的低16位作为程序存储器的地址,也有的使用低23位(如’C548、’C549)来作为程序存储器的地址。
3.1.4 直接寻址
直接寻址是利用数据指针和堆栈指针寻址,其特点是数据存储器地址由基地址(数据页指针DP或堆栈指针SP)和偏移地址共同构成,共16位。基地址位于数据存储器地址的高9位,偏移地址位于数据存储器地址(dmad)的低7位。图3.1.1和表3.1.3分别给出了直接寻址的指令代码的格式以及各位的说明。

图3.1.1 直接寻址指令代码的格式
表3.1.3 直接寻址的各位说明

DP和SP都可以与dmad偏移结合产生实际的地址。位于状态寄存器ST1的CPL位(直接寻址编辑方式)可以选择采用哪种方式生成实际地址。
① 当CPL=0,以数据页指针寄存器DP中的9位为高位,以指令中的7位(dmad)为低位,共同构成16位数据存储单元的地址,如图3.1.2所示。

图3.1.2 CPL=0时,16位数据存储单元的地址
② 当CPL=1时,将堆栈指针SP的16位地址与指令中的7位地址相加,形成16位的数据存储器地址,如图3.1.3所示。

图3.1.3 CPL=1时,16位数据存储单元的地址
因为DP地址的范围是从0~511(29-1),所以以DP为基准的直接寻址把存储器分成512页。7位dmad的范围是从0~127,所以每页有128个可以访问的单元,即由DP值确定是512页中的哪一页,由 dmad 确定是该页中的哪一个单元。DP 值可以由 LD 指令装入,RESET 指令将DP赋为0。重新上电以后,所有程序都需要对数据页指针DP进行初始化。
SP 可以指向存储器中的任意一个地址。dmad 可以指向当前页中具体的单元,从而允许访问存储器任意基地址中连续的128个单元。
3.1.5 间接寻址
间接寻址是利用辅助寄存器的内容作为地址指针来访问存储器。TMS320C54x 有 8 个 16位辅助寄存器(AR0~AR7)。每个寄存器都可以用来寻址64千字数据存储空间中的任何一个单元。两个辅助寄存器算术运算单元(ARAU0和ARAU1)可以根据辅助寄存器的内容进行操作,完成16位无符号数算术运算。
间接寻址的灵活性体现在:不仅能从存储器中读或写一个单16位的数据操作数,而且能在一条指令中访问两个数据存储单元(即从两个独立的存储器单元读数据,或读一个存储器单元的同时写另一个存储器单元,或读/写两个连续的存储器单元)。
1.单操作数寻址
图3.1.4列出了单操作数间接寻址指令的格式, 指令位的说明见表3.1.4。

图3.1.4 单操作数间接寻址指令的格式
表3.1.4 单操作数间接寻址指令的各位说明

表3.1.5列出了16种单操作数间接寻址的功能及其说明。
表3.1.5 单操作数间接寻址的功能及其说明

注:① 寻址16位字时增/减量为1,32位字时增/减量为2;
② 这种方式只能用写操作指令;
③ 这种方式不允许对存储器映像寄存器寻址。
表3.1.5中还有两种特殊的间接寻址方式:循环寻址方式和位倒序寻址方式,下面逐一进行介绍。
(1)循环寻址
在信号处理常用的卷积、相关、FIR滤波算法中,都需要在存储器中实现一个循环缓冲区,它是一个包含最新数据的滑动窗口。在寻址计算过程中,新进来的数据会覆盖较早的数据。循环寻址是实现循环缓冲区的关键。循环缓冲区的长度值由循环缓冲区长度寄存器(BK)确定。长度为R的循环缓冲区必须从N位地址的边界开始,其中N是满足2N>R的最小整数,即循环缓冲区基地址的N个最低有效位必须是0。例如,长度R=32的循环缓冲区必须从地址xxxx xxxx xx0000002(N=6,26>32)开始,且这32个值必须装入循环缓冲长度寄存器BK中。
循环缓冲区的有效基地址(EFB)就是用户选定的辅助寄存器(ARx)的低N位置0后所得到的值。循环缓冲区的尾基地址(EOB)是通过用BK的低N位代替ARx的低N位得到。循环缓冲区的index就是ARx的低N位,步长(step)就是加到辅助寄存器或从辅助寄存器中减去的值。循环寻址的算法为:
If 0 ≤ index+step < BK; index = index + step Else if index+step ≥ BK; index = index +step - BK Else if index+step < 0; index = index + step + BK
上述循环寻址算法,实际上是以BK寄存器中的值为模的取模运算。
循环寻址时,首先要指定一个辅助寄存器ARx指向循环缓冲区,循环缓冲区的最低地址应当置于2N的边界(2N大于循环缓冲区的长度)且步长应小于或等于循环缓冲区的长度。
(2)位倒序寻址
位倒序寻址可以提高FFT等算法的效率。例如16点FFT的位倒序寻址见表3.1.6。
表3.1.6 位倒序寻址

由表3.1.6可知,如果按照位倒序的方式寻址,就可以将乱序的结果整序。要达到这一目的,在’C54x中是非常方便的。为简化起见,假设辅助寄存器都是8位字长,AR1中存放数据存储器的基地址(011000002),指向X(0)的存储单元。设定AR0中的值为000010002(是FFT长度的一半)。再利用以下两条指令,可以将整序后的FFT变换结果从外设端口PA输出:
RPT #15 PORTW *AR1+0B,PA
2.双操作数寻址
双操作数寻址用于完成执行2次读操作或者1次读和1次并行存储操作(用‖表示)。这些指令代码都是1个字长,而且只能以间接寻址方式进行操作。
两个数据存储器操作数由Xmem和Ymem表示(见表3.1.1)。Xmem是读操作数,Ymem在读两个操作数时表示读操作数,在1次读同时并行1次写的指令中表示写操作。
如果在并行存储指令中(例如ST‖LD),源操作数和目的操作数指向相同的位置时,则写到目的地址以前进行读操作;如果双操作数指令(例如ADD)指向具有不同寻址模式的同一个辅助寄存器时,则用Xmod所定义的方式进行寻址。
图3.1.5和表3.1.7分别列出了双操作数寻址指令代码的格式以及各位的说明。

图3.1.5 双操作数寻址指令代码的格式
表3.1.7 双操作数寻址的各位说明

由于只有2位可以用于选择辅助寄存器,所以根据Xar或Yar的值可以选择4个寄存器。例如AR2~AR5,表3.1.8列出了Xar或Yar值同辅助寄存器的对应关系。
表3.1.8 Xar或Yar值同辅助寄存器的对应关系

表3.1.9列出了双操作数间接寻址的类型。
表3.1.9 双操作数间接寻址的类型

3.1.6 存储器映像寄存器寻址
存储器映像寄存器(MMR)寻址用于修改存储器映像寄存器的值,而不影响当前数据页指针(DP)或堆栈指针(SP)的值。由于DP和SP的值不需要修改,所以写寄存器操作的开销最小。存储器映像寄存器寻址可以工作在直接和间接寻址方式下。有以下两种产生MMR地址的方法。
① 在直接寻址方式下,高9位数据存储器地址被置0(不管当前DP或SP的值如何),利用指令中的低7位地址访问MMR。
② 在间接寻址方式下,高9位数据存储器地址被置0,按照当前辅助寄存器中的低7位地址访问MMR。访问结束后,辅助寄存器的高9位被强制置0。
有8条指令可以进行存储器映像寄存器寻址,即
LDM MMR,dst MVDM dmad,MMR MVMD MMR,dmad MVMM MMRx,MMRy POPM MMR PSHM MMR STLM src,MMR STM #1k,MMR
3.1.7 堆栈寻址
系统堆栈用于在发生中断或子程序调用时自动存放程序计数器(PC)中的值。堆栈也能用来保护现场或传送参数。’C54x的堆栈是从高地址向低地址方向填入的。处理器使用一个16位堆栈指针(SP)来对堆栈进行管理,SP始终指向存放在堆栈中的最后一个元素。有4条指令使用堆栈寻址方式:
● PSHD,将数据存储器中的一个数压入堆栈;
● PSHM,将一个存储器映像寄存器(MMR)中的值压入堆栈;
● POPD,从堆栈弹出一个数到数据存储单元;
● POPM,从堆栈弹出一个数到存储器映像寄存器(MMR)。
执行压入堆栈操作时,是先减小 SP 后再将数据压入堆栈的;而执行堆栈弹出操作时,则是先从堆栈弹出数据,然后再增加SP的值。