2007-11-28
文章介绍了几本书可以做C/C++语言的学习:
1、Advanced C: Techniques and Applications, Gerald E. Sobelman and
David E. Krekelberg, Que Corporation
2、American National Standard for Information Systems—Programming
Language C X3.159-1989, American National Standards Institute
(ANSI standard for C)
3、Programming in C, Steve G. Kochan, Hayden Book Company
4、Programming Language C++, ISO/IEC 14882–1998, American National
Standards Institute (ANSI standard for C++)
5、The Annotated C++ Reference Manual, Margaret A. Ellis and Bjarne
Stroustrup, published by Addison-Wesley Publishing Company, Reading,
Massachusetts, 1990
6、The C Programming Language (second edition), Brian W. Kernighan and
Dennis M. Ritchie, published by Prentice-Hall, Englewood Cliffs, New
Jersey, 1988, describes ANSI C.
7、The C++ Programming Language (third edition), Bjarne Stroustrup, published
by Addison-Wesley Publishing Company, Reading, Massachusetts,
1997
8、Understanding and Using COFF, Gintaras R. Gircys, published by O’Reilly
and Associates, Inc.
TI的代码编译可以分为:Complier/Assembler/Linker,生产Executable COFF File。
2007-12-1
代码优化的方法之一就是使用inline(内联函数),它将大大优化程序的运行速度,但是代码的存储空间将大大增加。当然inline使用时也有一些限制:
函数的返回参数为struct or union
函数的入参为struct or union
函数入参为volatile
函数入参有一个参数列表
声明了一个struct, union, or enum类型
包含一个static变量
包含一个volatile变量
为递归函数
包含一个pragma
函数的堆栈太大(定义了太多的局部变量)
使用cl2000 –v28并且指定-o的选项是最简单的优化法则,默认-o的等级是2。下面对-o等级做简单的解释:
-o0
对程序Control-flow-gragh的简化
将变量在寄存器中分配
循环的轮转
消除未使用的代码
简化表达式和声明
调用声明为inline的函数
-o1(包含-o0所有优化选项)
Performs local copy/constant propagation
去除未使用的声明
消除局部公共表达式
-o2(包含-o1所有优化选项)
循环的优化
消除全局公共表达式
消除全局未使用的声明
-o3(包含-o2所有优化选项)
去除所有没有调用的函数
简化从未使用函数的返回值
使用Inline方法调用小规格函数
重新排列函数的申明使得被调用函数的Attributes被提前得到
Propagates arguments into function bodies when all call sites pass the same value in the same argument position
确定文件级别变量的特性
2007-12-2
对于必须的内存访问使用Volatile关键字。优化器会分析数据流程图尽可能的避免内存访问。如果部分C/C++实现的Code必须通过内存访问获得,则需要使用volatile关键字表明这一点。优化器也不会对volatile变量进行任何优化。
对于-o3等级的优化器,它会自动inline扩展。
优化的具体项。
Cost-Based Register Allocation,根据变量或者编译临时值的类型、用法和使用频率,使用寄存器替代它们。
Alias Disambiguation,避免不同的指针变量指向同一地址。
Data Flow Optimizations,优化器以较小代价替换表达式,检查并去除不需要的assignments,避免对已经计算好的变量进行计算。
Expression Simplification,为了达到最好的效果,编译器将表达式简化成相同的形式,这样将减少指令和寄存器的使用。
Inline Expansion of Run-Time-Support Library Functions,编译器将使用inline code的方式调用较小的run-time-support函数,保存联合函数调用方式尽可能的使用其他优化方式。
Induction Variables and Strength Reduction,Induction variable和strength reduction将去除代码中的循环控制变量。
Loop-Invariant Code Motion,优化器识别出循环中的表达式总是固定值,该表达式的计算可以移到循环的外面,并且循环中的每次表达式的计算被预先计算好的值替换。
Loop Rotation,编译器会在循环的底部估计循环条件,并且保存跳出循环的分支。很多情况下,初始的检查条件和分支会被优化掉。
Register Variables,编译器将尽可能的使用寄存器存储局部变量、参数、临时变量,访问寄存器中的变量比访问内存更加方便,而且存储在寄存器中的指针更加高效。
Register Tracking/Targeting,编译器会检查寄存器中的内容避免在同一内容再次从内存中取出,变量、常量、结构等将通过straight-line code跟踪。Register targeting直接将需要的表达式转换成特殊寄存器,像分配寄存器变量或者从函数返回值。
Tail Merging,如果希望优化代码大小,Tail merging将对一些函数非常有效。Tail merging在相同指令的结尾找到相同的代码段,这段相关的指令将被写在相同的block中,这些代码所在的位置有新的分支指向block,这样就只剩下一段新的指令,而不是原来重复的几处。
Removing Comparisons to Zero,因为大部分ALU指令能够调整寄存器的状态,清楚的与0比较将是不必要的。如果先前的指令能够适当的设置寄存器,TMS320C28x C/C++编译器将可以不与0比较。
2007-12-6
链接C/C++程序。无论采用何种方法调用链接器,当连接C/C++程序时必须注意一些特别的需求:
Include 编译器的run-time-support library。
指明初始值的类型。
决定怎么在内存空间中分布代码。
Initialized sections
Name | Description | Restrictions |
.cinit | C初始记录对于初始化全局变量和静态变量 | Program |
.const | 全局的初始化静态常量,如字符串 | Low 64K data |
.econst | Far静态变量 | Anywhere in data |
.pinit | 全局构造表(C++) | Program |
.switch | 执行switch状态的表 | Program/Low 64K data(with –mt only) |
.text | 可执行代码和常量 | Program |
Uninitialized sections
Name | Description | Restrictions |
.bss | 全局变量和静态变量 | Low 64K data |
.ebss | Far全局变量和静态变量 | Anywhere in data |
.stack | 堆栈空间 | Low 64K data |
.sysmem | 函数通过Malloc申请的内存空间 | Low 64K data |
.esysmem | 函数通过Far_Malloc申请的内存空间 | Anywhere in data |
2008-1-3
TMS320C28x支持C++,标准为ISO/IEC 14882-1998
2008-1-12
一个函数调用另一个函数时,需要进行以下步骤:
1) 被调用的函数并不需要保存寄存器变量,但是当函数返回的时候,返回值需要保存在Stack中;
2) 如果被调用的函数返回参数为结构体,则调用函数将会为该结构申请一个内存空间,并且将该内存空间的地址作为被调用函数的第一个参数;
3) 被调用函数的参数是通过寄存器存放,必要时,可以存在放在Stack中。参数传递的规则如下:
a) 32-bit的参数(longs或者floats),第一存放在32-bit ACC(AH/AL)。其他32-bit参数或者函数指针以reverse order存放在Stack中。
b) 指针参数存放在XAR4和XAR5中,其他所有参数存放在Stack中。
c) 剩下的16-bit参数按照次序存放在AL、AH、XAR4、XAR5中(这些寄存器并没有使用的情况下)。
4) 所有不存放在寄存器中的参数都以reverse次序push到Stack中(最左边的参数在stack中位置为stack的末尾)。所有32-bit参数在stack中以偶数地址为边界。
结构参数事实上是以结构体的地址作为参数传入,被调用的函数必须有一个本地局部变量copy。
如果函数以省略号进行申明,表示函数可以接受变长的参数,这边进行了简单的修正。最后一个明确的参数存放在stack中,所以它的stack地址可以作为读取其他非申明参数的索引。
5) 调用者使用LCR指令调用函数,RPC寄存器变量将被push到stack中,函数的返回值将被存放在RPC寄存器中。
一个被调用函数需要进行以下步骤:
1) 如果被调用函数修改了XAR1、XAR2、或者XAR3,则必须保存修前的值,因为调用函数在这些寄存器中保存了变量,其他寄存器使用之前并不需要预先保存;
2) 被调用函数在stack中为局部变量、临时变量、函数可能使用的参数分配了足够的内存空间,在函数初始化时增加常量到SP寄存器中,内存空间的分配会发生;
3) 如果被调用函数需要使用结构体参数,它只会接收到一个结构体指针。如果被调用函数需要对该结构进行写操作,该结构体必须在stack中有一个本地保存的局部变量,接收的结构体指针被copy到本地保存的局部变量中。如果对于该结构没有写操作,被调用函数直接使用该指针参数作为引用。
当被调用函数需哟啊接收一个结构体参数时,必须谨慎的声明函数,包括它们被使用的地方(结构体参数为作为地址传递的)和它们被声明的地方(函数知道copy该结构体到本地局部变量)。
4) 被调用函数执行函数的code;
5) 被调用函数返回值被保存在寄存器中,规则如下:
16-bit 整形变量:AL
32-bit 整形变量:ACC
16-或者22-bit 指针:XAR4
如果函数返回结构体,调用者会为这个结构体申请内存空间,同时将被调用函数的返回内存空间地址传递进去(XAR4),对于返回结构体,被调用函数通过外部参数copy结构体到内存块中。
通过这种方法,调用者可以通知被调用函数是否返回结构体。
6) 被调用函数分配内存通过减去之前加在SP的值。
7) 被调用函数恢复之前Step1保存的所有寄存器变量。
8) 被调用函数通过LRETR指令返回。PC使用RPC寄存器保存的变量,之前RPC的值从stack中pop出,并保存。
2008-1-13
写中断程序时,需要注意以下几点:
1) 中断程序没有参数,即使声明了,它们也会被忽略掉;
2) 中断程序可以被一般的C/C++代码调用,但是其效率很低,因为调用时会保存所有的寄存器;
3) 中断程序能够响应一个中断或者多个中断。编译器不会为中断增加特殊代码,除了系统复位中断程序:c_init00。当进入中断程序时,不能认为run-time的stack已经建立起来了,因此,你无法分配局部变量以及保存任何信息在run-time stack中。
4) 为了使得中断程序和中断结合,中断函数的地址必须放在合适的中断向量表中。可以使用assembler和linker通过.sect创建中断地址表。
5) 在汇编程序中,记得在符号名称前增加下划线,例如:c_int00到_c_int00。
c_int00函数执行了以下操作,初始化C/C++环境:
1) 为run-time stack申请内存空间,设置初始的stack pointer变量;
2) 初始化寄存器状态位,并设置寄存器为期望值;
3) 将.cinit内初始化表的数据copy到申请内存空间的.bss内,在RAM自动初始化模式下,loader在函数运行前进行这一步的操作(而不是由boot程序);
4) 执行.pinit段中断全局构造;
5) 调用main()函数开始C/C++程序。