收藏 分享(赏)

DSP原理及应用--TMS320C54x软件开发.ppt

上传人:tkhy51908 文档编号:7972881 上传时间:2019-06-01 格式:PPT 页数:99 大小:1.02MB
下载 相关 举报
DSP原理及应用--TMS320C54x软件开发.ppt_第1页
第1页 / 共99页
DSP原理及应用--TMS320C54x软件开发.ppt_第2页
第2页 / 共99页
DSP原理及应用--TMS320C54x软件开发.ppt_第3页
第3页 / 共99页
DSP原理及应用--TMS320C54x软件开发.ppt_第4页
第4页 / 共99页
DSP原理及应用--TMS320C54x软件开发.ppt_第5页
第5页 / 共99页
点击查看更多>>
资源描述

1、1,第5章 TMS320C54x软件开发,2,引言,软件开发包括两部分,程序的编写,两者混合,环境和工具,非集成,集成:CCS5000,Code Compose Studio 5000,程序,运行环境和工具,汇编,C/C+,3,5.1 软件开发过程及开发工具,一、软件开发过程 1、 TMS320C54x DSP软件开发流程,4,5,2、对流图作简要说明 (1)程序文件说明 C源程序(.c)和汇编源程序(.asm) COFF目标文件(.obj):不可执行 可执行的COFF文件(.out):可执行 COFF:Common Object File Format,6,(2)器件的说明 C编译器(C C

2、ompiler) 汇编器(Assembler) 连接器(Linker) 十六进制转换公用程序(Hex Conversion Utility) 归档器(Archiver),7,二、调试工具 1、软件仿真器(Simulator)2、硬件在线仿真器(Emulator) 3、评估模块(EVM板),用主机的处理器和存储器,DSP的微处理器和微计算机模式,仿真,8,三、代码生成工具,9,5.2 公共目标文件格式,一、COFF文件的基本单元段 COFF:Common Object File Format段:Sections 1、段的特点同一个段在存储器空间中占用的单元是连续的段之间相互独立,10,2、段的分

3、类,段,已初始化段,未初始化段,.text,.data,.sect,.bss,.usect,包含可执行代码,包含运行程序所需的数据,常为变量保存空间,11,3、两个命名段伪指令 命名段:自定义与.text;.data;.bss不同的段 伪指令:.sect;.usect 格式: 符号 .usect “段名”,字数.sect “段名”,段起点 说明:符号为指向保留空间的第一个字同一个程序中用.usect和.sect定义的段的段 名不能相同,12,例如: .bss x, 1 ; 定义全局变量x,并分配1个字存储单元 stack .usect “.mystack“,10; 自定义.mystack段,使

4、用前没有内容; 10个字的存储空间,首地址为stack,; 标号stack一定要顶格写 .text (表示以下为可执行代码,直到新段名为止) start:STM #stack+stacksize,SPPSHM ST0 ; PSHM ST1 ;,13,二、汇编器对段的处理 1、处理过程汇编器对段的处理是通过段伪指令确定汇编语言 程序的各个部分属于哪个特定的段,并将段名相同的 语句汇编在一起。汇编器有.bss;.usect;.text;.data;.sect五个汇编伪指令 来完成这种功能。注意:如果在程序中没有用任何的伪指令,则汇 编器将把所有的程序块或数据块统一汇编到.text段中。,14,2、

5、子段(Subsections)大段中的小段就是子段,采用小段可以使存储器图更加紧密。子段的命名语法:基段名:子段名 如:.sect “.text:_func” 3、段程序计数器(SPC)汇编器就是靠SPC来对段进行处理 处理过程: 为每个段分配一个SPC指向该段的当前位置,并置初始值0; 当汇编器将程序代码或数据加到一个段内时,相应的SPC加; 执行一段时间后当再次遇到相同的段,则SPC继续增加。,15,三、链接器对段的处理 1、链接器对段的处理任务 即根据程序情况进行段匹配,将所有程序的数据段组合,代码段组合等。 为输出段选择存储器地址。 2、完成以上任务的两条命令,16,链接器默认的存储器

6、分配,17,MEMORY PAGE 0:PRAM : o=100h, l=1f00h PAGE 1: DRAM : o=2000h, l=1000h ,18,SECTIONS .text : PRAM PAGE 0.data : PRAM PAGE 0.bss : DRAM PAGE 1.mystack : DRAM PAGE 1 ,19,四、程序装入 1、硬件仿真器和CCS集成开发环境,具有内部的装入器,调用装入器的LOAD命令即可装入可执行程序。 2、将代码固化在片外存储器中,采用Hex转换工具(Hex conversion utility),例如Hex500将可执行的COFF目标模块(.

7、out文件)转换成几种其他目标格式文件,然后将转换后的文件用编程器将代码写入EPROM/Flash。,20,五、 COFF文件中的符号 COFF文件中有一个符号表,用于存储程序中的符号信息。链接器对符号重定位时使用该表,调试工具也使用该表来提供符号调试。 外部符号指在一个模块中定义,在另一个模块中使用的符号。可使用.def、.ref或.global汇编伪指令将符号定义为外部符号。.def在当前模块中定义,可以在别的模块中使用的符号;.ref在当前模块中引用,但在别的模块中定义的符号;.global可用于以上任何一种情况。,21,例如: X: ADD #56h,A;B y;.def x ;在此模

8、块中定义,可以在别的模块 中使用的符号.ref y ;在此模块中引用,但在别的模块中 定义的符号,22,5.3 常用汇编伪指令,23,一、段定义伪指令为便于链接器将程序、数据分段定位于指定的(物理存在的)存储器空间,并将不同的obj文件链接起来。段的使用非常灵活,但常用以下约定: .text 此段存放程序代码 .data 此段存放初始化了的数据 .bss 此段存入未初始化的变量 .sect 名称 定义一个有名段,放初始化了的数据或程序代码,24,二、条件汇编伪指令条件汇编伪指令告诉汇编器按照表达式的计算结果对代码块进行条件汇编 .if expression 标志条件块的开始,仅当条件为真(ex

9、pression的值非0即为真)时汇编代码 .elseif expression 标志若.if条件为假,而.elseif条件为真时要汇编代码块 .else 标志若.if条件为假时要汇编代码块 .endif 标志条件块的结束,并终止该条件代码块,25,三、引用其他文件和初始化常数伪指令 .include 文件名 将指定文件复制到当前位置,其内 容可以是程序、数据、符号定义等。 .copy 文件名 与.include类似。 .def 符号名 在当前文件中定义一个符号,可以被其他文 件使用。 .ref 符号名 在其他文件中定义,可以在本文件中使用的符号。 .global 符号名 其作用相当于.def

10、、.ref效果之和。,26,.mmregs 定义存储器映射寄存器的符号名,这样就可以用AR0、PMST等助记符替换实际的存储器地址。 .float 数1,数2 指定的各浮点数连续放置到存储器中(从当前段指针开始)。 .word 数1,数2 指定的各数(十六进制)连续放置到存储器中。 .space n 以位为单位,空出n位存储空间。 .end 程序块结束。,27,四、宏定义和宏调用TMS320C54x汇编支持宏语言。如果程序中需要多次执行某段程序,可以把这段程序定义(宏定义)为一个宏,然后在需要重复执行这段程序的地方调用这条宏。 宏定义如下: Macname .macroparameter 1,

11、parameter n .mexit.endm 宏调用如下:Macname parameter 1,parameter n,28,例如:完成P3=p1+p2 Add2 .macro p1,p2,p3LD p1,AADD p2,ASTL A, p3.endm.global shu1,shu2,heAdd2 shu1,shu2,he,29,5.4 链接器命令文件的编写与使用,一、 MEMORY伪指令及其使用MEMORY伪指令就是用来指定目标存储器的模型。MEMORY伪指令的一般语法为:MEMORYPAGE 0:name1: (attr): origin=constant,length=consta

12、nt;PAGE n:namen : (attr): origin=constant,length=constant;,30,说明: PAGE 指定存储器空间页面,最多255个。通常PAGE 0用于程序存储器,PAGE 1用于数据存储器, PAGE 2用于I/O存储器,默认为PAGE 0。 name是存储器区间的取名,可由164个字符组成,包括A-Z、a-z、$、.、_ attr指定存储区的1-4种属性origin指定存储区的起始地址 length指定存储区的长度,31,二、 SECTIONS伪指令及其使用 SECTIONS伪指令功能如下: 说明如何将输入段组合成输出段。 在可执行程序中定义输出

13、段。 指定输出段在存储器中存放的位置。 允许对输出段重新命名。,32,SECTIONS 伪指令的一般语法为: SECTIONS name : property ,property ,property .name : property ,property ,property .name : property ,property ,property .,33,例如: File1.obj file2.obj -o prog.out SECTIONS .text:load=ROM,run=800h .const:load=ROM .bss:load=RAM ,34,命令文件应用举例: 例1: a.Ob

14、j b.obj c.obj -o prog.out -m prog.map MEMORY RAM:origin=100h length=0100hROM:origin=01000h length=0100h SECTIONS .text:ROM.data:RAM.bss:RAM ,35,例2: MEMORY PAGE 0:PRAM : o=100h,l=1f00h PAGE 1: DRAM : o=2000h,l=1000h SECTIONS .text : PRAM PAGE 0.data : PRAM PAGE 0.bss : DRAM PAGE 1.mystack : DRAM PAGE

15、 1 ,36,汇编语言程序以.asm为扩展名,可以用任意的编辑器编写源文件。一条语句占源程序的一行,长度可以是源文件编辑器格式允许的长度,但汇编器每行最多读200个字符。因此,语句的执行部分必须限制在200个字符以内。,一、汇编语言源程序格式,助记符指令源语句的每一行通常包含4个部分:标号区、 助记符区、操作数区和注释区。,标号: 助记符 操作数 ; 注释,助记符指令语法格式:,37,DIANZI .set 1 ; 符号DIANZI 1Begin: LD # DIANZI ,AR1 ; 将1加载到AR1,标 号,助记符,操作数,注 释,例1、 助记符指令源语句举例。,38,语句的书写规则:,

16、所有语句必须以标号、空格、星号或分号(*或;)开始; 标号是可选项,若使用标号,则标号必须从第一列开始; 所有包含有汇编伪指令的语句必须在一行完成指定; 各部分之间必须用空格分开,Tab字符与空格等效; 程序中注释是可选项。如果注释在第一列开始时,前面必须标上星号或分号,在其他列开始的注释前面必须以分号开头; 如果源程序很长,需要书写若干行,可以在前一行用反斜杠字符()结束,余下部分接着在下一行继续书写。,39,1.标号,所有汇编指令和大多数汇编伪指令都可以选用标号, 供本程序或其它程序调用。使用标号时应注意:, 标号必须从语句的第1列写起,其后的冒号“:”可任选; 标号为任选项,若不使用标号

17、,则语句的第一列必须是空格、星号或分号; 标号是由字母、数字以及下划线和美元符号等组成,最多可达32个字符; 标号分大小写,且第一个字符不能是数字。,在使用标号时,标号的值是段程序计数器SPC的当前值。 例如:若使用.word伪指令初始化几个字,则标号将指到第一个字。,40,2.助记符,助记符用来表示指令所完成的操作,可以是汇编语言指令、汇编伪指令、宏伪指令。,助记符指令:一般用大写,不能从第一列开始 ;,汇编伪指令:用来为程序提供数据和控制汇编进程。以句号“.”开始,且用小写;,宏伪指令:用来定义一段程序,以便宏调用来调用这段程序。以句号“.”开始,且用小写;,宏调用:用来调用由宏伪指令定义

18、的程序段。,41,3.操作数,操作数是指指令中参与操作的数值或汇编伪指令定义的内容,紧跟在助记符的后面,由一个或多个空格分开。, 操作数之间必须用逗号“,”分隔; 操作数可以是常数、符号或表达式; 操作数中的常数、符号或表达式可用来作为地址、立即数或间接地址;,作为操作数的前缀有三种情况: 使用“#”符号作为操作数的前缀; 使用“*”符号作为操作数的前缀; 使用“” 符号作为操作数的前缀。,42, 用“#” 作前缀,例如:Label: ADD # 99, B STM #X_SIN,AR1,使用“#”号作为前缀,汇编器将操作数作为立即数处理。即使操作数是寄存器或地址,也将作为立即数。如果操作数是

19、地址,汇编器将把地址处理为一个数值,而不使用地址的内容。, 用“*”作前缀,使用“*”符号作为前缀,汇编器将操作数作为间接地址,即把操作数的内容作为地址。,43, 用“”作前缀,例如:Label: LD x, A,使用“”符号作为前缀,汇编器将操作数作为直接地址,即操作数由直接地址码赋值。,只要DP=0,将直接地址x中的内容装入指定的累加器A中。,例如:Label: LD * AR3, B,操作数*AR3指定一个间接地址。该指令将引导汇编器找到寄存器AR3的内容作为地址,然后将该地址中的内容装入指定的累加器B中。,44,4.注释,用来说明指令功能的文字,便于用户阅读。, 注释可位于句首或句尾,

20、位于句首时,以“*”或“;”开始,位于句尾时,以分号“;”开始。, 注释是任选项; 注释可单独一行或数行;,11 00000 .bss sym, ; 保留空间于.bss* 改变段,允许第五个mylab定义 *,例如:,45,汇编程序中的符号用于标号、常数和替代字符。, 符号名最多可长达200个字符; 由字母、数字以及下划线和美元符号(AZ,az,09,_和$)等组成; 在符号中,第1位不能是数字,并且符号中不能含空格。,作为标号的符号代表在程序中对应位置的符号地址。通常,标号是局部变量,在一个文件中局部使用的标号必须是唯一的。助记符操作码和汇编伪指令名(不带前缀“.”)为有效标号。标号分大小写

21、。例如:ABC,Abc,abc是3个不同的符号。在调用汇编器时使用-c选项,可以不分大小写。,1. 标号,二、汇编语言中的符号,46,2. 符号常数,【例5.2】 定义符号常数举例。,N .set 512 buffer .set 4 * Nnzg1 .set 1nzg2 .set 2nzg3 .set 3item .struct .int nzg1.int nzg2.int nzg3tang .endstructarray .tag item .bss array,tang* N,;定义常数 ;item结构定义 ;常数偏移nzg1 = 1 ;常数偏移nzg2 = 2 ;常数偏移nzg2 = 3

22、 ;声明数组,符号也可被设置成常数值。为了提高程序的可读性,可以用有意义的名称来代表一些重要的常数值。,47,4. 替代符号,可将字符串值(变量)赋给符号,使符号名与该变量等效,成为字符串的别名,这种用来代表变量的符号称为替代符号。,当汇编器遇到替代符号时,将用字符串值替代符号。和符号常数不同,替代符号可以被重新定义。可在程序中的任何地方将变量赋给替代符号。,例如:.asg “high“,AR2 ;寄存器AR2,3.预先定义的符号常数,汇编器有若干预先定义符号,包括: 美元符号$,代表段程序指针SPC的当前值; 映像寄存器符号,包括AR0AR7; 映像寄存器由汇编器设置为符号,指定存储器模式,

23、由-mk选项设置。,48,5. 局部标号,局部标号是一种特殊的标号,使用的范围和影响是临时性的。,注意:局部标号不能用伪指令来定义。,定义方法: 用$n来定义。n是09的十进制数; 用NAME?定义。NAME是任何一个合法的符号名。,局部标号可以被取消定义,并可以再次被定义或自动产生。,取消局部变量的方法: 使用.newblock伪指令; 使用伪指令.sect,.text或.data改变段 ; 使用伪指令.include或.copy,进入include文件; 达到include文件的结尾,离开include文件。,49,三、汇编语言中的表达式,1.运算符及优先级(p72),2.有效定义的表达式

24、,某些汇编器要求有效定义的表达式作为操作数。操作数是汇编时间常数或链接时可重定位的符号。有效定义的表达式是指表达式中的符号或汇编时间常数在表达式之前就已经被定义。有效定义的表达式的计算必须是绝对的。,50,【例5.4】 有效定义的表达式。,.datalabel1 .word 0.word 1.word 2label2 .word 3X .set 50hgoodsym1 .set l00h + X goodsym2 .set $ goodsym3 .set label1 goodsym4 .set label2-label1,; 将16位值0,1,2放入标号为label1的当前段连续字中,; 有

25、效定义的表达式,; 引用已定义的所有局部标号,; 有效定义的表达式,; 定义X的值,; 将3放入标号为label2的字中,51,3. 表达式的溢出,汇编时执行了算术操作以后,汇编器检查上溢和下溢的条件。当出现上溢或下溢时,汇编器会发出一个值被截断了的警告。汇编器不检查乘法的溢出状态。,4. 表达式的合法性,表达式中使用符号时,汇编器对符号在表达式中的使用有一些限制,由于符号的属性不同(定义不同),使表达式存在合法性问题。符号的属性分为3种:外部的、可重定位的和绝对的。用伪指令.global定义的符号是外部符号;在汇编阶段和执行阶段,符号值、符号地址不同的符号是可重定位符号,相同的是绝对符号。含

26、有乘、除法的表达式中只能使用绝对符号。表达式中不能使用未定义符号。,52,5.6 TMS320C54x C语言编程,53,(1) 用汇编语言开发 此方式代码效率高,程序执行速度快,可以充分合理地利用芯片提供的硬件资源。但程序编写比较烦琐,可读性较差,可移植性较差,软件的修改和升级困难。,(2) 用C语言开发 CCS平台包括优化ANSI C编译器,从而可以在C源程序级进行开发调试,增强软件的可读性,提高了软件的开发速度,方便软件的修改和移植。然而,C编译器无法实现在任何情况下都能够合理地利用DSP芯片的各种资源。,C54x DSP软件设计的方法通常有三种:,(3) C语言和汇编语言混合编程开发

27、采用混合编程的方法能更好地达到设计要求,完成设计任务。,54,C语言具有如下基本特点: (1) 语言简洁、紧凑,使用方便、灵活。 (2) 运算符丰富,表达式类型多样化。 (3) 数据结构类型丰富,具有现代化语言的各种数据结构。 (4) 具有结构化的控制语句。 (5) 语法限制不太严格,程序设计自由度大。(6) C语言允许访问物理地址,能进行位操作,能实现汇编语言的大部分功能,能直接对硬件进行操作。,55,1 存储器模式C54x DSP定点处理器有两种类型的存储器模式:程序存储器和数据存储器。前者主要用于装载可执行代码,后者主要用于装载外部变量、静态变量、系统堆栈以及一些中间运算结果。C54x

28、DSP的程序代码或数据以段的形式装载于存储器中。C语言程序经C编译器编译后,生成七个可重定位的段,其中四个被称为已初始化段,三个被称为未初始化段。,一、 存储器模式及分配,56,四个已初始化段分别是: .text 包括可执行代码、字符串和编译器产生的常量。 .cinit 包括初始化变量和常量表。 .const 包括字符串常量和以const关键字定义的常量。 .switch 为.const语句建立的表格。,57,三个未初始化段分别是: .bss 保留全局和静态变量空间。在程序开始运行时,C的引导 (boot)程序将数据从.cinit段拷贝到.bss段。 .stack 为C的系统堆栈分配存储空间,

29、用于变量的传递。 .sysmem 为动态存储器函数malloc、calloc、realloc分配存储器 空间。若C程序未用到此类函数,则C编译器不产生该段。,注意:在编写链接命令文件(.cmd文件)时, .text、.cinit、.switch段通常可以链接到系统的ROM或者RAM中去,但是必须放在程序段(page0);.const段通常可以链接到系统的ROM或者RAM中去,但是必须放在数据段(pagel);而.bss、.stack和.sysmem段必须链接到系统的RAM中去,并且必须放在数据段(pagel)。,58,例1、某工程的链接命令文件(.cmd文件) MEMORY /* TMS320

30、C54x DSP存储器分配 */ PAGE 0 : HPIRAM: origin = 0x100, length = 0x200 PROG: origin = 0x2000, length = 0x1000 PAGE 1 : DARAM1: origin = 0x03000, length = 0x1000 PAGE 2 : FLASHRAM: origin = 0x8000, length = 0x7fff ,59,SECTIONS /* 由C 定义 */ .vectors : load = PROG page 0 /*中断向量表*/ .text : load = PROG page 0 /

31、*可执行代码*/ .cinit : load = PROG page 0 /*初始化变量和常数表*/ .switch : load = PROG page 0 /*为.constant语句建立的表格*/ .stack : load = DARAM1 page 1 /*C 系统堆栈*/ .const : load = DARAM1 page 1 /*字符串常量和以const关键字定义的常量*/ .bss : load = DARAM1 page 1 /*全局和静态变量空间*/ .dbuffer1024 : DARAM1 page 1, align (1024) .coeffs1024 : DAR

32、AM1 page 1, align (1024) .hpibuffer : load = HPIRAM page 0/*由汇编定义*/.data : DARAM1 page 1 /*汇编定义的数据段*/,60,2存储器分配 C编译器提供的运行支持函数中包含有几个允许在运行时为变量分配存储器的函数,如malloc、calloc和recalloc。动态分配不是C语言本身的标准,而是由运行支持函数所提供的。为全局pool和heap分配的存储器空间定义在.sysmem块中。.sysmem段的大小可由链接器选项中的-heap项来设定,其方法是在-heap项后加一个常数。与堆栈类似,连接器也创建一个全局符

33、号_SYSMEM_SIZE。.sysmem段的大小由_SYSMEM_SIZE的数值来确定,默认值为l K字。为了在.bss段中保留空间,对于大的数据,可以用heap为其分配空间,而不将它们说明为全局或静态的。,例如,对于原定义的:struct big table1000 可以改用指针并调用malloc函数来定义: struct big *table table=(struct big*)malloc(1000*sizeof(struct big);,61,(1) 静态和全局变量的存储器分配在C程序中,静态变量被分配一个惟一的连续空间,该空间的地址由链接器决定。编译器安排这些变量的空间被分配在若

34、干个字的长度中,以保证每个变量按字边界对准。全局变量分配到数据空间,在同一模块中定义的变量分配到同一个连续的存储空间。,(2) 域/结构的对准 C编译器在为结构分配存储空间时,它分配足够的字以包含所有的结构成员。一组结构中,每个结构开始于字边界。所有的非域类型对准于字的边界。对域应分配足够多的比特。相邻域应装入一个字的相邻比特,不能跨越两个字,否则整个域会被分配到下一个字中。,62,寄存器规则概括如下:(1) 辅助寄存器 ARl、AR6、AR7由被调用函数保护,即可以在函数执行过程中修改,但在函数返回时必须恢复。在C54x DSP中,编译器将ARl和AR6用作寄存器变量。其中,AR1被用作第一

35、个寄存器变量,AR6被用作第二个寄存器变量,其顺序不能改变。另外五个辅助寄存器AR0、AR2、AR3、AR4、AR5则可以自由使用,即在函数执行过程中可以对它们进行修改,不必恢复。(2) 栈指针SP 堆栈指针SP在函数调用时必须予以保护,但这种保护是自动的,即在返回时,压入堆栈的内容都将被弹出。,二、寄存器规则,63,(3) ARP 在函数进入和返回时,必须为0,即当前辅助寄存器必须为AR0,而函数执行时则可以是其他值。(4) OVM 在默认情况下,编译器总认为OVM是0。因此,若在汇编程序中将OVM置为1,则在返回C环境时,必须将其恢复为0。(5) 其他状态位和寄存器可以任意使用,不必恢复。

36、,64,(1) 参数传递 在函数调用前,将参数以逆序压入运行堆栈。所谓逆序,即最右边的参数最先压入栈,然后自右向左将参数依次压入栈,直至第二个参数入栈完毕。对第一个参数,则不需压入堆栈,而是放入累加器A中,由A进行传递。若参数是长整型和浮点数时,则低位字先压入栈,高位字后压入栈。若参数中有结构,则调用函数先给结构分配空间,而该空间的地址则通过累加器A传递给被调用函数。一个典型的函数调用图如图所示。在该例中,我们可以看出,参数传递到函数,同时该函数使用了局部变量并调用另一个函数。第一个参数不由堆栈传递,而是放入累加器A中传递。(如图 (b)、图 (c)所示)。,三、函数调用规则,65,(2) 被

37、调用函数的执行过程 被调用函数依次执行以下几项任务:* 如果被调用函数修改了寄存器(如AR1、AR6、AR7),则必须将它们压栈保护。* 当被调用函数需分配内存来建立局部变量及参数区时,SP向低地址移动一个常数(即SP减去一个常数),该常数的计算方法如下:常数=局部变量长度+参数区中调用其他函数的参数长度,66,67,* 被调用函数执行程序。* 如果被调用函数修改了寄存器ARl、AR6和AR7,则必须予以恢复。将函数的返回值放入累加器A中。整数和指针在累加器A的低16位中返回,浮点数和长整型数在累加器A的32位中返回。如果函数返回一个结构体,则被调用函数将结构体的内容拷贝到累加器A所指向的存储

38、器空间。如果函数没有返回值,则将累加器A置0,撤销为局部帧开辟的存储空间。ARP在从函数返回时,必须为0,即当前辅助寄存器为AR0。参数不是由被调用函数弹出堆栈的,而是由调用函数弹出的。,68,* SP向高地址移动一个常数(即SP加上一个常数),该常数即为图6.1(b)所确定的常数,这样就又恢复了帧和参数区。* 被调用函数恢复所有保存的寄存器。* 函数返回。当C程序编译成汇编后, 上述过程如例6.2所示。,69,例2be_called: ;函数入口pshm AR6 ;保存AR6pshm AR7 ;保存AR7frame # -16 ;分配帧和参数区. ;函数主体frame #16 ;恢复原来的帧

39、和参数区pshm AR7 ;恢复AR7pshm AR6 ;恢复AR6ret ;函数返回,70,(3) 入参数区和局部变量区 当编译器采用CPL=1的编译模式时,采用直接寻址即可很容易寻址到参数区和局部变量区。例如:add *SP(6), A ;将SP+6所指单元的内容送累加器A以上直接寻址方式的最大偏移量为127,所以当寻址超过127时,可以将SP值复制到辅助寄存器中(如AR7),以此代替SP进行长偏移寻址。例如:mvmm SP, AR7 ;将SP的值送AR7.add *AR7(128), A ;AR7加128后所指向的单元内容送A,71,(4) 分配帧及使用32位内存读/写指令。* 一些C5

40、4x DSP指令提供了一次读/写32位的操作(如DLD和DADD),因此必须保证32位对象存放在偶地址开始的内存中。为了保证这一点,C编译器需要初始化SP,使其为偶数值。* 由于CALL指令使SP减1,因此SP在函数入口设置为奇数;而长调用FCALL指令使SP减2,故SP在函数入口设定为偶数。,72,* 使用CALL指令时,应确保PSMH指令的数目加上FRAME指令分配字的数目为奇数,这样SP就指向一个偶地址;同样,使用长调用FCALL指令时,应保证PSMH指令的数目与FRAME指令分配字的数目和为偶数,以保证SP指向偶地址。 * 为了确保32位对象在偶地址,可通过设置SP的相对地址来实现。

41、* 由于中断调用时不能确保SP为奇数还是偶数,因此,中断分配SP指向偶数地址。,73,四、中断处理C函数可以直接处理中断。但是在用C语言编写中断程序时,应注意以下几点:(1) 中断的使能和屏蔽由程序员自己来设置。这一点可以通过内嵌汇编语句来控制中断的使能和屏蔽,即通过内嵌汇编语句来设置中断屏蔽寄存器IMR及INTM,也可通过调用汇编程序函数来实现。(2) 中断程序不能有入口参数,即使声明,也会被忽略。(3) 中断子程序即使被普通的C程序调用,也是无效的,因为所有的寄存器都已经被保护了。,74,(4) 将一个程序与某个中断进行关联时,必须在相应的中断矢量处放置一条跳转指令。采用.sect汇编指令

42、可以建立这样一个跳转指令表以实现该功能。 (5) 在汇编语言中,必须在中断程序名前加上一个下划线。(6) 用C语言编写的中断程序必须用关键字interrupt说明。(7) 中断程序用到的所有寄存器,包括状态寄存器都必须保护。(8) 如果中断程序中调用了其他的程序,则所有的寄存器都必须保护。,75,五、表达式分析当C程序中需要计算整型表达式时,必须注意到以下几点:(1) 算术上溢和下溢。TMS320C54x DSP采用16位操作数,产生40位结果,算术溢出是不能以一种可预测的方式进行处理的。(2) 整除和取模。TMS320C54x DSP没有直接提供整除指令,因此,所有的整除和取模运算都需要调用

43、库函数来实现。这些函数将运算表达式的右操作数压入堆栈,将左操作数放入累加器的低16位。函数的计算结果在累加器中返回。,76,(3) 32位表达式分析。一些运算在函数调用时并不遵循标准的C调用规则,其目的在于提高程序运行速度和减少程序代码空间。这些运算包括通过变量的左移、右移、除法、取模和乘法。(4) C代码访问16位乘法结果的高16位,而无需调用32位乘法的库函数。访问有符号数乘法结果和无符号数乘法结果的高16位,分别如下所示。,77,有符号结果: int n1,n2,result; result=(long)n1*(long)n2)16; 无符号结果: unsigned n1,n2,resu

44、lt; result=(unsigned long)n1*(unsigned long)n2)16;,78,C语言程序编写过程步骤: (1) 编辑器编辑C程序readdata.c; (2) 编译程序将C程序编译汇编成目标文件readdata.obj; (3) 编辑一个链接命令文件(.cmd文件); (4) 链接生成.out文件,用硬件仿真器进行调试。,六、C语言程序实例,79,例3、用C语言编写C54x DSP的IO口的读程序,实现从I O口地址8000H连续读入1000个数据并存入数组中。,C程序readdata.c: #include“portio.h” /*包含头文件portio.h*/

45、 #define RD_PORT 0x8000 /*定义输入I/O口*/ static int indata1000; /*定义全局数组*/ main() int I; for(I=0;I1000;I+) portRead(RD_PORT); /*从I/O口读数据*/ ,80,5. 7 用C语言和汇编语言混合编程,81,C语言和汇编语言的混合编程有以下几种方法:。(1) 独立编写汇编程序和C程序,分开编译或汇编,形成各自的目标代码模块,再用链接器将C模块和汇编模块链接起来。这种方法灵活性较大,但用户必须自己维护各汇编模块的入口和出口代码,自己计算传递的参数在堆栈中的偏移量,工作量较大,但能做到

46、对程序的绝对控制。(2) 在C程序中使用汇编程序中定义的变量和常量。(3) 在C程序中直接内嵌汇编语句。用此种方法可以在C程序中实现C语言无法实现的一些硬件控制功能,如修改中断控制寄存器,中断标志寄存器等。,一、C54x DSP混合编程方法,82,(4) 将C程序编译生成相应的汇编程序,手工修改和优化C编译器生成的汇编代码。采用此种方法时,可以控制C编译器,使之产生具有交叉列表的C程序和与之对应的汇编程序,而程序员可以对其中的汇编语句进行修改。优化之后,对汇编程序进行汇编,产生目标文件。根据编者经验,只要程序员对C和汇编均很熟悉,这种混合汇编方法的效率可以做得很高。但是,由交叉列表产生的C程序

47、对应的汇编程序往往读起来颇费劲,因此对一般程序员不提倡使用这种方法。,83,1. 独立的C和汇编模块接口独立的C和汇编模块接口是一种常用的C和汇编语言接口方法。采用此方法在编写C程序和汇编程序时,必须遵循有关的调用规则和寄存器规则。调用规则和寄存器规则已在前面作了详述。如果遵循了这些规则,那么C和汇编语言之间的接口是非常方便的。C程序可以直接引用汇编程序中定义的变量和子程序,汇编程序也可以引用C程序中定义的变量和子程序。,84,例4、 C程序: extern int asmfunc( ); /*声明外部的汇编子程序*/*注意函数名前不要加下划线*/ int gvar; /*定义全局变量*/ m

48、ain( ) int i=5; i =asmfunc(i); /*进行函数调用*/ ,85,汇编程序: _asmfunc: ;函数名前一定要有下划线 STL A,*(_gvar) ;i的值在累加器A中 ADD*(_gvar),A ;返回结果在累加器A中 RET ;子程序返回,86,2. C程序中访问汇编程序变量 从C程序中访问汇编程序中定义的变量或常数时,根据变量和常数定义的位置和方法的不同,可分为三种情况。(1) 访问在.bss段中定义的变量,方法如下:* 采用.bss命令定义变量;* 用.global将变量说明为外部变量;* 在汇编变量名前加下划线“_”;* 在C程序中将变量说明为外部变量,然后就可以像访问普通变量一样访问它。,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报