好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

第6章CC语言程序设计.ppt

150页
  • 卖家[上传人]:工****
  • 文档编号:591137166
  • 上传时间:2024-09-16
  • 文档格式:PPT
  • 文档大小:7.54MB
  • / 150 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • DSPDSP原理与应用原理与应用第第6章章 C/C++语言程序设计语言程序设计刘忠国:刘忠国:liuzhg@liuzhg@:18764171197:18764171197 ; ; : jnliuzg : jnliuzg 山东大学生物医学工程山东大学生物医学工程1 n参考资料:n山大课程中心《DSPDSP原理与应用原理与应用》网站: nTMS320C55x Optimizing CC++ Compiler Users Guide (Rev. F) (SPRU281F, 2003年年)nTMS320C55x DSP Programmer’s Guide (spru376a, 2001) 2 第第6章章 C/C++语言程序设计语言程序设计3n6.1  C55x C/C++语言概述语言概述n6.2  C55x C/C++语言编程基础语言编程基础n6.3  C55x C/C++编译器的使用编译器的使用n6.4  TMS320C55x的的C代码优化代码优化n6.5  C55x C和汇编语言混合编程和汇编语言混合编程 6.1 C55x C/C++语言概述语言概述n6.1.1   C/C++语言概况语言概况n6.1.2   C55x C/C++语言概况语言概况 4 6.1.1 C/C++语言概况语言概况5l汇编语言依赖于计算机硬件,程序的可读性和汇编语言依赖于计算机硬件,程序的可读性和可移植性比较差。

      可移植性比较差一般高级语言具有很好的可一般高级语言具有很好的可移植性,但是难以实现汇编语言的某些功能移植性,但是难以实现汇编语言的某些功能((如对内存地址的操作、位操作等如对内存地址的操作、位操作等)lC/C++语言作为一种高级语言,语言作为一种高级语言,既可以访问物既可以访问物理地址又可以进行位操作理地址又可以进行位操作,,能直接对硬件进行能直接对硬件进行操作操作,适合用作,适合用作DSP开发语言开发语言 l  C/C++语言具有如下基本特点:语言具有如下基本特点:u语言简洁、紧凑,使用方便、灵活语言简洁、紧凑,使用方便、灵活u运算符丰富,表达式类型多样化运算符丰富,表达式类型多样化u数据结构类型丰富数据结构类型丰富u具有结构化的控制语句具有结构化的控制语句u语法限制不太严格,程序设计自由度大语法限制不太严格,程序设计自由度大uC/C++语言允许访问物理地址,能进行位操语言允许访问物理地址,能进行位操作,能实现汇编语言的大部分功能,能直接对作,能实现汇编语言的大部分功能,能直接对硬件进行操作硬件进行操作6 6.1.2 C55x C/C++语言概况语言概况lC55x C/C++编译器全面支持编译器全面支持ANSI C/C++语言标语言标准准, 能够把按照标准能够把按照标准ANSI C/C++规范编写的源程序规范编写的源程序进行全面优化进行全面优化, 编译成编译成C55x 汇编语言源程序。

      汇编语言源程序lC55x C/C++编译器工具拥有完整的编译器工具拥有完整的实时运行库实时运行库, 所所有的库函数均符合有的库函数均符合ANSI库标准lC55x C/C++编译器编译器输出文件的特性输出文件的特性uC55x C/C++编译器生成的汇编语言便于查编译器生成的汇编语言便于查看看, 用户用户能看到产生自能看到产生自C/C++源程序的代码源程序的代码uCOFF文件文件允许允许用户用户在链接时定义自己的在链接时定义自己的系统存储器配置系统存储器配置, 使用户可把代码和数据链使用户可把代码和数据链接进特定的内存区域接进特定的内存区域, 提高程序性能提高程序性能uCOFF文件文件支持源程序级的调试支持源程序级的调试7库函数包括库函数包括标准输入标准输入输出、串操作、动态输出、串操作、动态内存分配、数据转换、内存分配、数据转换、三角函数、指数函数、三角函数、指数函数、双曲函数等双曲函数等,但是,但是不不包含信号处理函数包含信号处理函数,,因为它们涉及到目标因为它们涉及到目标系统的具体特性系统的具体特性 第第6章章 C/C++语言程序设计语言程序设计8n6.1  C55x C/C++语言概述语言概述n6.2  C55x C/C++语言编程基础语言编程基础n6.3  C55x C/C++编译器的使用编译器的使用n6.4  TMS320C55x的的C代码优化代码优化n6.5  C55x C和汇编语言混合编程和汇编语言混合编程 n6.2.1  数据类型数据类型n6.2.2  关键字关键字 n6.2.3  寄存器变量和参数寄存器变量和参数n6.2.4  asm指令指令n6.2.5  Pragma指令指令 n6.2.6标准标准ANSIC语言模式的改变语言模式的改变(-pk,-pr和和-ps选项选项)n6.2.7  存储器模式存储器模式n6.2.8  存储器分配存储器分配n6.2.9  中断处理中断处理n6.2.10 运行时间支持算法及转换程序运行时间支持算法及转换程序n6.2.11 系统初始化系统初始化6.2 C55x C/C++语言编程基础语言编程基础10 6.2.1 数据类型数据类型lC55x C语言支持的数据类型语言支持的数据类型:类型型长度度(位位)内容内容最小最小值 最大最大值(带符号符号)字符型字符型(signed) char16ASCII码 -32 76832 767无符号字符型无符号字符型unsigned char16ASCII码065 535(带符号符号)短整型短整型(signed) short162补码-32 76832 767无符号短整型无符号短整型unsigned short16二二进制数制数065 535(带符号符号)整型整型(signed) int162补码-32 76832 767无符号整型无符号整型unsigned int16二二进制数制数065 535(带符号符号)长整型整型(signed) long322补码-2 147 483 6482 147 483 647无符号无符号长整型整型unsigned long32二二进制数制数04 294 967 29511-215 ~ 215 -1-231 ~ 231 -1 类型型长度度(位位)内容内容最小最小值最大最大值带符号特符号特长整型整型long long402补码−549 755 813 888549 755 813 888无符号特无符号特长整型整型unsigned long long40二二进制数制数01 099 511 627 775枚枚举enum162补码-32 76832 767浮点浮点float 3232位位IEEE 1.18E-38 3.40E+38双精度双精度 double3232位位IEEE 1.18E-38 3.40E+38长双精度双精度long double3232位位IEEE 1.18E-38 3.40E+38数据指数据指针(小存小存储器模式器模式)16二二进制数制数00xFFFF数据指数据指针(大存大存储器模式器模式)23二二进制数制数00x7FFFFF程序指程序指针pointers (function)24二二进制数制数00xFFFFFF12lC55x C语言支持的数据类型语言支持的数据类型:-239 ~ 239 -1 S 阶码阶码E 尾数尾数 M31 30 23 22 0←32位浮点数真值位浮点数真值: x = (-1-1)s   (1.MM)   2 (E-E-127)二进制小数二进制小数正数的正数的表示范围表示范围实际上2的指数值取-126~127 (数范围2-126 ~ 2*2127 ), 保留的特殊指数值-127和128用来表示非数NaN, ±0,±∞等特殊值。

      1.11111111111111111111111≈2≈2 l定义各种数据类型时应注意如下规则:定义各种数据类型时应注意如下规则:u避免设避免设int和和long为相同大小为相同大小;u定点算法定点算法(特别乘法特别乘法)尽量用尽量用int类型类型用long类型作类型作乘法操作数会调用运行时间库乘法操作数会调用运行时间库(run-time library)程程序序;u用用int或或unsigned int类型而非类型而非long类型来循环计数类型来循环计数;u最好使用最好使用int类型类型作循环指数变量和其它位数不太重作循环指数变量和其它位数不太重要时的整型变量要时的整型变量, 因为因为int是对目标系统操作是对目标系统操作最高效最高效的的整数类型而不管芯片结构如何整数类型而不管芯片结构如何u避免设避免设char为为8位或位或long为为64位位;136.2.1 数据类型数据类型 6.2.2 关键字关键字1. const lC55x C编译器支持标准编译器支持标准C语言的语言的const关键字关键字l将这个关键字使用到对任意变量或数组的定义上可以将这个关键字使用到对任意变量或数组的定义上可以确保它们的确保它们的值不改变值不改变。

      l若若定义一个对象为定义一个对象为const, 那么那么const段就会为该对象段就会为该对象分配存储空间分配存储空间 u若定义对象时又若定义对象时又加加volatile (例例 volatile const int x),  volatile使使分配到分配到RAM(程序不改变程序不改变const volatile的对象的对象, 但是程序外的东西可以改变之但是程序外的东西可以改变之) ;u若对象是若对象是auto变量变量(作用域为作用域为函数内函数内) ;lconst关键字关键字可定义大常数表可定义大常数表并将之并将之分配到系统分配到系统ROM中中14使使const就就像没用一样像没用一样.例例: const int digits [] = {0,1,2,3,4,5,6,7,8,9};const数据存储分配有数据存储分配有两个例外两个例外: : 2. ioportlC55x C编译器对标准编译器对标准C语言进行了扩展语言进行了扩展, 增加了增加了ioport关键字关键字来支持来支持I/O寻址模式寻址模式lioport类型限定词可和标准类型类型限定词可和标准类型(包括数组、结构体、包括数组、结构体、共用体和枚举共用体和枚举)一起使用。

      一起使用l当与数组一起用时当与数组一起用时, ioport限制的是数组单元限制的是数组单元而而非数组非数组类型类型本身lioport可单独使用可单独使用, 此时此时int限定词就是默认的限定词就是默认的15ioport int k ; ioport int x[5] ;  lioport类型限定词只能用于全局或静态变量类型限定词只能用于全局或静态变量局部变量不能用部变量不能用ioport限制限制,  除非变量是个指针除非变量是个指针ioport int k  ; /*正确正确,可限定全局变量可限定全局变量* /void foo(void){ioport int i ; /*错误错误,不能限定局部变量不能限定局部变量* /ioport int *j  ; /*正确正确, 可限定指针可限定指针* /}16例例6-1,,ioport关键字的使用关键字的使用2. ioport 3. interrupt17interrupt void TIME_ISR(){   unsigned int flags;      ...}nC55x C编译器对标准编译器对标准C语言进行了扩展语言进行了扩展,  增加了增加了interrupt关键字关键字, 来指定某个函来指定某个函数为中断函数数为中断函数。

      4. onchiplOnchip关键字声明一个关键字声明一个特殊指针特殊指针, 该指针该指针所指向数据所指向数据可用作双可用作双MAC指令的操作数指令的操作数在链接时这些数据必须在链接时这些数据必须被链接到被链接到DSP片内存储器片内存储器, 否则会导致经否则会导致经BB总线而引总线而引用外部扩展存储器而发生错误用外部扩展存储器而发生错误18例例,,onchip int x[100] ;      /* 数组声明数组声明 */onchip int *p;     /* 指针声明指针声明 */ 5. volatilel在任何情况下在任何情况下, 优化器优化器会通过分析数据流来会通过分析数据流来避免存储避免存储器访问器访问如下例中如下例中*ctrl被优化成被优化成只读一次只读一次存储器单元存储器单元, 即即*ctrl在循环中值将不变在循环中值将不变(即使储器单元值变化了即使储器单元值变化了): unsigned int *ctrl;while (*ctrl !=0xFF)   ;若若*ctrl =0xFF则退出循环则退出循环19l若程序依靠存储器访问若程序依靠存储器访问, 则必须使用则必须使用volatile关键字关键字来来指明这些访问。

      指明这些访问编译器将不会优化任何对编译器将不会优化任何对volatile变量变量的引用为纠正上例中错误的引用为纠正上例中错误, 可加可加volatile:volatile unsigned int *ctrl; 6.2.3 寄存器变量和参数l寄存器变量就是用寄存器变量就是用register关键字关键字声明的变量声明的变量l依依是否用优化器是否用优化器, C编译器编译器对寄存器变量用不同的处理方式对寄存器变量用不同的处理方式:u当当使用优化器使用优化器进行编译时进行编译时, , 编译器编译器忽略任何寄存器声明忽略任何寄存器声明, , 通过一通过一种最有效使用寄存器的代价算法种最有效使用寄存器的代价算法, , 把寄存器分配给变量和临时量把寄存器分配给变量和临时量u不用优化器时不用优化器时, , 编译器编译器尽量尽量将将registerregister修饰的变量分配到修饰的变量分配到用来存用来存放临时表达式结果的放临时表达式结果的寄存器寄存器中中. .若编译器运行若编译器运行超出超出了合适的寄存器了合适的寄存器, 它将它将通过移动寄存器内容到存通过移动寄存器内容到存储器来释放寄存器储器来释放寄存器。

      若定义了太多的寄存器变量若定义了太多的寄存器变量, 则会限制编译器则会限制编译器用来存放临时表达式结果的寄存器数目这个限制会引起过量的从用来存放临时表达式结果的寄存器数目这个限制会引起过量的从寄存器到存储器的移动动作寄存器到存储器的移动动作20l编译器会尽量分配好所有声明的寄存器变量编译器会尽量分配好所有声明的寄存器变量l标量型标量型(整型、浮点型和指针类型整型、浮点型和指针类型)对象都可声明为寄存对象都可声明为寄存器变量器变量,而而像数组像数组等其它类型对象等其它类型对象不行不行 6.2.4 asm指令lasm指令可直接将指令可直接将C55x汇编语言指令汇编语言指令嵌入到编译器嵌入到编译器的汇编语言输出中的汇编语言输出中,就像是对叫做就像是对叫做asm的函数的调用的函数的调用l指令格式:指令格式:        asm (“assembler text”);21例例:asm(“ BCLR  INTM”);//引号引号内若无标号必须内若无标号必须以空格以空格开头开头asm (“ nop”) ; //插入一条汇编指令插入一条汇编指令nopasm(”STR: .string \”abc\” ”); //指令可含引号指令可含引号l插入的代码必须是插入的代码必须是合法的汇编语言指令合法的汇编语言指令:u像其它汇编语言指令一样,包含引用的代码行像其它汇编语言指令一样,包含引用的代码行必须必须用标号、空格、星号、分号开头用标号、空格、星号、分号开头。

      编译器不检查字符编译器不检查字符串如果有错,汇编器会将其检测出来如果有错,汇编器会将其检测出来 l使使用用asm指令存在的问题指令存在的问题::u它容易破坏它容易破坏C环境环境,因为,因为C编译器在编译嵌入编译器在编译嵌入了汇编语言的了汇编语言的C程序时并不检查或分析嵌入的汇程序时并不检查或分析嵌入的汇编语句u当使用带当使用带asm指令的优化器时必须小心指令的优化器时必须小心虽然优化器不会移除优化器不会移除asm指令,但它可能重新改变指令,但它可能重新改变周围代码顺序并可能引起不可预知的结果周围代码顺序并可能引起不可预知的结果226.2.4 asm指令 6.2.5 Pragma指令lPragma告诉编译器的预处理器告诉编译器的预处理器如何处理函数如何处理函数(或符号或符号)l须须在函数体外在函数体外使用使用pragma, 且出现在且出现在对函数、符号对函数、符号的的任何任何声明、定义或引用之前声明、定义或引用之前否则, 编译器会输出警告编译器会输出警告lC55x C编译器支持如下编译器支持如下pragma指令指令:23CODE_SECTIONC54X_CALLC54X_FAR_CALLDATA_ALIGNDATA_SECTIONFUNC_CANNOT_INLINEFUNC_EXT_CALLEDFUNC_IS_PUREFUNC_IS_SYSTEMFUNC_NEVER_RETURNSFUNC_NO_GLOBAL_ASGFUNC_NO_IND_ASGMUST_ITERATEUNROLL例例:#pragma DATA_ALIGN(x,2);     short x[10]; 参考参考 .align 2 l CODE_SECTION指令及其用法指令及其用法u语法法:#pragma CODE_SECTION(func_name,"section_name")24u作用作用: 把把C函数函数func_name的代的代码配置到由配置到由section_name定定义的程序段中。

      的程序段中uC源程序:源程序:#pragma CODE_SECTION(funcA,“codeA”)int funcA(int a){ int i; return (i = a);} u汇编源程序:源程序: .sect “codeA” .global _funcA* FUNCTION NAME: _funcA *_funcA: RET 25u例如:例如:C源程序:源程序:#pragma DATA_SECTION(bufferB, "my_sect")char bufferA[512];char bufferB[512]; u则汇编源程序:源程序: .global _bufferA .bss _bufferA,512 .global _bufferB _bufferB: .usect "my_sect", 512u语法:法:#pragma DATA_SECTION(var_name, "section_name")l DATA_SECTION指令及其用法指令及其用法u作用作用: var_name是包含在是包含在C函数内的函数内的变量名称量名称, 该指令将指令将数据数据var_name配置到由配置到由section_name定定义的数据段中的数据段中. 6.2.6 标准标准ANSI C语言模式的改变语言模式的改变(-pk、、-pr和和-ps选项选项)        编译源代码有如下的模式:编译源代码有如下的模式:uNormal ANSI模式(模式(默认默认))uK&R C模式(模式(不适用于不适用于C++代码 ))u宽松宽松ANSI模式模式u严格严格ANSI模式模式26 3.2.5 构建构建(Build)操作的参数设置操作的参数设置27n构建参数包括构建参数包括汇编器参数和器参数和链接器参数接器参数(对C程序程序还包括包括编译器参数器参数)。

      方法方法:将鼠将鼠标移至移至“Project Explorer” 中中的当前工程文件的当前工程文件Ex3_1.pjt处, 右右击菜菜单选择“Properties”, 打开打开Properties窗口 2.兼容兼容K&R C(-pk选项选项)l主要用来简化用主要用来简化用C55x ANSI C编译器对以前编译器对以前C标准代码的编译过程标准代码的编译过程.l编译器有一个编译器有一个K&R  (–pk)选项,用来改变语选项,用来改变语言的段规则来言的段规则来兼容老版本的代码兼容老版本的代码.l总体说来,总体说来,–pk选项使编译要求比选项使编译要求比ANSI C更加更加容易达到容易达到.l同时,该选项支持同时,该选项支持ANSI C语言的语言的新功能,如新功能,如函数原型、枚举、初始化和预处理器结构函数原型、枚举、初始化和预处理器结构.28 l编译器默认的模式是编译器默认的模式是Normal ANSI模式,模式,在此模式下:在此模式下:u大多数违反大多数违反ANSI标准的语句都报错标准的语句都报错u违反严格违反严格ANSI标准的语句给出警告标准的语句给出警告u语言扩展的语句都是允许的语言扩展的语句都是允许的1. Normal ANSI模式模式(默认默认)29 2.兼容兼容K&R C(-pk选项选项)l编译器编译器有一个有一个K&R  (–pk)选项,用来改变语言的段选项,用来改变语言的段规则来规则来兼容老版本的代码兼容老版本的代码.l–pk选项使编译要求比选项使编译要求比ANSI C更加容易达到更加容易达到.l同时,该选项支持同时,该选项支持ANSI C语言的语言的新功能,如函数原新功能,如函数原型、枚举、初始化和预处理器结构型、枚举、初始化和预处理器结构.30lK&R C 与与 ANSI C的区别的区别lC语言由语言由Dennis M. Ritchie在在1973年设计和实现年设计和实现。

      到到1978年年Ritchie和和Bell实验室的另一位程序专家实验室的另一位程序专家Kernighan合写了著名的合写了著名的《《The C Programming Language》》由这本书定义的由这本书定义的C语言后来语言后来被人们称作被人们称作 K&R Cl随着随着C语言语言使用和问题的出现,美国国家标准局使用和问题的出现,美国国家标准局((ANSI)对)对C语言语言进进行标准化,行标准化,1988年年10月颁布的月颁布的ANSI标准标准X3.159-1989,也就是后,也就是后来人们所说的来人们所说的ANSI C标准由这个标准定义的由这个标准定义的C语言被称作语言被称作ANSI ClANSI C标准很快被采纳为国际标准和各国的标准国际标准为标准很快被采纳为国际标准和各国的标准国际标准为ISO/IEC 9899-1990,中国国家标准,中国国家标准GB/T 15272-94是国际是国际ISO标准的中文翻译标准的中文翻译lANSI C标准化工作的一个主要目标是清除原来标准化工作的一个主要目标是清除原来C语言中的不安全、不语言中的不安全、不合理、不精确、不完善的东西由此也产生了合理、不精确、不完善的东西。

      由此也产生了ANSI C与与K&R C之间之间的差异从总体上看,这些差异反应的是的差异从总体上看,这些差异反应的是C语言走向完善、走向成熟语言走向完善、走向成熟 3.严格严格ANSI模式模式 (–ps选项选项)l使用使用-ps选项选项可以使编译器工作在严格可以使编译器工作在严格ANSI模式,这种模式下:模式,这种模式下:u会在违反会在违反ANSI规则的时候报错,规则的时候报错,语言扩语言扩展因违反严格展因违反严格ANSI规则,所以不可用规则,所以不可用u这些语言扩展的例子这些语言扩展的例子: inline和和asm关键关键字不可用字不可用31Strict ISO Mode 4. 宽松宽松ANSI模式模式(–pr选项选项)l使用使用-pr选项选项可以使编译器工作在宽松可以使编译器工作在宽松ANSI模模式中式中:u违反严格的违反严格的ANSI标准的情况下不发送警告消标准的情况下不发送警告消息息(普通普通ANSI模式中会发送模式中会发送), 也不发送错误消也不发送错误消息息(严格严格ANSI模式中会发送模式中会发送);u编译接受对编译接受对ANSI C标准的扩展,甚至是和标准的扩展,甚至是和ANSI C冲突的时候。

      冲突的时候 32Relaxed ISO Mode 6.2.7存储器模式存储器模式lC编译器将存储器当作一个由编译器将存储器当作一个由代码子模块代码子模块和和数据子数据子模块模块组成的线性模块组成的线性模块l每个由每个由C程序生成的代码子模块或数据子模块被放程序生成的代码子模块或数据子模块被放到到各自的连续存储空间各自的连续存储空间中l编译器认为目标存储器的全编译器认为目标存储器的全部部24位地址都有效位地址都有效l编译器支持两种存储器模型:编译器支持两种存储器模型:u小存储模式和大存储器模式小存储模式和大存储器模式u两种存储模式的两种存储模式的数据数据在存储器中的在存储器中的放置和访问不同放置和访问不同33 1. 小存储器模式(默认模式)小存储器模式(默认模式)l用小存储器模式得到比大存储模式用小存储器模式得到比大存储模式更少的代码和数据更少的代码和数据l小存储器模式下小存储器模式下,以下段都分配在以下段都分配在64KB单页存储器内单页存储器内:u.bss和和.data段(所有静态和全局数据)段(所有静态和全局数据)u.stack和和.sysstack段(第一和第二系统堆栈)段(第一和第二系统堆栈)。

      u.sysmem段(动态存储空间)段(动态存储空间)u.const段34l在小存储器模式中在小存储器模式中,对对.text段段(代码代码)、、.switch段段(switch语句语句)和和.cinit段段(变量初始化变量初始化)的的大小和位置没有限制大小和位置没有限制l小存储器模式下编译器使小存储器模式下编译器使用用16位数据指针来访问数据位数据指针来访问数据XARn寄存器的寄存器的高高7位用来设置指向包含位用来设置指向包含.bss段的存储页段的存储页在程序执行在程序执行过程中它们的过程中它们的值保持不变值保持不变 3.2.5 构建构建(Build)操作的参数设置操作的参数设置35n构建参数包括构建参数包括汇编器参数和器参数和链接器参数接器参数(对C程序程序还包括包括编译器参数器参数)方法:将鼠将鼠标移至移至“Project Explorer” 中中的当前工程文件的当前工程文件Ex3_1.pjt处, 右右击菜菜单选择“Properties”, 打开打开Properties窗口nCCS设置方法置方法: 将鼠将鼠标移至移至“Project Explorer” 中的当前中的当前工程文件如工程文件如Ex3_1.pjt处, 右右键菜菜单选择“Properties”, 打打开开Properties窗口:依次窗口:依次选择Build→C5500 Compiler → Processor Options,然后在,然后在弹出窗口的出窗口的Specify Memory Model(small / large / huge)一一栏的下拉菜的下拉菜单中中选择large。

      n构建参数包括构建参数包括汇编器参数和器参数和链接器参数接器参数(对C程序程序还包括包括编译器参数器参数)方法:将鼠将鼠标移至移至“Project Explorer” 中中的当前工程文件的当前工程文件Ex3_1.pjt处, 右右击菜菜单选择“Properties”, 打开打开Properties窗口3.2.5 构建构建(Build)操作的参数设置操作的参数设置36从从small / large / huge中中选择large点点击处理器理器选项(Processor Options) 2.大存储器模式大存储器模式l大存储器模式大存储器模式支持不严格的数据放置支持不严格的数据放置用-ml shell选项就可以应用该模式选项就可以应用该模式l在大存储器模式下,在大存储器模式下,数据指针为数据指针为23位位,在存储器中,在存储器中占占2字空间stack和和.sysstack段必须在同一页上段必须在同一页上 l在大存储器模式下编译代码时,必须和在大存储器模式下编译代码时,必须和rts55x.lib运行时间库链接运行时间库链接l链接器链接器不允许同时存在大存储器模式和小存储器模不允许同时存在大存储器模式和小存储器模式式。

      应用程序中的所有文件都必须使用相同的存储应用程序中的所有文件都必须使用相同的存储器模式37 6.2.8 存储器分配存储器分配1. C编译器生成的段编译器生成的段lC编译器生成的段有两种基本的类型编译器生成的段有两种基本的类型, 即即初始化段和未初始化段和未初始化段初始化段;l初始化段初始化段有:有:u.cinit段段, 包含初始化数据表格和常数包含初始化数据表格和常数;u.pinit段段, 含实时运行时含实时运行时调用调用全局对象构造器全局对象构造器的表格的表格;u.const段段, 包含包含用用const定义定义(不能同时被不能同时被volatile定定义义)的字符串常量和数据的字符串常量和数据;u.switch段段,  包含包含switch语句语句所用表所用表;u.text段段, 包含所有可执行代码包含所有可执行代码¤¤汇编器产生汇编器产生.data段段, 但但C编译器并不用此段编译器并不用此段38 1. C编译器生成的段编译器生成的段39l未初始化段未初始化段保留了存储器空间保留了存储器空间,一段程序可以在运一段程序可以在运行期间使用这个空间来生成和存储变量:行期间使用这个空间来生成和存储变量:u.bss段段, 为为全局和静态变量保留了空间全局和静态变量保留了空间。

      在启动在启动和装载的时候,和装载的时候,C启动程序或装载程序启动程序或装载程序从从.cinit段段(通常在通常在ROM中中)复制数据并用这些数据来复制数据并用这些数据来初始化初始化.bss段中的变量段中的变量;u.stack段,为段,为C系统堆栈系统堆栈分配存储地址分配存储地址(用堆栈指用堆栈指针针(SP)来管理堆栈来管理堆栈)这个存储地址用来传递变这个存储地址用来传递变量和局部存储量和局部存储 u.sysstack段段, 为为第二系统堆栈第二系统堆栈分配存储地址分配存储地址(用该堆用该堆栈指针栈指针(SSP)来管理该堆栈来管理该堆栈);u.sysmem段段, 为动态存储分配保留空间这个空间为动态存储分配保留空间这个空间被被malloc、、calloc和和realloc函数调用若函数调用若C程序程序不使不使用用这些函数,编译器就这些函数,编译器就不会创建不会创建.sysmem段段;u.cio段段, 支持支持C  I/O这个空间用来这个空间用来作为缓冲区作为缓冲区, 缓缓冲区标号为冲区标号为_CIOBUF_任何类型的任何类型的C  I/O被执行时被执行时(如如printf和和scanf), 就会建立缓冲区。

      就会建立缓冲区u对任何被执行的对任何被执行的stream I/O类型类型, 缓冲区包含一个缓冲区包含一个内部内部C  I/O命令命令(及需要的参数及需要的参数)及从及从C  I/O命令返回命令返回的数据必须在链接器命令文件中对必须在链接器命令文件中对.cio段进行分配段进行分配才能用才能用C  I/O401. C编译器生成的段编译器生成的段 MEMORY、、SECTIONS指令指令:  默认的分配法默认的分配法MEMORY{ ROM (RIX) :    origin = 0100h, length = 0FEFFh  VECTOR(RIX): origin=0FFFF00h, length=0100h  RAM (RWIX) : origin=010100h, length=0FFFFh}SECTIONS{ .text > ROM  .switch > ROM  .const > ROM  .cinit > ROM  .vectors > VECTOR .data > RAM .bss > RAM .sysmem > RAM .stack > RAM .sysstack > RAM .cio > RAM}41 表表6-2 段及其存储位置段及其存储位置42段段存储器类型存储器类型段段存储器类型存储器类型.textROM或或RAM.bssRAM.cinitROM或或RAM.stackRAM.constROM或或RAM.sysstackRAM.dataROM或或RAM.sysmemRAM.pinitROM or RAM.cioRAM 2. 堆栈堆栈l在在C编译器中编译器中, 使用使用C系统堆栈系统堆栈来放置局部变量、传来放置局部变量、传递参数给函数、保存处理器状态递参数给函数、保存处理器状态, 堆栈被放在存储堆栈被放在存储器的一个连续块中器的一个连续块中, 并并从高地址到低地址存放数据从高地址到低地址存放数据。

      l编译器编译器用堆栈指针用堆栈指针(SP)来管理该堆栈来管理该堆栈l代码不会检查是否在运行时间内堆栈出现溢出代码不会检查是否在运行时间内堆栈出现溢出, 必必须为堆栈分配合适的存储空间须为堆栈分配合适的存储空间lC55x支持支持第二系统堆栈第二系统堆栈,  编译器使编译器使用第二堆栈指用第二堆栈指针针SSP来管理第二系统堆栈来管理第二系统堆栈43或称运行时间堆栈或称运行时间堆栈(run-time  stack) 2. 堆栈堆栈l系统堆栈和第二系统堆栈大小系统堆栈和第二系统堆栈大小由链接器设置链接器由链接器设置链接器生成生成全局符号全局符号 __ STACK_SIZE 和和__SYSSTACK_SIZE, 并给它们指定一个等于各自堆栈并给它们指定一个等于各自堆栈大小的值大小的值l两种两种默认堆栈大小都是默认堆栈大小都是1000字节字节在链接时间内在链接时间内, 通通过链接器命令中的过链接器命令中的-stack或或-sysstack选项可以改变堆选项可以改变堆栈大小栈大小44-e start                  /*从全局标号从全局标号start开始执行程序开始执行程序*/–stack  500           /*设置数据堆栈大小设置数据堆栈大小500字字*/–sysstack  500     /*设置系统堆栈大小设置系统堆栈大小500字字*/MEMORY{ DARAM: o=0x100, l=0x7f00DARAM2: o=0x8000, l=0x8000}SECTIONS{ .text: {} > DARAM.bss: {} > DARAM.stack {} > DARAM}例例 Ex3_1.cmd,链接器命令文件举例。

      链接器命令文件举例 3.动态存储器分配动态存储器分配l编译器提供的运行时间支持库含几个在运行时间内编译器提供的运行时间支持库含几个在运行时间内给变量动态分配存储器的函数给变量动态分配存储器的函数(malloc,calloc和和realloc);l存储器的分配来自存储器的分配来自全局池全局池(pool)或堆或堆(heap), 在在.sysmen段内定义了池或堆段内定义了池或堆可通过可通过-heap size选选项项和链接器命令来设置和链接器命令来设置.sysmem段的大小段的大小l链接器会生成一个链接器会生成一个全局符号全局符号__SYSMEM_SIZE,,并为它指定等于并为它指定等于heap字节数的值字节数的值默认大小为默认大小为2000字节46-e start                  /*从全局标号从全局标号start开始执行程序开始执行程序*/–heap  1000           /*设置全局堆大小设置全局堆大小1000字字*/–stack  500           /*设置数据堆栈大小设置数据堆栈大小500字字*/–sysstack  500     /*设置系统堆栈大小设置系统堆栈大小500字字*/MEMORY{ DARAM: o=0x100, l=0x7f00DARAM2: o=0x8000, l=0x8000}SECTIONS{ .text: {} > DARAM.bss: {} > DARAM.stack {} > DARAM}例例 Ex.cmd,链接器命令文件举例。

      链接器命令文件举例 3.动态存储器分配动态存储器分配l动态分配的对象必须用指针寻址动态分配的对象必须用指针寻址全局堆是独立的段全局堆是独立的段(.sysmem), 动态分配的存储大小不能超过动态分配的存储大小不能超过堆的大小堆的大小;l为保留为保留.bss段的空间段的空间, 大数组所用空间可从大数组所用空间可从全局堆全局堆中分中分配配, 而不是将其定义为全局或静态变量而不是将其定义为全局或静态变量(.bss)47例如例如,不用如下定义:,不用如下定义:    int x[100]   ;在在.bss段段定义为定义为全局全局数组数组而使用指针并调用而使用指针并调用malloc函数:函数:int  *x;          x=(int*)malloc(100*sizeof(int))  ;在在. sysmem段段 6.2.9 中断处理中断处理u当当C C环境初始化时环境初始化时, ,启动程序是禁止中断的启动程序是禁止中断的u如果系统要使用中断,如果系统要使用中断,对相关的中断必须对相关的中断必须进行设置处理进行设置处理( (允许使能或屏蔽允许使能或屏蔽) ) u这种设置对这种设置对C C环境无破坏影响,环境无破坏影响,通过通过asmasm嵌嵌入语句入语句容易实现。

      容易实现481.  关于中断的几个要点关于中断的几个要点2.  C中断程序的使用中断程序的使用3.  保存中断入口的现场信息保存中断入口的现场信息例例:  asm(“ BCLR  INTM"); 6.2.9 中断处理中断处理491.1.关于中断的几个要点关于中断的几个要点l其他函数能完成的任务其他函数能完成的任务,中断程序也能完成中断程序也能完成,包括访问包括访问全局变量全局变量、为局部变量分配地址为局部变量分配地址、调用其它函数调用其它函数l在写中断程序时需注意:在写中断程序时需注意:①①对可屏蔽中断进行屏蔽或允许处理对可屏蔽中断进行屏蔽或允许处理 (通过通过IER0,1寄存寄存器器)通过嵌入汇编语言语句通过嵌入汇编语言语句可以可以使能或禁止中断使能或禁止中断, 也也可修改可修改IER0,1寄存器寄存器而不会破坏而不会破坏C环境或环境或C指针②②中断处理程序中断处理程序不能有参数不能有参数, 即使声明了参数也被忽略即使声明了参数也被忽略③③中断处理程序不中断处理程序不能被普通能被普通C代码调用代码调用④④要分配堆栈到偶地址要分配堆栈到偶地址(编写中断函数代码时编写中断函数代码时, 使堆栈指针使堆栈指针指向偶地址,指向偶地址,保证长字操作正确保证长字操作正确) 。

      例例:asm(“ BCLR  INTM”);//引号引号内若无标号必须内若无标号必须以空格以空格开头开头asm (“ AND #0FFF8H, port(#0x0”) ; //IER0,1的地址为的地址为0x0, 0x01 在写中断程序在写中断程序 时需要注意时需要注意: :50⑤⑤中断处理程序可处理单个中断或多个中断中断处理程序可处理单个中断或多个中断编译器不会编译器不会生成专用于某一个中断的代码生成专用于某一个中断的代码(c_int00除外除外)c_int00是系统复位中断是系统复位中断当进入c_int00中断时中断时, 运行运行时间堆栈时间堆栈并没有被建立起来并没有被建立起来, 因此不能为局部变量分配因此不能为局部变量分配地址地址, 也不能在运行时间堆栈中保存任何信息也不能在运行时间堆栈中保存任何信息⑥⑥汇编语言中汇编语言中, 需在中断程序名前加下划线需在中断程序名前加下划线,如如_c_int00⑦⑦为了将中断程序和中断联系起来,需要将分支程序为了将中断程序和中断联系起来,需要将分支程序(用用汇编跳转指令汇编跳转指令)放在合适的中断向量中放在合适的中断向量中,,通过通过.sect指令指令创建一个创建一个中断向量表定义段(中断向量表定义段(简单的分支指令表简单的分支指令表))就可就可以实现此操作以实现此操作。

               见见例例8.27的中断向量表的定义的中断向量表的定义//DSP C55x C语言语言中断函数的实现中断函数的实现,没有中断号,没有中断号interrupt void timer0Isr(){            ...}//单片机单片机C51 C语言语言中断函数的实现中断函数的实现,,对应对应1个中断号个中断号void ISRname(void)  interrupt  n   //n为中断号为中断号{  ...} *建立中断向量表的汇编文件建立中断向量表的汇编文件    .sect  ".vectors"*-----全局变量定义或声明全局变量定义或声明, 其他文件引用或定义其他文件引用或定义----------*     .global   _VECSTART    .global   _timer0Isr    .ref     _c_int00    .def   nmi, int0, int1, int2, int3, int4, int5, int6    .def   int7, int8, int9, int10, int11, int12, int13    .def   int14, int15, int16, int17, int18, int19, int20    .def   int21, int22, int23, int24, int25, int26, int27    .def   int28, int29,  no_isr_VECSTART:         .ivec  _c_int00, c54x_stk ; 初始化中断向量入口地址初始化中断向量入口地址nmi  .ivec   no_isr         nop_16int0  .ivec no_isr         nop_16 ;2字节的字节的nopint1  .ivec no_isr         nop_16(2) CSL中断向量表的定义中断向量表的定义(vectors.asm或或vectors.s55)如下如下:51例例8-27label: .ivec [address [, stack mode]] ;指令指令初始化中断向量的初始化中断向量的中服中服ISR入口入口地址地址     .textno_isr:     b     #no_isr int2 .ivec no_isr        nop_16int3 .ivec no_isr       nop_16int4 .ivec _timer0Isr       ;nop_16int5 .ivec no_isr      nop_16int6 .ivec no_isr      nop_16int7 .ivec no_isr      nop_16int8 .ivec no_isr      nop_16int9 .ivec no_isr      nop_16int10 .ivec no_isr      nop_16int11 .ivec no_isr      nop_16(2) CSL中断向量表的定义中断向量表的定义(vectors.asm或或vectors.s55)如下如下:53int12 .ivec no_isr      nop_16int13 .ivec no_isr      nop_16int14 .ivec no_isr      nop_16int15 .ivec no_isr      nop_16int16 .ivec no_isr      nop_16int17 .ivec no_isr      nop_16int18 .ivec no_isr      nop_16int19 .ivec no_isr      nop_16int20 .ivec no_isr      nop_16int21 .ivec no_isr      nop_16int22 .ivec no_isr      nop_16int23 .ivec no_isr      nop_16int24 .ivec no_isr      nop_16int25 .ivec no_isr      nop_16int26 .ivec no_isr      nop_16int27 .ivec no_isr      nop_16int28 .ivec no_isr      nop_16int29 .ivec no_isr      nop_16     .textno_isr:     b   #no_isr 2. C中断程序的使用中断程序的使用l通过通过interrupt关键字关键字可以用可以用C函数直接处理中断函数直接处理中断,例例:interrupt void timer0Isr(){            ...}linterrupt关键字可以与定义为返回关键字可以与定义为返回void并不含参数并不含参数的函数一起使用。

      中断函数体可以有局部变量的函数一起使用中断函数体可以有局部变量, 可以可以自由使用堆栈自由使用堆栈lc_int00是是C程序入口程序入口这个名字这个名字专用于系统重启中专用于系统重启中断断这个特殊的中断程序这个特殊的中断程序对系统初始化对系统初始化, 并调用主函并调用主函数数因没有调用者因没有调用者, 所以所以c_int00不保存任何寄存器不保存任何寄存器 54 3. 保存中断入口的现场信息保存中断入口的现场信息l中断程序所用到的所有寄存器中断程序所用到的所有寄存器(包括状态寄包括状态寄存器存器)必须被保存必须被保存l如果中断程序还调用其它函数,如果中断程序还调用其它函数,表表6-6列出列出的所有寄存器的所有寄存器都必须被保存都必须被保存 556.2.9 中断处理中断处理 566.2.10运行时间支持算法及转换程序运行时间支持算法及转换程序l运行时间支持库运行时间支持库包含了众多的包含了众多的汇编语言程序汇编语言程序,,用来为用来为C55x指令集指令集并并不支持的不支持的C运算运算提供算法提供算法和转换功能和转换功能l这些程序包括整数除法、整数取模和浮点运算这些程序包括整数除法、整数取模和浮点运算l这些程序需要遵循标准这些程序需要遵循标准C语言调用规则。

      语言调用规则rts55.lib, rts55x.lib, rts.src含含C语言语言使用运行时间的使用运行时间的本征函数本征函数(intrinsics) 6.2.11 系统初始化系统初始化l在在运行运行C程序之前必须先建立程序之前必须先建立C运行环境运行环境,该工作由,该工作由被称为被称为_c_int00的的C启动程序来完成启动程序来完成,运行时间支,运行时间支持源程序库持源程序库((rts.src)中叫做)中叫做boot.asm的模块中的模块中包含了启动源程序包含了启动源程序l为使系统开始运行,必须由硬件复位为使系统开始运行,必须由硬件复位调用调用_c_int00函数,将函数,将_c_ int00函数和其它目标模块链接起来函数和其它目标模块链接起来当使用链接器选项当使用链接器选项-c或或-cr并将并将rts.src作为一个链接作为一个链接输入文件时,这个链接过程能够自动完成输入文件时,这个链接过程能够自动完成l当当C程序被链接时程序被链接时,链接器会在可执行输出模块中,链接器会在可执行输出模块中给符号给符号_c_int00设置入口点的值设置入口点的值57-c: 在运行时自动初始化变量在运行时自动初始化变量; -cr: 在装载时自动初始化变量在装载时自动初始化变量.  6.2.11 系统初始化系统初始化u建立堆栈和第二系统堆栈。

      建立堆栈和第二系统堆栈u通过通过从从 .cinit段中的初始化表中复制数据到段中的初始化表中复制数据到.bss段段中的变量中的变量来来初始化全局变量初始化全局变量(运行时初始化运行时初始化,-c选项选项)u若在若在装载时就初始化变量装载时就初始化变量(-cr选项选项), 装载器就会在装载器就会在程序运行前程序运行前执行该步骤执行该步骤(而不是由启动程序完成的而不是由启动程序完成的)u调用调用main函数函数开始执行开始执行C程序58    本小节内容:本小节内容:               1. 变量的自动初始化变量的自动初始化;   2. 全局构建器全局构建器;                 3. 初始化表初始化表; 4. 运行时间变量初始化运行时间变量初始化;   5. 装载时间变量初始化装载时间变量初始化l _c_int00函数执行如下工作来初始化函数执行如下工作来初始化C环境:环境: 1. 变量的自动初始化变量的自动初始化l任何任何被声明预初始化的全局变量被声明预初始化的全局变量必须在必须在C程序开始程序开始运行运行前被分配初始值前被分配初始值, 检索这些变量数据并用这些数据初始检索这些变量数据并用这些数据初始化变量的过程叫做化变量的过程叫做自动初始化自动初始化(autoinitialization)。

      l编译器会创建一些表编译器会创建一些表,这些表含有用来,这些表含有用来初始化初始化.cinit段段中的中的全局和静态变量的数据全局和静态变量的数据每个编译过的模块都包每个编译过的模块都包含这些初始化表链接器会把它们组合到一个单一的含这些初始化表链接器会把它们组合到一个单一的.cinit表表中启动程序或装载器利用这个表来初始化所中启动程序或装载器利用这个表来初始化所有的系统变量有的系统变量l在标准在标准ANSI C语言中语言中, 没有显式初始化的全局和静态没有显式初始化的全局和静态变量必须在程序执行前设置为变量必须在程序执行前设置为0C55x C编译器不对编译器不对任何未初始化变量进行预初始化,因此任何未初始化变量进行预初始化,因此程序员必须显程序员必须显式初始化任何初始值为式初始化任何初始值为0的变量(的变量(否则不按预期执行否则不按预期执行))59.cinit段段 1. 变量的自动初始化变量的自动初始化lC55x C编译器不对任何未初始化变量进行预初始化,因此编译器不对任何未初始化变量进行预初始化,因此程序程序员必须显式初始化任何初始值为员必须显式初始化任何初始值为0的变量的变量60n没显式初始化的全局和静态变量可能使程序不按预期执行没显式初始化的全局和静态变量可能使程序不按预期执行,n 一个实验演示的例子是实验一个实验演示的例子是实验8的定时中断函数原程序如下的定时中断函数原程序如下:void interrupt Timer(){ nCount++; nCount%=16;   if ( nCount==0 )      LBDS^=1; //或用或用’LBDS =nCount;’使使4个灯都变化个灯都变化   }  //可使可使5509A板上板上4个指示灯的最低位灯定时闪烁个指示灯的最低位灯定时闪烁。

      n(4个指示灯个指示灯, 分别对应分别对应LBDS寄存器的二进制值的低寄存器的二进制值的低4位位)n有同学增加有同学增加全局变量全局变量,int  ii, 但没给初值但没给初值,将程序改成:将程序改成:void interrupt Timer(){ ii++;    LBDS=ii;   if ( ii==3 )     ii=0; //只让最低只让最低2个灯变化个灯变化, 其他灯不变其他灯不变}  //计划使计划使4个指示灯的最低个指示灯的最低2位定时按二进制数变化闪烁位定时按二进制数变化闪烁n预想预想ii从从0值开始变化值开始变化,只使指示灯的低只使指示灯的低2位亮灭来回变位亮灭来回变化化,但是但是初值是随机初值是随机的的, 当当ii初值超过了初值超过了3时时,在很长的时在很长的时间里不能满足条件间里不能满足条件ii==3, 所以指示灯的变化是所以指示灯的变化是4个指示个指示灯都在变化灯都在变化 2. 全局构建器全局构建器( Global Object Constructors )l所有所有具有构建器具有构建器(constructor)的全局变量的全局变量必须在运行必须在运行main()函数前使它们的构建器被调用。

      函数前使它们的构建器被调用61l链接器则将各输入文件中的链接器则将各输入文件中的.pinit段链接成一个单一的段链接成一个单一的.pinit段段, 启启动程序将使动程序将使用这个表来运行这些构用这个表来运行这些构建器建器l编译器会编译器会在在.pinit段段中依次建立中依次建立一个一个全局构建器地址表全局构建器地址表全局对象构造函数全局对象构造函数 3. 初始化表初始化表((Initialization Tables))l.cinit段中的表包含段中的表包含可变大小的初始化记录可变大小的初始化记录每个必须被自动初始化的变量在须被自动初始化的变量在.cinit段中都有一条记录段中都有一条记录第一位域第一位域16 bit16 bit( (字字0 0) )包含了初始化包含了初始化数据的长数据的长度度( (以字为单位以字为单位),),位位1414和位和位1515为保留位为保留位一条初始化记录长度可达初始化记录长度可达2 214 14 -1-1字第二位域第二位域2424位位, ,包含初包含初始化数据要始化数据要复制到的复制到的.bss.bss段的存段的存储器首地址储器首地址第三位域包含第三位域包含8位位的的标志位标志位:位位0为存储器为存储器空间指示空间指示(I/O (1)或或数据数据(0)), 其余位其余位: 保留位保留位.第四个位域第四个位域( (字字3 3到到n n) )包包含复制到初含复制到初始化变量的始化变量的数据数据。

      62如如main函数前的函数前的:  int i = 3;(字字1-2)long a[5] = {1,2,3,4,5} 例例6-2,初始化变量和初始化表,初始化变量和初始化表((a)初始化变量:)初始化变量: int i = 3;float f = 1.0;char s[] = “abcd”;long x = 4; long a[5] = {1,2,3,4,5};((b)上面所定义变量的初始化信息:)上面所定义变量的初始化信息:.sect “.cinit” ; 初始化段初始化段* 变量变量i的初始化记录的初始化记录 .field 1,16 ;将值将值1(数据长度数据长度1字字)放到放到16位的位域位的位域中中 .field _i+0,24 ;将将_i在在.bss中的中的地址地址值值放到放到24位的位域位的位域中中 .field 0,8 ;将将0值值 (数据存储器标志值数据存储器标志值为为0)放到放到8位的域位的域中中 .field 3,16 ; int i是的是的初始化值为初始化值为3, 占占16位的位域位的位域63初始化初始化记录数据数据长度度.bss段中的段中的变量指量指针存存储器空器空间指示指示初始化初始化数据数据 * 变量变量f的初始化记录的初始化记录     .field 2,16            ; 数据长度(数据长度(2字)字)    .field _f+0,24             ; 在在.bss中的地址中的地址    .field 0,8             ; 数据存储器数据存储器    .xlong 0x3f800000    ;浮点是浮点是32位位(符号符号1+移码阶码移码阶码8+尾数尾数23)* 变量变量s的初始化记录的初始化记录     .field IR_1,16         ;数据长度数据长度5(4个字符加结束符个字符加结束符0)    .field _s+0,24         ; .bss中的地址中的地址    .field 0, 8          ; 数据存储器数据存储器    .field 97, 16      ; a的的ASCII码值为码值为97    .field 98, 16        ; b    .field 99, 16      ; c    .field 100, 16      ; d    .field 0, 16        ; 字符串结束字符串结束IR_1  .set   5               ; 符号值给出成员个数符号值给出成员个数64 float f = 1.0; S 阶阶码码E 尾数尾数 M31 30 23 22 0 char s[] = “abcd”;←32位浮点数真值位浮点数真值: x = (-1-1)s   (1.MM)   2 (E-E-127)二进制小数二进制小数 * 变量变量a的初始化记录的初始化记录       .field IR_2, 16    ; 数据长度数据长度      .field _a+0, 24    ; .bss中的地址中的地址      .field 0, 8        ; 数据存储器数据存储器      .field 1, 32       ; 数组开始数组开始      .field 2, 32;      .field 3, 32;    .field 4, 32;      .field 5, 32       ; 数组结束数组结束 IR_2  .set 10     ; 数组大小数组大小¤¤.cinit.cinit段段必须按上述格式必须按上述格式只能只能包含包含初始化表初始化表。

      若把汇编语言模块接入若把汇编语言模块接入C/C++C/C++程序程序, , . .cinitcinit段段不能用作其他不能用作其他用途65* 变量变量x的初始化记录的初始化记录            .field 2,16       ; 数据长度(数据长度(2字)字)           .field _l x+0,24   ; 在在.bss中的地址中的地址           .field 0,8         ; 数据存储器数据存储器           .field 4,32        ; long是是32位位long x = 4;long a[5] = {1,2,3,4,5}; 4. 运行时间变量初始化运行时间变量初始化l运行时间运行时间自动初始化自动初始化是自动初始化的默认模式是自动初始化的默认模式为为使用这种模式使用这种模式, 可采用链接器的可采用链接器的-c选项l采用这种方法采用这种方法,  .cinit段随着所有其它初始化段被装段随着所有其它初始化段被装载到存储器载到存储器(通常为通常为ROM)中中, 全局变量在运行时间全局变量在运行时间被初始化被初始化l链接器定义了一个叫做链接器定义了一个叫做cinit的特殊符号,用以指向的特殊符号,用以指向存储器中初始化表的起始地址存储器中初始化表的起始地址。

      当程序开始当程序开始运行时运行时, C启动程序从启动程序从cinit指向的表中复制数据到指向的表中复制数据到.bss段中段中的的特定变量中特定变量中l这使得初始化数据能被存储到这使得初始化数据能被存储到ROM中中, 并在每次程并在每次程序开始执行时复制到序开始执行时复制到RAM中66  图图6-3 运行时间变量自动初始化过程运行时间变量自动初始化过程¤¤这种方法适用于这种方法适用于应用程序已烧入到应用程序已烧入到ROMROM中的系统中的系统674. 运行时间变量初始化运行时间变量初始化运行时运行时(*.obj) 5. 装载时间变量初始化装载时间变量初始化l在装载时间自动初始化变量在装载时间自动初始化变量会减少启动时间并节省会减少启动时间并节省被初始化表使用的存储器,从而改善了系统性能被初始化表使用的存储器,从而改善了系统性能用用-cr链接器选项链接器选项可以选择这种模式可以选择这种模式l当用当用-cr选项时选项时, 链接器将链接器将.cinit段头的段头的STYP_COPY标志位置标志位置1, 这样装载器就不会把这样装载器就不会把.cinit段装载到存储段装载到存储器中器中(.cinit段不占用存储器空间段不占用存储器空间(通常是通常是ROM))。

      l链接器置链接器置cinit符号为符号为–1(通常通常cinit指向初始化表的指向初始化表的起始地址起始地址), 告诉启动程序存储器中没有初始化表告诉启动程序存储器中没有初始化表,  因此在启动时不进行初始化因此在启动时不进行初始化68 l为在为在装载时间实现自动初始化装载时间实现自动初始化,装载器装载器必须能执行工作必须能执行工作::u能检测到目标文件中有能检测到目标文件中有.cinit段存在段存在;u保证保证STYP_COPY在在 .cinit段头中被置段头中被置1, 这样就不会这样就不会复制复制.cinit段到存储器段到存储器(通常是通常是ROM)中去中去;u能理解识别能理解识别.cinit段中段中初始化表初始化表的格式图图6-4 装载时间变量自动初始化过程装载时间变量自动初始化过程69装载器装载器不是编译程序包的一部分不是编译程序包的一部分 第第6章章 C/C++语言程序设计语言程序设计70n6.1  C55x C/C++语言概述语言概述n6.2  C55x C/C++语言编程基础语言编程基础n6.3  C55x C/C++编译器的使用编译器的使用n6.4  TMS320C55x的的C代码优化代码优化n6.5  C55x C和汇编语言混合编程和汇编语言混合编程 6.3 C55x C/C++编译器的使用编译器的使用l要把用要把用C/C++语言编好的源程序转换成语言编好的源程序转换成TMS320 C55x能够运行的代码,需经过编译、汇编和链接能够运行的代码,需经过编译、汇编和链接等多个步骤。

      等多个步骤lTI公司提供了一个公司提供了一个编译器外壳程序编译器外壳程序cl55,利用它可,利用它可以通过一条命令完成这些步骤以通过一条命令完成这些步骤l本节主要介绍如何使用本节主要介绍如何使用cl55对对C55x C语言源程序语言源程序进行编译、汇编和链接等操作进行编译、汇编和链接等操作71l6.3.1 编译器外壳程序编译器外壳程序cl55简介简介l6.3.2 cl55程序的选项程序的选项l6.3.3 编译器和编译器和CCS 6.3.1 编译器外壳程序编译器外壳程序cl55简介简介l编译器外壳程序编译器外壳程序cl55能够运行下列一个或多个模块:能够运行下列一个或多个模块:u编译器编译器;Ø编译器包括编译器包括剖析器剖析器(parser), 优化器优化器(optimizer)和和代码产生器代码产生器(code generator);Ø它能够接受它能够接受C/C++源代码源代码, 产生产生C55x 汇编语言源代码汇编语言源代码;Ø编译器通过输入文件扩展名区分源代码类别编译器通过输入文件扩展名区分源代码类别: .cpp, .cxx或或.cc为为C++源代码源代码, .c为为C源代码源代码, .asm, .abs或或.s*为汇编源代码为汇编源代码Ø链接器用于把汇编器产生的链接器用于把汇编器产生的.obj.obj目标文件链接成一个可执行目标文件链接成一个可执行的目标文件。

      的目标文件Ø这里链接器是一个可选项缺省状态下,这里链接器是一个可选项缺省状态下,cl55cl55只对源程序文只对源程序文件进行编译和汇编件进行编译和汇编, ,如果需要同时进行链接,使用如果需要同时进行链接,使用––z z选项即可选项即可72u汇编器汇编器:用于产生用于产生COFF格式的目标文件格式的目标文件(扩展名扩展名.obj);u链接器链接器;预处理预处理,检查语法等检查语法等 l编译器外壳程序编译器外壳程序cl55的调用的调用::cl55 [options][filenames] [-z[link_options][object files]]73l其中:其中:ucl55为编译器外壳程序为编译器外壳程序cl55的命令名的命令名;uoptions为命令选项为命令选项, 影响影响cl55处理输入文件的方式处理输入文件的方式;ufilenames为一个或多个为一个或多个C/C++ 源程序源程序, 汇编源程汇编源程序或目标文件序或目标文件;u–z选项用于链接器的使用选项用于链接器的使用;ulink_options为链接器选项为链接器选项;uobject files为链接器输出的目标文件为链接器输出的目标文件。

      6.3.2 cl55程序的选项程序的选项lCl55程序选项不但控制着编译器外壳程序程序选项不但控制着编译器外壳程序cl55本身本身, 还影响着它所生成的还影响着它所生成的C55x应用程序应用程序;l表表6–3列出了编译器和链接器的常用选项列出了编译器和链接器的常用选项, 其它选项请其它选项请参考本书的其它相关章节或文献参考本书的其它相关章节或文献:  TMS320C55x Optimizing C/C++ Compiler User’s Guide (SPRU281C, SPRU281F, 2003年年)74l使用使用Cl55选项时要注意以下几点:选项时要注意以下几点:u选项以短横线选项以短横线“-”开头,可以是单个或几个字母开头,可以是单个或几个字母u不带参数的多个单字母选项可以组合在一起不带参数的多个单字母选项可以组合在一起, 如如:–sgq 与与–s –g –q等价 l 使用使用Cl55选项时要注意以下几点选项时要注意以下几点(续续):u选项中的字母不区分大小写选项中的字母不区分大小写u对于两个字母的选项,如果它们的首字母相同,也对于两个字母的选项,如果它们的首字母相同,也可以组合在一起,如可以组合在一起,如: –pi –pk –pl 可以组合成可以组合成–pikl。

      u对于带参数的多个选项对于带参数的多个选项(如如–uname和和–idirectory)不能进行组合不能进行组合u对于带参数的选项,参数可以紧跟在选项字母后,对于带参数的选项,参数可以紧跟在选项字母后,也可以与选项字母之间用空格隔开,如:也可以与选项字母之间用空格隔开,如:–u name或或–uname均为合法但当参数为数字时必须紧跟在选均为合法但当参数为数字时必须紧跟在选项字母后,如项字母后,如: –o3为合法,为合法,–o 3则为非法则为非法u文件和选项的排列次序可以是任意的,但文件和选项的排列次序可以是任意的,但–z选项必选项必须位于编译器选项之后须位于编译器选项之后756.3.2 cl55程序的选项程序的选项 l 使用使用Cl55选项时要注意以下几点选项时要注意以下几点(续续):u选项中的字母不区分大小写选项中的字母不区分大小写u对于两个字母的选项,如果它们的首字母相同,也对于两个字母的选项,如果它们的首字母相同,也可以组合在一起,如可以组合在一起,如: –pi –pk –pl 可以组合成可以组合成–piklu对于带参数的多个选项对于带参数的多个选项(如如–uname和和–idirectory)不能进行组合。

      不能进行组合u对于带参数的选项,参数可以紧跟在选项字母后,对于带参数的选项,参数可以紧跟在选项字母后,也可以与选项字母之间用空格隔开,如:也可以与选项字母之间用空格隔开,如:–u name或或–uname均为合法但当参数为数字时必须紧跟在选均为合法但当参数为数字时必须紧跟在选项字母后,如项字母后,如: –o3为合法,为合法,–o 3则为非法则为非法u文件和选项的排列次序可以是任意的,但文件和选项的排列次序可以是任意的,但–z选项必选项必须位于编译器选项之后须位于编译器选项之后766.3.2 cl55程序的选项程序的选项 表表6–3 编译器和链接器的常用选项编译器和链接器的常用选项(1)77选 项作作 用用–@filename把名把名为filename的文件的内容附加到的文件的内容附加到编译器的器的命令行上使用命令行上使用该选项可以避免操作系可以避免操作系统对于于命令行命令行长度的限制度的限制–abs在在–z选项后使用,后使用,产生一个生一个绝对列表文件注列表文件注意必意必须在在–z选项后用后用–o选项指明指明.out文件b产生一个生一个扩展名展名为.aux的的辅助信息(有关堆助信息(有关堆栈大小和函数大小和函数调用)文件。

      用)文件–c取消取消链接当你在接当你在环境境变量量C_OPTION或或C55X_C_OPTION中使用了中使用了–z 选项, 但是又不但是又不想想进进行行链链接接时时, 可以采用可以采用该选项该选项–dname[=def] 为预处理器理器预定定义常数名常数名, 等价于在每一个等价于在每一个C/C++源文件源文件头部插入部插入#define name def如果省略果省略[=def ], 则则name会被置会被置1–g 使能符号使能符号调试–gw使能符号使能符号调试, 在目在目标标文件中采用文件中采用DWARF调试格式 表表6–3 编译器和链接器的常用选项编译器和链接器的常用选项(2)78选 项作作 用用–idirectory指明指明#include的搜索路径的搜索路径–k保留保留编译器器输出的出的汇编语言文件通常言文件通常,外壳程序外壳程序在在编译编译完成后会完成后会删删除除输输出的出的汇编语汇编语言文件 –mb指明所有数据存指明所有数据存储器器为片内存片内存储器该选项使使编译器采用双器采用双MAC指令指令对程序程序进行行优化必须确保确保在在链接命令文件中把所有数据放在片内存接命令文件中把所有数据放在片内存储器。

      器–mc允允许通常在通常在.const段中的常数作段中的常数作为只只读的、初始化的、初始化的静的静态变量该选项使得在运行使得在运行时间将被装将被装载进扩展存展存储器的常数器的常数值依然在依然在page 0给予保留–mg使使编译器和器和汇编器采用代数格式的器采用代数格式的汇编语句缺省状状态下,下,编译器和器和汇编器采用助器采用助记符格式的符格式的汇编语句在同一个源文件中不能同句在同一个源文件中不能同时采用两种格式的采用两种格式的汇编语句 –mr防止防止编译器器产生生blockrepeat、、localrepeat和和repeat指令该选项仅在用了在用了–o2或或–o3时才有用 79选 项作作 用用–ms进行代行代码空空间优化而不是代化而不是代码执行速度行速度优化–n只只对源文件源文件进行行编译, 不不进进行行汇编汇编和和链链接该选项该选项会覆盖掉会覆盖掉-z选项 –q压缩来自各种工具的来自各种工具的标志和志和进程信息,只有源文件程信息,只有源文件名和出名和出错信息被信息被输出–压缩除了出除了出错信息以外的所有信息以外的所有输出信息–s如果使能了如果使能了优化器化器(–on 选项), 则则–s选项将把将把优化化器的注器的注释插入到插入到汇编语言源代言源代码中。

      如果未使能中如果未使能优化器化器, 则该选项则该选项将把将把C/C++源代源代码插入到插入到汇编语言言源代源代码中–s选项中中隐含了含了–k 选项–ss把原始的把原始的C/C++源代源代码插入到插入到编译器器产生的生的汇编语言代言代码中如果使能了中如果使能了优化器化器(–on 选项),则则–ss选项将会将会对你的代你的代码进行大幅度地重新行大幅度地重新调整–uname 取消取消预定定义的常数名的常数名表表6–3 编译器和链接器的常用选项编译器和链接器的常用选项(3) 6.3.3 编译器和编译器和CCSl当利用当利用CCS构建构建一个工程时,一个工程时,CCS会调用会调用合适的代码产生工具完成编译、汇编和链合适的代码产生工具完成编译、汇编和链接任务接任务l编译器、汇编器和链接器的有关选项在编译器、汇编器和链接器的有关选项在CCS的相关选项对话框中进行设置的相关选项对话框中进行设置80 l 使用使用Cl55选项时要注意以下几点选项时要注意以下几点(续续):u选项中的字母不区分大小写选项中的字母不区分大小写u对于两个字母的选项,如果它们的首字母相同,也对于两个字母的选项,如果它们的首字母相同,也可以组合在一起,如可以组合在一起,如: –pi –pk –pl 可以组合成可以组合成–pikl。

      u对于带参数的多个选项对于带参数的多个选项(如如–uname和和–idirectory)不能进行组合不能进行组合u对于带参数的选项,参数可以紧跟在选项字母后,对于带参数的选项,参数可以紧跟在选项字母后,也可以与选项字母之间用空格隔开,如:也可以与选项字母之间用空格隔开,如:–u name或或–uname均为合法但当参数为数字时必须紧跟在选均为合法但当参数为数字时必须紧跟在选项字母后,如项字母后,如: –o3为合法,为合法,–o 3则为非法则为非法u文件和选项的排列次序可以是任意的,但文件和选项的排列次序可以是任意的,但–z选项必选项必须位于编译器选项之后须位于编译器选项之后816.3.2 cl55程序的选项程序的选项 第第6章章 C/C++语言程序设计语言程序设计82n6.1  C55x C/C++语言概述语言概述n6.2  C55x C/C++语言编程基础语言编程基础n6.3  C55x C/C++编译器的使用编译器的使用n6.4  TMS320C55x的的C代码优化代码优化n6.5  C55x C和汇编语言混合编程和汇编语言混合编程 6.4 TMS320C55x的的C代码优化代码优化l由于由于C语言程序的执行效率无法达到汇编语言程序的水语言程序的执行效率无法达到汇编语言程序的水平,所以常常在编写完平,所以常常在编写完C程序后还要程序后还要进行进行C代码优化以代码优化以提高效率提高效率,,以达到实时性要求以达到实时性要求。

      lC55x的的C/C++编译器有一个称为编译器有一个称为优化器优化器(optimizer) 的程序模块优化器通过执行一些的程序模块优化器通过执行一些操作操作(如如简化循环简化循环, 重新安排语句和表达式重新安排语句和表达式, 把变量用寄存器把变量用寄存器实现等实现等), 可以提高可以提高C/C++程序的运行速度程序的运行速度, 减少其代减少其代码长度83l6.4.1 编译器的优化选项编译器的优化选项l6.4.2 嵌入函数嵌入函数((Inline Function))l6.4.3 优化优化C代码的主要方法代码的主要方法 n6.4.1编译器的优化选项编译器的优化选项6.4 TMS320C55x的的C代码优化代码优化84Ø1. 基本优化选项基本优化选项(调用优化调用优化)Ø2. 文件级文件级(File-Level)优化选项优化选项Ø3. 程序级程序级(Program-Level)优化选项优化选项 6.4.1编译器的优化选项编译器的优化选项1.基本优化选项.基本优化选项(调用优化调用优化)l–o0:采取的主要优化措施有:采取的主要优化措施有:  简化控制流程简化控制流程,  把把变量安排到寄存器变量安排到寄存器, 简化循环简化循环, 忽略未用代码忽略未用代码, 简化简化语句和表达式语句和表达式, 把调用函数扩展为把调用函数扩展为内嵌函数内嵌函数等。

      等l–o1::在在–o0级优化的基础上级优化的基础上,进一步采取局部优,进一步采取局部优化措施,如:化措施,如:进行进行COPY扩展,删除未用分配,消扩展,删除未用分配,消除局部公共表达式除局部公共表达式等  inline关键字说明的函数关键字说明的函数85 1.基本优化选项.基本优化选项(调用优化调用优化)l–o2:在:在–o1级优化的基础上,进一步采取全局部优级优化的基础上,进一步采取全局部优化措施,如:化措施,如:进行循环优化,删除全局公共子表达式,进行循环优化,删除全局公共子表达式,消除全局未用分配消除全局未用分配等l–o3:这是:这是最大可能的优化级别最大可能的优化级别在–o2级优化的基级优化的基础上础上, 进一步进行的主要优化进一步进行的主要优化, 包括包括: 对于对于从未调用的从未调用的函数移除其代码函数移除其代码, 对于从对于从未使用返回值的函数删除其未使用返回值的函数删除其返回代码返回代码, 把小函数代码自动嵌入到程序中把小函数代码自动嵌入到程序中(参考参考-oi选项选项), 重新安排函数声明的次序等重新安排函数声明的次序等l-oi:当采用:当采用–o3级优化时,优化器自动嵌入级优化时,优化器自动嵌入被调用的小函数。

      被调用的小函数只有小于只有小于size的函数才能被嵌入的函数才能被嵌入86 1.基本优化选项.基本优化选项(调用优化调用优化)l–o2:在:在–o1级优化的基础上,进一步采取全局部优级优化的基础上,进一步采取全局部优化措施,如:化措施,如:进行循环优化,删除全局公共子表达式,进行循环优化,删除全局公共子表达式,消除全局未用分配消除全局未用分配等l–o3:这是:这是最大可能的优化级别最大可能的优化级别在–o2级优化的基级优化的基础上础上, 进一步进行的主要优化进一步进行的主要优化, 包括包括: 对于对于从未调用的从未调用的函数移除其代码函数移除其代码, 对于从对于从未使用返回值的函数删除其未使用返回值的函数删除其返回代码返回代码, 把小函数代码自动嵌入到程序中把小函数代码自动嵌入到程序中(参考参考-oi选项选项), 重新安排函数声明的次序等重新安排函数声明的次序等l-oi:当采用:当采用–o3级优化时,优化器自动嵌入级优化时,优化器自动嵌入被调用的小函数被调用的小函数只有小于只有小于size的函数才能被嵌入的函数才能被嵌入87 2.文件级(.文件级(File-Level)优化选项)优化选项l–o3选项使编译器进行文件级优化。

      可以单独使选项使编译器进行文件级优化可以单独使用用–o3选项进行普通的文件级优化,也可以选项进行普通的文件级优化,也可以与其与其它选项组合起来进行更专门的优化它选项组合起来进行更专门的优化:u要想要想控制文件级优化,可使用控制文件级优化,可使用–ol选项选项:Ø–ol0:告诉编译器在源程序文件中:告诉编译器在源程序文件中声明声明了一个与了一个与标准库函数标准库函数同名的函数同名的函数, 并更改并更改相应的库函数相应的库函数;Ø–ol1:告诉编译器在源程序文件中:告诉编译器在源程序文件中声明声明一个与标一个与标准库函数准库函数同名的函数同名的函数 ;88 Ø–ol2:告诉编译器在源程序文件中不声明或改变:告诉编译器在源程序文件中不声明或改变任何标准库函数当在命令文件或环境变量中选任何标准库函数当在命令文件或环境变量中选择了择了–ol0或或–ol1选项时,可以通过选项时,可以通过–ol2选项选项取消取消–ol0或或–ol1选项选项;u采用采用–o3选项时,选项时,可使用可使用–on选项产生选项产生一个扩展名一个扩展名为为.nfo的优化信息文件的优化信息文件:Ø–on0:取消优化信息文件的产生:取消优化信息文件的产生;Ø–on1:产生优化信息文件:产生优化信息文件;Ø–on2:产生详细的优化信息文件:产生详细的优化信息文件.89l用用–o3与其它选项组合起来进行更专门的优化与其它选项组合起来进行更专门的优化: 3.程序级(.程序级(Program-Level)优化选项)优化选项l通过使通过使用用-pm选项和选项和-o3选项就可以进行程序级优化选项就可以进行程序级优化。

      通过程序级优化,通过程序级优化,所有源文件都被编译到一个中间文所有源文件都被编译到一个中间文件中件中这个中间文件提供给编译器在编译过程中这个中间文件提供给编译器在编译过程中完整完整的程序总览的程序总览因为编译器能够访问整个程序,因此它因为编译器能够访问整个程序,因此它会会执行一些很少在文件级优化中应用的优化执行一些很少在文件级优化中应用的优化l如果一个函数的如果一个函数的特定参量的值不变特定参量的值不变,编译器就会用这,编译器就会用这个个值替换函数中的这个参量值替换函数中的这个参量l如果一个函数的如果一个函数的返回值从不使用返回值从不使用,编译器就会,编译器就会删除删除该该函数的函数的返回代码返回代码l如果一个如果一个函数从未被调用函数从未被调用,编译器就会,编译器就会删除该函数删除该函数90 l要想察看编译器进行程序级优化的情况,可以使用要想察看编译器进行程序级优化的情况,可以使用–on2选项产生一个优化信息文件选项产生一个优化信息文件 l要想要想控制程序级优化,可以使用控制程序级优化,可以使用–op选项:选项:u–op0:有被其它模块调用的函数和在其它模块:有被其它模块调用的函数和在其它模块中编辑的全局变量。

      中编辑的全局变量u–op1:没有被其它模块调用的函数,有在其它:没有被其它模块调用的函数,有在其它模块中编辑的全局变量模块中编辑的全局变量u–op2:没有被其它模块调用的函数,也没有在:没有被其它模块调用的函数,也没有在其它模块中编辑的全局变量,为缺省值其它模块中编辑的全局变量,为缺省值u–op3:有被其它模块调用的函数,没有在其它:有被其它模块调用的函数,没有在其它模块中编辑的全局变量模块中编辑的全局变量913.程序级(.程序级(Program-Level)优化选项)优化选项 6.4.2嵌入函数嵌入函数((Inline Function))l当程序调用一个嵌入函数时,会当程序调用一个嵌入函数时,会把该函数的代码插把该函数的代码插入到调用处入到调用处l嵌入函数有助于提高代码运行效率嵌入函数有助于提高代码运行效率, 主要优点:主要优点:u省去了函数调用有关的操作省去了函数调用有关的操作;u优化器可以把嵌入函数代码和周围代码放在一优化器可以把嵌入函数代码和周围代码放在一起自由地进行优化起自由地进行优化l但是,嵌入函数会大幅度地增加程序代码长度,但是,嵌入函数会大幅度地增加程序代码长度,适适合于小函数和调用次数较少的场合合于小函数和调用次数较少的场合。

      l嵌入函数有以下方法:嵌入函数有以下方法:1. 嵌入本征函数嵌入本征函数;  2. 自动自动嵌入小函数嵌入小函数;   3.  利用利用inline关键字嵌入函数关键字嵌入函数92 1. 嵌入本征函数嵌入本征函数lC55x有很多有很多本征函数本征函数(intrinsic operators, 像函数一样调用像函数一样调用, 以下划线以下划线_打头打头, 完成加减乘完成加减乘移位移位, 饱和取整等运算饱和取整等运算)编译时,编译器会用编译时,编译器会用有效代码取代本征函数有效代码取代本征函数l无论是否使用优化器,这种嵌入操作都会自动无论是否使用优化器,这种嵌入操作都会自动进行l关于本征函数的详细介绍关于本征函数的详细介绍, 请参考请参考本章第本章第6.4.3小节93 2. 自动嵌入小函数自动嵌入小函数l通过通过–o3选项选项, 优化器将优化器将自动地嵌入所调用的自动地嵌入所调用的小函数小函数小函数长度的上限由小函数长度的上限由-oi 选选项指定项指定, 即任何长度超过即任何长度超过size的函数不能被自的函数不能被自动嵌入若选择动嵌入若选择-oi 0, 等价于等价于取消自动嵌入取消自动嵌入。

      l函数大小以编译器内部的绝对单位为准进行函数大小以编译器内部的绝对单位为准进行计算,用计算,用-onx选项选项(−on1 or −on2)可看到可看到某函数大小某函数大小94 3. 利用利用inline关键字嵌入函数关键字嵌入函数l如果如果inline关键字对函数进行限定关键字对函数进行限定,  则该则该函数函数被调用时将被嵌入到调用处被调用时将被嵌入到调用处, 而不是采用普通而不是采用普通的函数调用操作方式的函数调用操作方式l为使为使inline关键字生效关键字生效, 必须采用必须采用–o(–o0, –o1, –o2 或或–o3)选项–pi选项用于选项用于关闭关闭基于基于inline关键字的关键字的函数嵌入函数嵌入95inline  float volume_sphere(float r)  {  return 4.0/3.0 * PI * r * r * r; } int foo(...)  { ... volume = volume_sphere(radius); ...} 6.4.3 优化优化C代码的主要方法代码的主要方法表表6-4 主要优化技术总结主要优化技术总结96优化技术优化技术可能的性可能的性能提升能提升应用应用难度难度使用使用频率频率问题问题1. 生成高效循环代码生成高效循环代码高高易易经常经常降低降低可移可移植性植性2. 高效地使用高效地使用MAC硬件硬件高高中等中等 经常经常3. 使用本征函数使用本征函数高高中等中等 经常经常避免循环寻址中的避免循环寻址中的模运算符模运算符(%)中等中等易易有时有时4. 对对16位数使用长整型访问位数使用长整型访问低低中等中等少少5. 产生高效控制代码产生高效控制代码低低易易少少参考参考: Robert Oshana. DSP Software Development Techniques for Embedded and Real-Time Systems Newnes, imprint of Elsevier (September 29, 2005)TMS320C55x DSP Programmer’s Guide (spru376a,2001) 1.生成高效循环代码.生成高效循环代码通过改进通过改进C循环代码可以极大地提高代码的性能:循环代码可以极大地提高代码的性能:u避免循环体内的函数调用避免循环体内的函数调用。

      这使得编译器可以高效这使得编译器可以高效地使用地使用硬件循环结构硬件循环结构(repeat、、localrepeat和和blockrepeat, 即用即用RPT,RPTBLOCAL,和和RPTB指令指令, 否则因调用函数需保存次数等无法用这些指令否则因调用函数需保存次数等无法用这些指令)u保持小循环代码保持小循环代码来使编译器使用来使编译器使用localrepeatu分析往返计数分析往返计数(trip count)问题问题,用用int,使用使用MUST-ITERATE pragmaTrip count is the number of times a loop iterates.))u使用使用-o3和和-pm编译器选项编译器选项97#pragma MUST_ITERATE(10,10);for(i = 0; i< trip_count; i++) { ...可硬件循环,避免0值旁路等 2.高效地使用.高效地使用MAC硬件硬件lC55x有专门硬件高效执行有专门硬件高效执行MAC运算运算一个周期中一个周期中可执行一个单乘加或一个双乘加可执行一个单乘加或一个双乘加(dual-MAC)运算u用单乘加操作写高效的小循环用单乘加操作写高效的小循环(求和变量用局部变求和变量用局部变量可产生单重复的量可产生单重复的MAC指令指令, 全局变量则不会全局变量则不会);u产生双乘加操作产生双乘加操作;983.使用本征(.使用本征(intrinsics)函数)函数lC55x提供一种特殊函数提供一种特殊函数——本征本征(intrinsics)函数函数, 使用它可以迅速优化使用它可以迅速优化C代码代码。

      l本征函数前有下划线本征函数前有下划线"_" , 调用方法和普通函数相同调用方法和普通函数相同参考参考TMS320C55x DSP Programmer’s Guide:3.4.2.2 Generating Dual-MAC Operations  表表6-5 C55x C/C++编译器的本征函数编译器的本征函数100本征函数函数描述short _abs(short src) ;返回一个16位整数的绝对值long _labs(long src);返回一个32位整数的绝对值short _abss(short src);通过置位SATA对一个16位整数进行饱和,返回其绝对值: _abss(0x8000)=>0x7FFFlong _labss(long src);置位SATD,对32位整数进行饱和,返回其绝对值: _labss(0x8000000)=>0x7FFFFFFFlong long _llabss(long long src);通过置位SATD对一个40位整数进行饱和,返回其绝对值short _norm(short src); 返回归一化16位整数所需的移位值(左移)short _lnorm(long src); 返回归一化32位整数所需的移位值(左移)long _rnd(long src);对一个32位整数加上215, 将低16位清0; 通过置位SATD进行饱和处理short _sadd(short src1, short src2);short _a_sadd(short src1, short src2);执行16位整数加法, 通过置位SATA对和进行饱和处理 101本征函数函数描述short _abs(short src) ;返回一个16位整数的绝对值long _labs(long src);返回一个32位整数的绝对值short _abss(short src);通过置位SATA对一个16位整数进行饱和,返回其绝对值: _abss(0x8000)=>0x7FFFlong _labss(long src);置位SATD,对32位整数进行饱和,返回其绝对值: _labss(0x8000000)=>0x7FFFFFFFlong long _llabss(long long src);通过置位SATD对一个40位整数进行饱和,返回其绝对值short _norm(short src); 返回归一化16位整数所需的移位值(左移)short _lnorm(long src); 返回归一化32位整数所需的移位值(左移)long _rnd(long src);对一个32位整数加上215, 将低16位清0; 通过置位SATD进行饱和处理short _sadd(short src1, short src2);short _a_sadd(short src1, short src2);执行16位整数加法, 通过置位SATA对和进行饱和处理本征函数对应汇编语言指令本征函数对应汇编语言指令-参考参考手册手册的的” 6.5.4 Using Intrinsics to Access Assembly Language Statements”-例如下表例如下表 102本征函数函数描述long _lsadd(long src1, long src2);long _a_lsadd(long src1, long src2);执行32位整数加法, 通过置位SATD对和进行饱和处理long long _llsadd(long long src1, long longsrc2);long long _a_llsadd(long long src1, long longsrc2);执行40位整数加法, 通过置位SATD对和进行饱和处理long _smac(long src, short op1, short op2);long _a_smac(long src, short op1, short op2);把两个16位整数op1与op2相乘, 把结果左移一位;把积加到32整数src上,并进行饱和处理,返回32整数结果(置位SATD,SMUL, FRCT)long _smacr(long src, short op1, short op2);long _a_smacr(long src, short op1, short op2);把两16位整数op1与op2相乘, 结果左移一位;积加到32整数src上,再加215,低16位清0;并进行饱和处理,返回32整数结果(置位SATD, SMUL, FRCT)long _smas(long src, short op1, short op2);long _a_smas(long src, short op1, short op2);把两个16位整数op1与op2相乘, 把结果左移一位;从32整数src中减去积,并进行饱和处理,返回32整数结果(置位SATD,SMUL, FRCT) 103long _smasr(long src, short op1, short op2);long _a_smasr(long src, short op1, short op2);把两个把两个16位整数位整数op1与与op2相乘相乘, 把把结果左移一位果左移一位;从从32整数整数src中减去中减去积, 再再加上加上215,将低将低16位清位清0; (置位置位SATD,SMUL, FRCT) short _smpy(short src1, short src2); 把两个把两个16位整数位整数src1和和src2相乘相乘, 把把结果左移一位果左移一位;进行行16位位饱和和处理理,返返回回16整数整数结果果(置位置位SATD, FRCT) long _lsmpy(short src1, short src2); 把两个把两个16位整数位整数src1和和src2相乘相乘, 把把结果左移一位果左移一位;进行行32位位饱和和处理理,返返回回32整数整数结果果(置位置位SATD, FRCT)long _smpyr(short src1, short src2); 把两把两16位整数位整数src1和和src2相乘相乘, 结果果左移一位左移一位; 再加上再加上215,将低将低16位清位清0;返返回回32整数整数结果果(置位置位SATD, FRCT) short _sneg(short src);对16位整数求位整数求补,对结果果进行行饱和和处理理_sneg(0xffff8000) => 0x00007FFF 104long _lsneg(long src); 对32位整数求补,结果进行饱和处理: _lsneg(0x80000000)=>0x7FFFFFFFlong long _llsneg(long long src); 对40位整数求补,对结果进行饱和处理short _sshl(short src1, short src2);将16位整数src1左移src2位, 返回16整数结果(置位SATD) long _lsshl(long src1, short src2);将32位整数src1左移src2(16位整数)位, 返回32整数结果(置位SATD) short _ssub(short src1, short src2); 16位整数src1减src2(置位SATA) , 对结果进行饱和处理, 返回16整数结果long _lssub(long src1, long src2); 16位整数src1减src2(置位SATA) , 对结果进行饱和处理, 返回32整数结果long long _llssub(long long src1,long long src2)16位整数src1减src2(置位SATA) , 对结果进行饱和处理, 返回40整数结果long _lsat(long long src);把40位整数转化成32位整数,需要时进行饱和处理short _shrs(short src1, short src2); 将16位整数src1右移src2位, 返回16整数结果(置位SATD)long _lshrs(long src1, short src2); 将32位整数src1右移src2(16位整数)位, 返回32整数结果(置位SATD) 例例6-5,通过加法的例子说明其优化效果。

      通过加法的例子说明其优化效果    (a) 标准标准C语言饱和加法:语言饱和加法:int sadd(int a,int b){int result;result = a + b;if(((a^b)&0x8000)==0) //检查检查"a"和和"b"符号是否相同符号是否相同{//若若"a"和和"b"符号相同符号相同,检查是上溢还是下溢检查是上溢还是下溢 if((result^a)&0x8000) {//若若"result"和和"a"符号不相同符号不相同,发生上溢或下溢发生上溢或下溢//若若"a"是正数是正数,把把"result"设置成最大正数设置成最大正数//若若"a"是负数是负数,把把"result"设置成最大负数设置成最大负数  result = (a<0)?0x8000:0x7FFF;}}return result;}105 ((b)由标准)由标准C语言饱和加法生成的低效汇编代码:语言饱和加法生成的低效汇编代码:_sadd: MOV  T1, AR1;XOR  T0, T1;BTST @#15, T1, TC1;ADD  T0, AR1BCC  L2, TC1;MOV  T0, AR2;XOR  AR1, AR2;BTST @#15, AR2, TC1 ;BCC  L2, !TC1;BCC  L1, T0 < #0;MOV  #32767, T0;B L3; L1:MOV  #−32768, AR1;L2:MOV  AR1, T0;L3:return;106 ((c)通过调用本征函数)通过调用本征函数sadd后的后的C代码:代码:int sadd(int a,int b){return _sadd(a,b);}((d)通过调用本征函数)通过调用本征函数sadd后生成的汇编代码:后生成的汇编代码:_sadd:BSET ST3_SATAADD T1,T0;BCLR ST3_SATAreturn;107 l使用使用本征函数本征函数可减少编码量和系统开销可减少编码量和系统开销, 但会但会降低代降低代码的可移植性码的可移植性, 为此可以为此可以用用ETSI(European Telecommunications Standards Institute)函数函数代替本征函数代替本征函数。

      l对对C55x代码代码, gsm.h使用本征函数定义了使用本征函数定义了ETSI函数函数lETSI函数可以在主机或其它没有本征函数的目标系函数可以在主机或其它没有本征函数的目标系统中编译时使用统中编译时使用108例例6-6,使用,使用ETSI函数执行函数执行sadd的的C代码代码#include int sadd(int a,int b){ return add(a,b);        /* ETSI函数函数 */} 4.对.对16位数使用长整型访问位数使用长整型访问l在某些情况下在某些情况下, 把把16位数据作为位数据作为long类型进行访问可类型进行访问可显著提高效率显著提高效率, 例如将数据从一个存储器地址快速地例如将数据从一个存储器地址快速地传到另一个存储器地址传到另一个存储器地址因因32位访问也可在单周期中位访问也可在单周期中出现出现, 这样可减少一半的数据移动时间这样可减少一半的数据移动时间;l唯一限制在于唯一限制在于数据必须排在偶字边界上数据必须排在偶字边界上若传递的数若传递的数据是据是2的倍数的倍数, 则代码简单很多则代码简单很多, 可以用可以用DATA ALIGN pragma来排列数据:来排列数据:     short x[10];#pragma DATA_ALIGN(x,2);109 例例6-7, 通过通过32位指针复制位指针复制16位数据的存储器复制函数。

      位数据的存储器复制函数void copy(const short *a, const short *b, unsigned short n){ unsigned short i;unsigned short na;long *src, *dst;/*这段程序假设这段程序假设传递数据的字数传递数据的字数n为为2的倍数的倍数. 字数字数n除除以以2得到双字传输次数得到双字传输次数*/na = (n>>1) −1 ; /*字数字数n右移右移1即即n除以除以2*//*设置设置SRC和和DST的开始地址的开始地址 * /src = (long *)a;dst = (long *)b;for (i=0; i<= na; i++) /*循环次数循环次数: na+1  */{*dst++ = *src++; /*传输次数传输次数: na+1=n/2 */}}110 5.生成高效控制代码.生成高效控制代码(条件分支转移程序条件分支转移程序)l控制代码会测试多种情况来决定采取什么样的合适动作控制代码会测试多种情况来决定采取什么样的合适动作;l若程序中若程序中“case”个数少于个数少于8,  编译器在执行编译器在执行嵌套的嵌套的if–then–else和和switch/case结构结构时会生成时会生成相似相似的结构。

      的结构因为第一个为真的条件在执行时的分支最少因为第一个为真的条件在执行时的分支最少, 所以最好所以最好将最常出现的情况写在第一个将最常出现的情况写在第一个“case” 后后l当程序中当程序中“case”超过超过8时时, 编译器会生成一个编译器会生成一个.switch标标号的段号的段这种情况下这种情况下, 仍然最好将仍然最好将最常执行的代码放在最常执行的代码放在第一个第一个“case”后后l在单条件语句中最好测试在单条件语句中最好测试0, 因为通常测试因为通常测试0会得到更高会得到更高效的代码(效的代码(见下例见下例))111 例,对比下面两段例,对比下面两段C代码:代码:if (a!=1)      /*测试测试1*/    else         若知道若知道a总是总是0或或1,则可以得到更高效的,则可以得到更高效的C代码:代码:if (a==0)     /*测试测试0*/    else    112 第第6章章 C/C++语言程序设计语言程序设计n6.1  C55x C/C++语言概述语言概述n6.2  C55x C/C++语言编程基础语言编程基础n6.3  C55x C/C++编译器的使用编译器的使用n6.4  TMS320C55x的的C代码优化代码优化n6.5  C55x C和汇编语言混合编程和汇编语言混合编程113 6.5 C55x C和汇编语言混合编程和汇编语言混合编程n6.5.1  C和汇编语言混合编程概述和汇编语言混合编程概述n6.5.2  寄存器规则寄存器规则n6.5.3  函数结构和调用规则函数结构和调用规则n6.5.4  C和汇编语言的接口和汇编语言的接口114 6.5.1 C和汇编语言混合编程概述和汇编语言混合编程概述l用汇编语言编程能够针对所采用用汇编语言编程能够针对所采用DSP芯片的具体特点芯片的具体特点, 所编程序执行效率高。

      但是所编程序执行效率高但是, 不同公司的不同公司的DSP芯片所芯片所提供的汇编语言各不相同提供的汇编语言各不相同, 即使是同一公司的芯片即使是同一公司的芯片, 由由于芯片的类型不同于芯片的类型不同, 其汇编语言也不尽相同其汇编语言也不尽相同l用用汇编语言开发汇编语言开发DSP产品周期很长产品周期很长,软件修改、升级、,软件修改、升级、移植都非常困难移植都非常困难l采用采用C语言编程具有开发效率高语言编程具有开发效率高的优点的优点, 有助于提高产有助于提高产品开发速度品开发速度, 程序修改、升级和移植也很方便程序修改、升级和移植也很方便l但是但是, 与汇编语言编写的程序相比与汇编语言编写的程序相比, C语言执行效率较语言执行效率较低低, 通常不能满足实时性要求通常不能满足实时性要求, 且无法控制某些硬件且无法控制某些硬件115 6.5.1 C和汇编语言混合编程概述和汇编语言混合编程概述l一般来说,只是在一般来说,只是在DSP运算能力不是很紧张运算能力不是很紧张时才采用时才采用C语言开发语言开发DSP程序,更加普遍的程序,更加普遍的是是采用采用C和汇编语言混合编程和汇编语言混合编程l通常,对于通常,对于实时性要求不高的实时性要求不高的部分如主控程部分如主控程序采用序采用C语言编写语言编写,对于,对于实时性要求较高的实时性要求较高的模块如模块如FFT、、FIR\IIR滤波滤波等则采用等则采用汇编语汇编语言编写言编写。

      116 6.5 C55x C和汇编语言混合编程和汇编语言混合编程n6.5.1  C和汇编语言混合编程概述和汇编语言混合编程概述n6.5.2  寄存器规则寄存器规则n6.5.3  函数结构和调用规则函数结构和调用规则n6.5.4  C和汇编语言的接口和汇编语言的接口117 6.5.2 寄存器规则寄存器规则l在在C环境下对特殊操作使用特殊寄存器有严格的规环境下对特殊操作使用特殊寄存器有严格的规定定,,C程序中嵌入汇编程序需要遵循这些规则,所程序中嵌入汇编程序需要遵循这些规则,所以以DSP程序员必须懂得程序员必须懂得寄存器规则寄存器规则l寄存器规则规定了寄存器规则规定了编译器如何使用寄存器和如何在编译器如何使用寄存器和如何在函数调用时保存数值函数调用时保存数值l寄存器规则规定寄存器规则规定在函数调用时用到的寄存器要预先在函数调用时用到的寄存器要预先保存保存这个工作部分由父函数完成这个工作部分由父函数完成,没有被父函数保没有被父函数保存而子函数又用到的由存而子函数又用到的由子函数保存子函数保存118 表表6-6 寄存器使用和保存规则寄存器使用和保存规则119寄存器保存者用途AC0,AC1,AC2,AC3父函数 16,32或40位数据,或24位代码指针(X)AR0~(X)AR4父函数16或23位指针,或16位数据(X)AR5~(X)AR7子函数16或23位指针,或16位数据T0,T1父函数T2,T3子函数ST0,ST1,ST2,ST3父函数BK03, BK47, BKC父函数RPTC父函数CSR父函数BRC0、BRC1父函数BRS1父函数BSA0、REA1父函数SP 返回前进栈的必须出栈SSPPCRETA子函数CFCT子函数(X)DP子函数 大存储模式下不用在在函数调用时函数调用时如何使如何使用寄存器保存数值用寄存器保存数值调用保存调用保存(save on call)入口保存入口保存(save on entry) 表表6-7  ST0_55状态寄存器作用状态寄存器作用l状态寄存器记录了状态寄存器记录了DSP运行状态。

      表运行状态表6-7~~表表6-10给出了给出了状态寄存器各字段作用、默认值及能否修改状态寄存器各字段作用、默认值及能否修改字段字段名称名称默默认值编译器能否修改器能否修改ACOV[0~~3]溢出溢出标志志是是CARRY进位位标志志是是TC [1~~2]检验、控制、控制标志志是是DP [7~~15]数据数据页寄存器寄存器否否120 表表6-8  ST1_55状态寄存器作用状态寄存器作用字段字段名称名称默默认值编译器能否修改器能否修改BRAF块重复重复标志志否否CPL编译标志志1否否XF外部外部标志志否否HM保持保持标志志否否INTM中断中断标志志否否M40运算运算标志志040位运算位运算时可以修改可以修改SATD饱和和标志志0是是SXMD符号符号扩展展标志志1否否C16双双16位运算模式位运算模式0否否FRCT分数模式分数模式0是是54CMC54兼容模式兼容模式0调用用C54x子函数子函数时可修改可修改ASM累加器移位模式累加器移位模式否否121 表表6-9  ST2_55状态寄存器作用状态寄存器作用字段字段名称名称默默认值编译器能器能否修改否修改ARMS辅助寄存器助寄存器间接接寻址模式址模式1否否DBGM调试模式模式否否EALLOW仿真仿真访问使能使能否否RDM舍入模式舍入模式0否否CDPLCCDP指指针线性性/循循环状状态0否否AR[0~~7]LC AR[0~~7]线性性/循循环状状态0否否122 表表6-10  ST3_55状态寄存器作用状态寄存器作用字段字段名称名称默默认值编译器能器能否修改否修改CAFRZ缓冲冲冻结否否CAEN缓冲使能冲使能否否CACLR缓冲清零冲清零否否HINT主机中断主机中断否否CBERR总线错误标志志否否MPNMC微微处理器理器/微机模式微机模式否否SATA饱和模式和模式(A单元元)0是是CLKOFFCLKOUT关关闭否否SMUL乘法乘法饱和模式和模式0是是SST存存储饱和模式和模式否否123 6.5 C55x C和汇编语言混合编程和汇编语言混合编程n6.5.1  C和汇编语言混合编程概述和汇编语言混合编程概述n6.5.2  寄存器规则寄存器规则n6.5.3  函数结构和调用规则函数结构和调用规则n6.5.4  C和汇编语言的接口和汇编语言的接口124 6.5.3  函数结构和调用规则函数结构和调用规则uC编译器对函数调用有一套编译器对函数调用有一套严格的规则严格的规则。

      u除特殊的运行时间支持函数除特殊的运行时间支持函数, 其它任何函数其它任何函数不管调用还是被调用都必须遵循这些规则不管调用还是被调用都必须遵循这些规则u不满足这些规则会破坏不满足这些规则会破坏C环境并会导致程序环境并会导致程序失败125本节内容:本节内容:  1.父函数如何调用其它函数.父函数如何调用其它函数2.被调用函数.被调用函数(子函数子函数)的响应的响应 例例: 一个典型的函数调用一个典型的函数调用时的时的堆栈使用堆栈使用126The term argument block refers to the part of the local frame used to pass arguments to other functions. Parameters are passed to a function by moving them into the argument block rather than pushing them on the stack. The local frame and argument block are allocated at the same time. 即将即将16位位PC←FP子子函函数数Caller’s argument block 子函数的响应子函数的响应: 1.父函数如何调用其它函数.父函数如何调用其它函数---步骤步骤:(1)将所要传到子函数的参数放入寄存器将所要传到子函数的参数放入寄存器(最多最多10个个)或堆栈或堆栈127l若子函数的若子函数的参量用省略号声明参量用省略号声明(表示表示参量数量可变参量数量可变),则则首先首先把最后一个显式声明的参量传到堆栈把最后一个显式声明的参量传到堆栈, 跟在后面再跟在后面再把其它参量把其它参量(其它未声明参量其它未声明参量)传到堆栈。

      传到堆栈u堆栈地址将作为访问其它未声明参量的索引堆栈地址将作为访问其它未声明参量的索引(FP);一个函数一个函数(父函数父函数)调用其他函数时要进行以下工作调用其他函数时要进行以下工作:int printf(int x, char *fmt, ...); 1.父函数如何调用其它函数.父函数如何调用其它函数---步骤步骤:(1)将所要传到子函数的参数放入寄存器将所要传到子函数的参数放入寄存器(最多最多10个个)或堆栈或堆栈128l最后一个参量最后一个参量之前所声明的参量之前所声明的参量遵循下面的遵循下面的规则规则:u编译器通常先对要传递的参量分类编译器通常先对要传递的参量分类, 然后然后按照类型将按照类型将参量放进寄存器参量放进寄存器(最多最多10个个)编译器使用的编译器使用的参量有参量有3类类:一个函数一个函数(父函数父函数)调用其他函数时要进行以下工作调用其他函数时要进行以下工作:Ø16位或位或23位数据指针位数据指针(int*, long*)Ø16位数据位数据(char, short, int)Ø32位数据位数据(long, float, double, 函数指针函数指针)int printf(int *p1, int x, long y, char *fmt, ...);u若参量是指向数据类型的指针若参量是指向数据类型的指针, 这个参量就是数据指这个参量就是数据指针针; 若一个参量能放进若一个参量能放进16位寄存器位寄存器, 就可看成就可看成16位数位数据据, 否则就是否则就是32位数据。

      位数据X)AR0-(X)AR4AC0-AC2T0,T1,AR0-AR4 129u双字长双字长(32位位)或少于或少于双字长的结构体会被当成双字长的结构体会被当成32位数位数据参量据参量, 并并通过寄存器通过寄存器(AC0-AC2若可用若可用)传递传递u若结构体长度大于若结构体长度大于32位位, 则通过则通过索引索引传输传输, 即编译器将即编译器将该结构体的地址该结构体的地址作为一个作为一个数据指针传递(数据指针传递(用用(X)AR0-(X)AR4传递传递))1)将所要传递到子函数的参数放入寄存器或堆栈将所要传递到子函数的参数放入寄存器或堆栈int fun(struct big a, struct small b, long y); 这是这是引用引用声明声明结构体长度大于结构体长度大于32位位, 编译器将该结编译器将该结构体的地址作为一个数据指针传递构体的地址作为一个数据指针传递少于双字长的结构体会被当成少于双字长的结构体会被当成32位数据参量位数据参量, 并通过寄存器传递并通过寄存器传递struct small { int x; };struct big { long x[10]; };。

      130((1)将所要传递到子函数的参数放入寄存器或堆栈将所要传递到子函数的参数放入寄存器或堆栈u若子函数返回一个结构体或联合体若子函数返回一个结构体或联合体, 则父函数在局部则父函数在局部(本地本地)堆栈中为结构体分配相应大小空间堆栈中为结构体分配相应大小空间(若长度不大若长度不大于于32位直接用位直接用AC0)父函数将父函数将该空间地址该空间地址作为隐含的作为隐含的第一个参量传递给子函数第一个参量传递给子函数, 这个参数被看成一这个参数被看成一数据指针数据指针struct s result=fn(x, y);→→fn(&result, x, y); u参量按照在函数声明中的排列顺序被分配给寄存器参量按照在函数声明中的排列顺序被分配给寄存器参量放置的寄存器类型由参数的类型决定参量放置的寄存器类型由参数的类型决定(表表6-11)若若参量数超过可用寄存器数量参量数超过可用寄存器数量(10个个), 多余参量会被压入多余参量会被压入堆栈堆栈参数参数类型型寄存器分配寄存器分配顺序序对应的数据的数据类型型16或或23位数据位数据指指针(X)AR0, (X)AR1, (X)AR2, (X)AR3, (X)AR4数数组,字符串字符串,指指针或占用空或占用空间超超过2字字节长的的结构体构体16位数据位数据T0, T1, AR0, AR1, AR2, AR3, AR4(无符号无符号)字符字符,短整数短整数, 整数整数32(40)位数据位数据 AC0, AC1, AC2长整数整数,浮点数和浮点数和长度不大度不大于于2个字个字节的的结构体构体132((1)将所要传递到子函数的参数放入寄存器或堆栈。

      将所要传递到子函数的参数放入寄存器或堆栈表表6-11 C函数调用中参量与寄存器的排列关系函数调用中参量与寄存器的排列关系            AC0        AC1       AC2        AR0        AR1void fn(long l1, long l2, long l3, int *p4, int *p5,  AR2        AR3      AR4      T0       T1int *p6, int *p7, int *p8, int i9, int i10); (2)子函数保存所有的子函数保存所有的入口保存寄存器入口保存寄存器(save-on-entry registers: T2、、 T3、、 AR5~~AR7)父函数必须通过父函数必须通过压入堆栈来保存其它在调用后会用到的寄存器的值压入堆栈来保存其它在调用后会用到的寄存器的值3) 父函数对子函数进行父函数对子函数进行调用执行子函数及返回执行子函数及返回)(4)父函数收集返回值父函数收集返回值Ø短数据短数据、、 长数据长数据和和数据指针数据指针分别返回在分别返回在T0、、 AC0和和(X)AR0中。

      若子函数返回的是一个中若子函数返回的是一个结构结构, 则父函数则父函数在本地堆栈中为结构体分配相应大小的空间在本地堆栈中为结构体分配相应大小的空间(长度大长度大于于32位时位时) (若长度不大于若长度不大于32位则直接用位则直接用AC0) 133Ø父函数将该空间地址作为第一个隐含参量传送给子函父函数将该空间地址作为第一个隐含参量传送给子函数数, 这个参数被看成一个数据指针这个参数被看成一个数据指针(若长度大于若长度大于32位位)1.父函数如何调用其它函数.父函数如何调用其它函数,  步骤步骤:(1)将所要传递到子函数的参数放入寄存器或堆栈将所要传递到子函数的参数放入寄存器或堆栈struct big { long x[10]; };struct small { int x; };  AC0                     AR0struct small fn(int *p1);struct big result=fn(x, y);→→fn(&result, x, y); 例例6-8,寄存器参量规则寄存器参量规则134这是这是引用引用声明声明结构体长度大于结构体长度大于32位位, 编译器将该结构编译器将该结构体的地址作为一个数据指针传递。

      体的地址作为一个数据指针传递少于双字长的结构体会被当成少于双字长的结构体会被当成32位数据参量位数据参量, 并通过寄存器传递并通过寄存器传递T0       T0        AC0        AR0int  fn(int i1, long l2, int *p3);AC0         AR0      T0       T1      AR1long  fn(int *p1, int i2, int i3, int i4);AR0                   AR1struct big fn (int *p1);T0        AR0                AR1int fn (struct big b, int *p1);struct big { long x[10]; };struct small { int x; };参数参数类型型 寄存器分配寄存器分配顺序序16或或23位位数据指数据指针(X)AR0, (X)AR1, (X)AR2, (X)AR3, (X)AR416位数据位数据T0, T1, AR0, AR1, AR2, AR3, AR432(40)位位数据数据AC0, AC1, AC2 135  AC0                     AR0struct small fn(int *p1); T0               AC0           AR0int fn(struct small b, int *p1); T0             stack        stack...int printf(char *fmt, ...);                AC0        AC1      AC2       stack      T0void fn(long l1, long l2, long l3, long l4, int i5);                AC0        AC1       AC2     AR0        AR1void fn(long l1, long l2, long l3, int *p4, int *p5,  AR2        AR3      AR4        T0       T1int *p6, int *p7, int *p8, int i9, int i10);参数参数类型型 寄存器分配寄存器分配顺序序16或或23位位数据指数据指针(X)AR0, (X)AR1, (X)AR2, (X)AR3, (X)AR416位数据位数据T0, T1, AR0, AR1, AR2, AR3, AR432(40)位位数据数据AC0, AC1, AC2fn函数有函数有10个参个参数数(书上个别参数书上个别参数对应不清楚对应不清楚)。

      2.被调用函数.被调用函数(子函数子函数)的响应的响应l(1) 被调用函数被调用函数在堆栈里在堆栈里为局部变量、临时存储区及为局部变量、临时存储区及函数可能调用的参数分配足够的存储空间这些工作函数可能调用的参数分配足够的存储空间这些工作在在函数调用开始的时候就完成了函数调用开始的时候就完成了l(2) 如果子函数修改一些如果子函数修改一些入口保存寄存器入口保存寄存器 (T2、、T3、、AR5~~AR7), 必须将这些值压入堆栈或存储到一个没必须将这些值压入堆栈或存储到一个没用的寄存器中被调用函数可以修改用的寄存器中被调用函数可以修改其它的寄存器其它的寄存器(见见表表6-6)而不用保存其中的值而不用保存其中的值l(3)若子函数的参数是一结构体若子函数的参数是一结构体, 则它所接收到的是一则它所接收到的是一个指向该结构体的指针个指向该结构体的指针(若长度不大于若长度不大于32位就用位就用AC0) 若在被调用函数中需要对结构体进行写操作若在被调用函数中需要对结构体进行写操作, 则则需把需把这个结构体复制到本地空间中这个结构体复制到本地空间中若不进行写操作若不进行写操作, 则可则可直接通过指针访问这个结构。

      直接通过指针访问这个结构136防止一些多次被用到的变量被改变刷新防止一些多次被用到的变量被改变刷新 l(4) 子函数执行代码子函数执行代码l(5) 若子函数返回一个值若子函数返回一个值, 它将该值按照以下规则放置它将该值按照以下规则放置:u短整型数据值返回到短整型数据值返回到T0中中;u长整型数据值返回到长整型数据值返回到AC0中中;u数据指针值返回到数据指针值返回到(X)AR0中中;u若子函数返回结构体若子函数返回结构体, 父函数父函数就会为结构体就会为结构体分配存储分配存储空间空间并传送指向这个空间的指针到并传送指向这个空间的指针到(X)AR0中要返回这个结构体回这个结构体, 被调用函数只要将该结构体复制到被被调用函数只要将该结构体复制到被这个指针所指的存储模块中这个指针所指的存储模块中l(6)子函数恢复所有在子函数恢复所有在第第2步步中保存的寄存器中保存的寄存器l(7)子函数恢复子函数恢复存储在堆栈中的值存储在堆栈中的值到原始位置到原始位置l(8)函数返回函数返回137 6.5 C55x C和汇编语言混合编程和汇编语言混合编程n6.5.1  C和汇编语言混合编程概述和汇编语言混合编程概述n6.5.2  寄存器规则寄存器规则n6.5.3  函数结构和调用规则函数结构和调用规则n6.5.4  C和汇编语言的接口和汇编语言的接口138 6.5.4  C和汇编语言的接口和汇编语言的接口     混合使用混合使用C代码和汇编语言代码的主要方法代码和汇编语言代码的主要方法有:有:l使用几个使用几个独立的汇编代码模块独立的汇编代码模块,并将它们与已编译的,并将它们与已编译的C模块进行模块进行链接链接,这是最通用的方法。

      这是最通用的方法l在在C源代码中源代码中使用汇编语言使用汇编语言变量和常数变量和常数(汇编文件定义汇编文件定义).l将将汇编语言程序汇编语言程序直接嵌入直接嵌入C源代码中源代码中l在在C源代码中源代码中使用使用本征函数本征函数直接调用汇编语言语句直接调用汇编语言语句139     本小节内容:本小节内容:1.在在C代码中访问汇编语言代码中访问汇编语言函数函数2.在在C代码中访问汇编语言代码中访问汇编语言变量变量3.在在C代码中访问汇编语言代码中访问汇编语言常数常数4.在在C代码中直接代码中直接嵌入汇编语言嵌入汇编语言 1. 在在C代码中访问汇编语言代码中访问汇编语言函数函数l在定义汇编函数时在定义汇编函数时, 需要在需要在函数名前加下划线函数名前加下划线 "_"来让来让编译器识别编译器识别140例例6-9: 从从C代码中访问汇编语言函数代码中访问汇编语言函数(函数名前无下划线函数名前无下划线_)a))C程序:程序:  /*声明汇编函数声明汇编函数*/extern int asmfunc(int,int *);int gvar=25  ;              /*定义全局变量定义全局变量*/main(){ int i=10;    i=asmfunc(i, &gvar);         /*调用函数调用函数*/   while(1)  {i++;}}((b)汇编程序)汇编程序:(文件中还有声明文件中还有声明: .global _asmfunc)_asmfunc:       ADD  *AR0, T0, T0   ;        RET;T0+*AR0 =>T0,  i=T0gvr=(AR0) T0,  AR0 2.  在在C代码中访问汇编语言代码中访问汇编语言变量变量::l访问访问.bss段或段或.usect段中段中没有初始化的变量没有初始化的变量::u使用使用.bss或或.usect指令指令来定义变量;来定义变量;u使用使用.global指令指令来定义为外部变量;来定义为外部变量;u在汇编语言中的在汇编语言中的变量前加下划线变量前加下划线“_”;;u在在C代码中声明变量为外部变量代码中声明变量为外部变量并正常地访问它。

      并正常地访问它例例6-10: 从C程序中访问定义在从C程序中访问定义在.bss段的变量段的变量a))C程序:程序:extern int var;/* 外部变量外部变量 */var = 1;/* 使用变量使用变量 */((b)汇编语言程序:)汇编语言程序:.bss _var, 1;定义变量定义变量.global _var;声明变量为外部变量声明变量为外部变量141(变量名前没有下划线_) l当当变量不是被存放在变量不是被存放在.bss段时段时, 比如用汇编语言定义比如用汇编语言定义的的查找表查找表并并不希望放在不希望放在RAM中中, 这时应该这时应该定义一个指定义一个指向该变量的指针向该变量的指针并从并从C语言中对其间接访问语言中对其间接访问u首先首先, 要要定义变量定义变量(带下划线带下划线_);u其次其次, 声明该变量为全局变量声明该变量为全局变量,这个,这个变量变量(起始地址起始地址)就可以被链接到存储空间的一个位置就可以被链接到存储空间的一个位置;1422.  在在C代码中访问汇编语言代码中访问汇编语言变量变量::((b)汇编程序:)汇编程序:.global  _sine           ;声明变量为外部变量声明变量为外部变量.sect ”sine_tab”      ;创建单独的段表创建单独的段表_sine:                            ;表从此开始表从此开始.float 0.0.float 0.015987.float 0.022145 ((a))C程序:程序:extern  float sine[] ;  /*这就是对象这就是对象*/float  *sine_p=sine;  /*声明指针指向它声明指针指向它*/f=sine_p[2];  /*正常访问该对象正常访问该对象*/u最后最后, 在在C程序中访问C程序中访问时时, 必须先必须先声明声明该对象为该对象为extern型型, 并且在其并且在其名称前面没有名称前面没有下划线下划线, 然后就可以正常访然后就可以正常访问它了。

      问它了 例例6-11,在,在C代码中访问没有在代码中访问没有在 .bss段中声明的变量段中声明的变量a))C程序:程序:extern  float sine[] ;  /*这就是对象这就是对象*/float  *sine_p=sine;  /*声明指针指向它声明指针指向它*/f=sine_p[2];  /*正常访问该对象正常访问该对象*/((b)汇编程序:)汇编程序:.global  _sine           ;声明变量为外部变量声明变量为外部变量.sect ”sine_tab”      ;创建单独的段表创建单独的段表_sine:                            ;表从此开始表从此开始.float 0.0.float 0.015987.float 0.022145 143((例例6-11完整程序)完整程序) 3. 在在C语言中访问汇编语言语言中访问汇编语言常数常数l通过使用通过使用.set和和.global指令可定义汇编语言的指令可定义汇编语言的全局全局常数常数, 也可在链接命令文件中使用链接分配语句定义也可在链接命令文件中使用链接分配语句定义汇编语言常数。

      汇编语言常数在在C语言中只有用特殊的运算符语言中只有用特殊的运算符&才才能访问这些常数能访问这些常数144((a)C语言程序:)C语言程序:extern int  table_size;                       /* 声明声明table_size为外部参数为外部参数*/#define TABLE_SIZE  ((int)(&table_size))……For(i=0; i

      asm语句对在编译器语句对在编译器输出中插入命令很有用输出中插入命令很有用l使用使用asm语句时语句时, 需注意需注意::u千万注意不要破坏千万注意不要破坏C语言操作环境语言操作环境C编译器在遇到内编译器在遇到内嵌嵌asm汇编语句时汇编语句时, 不会对其进行分析处理不会对其进行分析处理147asm(“ BCLR  INTM"); asm (“ nop”) ; //插入一条汇编指令插入一条汇编指令nop 第第6章作业章作业Ø 习题习题6-16 :: (实验实验) 利用利用第第3章章中中C语言工语言工程所用程所用命令文件命令文件Exam3_2.cmd,在,在CCS下下建立关于建立关于例例6-9的语言工程的语言工程,并对工程进行,并对工程进行构建、调试构建、调试148可利用打开已有工程文件可利用打开已有工程文件(教材例程教材例程)的方法:的方法:点菜点菜单Project->Importing Existing CCS Eclipse Projects,, 弹出窗框后出窗框后, 可可选择打开已有工程文件打开已有工程文件 补充:打开已有工程文件补充:打开已有工程文件(教材例程教材例程)的方法的方法149点菜点菜单Project->Importing Existing CCS Eclipse Projects,, 弹出窗框后出窗框后, 可可选择打开打开已有工程文件。

      已有工程文件 补充:打开已有工程文件补充:打开已有工程文件(教材例程教材例程)的方法的方法150点菜点菜单Project->Importing Existing CCS Eclipse Projects后后, 从从弹出窗框中可打开已有工程文件出窗框中可打开已有工程文件。

      点击阅读更多内容
      相关文档
      2025国开山东开大《土质学与土力学》形成性考核123答案+终结性考核答案.docx 中学综合素质知识点梳理【中学教师资格证】.docx 2025国开山东开大《特许经营概论》形成性考核123答案+终结性考核答案.doc 2025年高考英语全国一卷真题(含答案).docx 2025国开山东《农民专业合作社创建与管理》形成性考核123答案+终结性考核答案.docx 2025国开山东开大《自然现象探秘》形成性考核123答案+终结性考核答案.docx 2025国开山东《消费心理学》形成性考核123答案+终结性考核答案.doc 2025国开山东《小微企业管理》形成性考核123答案+终结性考核答案.doc 2025国开山东开大《资本经营》形成性考核123答案+终结性考试答案.docx 2025国开山东《小学生心理健康教育》形考123答案+终结性考试答案.docx 2025国开《视频策划与制作》形考任务1-4答案.docx 2025国开《亲子关系与亲子沟通》形考任务234答案+期末大作业答案.docx 2025国开电大《煤矿地质》形成性考核123答案.docx 2025国开电大《冶金原理》形考任务1234答案.docx 2025国开《在线学习项目运营与管理》形考任务1234答案.doc 2025国开电大《在线教育的理论与实践》阶段测验1-4答案.docx 2024 年注册环保工程师《专业基础考试》真题及答案解析【完整版】.docx 环保工程师---2023 年注册环保工程师《专业基础考试》真题及答案解析【完整版】.docx 2025国开《液压与气压传动》形考任务一参考答案.docx 2025年春江苏开放大学教育研究方法060616计分:形成性作业2、3答案.docx
      关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.