实时数字信号处理技术C软件开发代码产生工具和.ppt
实时数字信号处理技术 C6000 软件开发(3)代码产生工具和C6000程序结构,北京理工大学电子工程系 李云杰(O)010-,学习目标,软件开发流程和开发工具C6000程序基本结构,代码产生工具,代码产生工具(Code Generation Tools)C编译器汇编优化器汇编器连接器其它一些工具,C编译器,C编译器对符合ANSI标准的C代码进行编译,产生C6000汇编代码,分为:语法分析器C优化器代码产生器,C优化器,包括针对C代码的一般优化和针对C6000的优化:重新安排语句和表达式把变量分配给寄存器打开循环具有四个优化级别,C优化器,C代码产生器也可以完成一些优化工作C优化器最重要的优化处理软件流水pm把一个程序所有的C文件合成一个模块进行优化处理效率可达汇编语言代码的 70%80%,汇编优化器,对线性汇编代码(.sa文件)进行优化输入:用户编写的线性汇编代码输出:标准汇编代码.asm文件编程过程不需考虑:并行指令安排指令延迟寄存器使用效率可达汇编语言代码的 95%100%,汇编器,产生可重新分配地址的机器语言目标文件输入:C编译器产生的汇编文件汇编优化器输出的汇编文件文档管理器管理的宏库内的宏输出:目标代码是TI的COFF格式汇编代码内除机器指令外,还有汇编伪指令,连接器,根据用户说明的程序和数据存放地址,把汇编器产生的浮动地址代码和数据映射到用户系统的实际地址空间.输入:可重新分配地址的目标文件(.obj)输出:可执行的目标文件(.out),其它工具以及C运行库,文档管理器(Archiver)建库工具(Library-build Utility)十六进制转换工具(Hex Conversion Utility)交叉引用列表工具(Cross-reference Lister)C运行支持库(Run-time Support Library)c6000cgtoolsincludec6000cgtoolslib,DSPs程序的仿真模式,C6000程序基本结构,C程序的基本结构汇编代码结构线性汇编语言结构C程序和汇编代码的接口实现,C程序的基本结构,主程序 main.c连接命令文件.cmd c6000cgtoolsliblnk.cmdC运行库文件rtsxxxx.libc6000cgtoolslib,C程序的基本结构,若从EPROM中加载要运行的程序还需要Vectors.asmIST(中断服务表)被连接分配到0地址C运行环境入口点:_c_int00rtsxxx.lib,C程序的基本结构,CCS带有一个函数库 dev6x.lib其中包含有中断向量表,无需程序员写vectors.asm中断“挂”接也很方便针对C6000的外设预定义了大量的外设地址和宏定义regs.h 中有GET_BIT(),SET_BIT(),GET_FIELD()可以方便的对寄存器进行位操作.几乎所有外设寄存器的地址都已经定义,C程序的基本结构,使用devlib实现中断“挂”接Preprocesser 中头文件搜索路径设置为:.c6000evm6xdspinclude将dev6x.lib文件加入项目.c6000evm6xdsplib在.cmd文件中,将.vec段分配在0地址在主程序中使用#include 包含头文件在main()中调用intr_reset()函数调用intr_hook()等函数,C6000编译器的C环境实现,定义:C run-time environmentThe run time parameters in which your program must function.These parameters are defined by 1.the memory conventions2.register conventions3.stack organization 4.function call conventions5.system initialization.,存储器模型,C6000编译器把整个存储区当作单个线性存储块,并将它分为代码区和数据区编译器假定目标存储器的全部32-bit地址空间是可用的。定义存储器映象并将代码和数据分配到目标存储器的是连接器,而非编译器。Cmd文件是linker使用的。,C6000的存储器映射,程序和数据的存放不是随意的C6000存储器地址映射(Memory Map)决定着各种资源的访问地址,MAP 文件,-m选项 连接器输出存储器映象文件(.map)详细说明存储器的使用情况主要包括三个部分:存储器配置段分配图全局符号(全局变量、函数和段名)绝对地址,COFF文件格式,模块化的目标文件 COFF格式基本组成形式 段(sections)编译器生成的可重定位的代码和数据块初始化的段和未初始化段:已初始化段包含数据和可执行代码未初始化段存储器(一般指RAM)中的保留空间,程序在运行时用它来创建和存储变量.,已初始化段,.cinit段:包括变量初始值和常量值.const段:包括字符串文字(string literals),浮点常量和在C/C+中被声(明为const的数据(如果常量没有同时被声明为volatile).switch段:包含大的switch语句的跳转表(jump table).text段:包含所有的可执行代码.,未初始化段,.bss段:为全局变量和静态变量保留。如果为连接器设定-c选项,则在程序的开始,C引导程序会将.cinit段的数据(可在ROM中)复制到.bss段。.far段:为声明为far的全局变量和静态变量保留。.stack段:用于传递函数的参数和为局部变量分配存储器空间。.sysmem段:提请动态存储空间分配要求的有malloc,calloc和realloc等函数。,C编译器产生的代码段和数据段,C编译器产生的默认代码段和数据,C编译器产生的代码段和数据段,几点补充汇编器产生默认的.text,.bss和.data段。允许用CODE_SECTION和DATA_SECTION pragma来让编译器生成另外的段。除了.text段,各个初始化段和非初始化段均不能分配到内部程序存储器。,系统堆栈,编译器将堆栈用于:(1)保存函数调用后的返回地址;(2)给局部变量分配存储空间(3)传递函数参数(4)保存临时结果 运行时堆栈增长方向是从高向低,编译器用B15寄存器来管理堆栈,即将它作为堆栈指针(SP),指向堆栈中下一个空闲的存储器位置。,初始化变量,C/C+编译器生成的代码可固化到ROM中,.cinit段的初始化表也是贮存在ROM中。在系统初始化的时候,C/C+引导程序将表中的数据(ROM中)拷贝给.bss段中对应的变量(RAM中)运行时初始化加载时初始化,初始化变量 运行时初始化,Run-time Autoinitialization-c选项C初始化函数c_int00()会读取.cinit段中的每一个记录信息,分别初始化.bss段中的全局/静态变量。,初始化变量 加载时初始化,Load-time Initialization-cr 选项全局/静态变量的初始化工作由loader程序完成,在加载程序后,loader自己读取.cinit段的内容,初始化.bss段中数据,存储器模式,小存储器模式和大存储器模式。区别在于为.bss段分配存储空间方式。小存储器模式:.bss 32KByte,使用DP(B14)访问全局数据大存储器模式:不限制.bss段的大小 访问数据使用MVKL&MVKH,MVKL _x,A0 MVKH _x,A0 LDW*A0,B0,LDW*+DP(0 x7),B5,存储器模式,如果定义的全局/静态变量超过了32KB,仍然希望使用小模式获得较快的访问速度,怎么办?方法1:使用far关键字方法2:使用-ml0编译选项 Project Options Compile Advanced-ml/-ml0 集合数据类型是far存取-ml1 函数调用是far调用-ml2 函数调用是far调用,集合数据类型是far存取-ml3 函数调用是far调用,所有数据是far存取,寄存器使用规范,在C/C+环境下,一些具体的操作要使用哪些的寄存器来完成,是有严格的规范的。寄存器使用规范规定了编译器使用寄存器的方法以及函数调用过程中数值保存的方法。要在C/C+程序中嵌入汇编语言,必须理解并遵循寄存器使用规范。,函数调用约定,函数(父函数)在调用另一个函数(子函数)的时候执行下列操作 将传递到子函数的参数放入寄存器或堆栈.如果需要,保存寄存器(a/b09)到堆栈.调用者(父函数)调用函数(子函数).(对非C/C+代码)当返回时,调用者收回(reclaim)被调用者使用的堆栈空间.,函数调用(子函数),被调函数(子函数)为所有的局部的变量、临时存储区和它调用的函数的参数分配足够的堆栈空间。如果被调函数还继续调用其他的函数,返回地址必须保存在堆栈中。如果被调函数修改寄存器A10到A15或者B10到B15的值,必须将它们保存。被调函数执行其代码。存放返回值在A5:A4中。恢复3中保留的寄存器值释放1分配的堆栈利用B3,跳转返回父函数,系统初始化,运行一个C/C+程序之前,必须建立C/C+运行环境。这个工作是由C/C+引导程序调用c_int00函数完成的。系统运行开始时,跳转到或调用c_int00函数,但通常是硬件复位中断的中断服务程序调用它的。,系统初始化,定义系统堆栈.stack段并初始化堆栈指针定义.bss并初始化DP指针初始化全局的变量,这是通过将.cinit段中的初始化表复制给.bss段中为变量分配的存储空间来完成的。如果是在加载时初始化变量(cr选项),加载器(loader)在程序运行之前就完成了这个步骤(它不是通过引导程序执行的)调用main函数来运行C/C+程序,C_int_00源码 1,extern void _interrupt c_int00()/*-*/*SET UP THE STACK POINTER IN B15.*/*THE STACK POINTER POINTS 1 WORD PAST THE TOP OF THE STACK,SO SUBTRACT*/*1 WORD FROM THE SIZE.*/*-*/_asm(mvkl _stack,SP);_asm(mvkh _stack,SP);_asm(mvkl _STACK_SIZE-4,B0);_asm(mvkh _STACK_SIZE-4,B0);_asm(add B0,SP,SP);/*-*/*THE SP MUST BE ALIGNED ON AN 8-BYTE BOUNDARY.*/*-*/_asm(and 7,SP,SP);/*-*/*SET UP THE GLOBAL PAGE POINTER IN B14.*/*-*/_asm(.global$bss);_asm(mvkl$bss,DP);_asm(mvkh$bss,DP);,C_int_00源码 2,/*-*/*SET UP FLOATING POINT REGISTERS FOR C70 ONLY*/*-*/#ifdef _TMS320C6700 _asm(mvk 0,B3);/*round to nearest*/_asm(mvc B3,FADCR);_asm(mvc B3,FMCR);#endif/*-*/*GET THE POINTER TO THE AUTOINITIALIZATION TABLES INTO THE FIRST*/*ARGUMENT REGISTER(A4)*/*-*/_asm(.global cinit);_asm(mvkl cinit,A4);_asm(mvkh cinit,A4);/*-*/*PASS THE CURRENT DP TO THE AUTOINITIALIZATION ROUTINE.*/*-*/_asm(mv DP,B4);,/*-*/*CALL THE AUTOINITIALIZATION ROUTINE.*/*-*/_asm(.global _auto_init);_asm(mvkl$aiRL,B3);_asm(mvkh$aiRL,B3);_asm(mvkl _auto_init,B0);_asm(mvkh _auto_init,B0);_asm(b B0);/*far call*/_asm(NOP 5);_asm($aiRL:);/*-*/*CALL THE USERS PROGRAM.*/*-*/main();/*-*/*CALL EXIT.*/*-*/exit(1);,汇编代码结构,C6000任意一行汇编代码可能包括7项:标号(label)并行符号(|)条件(register)指令(mnemonic)功能单元(unit specifier)操作数(operand list)注释(;comment),x.int 10 MPY.M1 A1,A3,A7|ADD.L1x A2,B2,A5,汇编代码结构 标号,并行指令不能使用标号要使用标号,必须放在第一列,汇编代码结构 指令,指令:包括命令助记符和伪指令命令助记符:有效微处理器命令,执行程序操作伪指令:汇编语言中控制汇编过程和定义数据结构,所有伪指令以圆点打头,汇编代码结构 功能单元,圆点开始可选方式 3 种:指定具体使用的功能单元(.D1)可指定功能单元类型,汇编器安排具体单元(.M)(.M2)不指出功能单元,汇编器根据助记符安排,汇编代码结构 操作数,操作数直接用逗号隔开操作数类型 3 种寄存器操作数常数操作数指针操作数,汇编代码结构 注释,使用分号(;)时,注释可以在任何一列开始使用星号(*)时,注释必须从第一列开始不是必须,但是建议使用,一个汇编程序结构举例,程序 数据结构 算法,数据结构,算法,C程序的数据结构和算法实现,一个汇编程序结构举例,用汇编语言声明数据结构,一个汇编程序结构举例,用汇编语言编写算法,一个汇编程序结构举例,.sect“myData”m.int5x.int10b.int2y.int0.sect“myCode”startLD.D1*A0,A1.ST.D1 A7,*A6 endB endNOP 5,编程方法比较,*Typical efficiency vs.hand optimized assembly.,源文件,效率*,工作量,线性汇编程序,类似与手工汇编,但不是一种编程语言它的特点:不需要使用NOPs填充延迟间隙.不需指定功能单元.代码并行自动完成.允许标识符代替寄存器.,编写线性汇编代码,文件扩展名:“.sa”.编写过程:,NO NOPs requiredNO parallel instructions requiredNO functional units specifiedNO registers required,函数调用的参数传递和返回,“pm”and“pn”是C代码中定义的两个指针,可用来完成对线性汇编代码的调用.C代码中调用线性汇编编写的点积程序:,线性汇编代码利用.cproc来接收传来参数:,变量声明,除了传入的参数,其它的变量可以如下进行声明:,汇编优化器完成将这些值分配给寄存器的工作.,一个完整的线性汇编代码举例,Note:线性汇编代码会自动返回,不需要跳转指令,C程序和汇编语言接口,使用独立的汇编代码模块,并将其与编译完的C/C+模块连接在一起在C/C+源程序中内联函数(intrinsics),直接地调用汇编语句使用内联(inline)汇编语言直接嵌入C/C+源程序在C/C+源程序中使用汇编程序变量和常量,C代码中调用汇编函数,C and assembly functions 使用同样的资源(e.g.registers).C and assembly functions 可以交换数据.所以,关于数据和控制信息的交换及寄存器的共享有着相应的规则.,main()y=asmFunction(a,b);,_asmFunctionbb3,C代码中调用汇编函数,汇编代码中使用“_”来标识在C中声明的变量和函数.Labels 需要声明为global.,main_c.cint asm_Function(short,short);short x=0 x4000,y=0 x2000;int z;void main(void)z=asm_Function(x,y);,asm_Function.cint asm_Function(short a,short b)int y;y=(a*b)1;return y;,asm_Function.asm.global _asm_Function,C程序和汇编程序中的参数传递,C程序中调用汇编函数需要用到这些寄存器以传递参数和返回结果.,C程序和汇编程序中的参数传递,调用之前.,调用之后.,C程序和汇编程序中的参数传递,问题:C 程序会用到部分或者全部寄存器.汇编函数也可能用到部分或者全部寄存器.如果调用过程中不作相应处理,C程序中的一些数据会在汇编函数调用中被破坏.,C程序和汇编程序中的参数传递,解决办法:无论C还是汇编程序,都需要对它们用到的寄存器原值进行保存.,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0,C code automatically saves these registers,Assembly code must save these registers-responsibility of the programmer,内联函数(intrinsics),C6000编译器可以识别若干内联函数。内联函数直接调用某些汇编语句,这些汇编语句在C/C+中实现起来是很繁复或难以表达的。,内联(inline)汇编语言,要很小心不要破坏C/C+环境。对插入的汇编指令,编译器不做任何检查或者分析。,C/C+源程序使用汇编程序变量和常量,访问汇编语言中的全局变量访问汇编语言中的常量,访问汇编语言中的全局变量,利用.bss或者.usect伪指令定义变量.usect段中定义的变量,在C中需要声明为far利用.def或者.global伪指令使得变量可被外部访问汇编语言中的变量前要加下划线C/C+中相应变量要声明为extern,即可进行访问,访问汇编语言中的常量,利用伪指令.set,.def 和.global在汇编语言中定义一个常量正常变量在符号表中包含有其地址汇编常量在符号表中包含的是其数值编译器不能区分那些是地址,那些是数值解决办法:&操作符,