第5章 数据寻址
C54x DSP提供7种基本寻址方式。
■ Immediate addressing uses the instruction to encode a fixed value.
■ Absolute addressing uses the instruction to encode a fixed address.
■ Accumulator addressing uses an accumulator to access a location in program memory as data.
■ Direct addressing uses seven bits of the instruction to encode an offset relative to DP or to SP. The offset plus DP or SP determine the actual address in data memory.
■ Indirect addressing uses the auxiliary registers to access memory.
■ Memory-mapped register addressing modifies the memory-mapped registers without affecting either the current DP value or the current SP value.
■ Stack addressing manages adding and removing items from the system stack.
5.1 立即寻址
在立即寻址方式中,指令中包含有操作数,这种操作数有两类:
■ Short immediate values can be 3, 5, 8, or 9 bits in length.
■ Long immediate values are always 16 bits in length.
立即数可以放在单字长或双字长的指令中。3、5、8、9位的立即数放在下一个单字长的指令中,16位的立即数放在双字长的指令中。
放在指令中的立即数长度依赖于所使用的指令。表5-1列出了可以带立即数的C54x DSP指令字,同时,也列出了每种指令可以带立即的位数。
在立即寻址的语句中使用了一个”#“符号,这个符号后紧跟着一个数或一个符号,用以说明它是一个立即数。例如,要将80h装入累加器A中,可以写成:
LD #80h , A
图5-1用RPT指令来说明一个短立即数(#K)是如何放置在采用立即寻址的指令中的。在这条指令中,操作码放在指令的高半段,即单字长指令中的8~15位是操作码,剩下的部分就是立即数。
图5-2用RPT指令来说明一个长立即数(# 1k)是如何放置在采用立即寻址的指令中的。在这条指令中,操作码放在指令的高半段,即双字长指令中的0~15位是操作码,剩下的部分就是立即数。
5.2 绝对寻址
5.2.1 数据存储器地址(dmad)寻址
数据存储器地址(dmad)寻址使用一个特定值来说明数据空间的一个地址。
dmad寻址的语句用一个符号或一个数据来指明数据空间的一个地址。例如,要把数据空间中表示为SAMPLE的地址中的值复制到AR5指示的数据空间中的某个单元,可用以下语句:
MVKD SAMPLE, *AR5
在这个例子中,由SAMPLE指示的地址就是数据存储器地址(dmad)。
5.2.2 程序存储器地址(pmad)寻址
程序存储器地址(pmad)寻址使用一个特定值来说明程序空间的一个地址。
pmad寻址的语句用一个符号或一个数据来指明程序空间的一个地址。例如,要把程序空间中表示为TABLE的程序存储器单元中的值复制到由AR7指示的数据空间中的某个单元,可用以下语句:
MVPD TABLE, *AR7-
在这个例子中,由TABLE指示的地址就是程序存储器地址(pmad)。
5.2.3 口地址(PA)寻址
口地址(PA)寻址使用一个特定值来指定一个外部I/O口地址。
PA寻址的语句用一个符号或一个数值来指明口地址。例如,要把口地址为FIFO的I/O口的值复制到由AR5指示的一个数据存储个单元,可用写成:
PORTR FIFO, *AR5-
在这个例子中,FIFO指示口地址。
5.2.4 *(1k)寻址
*(1k)寻址用一个特定值来指定数据空间的一个地址。
*(1k)寻址的语句用一个符号或一个数值来指明数据空间的一个地址。例如,要把数据空间中地址为BUFFER的单元的内容装载到累加器A中,可以写成:
LD *(BUFFER) , A
*(1k)寻址的语句允许所有使用Smem寻址的指令去访问数据空间的任意单元,而不会改变DP值或初始化AR。当这种绝对寻址方式被使用时,指令的长度扩展一个字。例如,一个单字长的指令变成双字长指令或者一个双字长指令变成三字长指令。一个指令的啬影响了该指令在被延长的时隙中的可用性。
注意:使用*(1k)绝对寻址方式的指令不能和重复单指令(RPT, RPTZ)一起使用。
5.3 累加器寻址
累加器寻址用细加器中的值作为一个地址。这种寻址方式把程序存储器当作数据存储器来访问。
下面两条指令用累加器作为地址:
READA Smem
WRITA Smem
READA从累加器A指示的程序存储器单元中传送一个字到Smem指明的数据存储器单元中。
WRITA从Smem指示的一个数据存储器单元中传送一个字到累加器A指明的程序存储器单元中。
在重复的情况下,累加器A可以增加一个增量。
注意:C54x器件有不同的地址线,因此,程序存储器单元是由累加器的一些低位来指示的。
5.4 直接寻址
在直接寻址中,指令中包含有数据存储器地址(dma)的低7位。这7位dma作为偏移地址要和基地址结合起来形成16位的数据存储器地址主。基地址放在数据页指针DP中或堆栈指针SP中。采用这种寻址方式,不用改变DP或SP的值,就可以随意访问128个单元。
注意:直接寻址不是唯一的偏移量寻址,但是,这种方式的优点是它可将指令和地址放在单字中。
DP或SP可以和dma偏移量结合产生实际地址。在䍽寄存器ST1中的编译模式位(CPL)可选择用哪一种方法来产生地址。
When CPL = 0, the dma field is concatenated with the 9-bit DP field to form the 16-bit data-memory address.
When CPL = 1, the dma field is added (positive offset) to SP to form the 16-bit data-memory address.
直接寻址的语句用一个符号或一个数据来说明偏移量。例如,要把存储单元SAMPLE中的内容加到累加器B中,假设正确的基地址在DP(CPL=0)中或SP(CPL=1)中,指令可以写成:
ADD SAMPLE,B
SAMPLE地址的低7位存放在指令字中。
图5-3列出了使用直接寻址方式的指令的操作码格式。表5-2描述了直接寻址指令中各位的作用。图5-4描述了16位数据地址是如何形成的。
5.4.1 以数据页指针(DP)为基准的直接寻址
在以数据页指针(DP)为基准的直接寻址方式中,指令寄存器的7位dma与9位DP气拼接起来形成地址。图5-5所示说明了这两个值是如何组成最后地址的。
以DP为基准的直接寻址把存储器分成512页,这是因为DP的范围是0~511(即$2^9-1$)。由于dma的范围是0~127(即$2^7-1$),所以每一页有128个可寻址的单元。换句话说,DP指示2个128字的数据页中某一页,dma指出这一页中的某个特定单元。对第一页中的0单元访问和对第2页中的0单元访问的唯一不同是DP的值不一样。DP由LD指令来装载。
5.4.2 以堆栈指针(SP)为基准的直接寻址
在以SP为基准的直接寻址方式中,指令寄存器的7位dma作为一个正偏移量加到SP上形成有效的16位数据存储器地址。图5-6所示说明了这两个值是如何结合形成最后地址的。
SP指出存储器中的任意地址,dma指出这一页中的特定单元。允许访问一个存储器中从任意基地址开始的连续128(即2^7)个字的存储块。SP可以向堆栈中增加或称出数据项。
5.5 间接寻址
在间接那封方式中,64KB数据空间的任意单元都可以通过存在辅助寄存器中的16位地址进行访问。C54x DSP有8个16位的辅助寄存器(AR0~AR7)。间接寻址主要用于以固定步长顺序访问连续存储器单元的情况。
当存储器以间接方式寻址时,辅助寄存器和地址可以有选择地进行减量、增量、偏移或变址的修改。特殊模式还可以提供循环和位反转寻址。循环缓冲容量寄存器(BK)用于循环寻址。AR0除了可以像其它辅助寄存器一样使用外,还可以用于变址寻址和位反转寻址方式中。
间接寻址方式很灵活,不仅可以用一条指令从存储器读或写一个16位的数据操作数,而且可以用一条指令存取两个数据存储器单元。两个数据存储器单元的存取包括两个独立存储器单元的读、两个连续的存储器单元的读和写、一个存储器单元的读组合另一个存储器单元的写。
5.5.1 单操作数寻址
图5-7所示说明了单个数据存储器操作数(Smem)的间接寻址指令格式。表5-3描述了该指令各位的情况。
5.5.2 辅助寄存器算术单元(ARAU)和地址产生操作
两个辅助寄存器算术单元(ARAU0和ARAU1)对辅助寄存器的内容进行操作。这两个ARAU完成无符号的16位辅助寄存器的算术操作。某些地址可以通过预先修改辅助寄存器的值来获得。
以下操作可以对辅助寄存器进行装载:
Loaded with an immediate value using the STM instruction
Loaded via the data bus by writing to the memory-mapped auxiliary registers
Modified by the indirect addressing field of any instruction that supports indirect addressing
Modified by the modify auxiliary register (MAR) instruction
Used as loop counters using the BANZ[D] instruction
注意:Typically, STM or MVDK is used to load auxiliary registers. Both of these instructions allow the next instruction to use the new value in the register. Other instructions that load a new value into an AR produce a pipeline latency.
图5-8所示说明了用来产生地址的ARAU,此时使用的是单数据存储器操作数的间接寻址方式。如图所示,在间接寻址中,主要用来产生地址的部件是辅助寄存器算术(ARAU0和ARAU1)和辅助寄存器(AR0~AR7)。
5.5.3 单操作数地址的修改
用户可以修改指令中使用的地址,修改可以在该地址被存取之前或之后进行,也可以不修改地址。用户可以按步长"1"对地址增量或减量,或加16位偏移量,或用AR0中的值变址。这3种操作可在存取完成之前或之后进行,再加上不修改地址的情况,一共可以形成16种寻址方式,每一种方式都设定了一个相应的MOD值,MOD是使用间接寻址的指令编码中修改方式字段。
表5-4列出了单数据存储器操作数寻址类型、MOD值、汇编语句和每一种类型的功能。
5.5.3.1 增量/减量地址修改(MOD=0、1、2或3)
当某个AR被使用时,用户可以通过增量或减量来修改该AR的值。几种修改AR的语句分别见表5-4的MOD=0、1、2或3中,包括不修改AR、存取后执行减量操作(减量为1)、存取后等等增量操作(增量为1)、存取前执行增量操作(增量为1)等形式。存取前增量操作(*+ARx)仅被那些在写操作中访问操作数的指令支持。
5.5.3.2 偏移地址修改(MOD=12或13)
偏移量寻址是一种间接寻址方式,在存取前就确定的一个偏移量或一个步长被加到辅助寄存器中。有两种类型的偏移量寻址,在这两种方式中,指令的一部分是一个6位的长偏移量,它被加到辅助寄存器的值上,所得结果用来访问数据存储器的一个单元。在第一种情况中,辅助寄存器的内容不改变;在第二种情况中,辅助寄存器变为新的地址。
偏移量寻址在访问数组或结构中的一个元素时很有用,特别是辅助寄存器不修改的方式。当辅助寄存器修改时,这种特别适用于以固定步长去访问一个数组。
ARx修改或不修改的偏移量寻址方式的语句分别见表5-4中的MOD=12或13。
注意:(1)使用偏移量寻址的指令不能用重复指令进行重复操作。
(2)存取前采用16位字偏移量修改ARx的操作(*+ARx(1k))要附加周期,这是因为指令码有2个字或3个字长,最后一个字是偏移量。
5.5.3.3 变址地址修改(MOD=5或6)
变址寻址是一种间接寻址方式,在这种方式中,AR0的值可以回到任意一个其它的辅助寄存器ARx中去,或从任意一个其它的辅助寄存器ARx中减去AR0的值。变址寻址不同于偏移量寻址,在变址寻址中,变址或步长在代码执行过程中才能被确定。因为变址是在代码执行过程决定的,所以,用户可以很容易地调整步长。变址寻址比偏移量寻址多一个优点,就是指令不需要多增加一个附加字长。
从ARx中减去AR0和AR0加到ARx中去的语句分别见表5-4中的MOD=5或6。
5.5.3.4 循环地址修改(MOD=0、9、10、11或14)
许多算法,如卷积、相关和FIR滤波都需要存储器中实现一个循环缓冲器。在这些算法中,一个循环缓冲器就是一个包含当前数据的滑动窗口,当新数据进入时就覆盖掉旧数据。实现这样一个循环缓冲器的关键是实现循环寻址。
循环缓冲器容量寄存器(BK)说明循环缓冲器的容量大小。一个容量为R的循环缓冲器必须从N位边界开始(也就是说,循环缓冲器的苦地址的最低N位必须是0)。其中N是满足$2^N > R$的最小的号数。R值必须装入BK,例如,一个31个字长的循环缓冲器必须从最低5位是0的地址开始(就是xxxx xxxx xxx0 $0000_2$),并且必须存入BK。第二个例子,一个32字长的循环缓冲器必须从最低6位是0的地址开始(就是xxxx xxxx xx00 $0000_2$),并且32必须存入BK。在一些应用中,也许可以使用位反向寻址将一个$2^N$的缓冲器放在$2^N$边界,并且提供循环寻址的效果。
确定循环缓冲器的有效基地址(EFB)的方法是将用户选择的辅助寄存器(ARx)的最低N位清零。确定循环缓冲器的结束地址(EOB)的方法是用BK中的最低N位替换ARx的最低N位。循环缓冲器的变址(index)就是ARx的最低N位并且步长(step)是往辅助寄存器中加或减的量化值。使用循环缓冲器应遵守以下3条规则:
Place the first (lowest) address of the circular buffer on a $2^N$ boundary where $2^N$ is larger than the circular buffer size.
Use a step less than or equal to the circular buffer size.
The first time the circular queue is addressed, the auxiliary register must point to an element in the circular queue.
循环寻址的算法如下:
循环寻址可以用来进行单数据存储器操作数或双数据存储器操作数寻址。当BK为0时,循环修改量导致没有循环地址的修改。这一点特别适用于当一个双操作数必须进行等效于ARx+0的地址修改。
图5-9所示为各部分的关系图,包括BK、辅助寄存器(ARx)、循环缓冲器的底端、顶端和指向循环缓冲器的变址。
图5-10所示说明了循环缓冲器是如何实现的,并且说明了产生的值和循环缓冲器中的单元关系。
循环缓冲器典型的应用是步长为1的增量或减量(MOD=8和10)和步长为变址量的增量或减量(MOD=9和11)。由于存取前用一个16位字位移量(*ARX(1k)%)进行的修改要求附加一个字,所以这时的指令码就是2字长或3字长,且最后一个字是偏移量。一条采用间接的偏移量寻址的指令不能用单重复操作指令来重复。
这5种类型的循环寻址语句见表5-4中的MOD=8、9、10、11或14。
5.5.3.5 位反向地址修改(MOD=4或7)
位反向寻址加强了采用不同基数的FFT算法的执行速度和程序存储器。在这种寻址方式中,AR0指明了FFT点数的一半,AR0中包含的值必须等于$2^{N-1}$,其中N是整数,FFT的点数是2N。一个辅助寄存器指向数据的物理单元。当用户采用位反向寻址将AR0加到辅助寄存器中时,产生的地址是位反向形式,进位从左向右传播,而不是正常地从右向左传播。
两种位反向寻址方式的语句分别见表5-4中的MOD=4或7。
假设辅助寄存器是8位长,AR2表示存储器中数据的基地址($01100000_2$),并且AR0存的值为($00001000_2$),例5-1说明了AR2一系列的修改情况及最后AR2中的值。
表5-5所示为变址操作每一步的位模式和AR2最低4位的关系。AR2包含位反向地址。
5.5.4 双操作数地址修改
有些指令可以同时完成两个读操作,或者一个读和一个并行存储(用两条平行的竖线表示,即||)操作,这种指令要使用双数据存储器操作数寻址。这些指令都是一个字长并且只能用间接寻址模式操作。两个数据存储器操作数用Xmem和Ymem表示。
Xmem is a read operand with access through the D bus. Store instructions, for example STH and STL with shift operation, change Xmem to a write operand.
Ymem is used as a read operand in instructions with dual reads (accessed through the C bus) or as a write operand in instructions with a parallel store (accessed through the E bus).
在带有并行存储的指令中(如ST||LD),如果源操作数和目标操作数指向同一个单元,源操作数先读,然后再写目标操作数。如果一条双操作数指令(如ADD)的两个操作数用不同的寻址方式指向同一个辅助寄存器,那么按Xmod字段定义的模式来寻址。
图5-11所示为采用间接寻址的双数据存储器操作数指令格式。表5-6说明了指令中各位的功能。
因为在这种方式中,只有两位用来选择辅助寄存器,所以只能用到4个辅助寄存器AR2~AR5。表5-7说明了如何用Xar或Yar来选择辅助寄存器。
图5-12所示说明了使用双数据存储器操作数寻址是如何产生地址的。
双数据存储器操作数寻址用4个辅助寄存器AR2~AR5,两个ARAU和这些寄存器一起可以在单周期内访问两个操作数。
表5-8列出了双数据存储器操作数寻址的类型,以及每种类型修改字段的值(Xmod或Ymod)、汇编语句和功能。
在每种情况下,辅助寄存器的内容作为数据存储器操作数。当辅助寄存器中的地址用过之后,ARAU对它进行相应的算术运算。若禁止循环修改,就不可能进行变址寻址或相当于*ARx+0的寻址。将BK清零就可以禁止循环修改。
注意:在执行双操作数读的指令中,如果由Yar字段说明的辅助寄存器访问一个存储器映射寄存器,那么读的值不代表该寄存器的内容。
5.5.4.1 双操作数增量/减量地址修改(Xmod或Ymod=0、1或2)
用户可以用增量或减量来修改AR的值。当Xmod或Ymod=0时,ARx作为不带有增量或减量操作的数据存储器地址。当Xmod或Ymod=1时,在存取进行之后,ARx要进行减量操作。当当Xmod或Ymod=2时,在存取进行之后,ARx要作增量操作。
5.5.4.2 双操作数变址地址修改(Xmod或Ymod=3且BK=0)
当Xmod或Ymod=3且BK=0时,在每次存取结束之后,AR0加到ARx上。否则,双操作数变址寻址就同5.5.3.3中描述的一样。
5.5.4.3 双操作数循环寻址修改(Xmod或Ymod=3且BK≠0)
当Xmod或Ymod=3且BK≠0时,在每次存取结束之后,使用循环寻址将AR0加到ARx中。否则,双操作数循环寻址就同5.5.3.4中描述的一样。
5.5.4.4 使用双操作数格式的单操作数指令
有些指令只有一个数据存储器操作数,但是用了双数据存储器操作数寻址,因此它们适合单周期执行的单字格式。在这些指令中,只有Xmem有效,并且由Xmod和Xar字段确定操作数的寻址模式。以下4条单操作数指令可以在一个单周期内执行:
BIT Xmem, BITC
SACCD src, Xmem, cond
SRCCD Xmem, cond
STRCD Xmem, cond
以下5条带有移位选项的指令也支持这种单字周期执行的寻址方式:
ADD Xmem, SHFT, src
LD Xmem, SHFT, dst
STH src, SHFT, Xmem
STL src, SHFT, Xmem
SUB Xmem, SHFT, src
5.5.5 兼容(ARP)模式
ARP可以用于间接寻址,这就允许由ARP定义AR以简化TMS320C20x、TMS320C24x或TMS320C5x败类器件的代码转换。当CMPT=1且ARF=0时,ARP用来指示用哪一个AR来寻址存储器。图5-13所示说明了ARP是如何指示辅助寄存器的。
在使用ARP时,C54x器件与C5x是不同的。娄C54x器件使用ARP来指示AR时,该器件并不用同一条指令修改ARP。表5-9所示为C54x与C20x、C24x和C5x器件的汇编语句的比较。
图5-14所示为ARP模式的间接寻址指令格式。表5-10描述了ARP模式指令位的功能。
注意:当DSP在标准模式时(CMPT=0),ARP必须总设置为0。在复位时,ARP和CMPT自动设置为0。
5.6 存储器映射寄存器寻址
存储器映射寄存器寻址用来修改存储器映射寄存器,而不会影响当前的数据页指针(DP)的值或当前堆栈指针(SP)的值。因为在这种模式中,DP和SP都不必修改,所以对寄存器进行写操作的附加开销最小。存储器映射寄存器寻址可用于直接和间接寻址。
图5-15所示说明了存储器映射地址是如何产生的,有如下方法:
Forcing the nine most significant bits (MSBs) of data-memory address to 0, regardless of the current value of DP or SP when direct addressing is used
Using the seven LSBs of the current auxiliary register value when indirect addressing is used
注意:在间接寻址中,辅助寄存器的高9位在操作之后被强制清零。
例如,在存储器映射寄存器寻址方式中,如果AR1指向一个存储器映射寄存器且它的值为FF25h,那么AR1指向定时器周期寄存器(PRD),因为AR1最低7位是25h,贿PRD的地址就是0025h。操作执行完后,保留在AR1中的值是0025h。
注意:除了寄存器,数据0页中的任意便笺式RAM单元都可以用存储器映射寄存器寻址来修改。
只有以下8条指令可以用存储器映射寄存器寻址:
LDM MMR, dst
MVDM dmad, MMR
MVMD MMR, dmad
MVMM MMRx, MMRy
POPM MMR
PSHM MMR
STLM src, MMR
STM #lk, MMR
注意:下列间接寻址模式不允许用于存储器映射寄存器寻址:
*ARx(lk)
*+ARx(lk)
*+ARx(lk)%
*(lk)
在这些情况下,汇编会产生警告。
5.7 堆栈寻址
系统堆栈在中断和调用子程序时自动存储程序计数器的值,它也可以用来存放用户希望的额外的现场信息或传送数据值。堆栈存入信息是从最高端地址向最低端地址移动的。处理器用一个6位存储器映射寄存器,即堆栈指针(SP))来寻址堆栈。SP总是指向最后存入堆栈的元素。
下面4条指令用堆栈寻址模式访问堆栈:
PSHD pushes a data-memory value onto the stack.
PSHM pushes a memory-mapped register onto the stack.
POPD pops a data-memory value from the stack.
POPM pops a memory-mapped register from the stack.
压入堆栈操作之前要对SP中的地址作减量运算;弹出堆栈操作之后,要对SP中的地址作增量运算。图5-16所示为在X2压入堆栈(PSHD X2)前后堆栈和SP的状态。
其它一些操作也会影响堆栈和堆栈指针。在中断和调用子程序过程中,堆栈用来存入和恢复PC的内容。当调用一个子程序或一个中断发生时,返回地址会自动地存入堆栈中,调用子程序和中断的指令有CALAD[D]、CALL[D]、INTR和TRAP。
当一个子程序返回时,返回地址从堆栈中弹出,装入PC。用于子程序返回的指令有RET[D]、RETE[D]、RETEF[D]和RC[D]。
FRAME指令也能影响堆栈。这条指令将一个短立即数偏移量加到堆栈指针中。堆栈也可用于基于SP的直接寻址中。
5.8 存储器访问的数据类型
在C54x器件中存取存储器可用两种基本的数据类型:16位数据和32位数据。大多数指令可以存取16位数据,存取32位数据需要用特殊指令,这些特殊指令见表5-11。
对一个16位操作数的访问,一个16位字长的数据通过D总线从数据存储器中读出,通过E总线写入数据存储器。对一个32位操作数的访问,C总线(传送高位字)和D总线(传送低位字)都要用于读操作,只有E总线用于写操作,因此,写操作(DST指令)执行需要两个周期。
32位数据访问时,第一个访问字作为高位字(MSW),第二个访问字作为低位字(LSW)。如果第一个访问字是偶地址,那么第二个字就是下一个更高的地址。如果第一个访问字是奇地址,那么第二个字就放在前一个更低的地址。图5-17所示说明了这种效果。