DSP技术与应用实例
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第3章 TMS320C54x指令系统

TMS320C54x的助记符指令是由操作码和操作数两部分组成的。在汇编前,操作码和操作数都是用助记符表示的。例如:

            LD  #0FFH,A

的执行结果是将立即数0FFH传送至累加器A中。

3.1 寻址方式

TMS320C54x提供了7种基本的数据寻址方式。

3.1.1 立即数寻址

立即数寻址方式指令中有一个固定的立即数。在立即数寻址中,指令包括立即操作数。在一条指令中可有两种立即数:一种是短立即数(3,5,8或9位),另一种是16位的长立即数。立即数可以包含在单字或双字指令中,3,5,8或9位的立即数包含在单字指令中,16位的立即数包含在双字指令中。在一条指令中,立即数的长度是由所使用的指令的类型决定的。表3-1中列出了可以包含立即数的各条指令,并且指出了该指令中立即数的位数。

表3-1 支持立即数寻址的指令

立即数寻址的语法中有一点需要注意,应在数值或符号前面加一个“#”号表示是一个立即数,否则会被认为是一个地址。例如,把立即数0F0H装入累加器A中,其正确的指令为:

            LD  #0F0H,A

如果漏掉了“#”号,指令“LD 0F0H,A”就变成了把地址0F0H单元中的数装载到累加器A中去。另外,如果在#0F0H中不加第一个0,编译将提示错误信息。对于9FFF以上的十六进制数据,其前面必须加0,以表明是立即数。

下面两个例子用RPT指令来说明立即数寻址。

【例3-1】

            RPT  #99            ;将紧跟在RPT后面的下一条指令循环执行100次

在这个例子中,操作数是短立即数,与操作码在同一字中。

【例3-2】

            RPT  #0FFFFH        ;将紧跟在RPT的下一条指令循环执行10000H次

操作数是16位长立即数的双字指令,操作码占一个字,操作数紧跟其后也占一个字。

3.1.2 绝对地址寻址

绝对地址寻址方式指令中有一个固定的地址,指令按照此地址进行数据寻址。绝对地址的代码为16位,所以包含绝对地址寻址的指令至少有两个字长。绝对地址寻址有以下4种类型。

1.数据存储器地址寻址

数据存储器地址(dmad)寻址就是用程序标号或数据,来确定指令所需的数据空间的地址。例如,把数据空间DATA1标注的地址里的数复制到由AR2指向的数据存储单元中:

            MVKD  DATA1,*AR2

DATA1标注的地址就是一个dmad值。执行此指令的作用是将数据存储区单元的内容两两移动。应当注意的是,DATA1必须是程序中的标号,或者是一些DSP内部已经定义的单元。例如,将串口的接收数据送到指定单元中:

            MVDD DRR20,*AR2

这里,DRR20是内部已经定义的单元,其地址已经固定在存储区。

2.程序存储器地址寻址

程序存储器地址(pmad)寻址就是用一个符号或一个具体的数来确定程序存储器中的一个地址。例如,把用TABLE1标注的程序存储器单元中的一个字复制到AR2所指向的数据存储器单元中:

            MVPD  TABLE1,*AR2

TABLE1所标注的地址就是一个pmad值。程序存储器地址寻址基本上和数据存储器地址寻址一样,区别仅在于空间不同。

3.端口寻址

端口(PA)寻址就是用一个符号或一个常数来确定外部I/O口地址。例如,把一个数从端口地址为F2F0的I/O口复制到AR5指向的数据存储器单元中:

            PORTR  F2F0,*AR5

F2F0指的是端口地址。实际上,端口地址寻址只涉及两条指令,即端口读(PORTR)指令和端口写(PORTW)指令。

对于DSP片外的存储空间,也只有特定的两条指令WRITA和READA可以对其进行读或写,具体用法请参考累加器寻址方式。

4.* (1k)寻址

*(1k)寻址就是用一个符号或一个常数来确定数据存储器中的一个地址。例如,把地址为BUFFER的数据单元中的数装载到累加器A中:

            LD  *(BUFFER),A

*(1k)寻址的语法允许所有使用单数据存储器(Smem)寻址的指令,访问数据空间的任意单元而不改变数据页(DP)的值,也不用对AR进行初始化。当采用绝对寻址方式时,指令长度将在原来的基础上增加一个字。值得注意的是,使用*(1k)寻址方式的指令不能与循环指令(RPT,RPTZ)一起使用。

3.1.3 累加器寻址

累加器寻址方式将累加器内的当前值作为地址去访问该单元程序存储器。累加器的地址用累加器中的数作为一个地址,这种寻址方式可用来对存放数据的程序存储器寻址。只有两条指令(READA和WRITA)可以采用累加器寻址。

READA把累加器A所确定的程序存储器单元中的一个字,传送到Smem操作数所确定的数据存储器单元中。WRITA把Smem操作数所确定的数据单元中的一个字,传送到累加器A所确定的程序寄存器单元中。

3.1.4 直接寻址

直接寻址指令中的低7位是一个数据页内的偏移地址,而所在的数据页由数据页指针 DP 或SP决定。该偏移量加上DP和SP的值,决定了在数据存储器中的实际地址。

在直接寻址中,指令代码包含数据存储器地址的低7位。这7位作为偏移地址与DP或堆栈指针(SP)相结合,共同形成16位的数据存储器实际地址。虽然直接寻址不是偏移寻址的唯一方式,但这种方式的优点是每条指令代码只有一个字。直接寻址的语法格式中,用一个符号或一个常数来确定偏移值。例如:

            ADD  SAMPLE,A           ;把存储器单元SAMPLE中的内容加到累加器A中去

            ADD  @x,A               ;将符号@加在变量x的前面

地址SAMPLE的低7位放在指令字中。图3-1所示为使用直接寻址方式的指令代码的格式。表3-2中给出了使用直接寻址方式的指令代码各位的说明。

图3-1 使用直接寻址方式的指令代码的格式

表3-2 使用直接寻址方式的指令代码各位的说明

图3-2所示为直接寻址的方框图,DP和SP都可以与dmad值(图中的IR的低7位)相结合产生实际地址,位于状态寄存器ST1中的编译方式位(CPL)决定了选择哪种方式来产生实际地址。

图3-2 直接寻址的方框图

CPL=0dmad值与9位的DP值结合,形成16位的数据存储器地址。

CPL=1dmad值加上(正偏移)SP的值,形成16位的数据存储器地址。

如果选择DP和dmad值相结合产生实际地址,必须将状态寄存器ST1中的编译方式位(CPL)清零,指令寄存器(IR)中的低7位的dmad值与9位的DP值连接在一起形成实际地址,如图3-3所示。

图3-3 以DP为基准的直接寻址

因为DP值的范围为0~511(1~29),所以以DP为基准的直接寻址方式把存储器分成512页。7位的dmad值的变化范围为0~127,每页有128个可访问的单元。换言之,DP指向512页中的一页,dmad就指向了该页中的特定单元。访问第1页的单元0和访问第2页的单元0的唯一区别是DP值的变化。DP值可由LD指令装入。RESET指令将DP赋为0。注意:DP不能用上电进行初始化,在上电后它处于不定状态。所以,没有初始化DP的程序可能工作不正常,所有的程序都必须对DP初始化。

【例3-3】

                  LD       #x, DP       ;把立即数x送入状态寄存器ST0的DP位
                  LD       @u,A         ;把x页u存储单元中的内容装入到累加器中
                  ADD      @v,A         ;把x页v存储单元中的内容与累加器A中的内容相加

在以SP为基准的直接寻址中,如果选择SP和dmad值相结合产生实际地址,则必须将状态寄存器ST1中的编译方式位(CPL)置1。将指令寄存器中的低7位的dmad值作为一个正偏移与SP相加得到有效的16位数据存储器地址,如图3-4所示。

图3-4 以SP为基准的直接寻址

SP可以指向存储器中的任意一个地址。dmad可以指向当前页中一个确定的单元,从而允许访问存储器任意基地址中连续的128个字。

【例3-4】

                SSBX      CPL           ;对状态寄存器ST1的CPL置位,CPL=1
                  LD       @X1,A        ;SP指针加X1所形成的地址中的内容送累加器A中
                  ADD      @Y2,A        ;SP指针加Y2所形成的地址中的内容与累加器A中的值相加

由于DP与SP两种直接寻址方式是互相排斥的,当采用SP直接寻址后再次用到DP直接寻址之前,必须选用RSBX CPL指令对CPL清零。

3.1.5 间接寻址

间接寻址方式按照辅助寄存器中的地址访问存储器。在间接寻址中,64KW×16bit数据空间任意单元都可通过一个辅助寄存器中的16位地址进行访问。TMS320C54x有8个16位辅助寄存器(AR0~AR7),两个辅助寄存器算术单元(ARAU0和ARAU1),可以根据辅助寄存器的内容进行操作,完成无符号的16位算术运算。

间接寻址很灵活,不仅能从存储器中读或写一个单16位数据操作数,而且能在一条指令中访问两个数据存储器单元(即从两个独立的存储器单元读数据,或在读一个存储器单元的同时写另一个存储器单元,或读/写两个连续的存储器单元)。

1.单操作数寻址

单数据存储器操作数间接寻址指令的格式如图3-5所示,其各位说明如表3-3所示。

图3-5 单数据存储器操作数间接寻址指令的格式

表3-3 单数据存储器操作数间接寻址指令的各位说明

下面介绍表3-4中所用到的循环寻址和位倒序寻址。

2.循环寻址

在卷积、相关和FIR滤波等许多算法中,都需要在存储器中实现一个循环缓冲器。一个循环缓冲器就是一个包含最近数据的滑动窗口。当新的数据来到时,缓冲器就会覆盖最早的数据。循环缓冲器实现的关键是循环寻址的实现。循环缓冲器(BK)长度决定循环缓冲器的大小。大小为R的循环缓冲器必须从一个N位(N是满足2 NR的最小整数)边界开始,也就是说,循环缓冲器基地址的最低N位必须为0。R的值必须装入BK中。例如,含有31个字的循环缓冲器必须从最低5位为0的地址开始(即xxxxxxxxxxx000002),且31这个值必须装入BK中。又如,一个含有32个字的循环缓冲器必须从最低6位为0的地址开始(即xxxxxxxxxx0000002)。

表3-4 单数据存储器操作数的间接寻址类型

循环缓冲器的有效基地址(EFB)就是用户选定的辅助寄存器(ARx)的低N位清零后所得到的值。循环缓冲器的尾地址(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

图 3-6给出了 BK、辅助寄存器(ARx)、循环缓冲器的位地址和首地址,以及循环缓冲器的INDEX。对于一个需要8个循环缓冲单元的运算,循环指针在第一次的移动顺序是从1,2,3,4,5,6,7→8,第二次的移动顺序是从2,3,4,5,6,7→8→1,第三次的移动顺序是从3,4,5,6,7→8→1→2,依次下去,直到完成规定的循环次数。

3.位倒序寻址

位倒序寻址提高了执行速度和在FFT算法的程序中使用存储器的效率。在这种寻址方式中,AR0存放的整数N是FFT点数的一半,一个辅助寄存器指向一个数据存放的物理单元。当使用位倒序寻址方式把AR0加到辅助寄存器中时,地址以位倒序的方式产生,即进位是从左向右的,而不是从右向左。例如,以下为0110与1100以位倒序的方式相加:

假设辅助寄存器是8位的,AR2表示在存储器中数据的基地址01100000(二进制数),AR0的值为00001000(二进制数),下面给出在位倒序寻址中,AR2值的修改顺序和修改后的值:

图3-6 循环寻址的框图

            *AR2+0B    ;AR2=01100000  (第0值)
            *AR2+0B    ;AR2=01101000  (第1值)
            *AR2+0B    ;AR2=01100100  (第2值)
            *AR2+0B    ;AR2=01101100  (第3值)
            *AR2+0B    ;AR2=01100010  (第4值)
            *AR2+0B    ;AR2=01101010  (第5值)
            *AR2+0B    ;AR2=01100110  (第6值)
            *AR2+0B    ;AR2=01101110  (第7值)

开始时,AR2的值是01100000,第一次寻址在正常方式下应该是01100001,即在01100000的基础上加1,而位倒序方式不是加1,而是加上AR0的值,也就是

(0110 0000)+(0000 1000)

所以结果就是0110 1000。第二次寻址就是计算

(0110 1000)+(0000 1000)

结果就是0110 0100。依次计算。应当注意的是,这些计算都采用从左到右的计算顺序。

表3-5给出了索引步长的位模式和AR2的低4位的关系,其中包含位倒序寻址。

表3-5 位倒序寻址

4.双数据存储器操作数寻址

双数据存储器操作数寻址用在完成两个读,或一个读同时并行一个写存储的指令中。这些指令只有一个字长,且只能以间接寻址方式工作。用Xmem和Ymem代表这两个数据存储器操作数,Xmem表示读操作数,Ymem在读两个操作数时表示读操作数,而在一个读同时并行一个写的指令中表示写操作数。如果源操作数和目的操作数指向同一个单元,则在并行存储指令中(如ST||LD),读在写之前。如果一个双操作数指令(如ADD)指向同一辅助寄存器,且这两个操作数的寻址方式不同,那么就用Xmod所确定的方式来寻址。双数据存储器操作数间接寻址指令的格式如图3-7所示,其各位说明见表3-6。

图3-7 双数据存储器操作数间接寻址指令的格式

表3-6 双数据存储器操作数间接寻址指令代码的各位说明

表3-7中列出了由指令的Xar和Yar域选择的辅助寄存器。

表3-7 由指令的Xar和Yar域选择的辅助寄存器

表3-8中列出了双数据存储器操作数间接寻址的类型、更改域的值(Xmod和Ymod)、汇编器的语法及每种类型的功能。

表3-8 双数据存储器操作数间接寻址的类型

3.1.6 存储器映射寄存器寻址

存储器映射寄存器寻址用来修改存储器映射寄存器而不影响当前数据页指针(DP)或堆栈指针(SP)的值,以存储器映射寄存器中的修改值去寻址。因为DP和SP的值不需要改变,因此写一个寄存器的开销是最小的。存储器映射寄存器寻址既可以在直接寻址中使用,又可以在间接寻址中使用。在直接寻址方式下,让数据存储器地址的高9位清零,而不管DP或SP的值;在间接寻址方式下,只用当前辅助寄存器的低7位。例如,AR1是用来指向一个存储器映射寄存器,包含的值为FF25H。既然AR1的低7位是25H,且PRD的地址为0025H,那么AR1指向定时器周期寄存器。执行后,存放在AR1中的值为0025H。存储器映射寄存器寻址如图3-8所示。

图3-8 存储器映射寄存器寻址

只有以下8条指令可以使用存储器映射寄存器寻址:

            LDM      MMR,dst
            MVDM     dmad,MMR
            MVMD     MMR,dmad
            MVMM     MMRx,MMRy
            POPM     MMR
            PSHM     MMR
            STLM     src,MMR
            STM      #1k,MMR

但是,对于*ARx(1k),*+ARx(1k),*+ARx(1k)%,*(1k)等所表示的存储器映射寄存器不能使用该寻址方式,编译时,汇编器会给出警告性错误。

3.1.7 堆栈寻址

堆栈寻址方式把数据压入和弹出堆栈,按照后进先出的原则进行寻址。系统堆栈用来在中断和调用子程序期间自动存放程序计数器,也能存放额外的数据项或传递数据值。处理器使用一个16位的存储器映射寄存器的一个堆栈指针(SP),对堆栈寻址,它总是指向存放在堆栈中的最后一个元素。

共有以下4条指令使用堆栈寻址方式访问堆栈:

PSHD——把一个数据存储器的值压入堆栈;

PSHM——把一个存储器映射寄存器的值压入堆栈;

POPD——把一个数据存储器的值弹出堆栈;

POPM——把一个存储器映射寄存器的值弹出堆栈。

图3-9说明堆栈操作对堆栈指针(SP)的影响。

图3-9 堆栈操作对堆栈指针的影响

有很多操作或指令都会影响堆栈里的内容,在中断和调用子程序时,堆栈保存当前的PC值。影响堆栈的指令包括CALA[D],CALL[D],CC[D],INTR,TRAP,RET[D],RETE[D],RETEF[D],RC[D],FRAME等。