为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

第4章 C55x处理器的软件设计

2012-10-06 50页 ppt 1MB 11阅读

用户头像

is_144896

暂无简介

举报
第4章 C55x处理器的软件设计nullnull第4章 C55x处理器的软件设计 内容提要 C55x系列处理器应用灵活、处理能力强大,为开发、使用提供了一个很好的硬件平台,要使这个平台更好的发挥作用,高效、方便的软件设计是不可或缺的。 程序的主体框架和对实时性要求不高的部分采用C/C++语言,而算法实现采用汇编语言,这样能够充分发挥二者的优点,解决易读性和效率之间的矛盾。同时也改善了软件的移植性,在软件移植时不用改变程序的主体框架,只要为处理器提供相应的算法即可。 本章主要介绍了C55x处理器的程序基本结构,C语言编程以及优化,...
第4章 C55x处理器的软件设计
nullnull第4章 C55x处理器的软件设计 内容提要 C55x系列处理器应用灵活、处理能力强大,为开发、使用提供了一个很好的硬件平台,要使这个平台更好的发挥作用,高效、方便的软件设计是不可或缺的。 程序的主体框架和对实时性要求不高的部分采用C/C++语言,而算法实现采用汇编语言,这样能够充分发挥二者的优点,解决易读性和效率之间的矛盾。同时也改善了软件的移植性,在软件移植时不用改变程序的主体框架,只要为处理器提供相应的算法即可。 本章主要介绍了C55x处理器的程序基本结构,C语言编程以及优化,C语言与汇编语言的混合编程,通用目标文件格式,最后对C55x处理器的数字信号处理库和图像、视频处理库进行了介绍。 null第4章 C55x处理器的软件设计 4.1 C55x处理器程序基本结构 4.2 C语言程序开发及优化 4.3 C语言与汇编语言的混合编程 4.4 通用目标文件格式 4.5 C55x处理器的数字信号处理库和图像、视频处理库 null第4章 C55x处理器的软件设计 C55x处理器软件开发流程 null第4章 C55x处理器的软件设计 ● 汇编器:是把汇编源代码转换成机器语言。 ● 汇编器:是把汇编源代码转换成机器语言。 ● 链接器:则将多个目标文件结合成一个可执行文件 。 ● 归档器:可以把一组文件归档为一个库,供用户使用。 如果用户只用汇编语言编写程序,则将跳过C编译器而直接通过汇编器生成目标文件。null第4章 C55x处理器的软件设计 4.1 C55x处理器程序基本结构 根据任务调度的方式不同,C55x处理器程序大体可以分为两类 : (1) 由程序自己完成任务调度 程序运行效率高,对硬件中断响应快,程序运行稳定,适合于任务较为单一,实时性较强的应用; (2) 由嵌入式操作系统完成任务调度 但如果要利用处理器同时完成多个任务,应用嵌入式操作系统是十分有必要的,这是因为嵌入式操作系统可以将应用分解为多个任务,简化了应用系统软件设计,更为重要的是良好的多任务设计有助于提高系统的稳定性和可靠性。null第4章 C55x处理器的软件设计 4.1.1 自我调度程序的基本结构 虽然嵌入式操作系统已经发展得较为成熟,但通过程序自身完成任务调度仍然保持着旺盛的生命力,这是因为这种方式适合于DSP这种需要对大量实时数据完成顺序处理的应用。下面给出自我调度程序的基本结构。 中断程序1; …… 中断程序m; Main() { DSP_INT(){……}; //DSP初始化 For(;;) //主循环 { if(条件1) //判断条件1 { 处理模块1; //条件满足运行处理模块1 }; …… if(条件n) //判断条件n { 处理模块n; //条件满足运行处理模块n }; } }null第4章 C55x处理器的软件设计  初始化部分通常完成DSP软、硬件的初始化设置,启动系 统硬件,使能DSP中断,启动DMA传送等工作。  主循环部分是程序的主体,将由它完成数据输入、处理和输出等工作。主循环由条件判断和处理模块组成,当满足条件时运行处理模块,不满足条件则自动跳到下一个判断条件。  中断程序通常不进行数据处理,只通过设置判断标志来影响主循环部分的运行。 自我调度程序通常由中断程序部分、初始化部分和主循环部分组成 :4.1.1 自我调度程序的基本结构null第4章 C55x处理器的软件设计 为了满足实时运行的要求,自我调度程序的主循环部分必须将处理时延限制在最大可接受时延内,具体来说就是运行主循环的所有分支的时间总和必须小于最大可接受时延,如果不能满足这一条件,则在最坏情况下,会造成处理数据的不连续,而无法实现数据的实时处理。 当所编写的程序没有满足上述条件时,则需要对处理流程进行修改,或修改处理算法以满足条件。 4.1.1 自我调度程序的基本结构null第4章 C55x处理器的软件设计 在数字信号处理器中运行的操作系统必须满足系统实时性要求,而操作系统的实时方式可以分成两种——硬实时方式和软实时方式。 软实时系统由软件来进行任务的切换,而硬实时系统则按照固定时钟节拍切换任务。软实时系统使各个任务尽快运行,而不要求限定某个任务在多长时间内完成;硬实时系统中各任务不仅要执行无误,而且要准时。 4.1.2 应用嵌入式操作系统 嵌入式实时操作系统的作用就是合理调度、分配任务的运行,使各个任务正确、及时地执行。 null第4章 C55x处理器的软件设计 嵌入式操作系统的核心是操作系统内核,在多任务系统中,内核负责管理各个任务,为每个任务分配CPU时间,负务间的通信和任务切换。根据其重要程度的不同系统中每个任务被赋予一定的优先级,内核将根据任务的优先级进行任务调度。基于优先级的内核可以分成不可剥夺型和可剥夺型两种类型。 4.1.2 应用嵌入式操作系统 null第4章 C55x处理器的软件设计 1. 不可剥夺型内核 不可剥夺型内核要求每个任务主动放弃CPU使用权,这种任务的调度方法也可以叫做合作型多任务,每个任务相互合作,共享一个CPU。 不可剥夺型内核中的异步事件由中断服务来处理,中断服务可以使一个高优先级的任务由挂起态变为就绪态;但在中断服务之后,CPU的使用权还给原来被中断的任务,直到该任务主动放弃CPU的使用权,一个高优先级的任务才能进入运行态。 4.1.2 应用嵌入式操作系统 null第4章 C55x处理器的软件设计 这种内核的优点是响应中断快,采用不可剥夺型内核允许任务使用不可重入函数,每个任务调用不可重入型函数不必担心其他任务可能使用该函数而造成数据破坏。使用不可剥夺型内核时,任务的响应时间取决于最长任务的执行时间。使用该内核很少需要使用信号量保护共享数据,这是因为正在运行的任务不必担心其他任务抢占CPU;但如果任务使用共享设备时,还应使用互斥型信号量。 4.1.2 应用嵌入式操作系统 1. 不可剥夺型内核 null第4章 C55x处理器的软件设计 不可剥夺型内核的缺点是响应时间具有不确定性,无法确定最高优先级的任务何时能够获得CPU的使用权。 2. 可剥夺型内核 可剥夺型内核运行时,一旦具有最高优先级的任务就绪,就总能得到CPU的使用权。当有一个具有更高优先权的任务进入就绪态时,当前运行的任务将被挂起,更高级的任务立刻得到CPU的使用权。1. 不可剥夺型内核 4.1.2 应用嵌入式操作系统 null第4章 C55x处理器的软件设计 如果是中断服务子程序使一个高优先级的任务进入就绪状态,中断完成后,被中断的任务被挂起,开始运行更高级的任务。使用可剥夺型内核可以随时执行最高级任务,这使得任务的响应时间得以最优化。使用可剥夺内核要求应用程序不应直接使用不可重入函数,如果要使用则应满足互斥条件。 4.1.2 应用嵌入式操作系统 2. 可剥夺型内核 null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 内核的主要工作是完成任务的调度,任务也可称作线程,是一个简单的程序,该程序认为CPU完全属于自己。操作系统要求把系统所要完成的工作分解为多个任务,每个任务都是应用的一部分。任务都被赋予一定的优先级,并拥有自己的一套CPU寄存器和堆栈空间。null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 任务是一个无限循环,它必须处于下列5个状态之一: 休眠状态是任务驻留在内存之中,但并没有被系统内核所调用; 就绪状态是任务已经准备好,但由于该任务的优先级比正在运行的任务的 优先级低,还暂时不能运行; 运行状态是任务拥有CPU的使用权,正在运行; 挂起状态是任务正在等待某一个事件的发生以结束目前的等待(如等待外设的I/O操作、等待共享资源、等待定时或超时信息等事件); 发生中断时,CPU进入中断服务程序,而暂时不能运行当前的任务,任务就进入了被中断态。 null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 操作系统需要在多个任务之间转换和调度,这是因为CPU在某一时刻只能为一个任务提供服务,CPU必须为一系列任务轮流服务。多任务运行可以使CPU的利用率达到最高,并使应用程序模块化,使用多任务可以使程序更容易设计和维护。 当任务从当前任务切换到另一个任务时,必须保存正在执行的任务的当前状态。所谓“任务的当前状态”即CPU寄存器中的所有内容;这些内容被保存在任务自己的堆栈中,以备任务下次执行时恢复当前状态。在保存完当前任务后,要把下一个任务的当前状态装入CPU寄存器,并开始下一个任务的运行,这一过程叫做“任务切换”。null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 每个任务都有其优先级,任务越重要,被赋予的优先级应越高。如果程序执行过程中任务的优先级不变,则称为静态优先级;反之则称为动态优先级。 所谓“任务管理”就是在内核的控制下任务在五种状态之间切换。 null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 不同任务之间有可能会使用共同的资源,当它们同时使用共享资源时有可能发生错误,嵌入式操作系统提供了信号量这一约定机制,通过该机制可以控制共享资源的使用权,或标志某一事件的发生,也可以用来为两个任务同步。信号量有两种类型——二进制型和计数器型,实际上二进制型可以看作一个只有一位的计数器型信号量。 null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 信号量可以看作一把钥匙。当任务要运行时首先要取得这把钥匙。如果信号量已经被其他任务占用,那么该任务只好挂起并等待信号量被当前使用者释放。 null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 任务要使用信号量,首先要对信号量进行初始化。 如果任务要得到信号量,首先要执行“等待”操作。 如果该信号量有效(信号量的值大于0),则该信号量值减1,任务得以继续执行。 如果信号量的值为0,等待信号量的任务就被列入等待信号量任务表。 null第4章 C55x处理器的软件设计 如果等待时间超过某一设定值,该信号量还无效,那么等待信号量的任务自动进入就绪状态并准备运行,并向系统报一个“超时错误”信息。4.1.2 应用嵌入式操作系统 null第4章 C55x处理器的软件设计 实际上,等待该信号量的任务可能有多个。在嵌入式操作系统中通常依照优先级来决定由哪个任务取得信号量。 任务还可以释放信号量。 如果有任务等待该信号量,那么就会有一个任务进入就绪状态,信号量的值不增加。 如果这时没有任务等待信号量,则信号量的值加1。4.1.2 应用嵌入式操作系统 null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 两个任务之间可以利用信号量来取得同步,这种同步可以分成两类——单向同步和双向同步。所谓“单向同步”是指任务用一个信号量触发另一个任务。单向同步null第4章 C55x处理器的软件设计 当两个任务需要相互同步对方,这时就要用到双向同步。 两个任务的双向同步4.1.2 应用嵌入式操作系统 null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 任务之间的通信可以通过两个途径:全局变量或消息。 使用全局变量必须保证任务或中断服务子程序,在使用该变量时没有其他的任务或中断服务子程序访问该变量。 另外,如果任务没有其他机制通知其变量已经被修改了,任务就只能周期性地查询该变量的值。要避免这种情况,可以考虑使用消息邮箱或消息队列。null第4章 C55x处理器的软件设计 4.1.2 应用嵌入式操作系统 消息邮箱是一个任务或一个中断程序。通过一个指针型变量把一个消息(指针)放到邮箱之中,而一个或多个任务通过内核服务可以接收到这个消息。 内核可以提供下列邮箱服务:  初始化邮箱内的消息;  将消息放入邮箱;  等待消息进入邮箱;  从邮箱中取得消息。null第4章 C55x处理器的软件设计 消息队列则是任务或中断程序把一个消息指针放到消息队列之中,而一个或多个任务通过内核服务从消息队列中接收消息。 内核提供消息队列服务如下:  消息队列初始化,即将消息队列清空;  将一个消息放到消息队列之中;  等待消息到来;  得到消息。4.1.2 应用嵌入式操作系统 null第4章 C55x处理器的软件设计 TMS320C55x处理器为C语言开发提供了一系列工具,包括:优化C/C++编译器、链接器和归档器。 并支持混合编程。 C语言的优点在于程序可读性强。4.2 C语言程序开发及优化null第4章 C55x处理器的软件设计 4.2.1 C语言中的数据类型 C55x支持下列数据类型包括字符、定点数、浮点数、指针等。 4.2 C语言程序开发及优化null第4章 C55x处理器的软件设计 char, unsigned char pointers(数据指针) 小存储器模式 16位 0xFFFF null第4章 C55x处理器的软件设计 指针分为程序指针和数据指针两种,其区别在于程序指针寻址是按字节寻址,而数据指针以字为单位进行寻址。 null第4章 C55x处理器的软件设计 C55x处理器包含数据空间和I/O空间,为了在C/C++中对I/O空间进行寻址,编译器给出了关键字ioport,以支持I/O寻址模式。 ioport关键字可以用在数组、结构、联合以及枚举类型当中。 当用在数组中时,ioport可以作为数组中的元素;在结构中使用ioport,只能是指向ioport数据的指针而不能直接作为结构的成员。 4.2 C语言程序开发及优化4.2.2 对I/O空间进行寻址 null第4章 C55x处理器的软件设计 ioport类型只能用来声明全局或静态变量,如果在本地变量中使用ioport类型,则变量必须用指针声明。接下来给出指针声明ioport类型的例子:void foo (void) { ioport int i; /* 无效的声明 */ ioport int *j; /* 有效声明 */ }应当注意声明ioport类型的指针只有16位,这是因为I/O空间是16位寻址,而不受大/小存储器模式的限制。4.2.2 对I/O空间进行寻址 null第4章 C55x处理器的软件设计 在printf()中不能直接引用ioport指针,如果要引用,则必须进行强制类型转换“void *”,具体例子如下: ioport int *p; printf(“%p\n”, (void*)p); 4.2.2 对I/O空间进行寻址 null第4章 C55x处理器的软件设计 这段代码的编译结果如下: _foo: MOV #_i,port(#_ioport_pointer) ; 存储i在I/O空间的地址 MOV port(#_ioport_pointer),AR3 ; 载入i的地址 MOV *AR3,AR1 ; 将i的内容存放到AR1中 MOV AR1,*abs16(#_j) ; 将i的内容保存到j return 给出在本地变量中使用ioport类型的例子: int * ioport ioport_pointer; /* ioport 指针 */ int i; int j; void foo (void) { ioport_pointer = &i; j = *ioport_pointer; }null第4章 C55x处理器的软件设计 下来给出一个指向I/O空间数据指针的例子: /* 指向ioport数据: */ ioport int * ptr_to_ioport; ioport int i; void foo (void) { int j; i = 10; ptr_to_ioport = &i; j = *ptr_to_ioport; }上面代码编译结果如下: _foo: MOV #_i,*abs16(#_ptr_to_ioport) ; 存储_i的地址 MOV *abs16(#_ptr_to_ioport),AR3 AADD #–1, SP MOV #10,port(#_i) ; 向_i中存入10 MOV *AR3,AR1 MOV AR1,*SP(#0) AADD #1,SP return null第4章 C55x处理器的软件设计 上面代码编译结果如下: _foo: MOV #10,port(#_i) ; 将10存在_i中 MOV #_i,port(#_iop_ptr_to_ioport) ; 存储_i的地址 MOV port(#_iop_ptr_to_ioport),AR3 ; 载入_i的地址 MOV *AR3, AR1 ; 载入_i MOV AR1,port(#_j) ; 将10存到_j中 return下面的例子是利用ioport指针指向I/O空间的数据: /* 指向ioport数据的ioport指针: */ ioport int * ioport iop_ptr_to_ioport; ioport int i; ioport int j; void foo (void) { i = 10; iop_ptr_to_ioport = &i; j = *iop_ptr_to_ioport; }null第4章 C55x处理器的软件设计 4.2.3 interrupt关键字 中断操作需要使用特定的寄存器保存规则,并具有特殊的返回顺序。 C55x编译器使用了关键字“interrupt”定义中断函数。 当C/C++代码被中断时,中断程序必须保存所有与程序有关的寄存器。 当使用“interrupt”关键字定义函数时,中断函数必须返回空并且没有参数传递。 null第4章 C55x处理器的软件设计 4.2.3 interrupt关键字 中断函数可以定义本地变量并且使用堆栈。接下来给出定义中断函数的例子: interrupt void int_handler() { unsigned int flags; ... } c_int00是C/C++程序的入口点,这个函数名被系统复位中断保留,该中断服务程序用来初始化系统并调用main函数。null第4章 C55x处理器的软件设计 onchip关键字的作用是告诉编译器由该关键字定义的指针所指向的数据可以作为一个双乘法指令中的操作数。 如果onchip关键字向函数传递数据,或者最终所引用的数据是用onchip定义的,则该数据必须在片上内存。 如果该数据在片外,则当通过BB数据总线访问该数据时将产生一个总线错误。 下面给出用onchip定义数组和指针的例子。 onchip int x[100]; /* array declaration */ onchip int *p; /* pointer declaration */ 4.2.4 onchip关键字 null第4章 C55x处理器的软件设计 4.2.5 C语言的优化 如果将未经优化的C语言程序直接运行会发现运行效率较低,并且产生的代码较大,而通过优化可以较好地解决这些问题。 优化的作用是对循环进行化简,重新组织表达式和声明,将变量直接分配到寄存器中。 通过优化可以提高程序运行效率,缩小程序编码数量。 null第4章 C55x处理器的软件设计 4.2.5 C语言的优化 C/C++编译器提供了不同的优化选择,通过修改cl55命令行中的-on选择就可以方便地选择不同的优化等级,n代表优化等级,包括0、1、2和3。下面给出不同优化等级的功能。 (1) O0  简化控制流图  把变量分配到寄存器  分析循环的各种情况,只保留一个退出循环的分支 删除未用的代码 简化表达式和声明 把用inline声明的函数变为调用关系null第4章 C55x处理器的软件设计 4.2.5 C语言的优化 (2) O1 除了 O0的各种优化功能外,还有如下功能: 在分配变量时,将数值直接赋给变量而不是给出变量的索引值 去掉没有用的分配变量和表达式 去掉本地通用表达式null第4章 C55x处理器的软件设计 (3) O2 除了 O1的各种优化功能外,还有如下功能: 完成循环优化 去掉全局通用的子表达式 去掉全局没有用的分配变量和表达式 完成循环的化解 当只用-o选项时优化器自动进行-O2优化4.2.5 C语言的优化 null第4章 C55x处理器的软件设计 (4)O3 除了 O2的各种优化功能外,还有如下功能: 去掉未调用的函数 简化返回值未使用的函数 将小函数进行内嵌调用 对被调用的函数声明进行重新排序,以便被优化的调用方能够找到该函数 完成文件级优化4.2.5 C语言的优化 null第4章 C55x处理器的软件设计 4.2.5 C语言的优化 优化器分析数据流时将尽量减少对内存的访问,如果这个数据必须从内存中得到,则该数据必须用volatile关键字定义,这样可以使编译器不对该变量进行优化。 例如声明一个指针 unsigned int *ctrl; 当在循环中有如下语句时 while (*ctrl != 0xFF); 优化器将只在进入循环的初始化中进行一次内存读,而在循环当中不在更新该变量的内容,如果该变量被中断或其他程序改变,由于循环中的ctrl的值没有更新,将会使程序不能按照正确的方式执行,这里应当用如下方法声明ctrl: volatile unsigned int *ctrl; 特别当该变量在中断函数中被赋值,而该变量在主函数的循环中被用到时,必须用volatile声明该变量。 null第4章 C55x处理器的软件设计 4.3.1 在C语言中直接嵌套汇编语句 C55x的C/C++编译器允许使用者在C语言代码中直接嵌套汇编语句,嵌套汇编语句的语法十分简单,只需在嵌入的汇编语句前面加上asm标示符,左右加上一个双引号和一个小括号即可。 asm ("汇编语句") 4.3 C语言与汇编语言的混合编程null第4章 C55x处理器的软件设计 4.3.1 在C语言中直接嵌套汇编语句 采用直接嵌套汇编语句的方法比较适合完成对硬件进行操作、设置状态寄存器、开关中断等工作,这样做往往要比用C语言实现效率更高。 用C语言打开中断的代码: IRQ_globalEnable(); //全局开中断 下面给出该代码编译后的结果: 0115A6 IRQ_globalEnable: 0115A6 3C3B MOV #3,AR3 0115A8 DF6105 MOV uns(*AR3),AC0 0115AB 76080040 BFXTR #2048,AC0,T0 0115AF 20 NOP 0115B0 46B2 BCLR ST1_INTM 0115B2 4804 RET 可以看到采用C语言打开全局中断共用了6条语句,考虑到调用子函数的开销,完成该功能一共要花费10个左右的指令周期,而采用嵌套汇编语句的方法则只用一条指令即可: asm ("BCLR ST1_INTM") null第4章 C55x处理器的软件设计 4.3.1 在C语言中直接嵌套汇编语句 采用直接嵌套的方法要十分小心,这是因为C语言编译器并不检查和分析所嵌入的汇编语句,而嵌入的语句很可能改变C语言的运行环境。 例如嵌入跳转指令或者标号将会引起不可预测的后果。 如果采用嵌套汇编语句,在编译程序时不应采用优化功能,采用优化功能可能会调整汇编语句周围代码的排列顺序,有可能改变程序的运行结果。 如果采用该方法实现较复杂的功能,会造成程序的可读性较差,并影响程序的可移植性,因此在采用汇编语言实现较复杂的功能时,更可行的方法是独立编写C语言程序和汇编程序,C语言通过函数调用汇编子程序,这样既可以提高程序的运行效率,又保证了程序的可移植性,这要做的优点还有程序的结构性较好,并不影响C语言编译器的优化功能。 null第4章 C55x处理器的软件设计 要很好地使用C语言与汇编的混合编程技术,必须对C语言调用子函数的规则详细掌握,这些规则包括C/C++中寄存器的使用、函数的结构及调用规则等,只有这样才能正确完成C语言对汇编模块的调用。4.3.2 C语言调用汇编模块的接口 null第4章 C55x处理器的软件设计 4.3.2 C语言调用汇编模块的接口 1. C/C++中的寄存器规则 这些规则决定编译器在C语言环境下如何使用寄存器和如何在调用函数时传递参数。 在函数调用时把函数调用方叫做父函数,被调用方叫做子函数。 规则在函数调用时所用到的寄存器需要预先保存,保存工作部分由父函数完成,父函数没有保存的而又被子函数用到的寄存器由子函数保存。 null第4章 C55x处理器的软件设计 null第4章 C55x处理器的软件设计 状态寄存器作为标志DSP运行状态的寄存器在运行中起着重要的作用,表4-3介绍了各状态寄存器各字段的作用、默认值以及是否可以修改。 ST0-551. C/C++中的寄存器规则null第4章 C55x处理器的软件设计 ST1-55nullST2-55第4章 C55x处理器的软件设计 nullST3-55第4章 C55x处理器的软件设计 null第4章 C55x处理器的软件设计 2. 函数调用规则 父函数在调用子函数时首先要将所要传递的参数放入寄存器或堆栈: ⑴ 如果一个函数的变量用一个省略号声明(标志参数的数量是变化的),则剩余的参数跟着最后一个被声明的参数被传到堆栈,而堆栈的地址将作为访问其他未声明参数的索引。null第4章 C55x处理器的软件设计 2. 函数调用规则⑵ 编译器通常先对所要传递的参数归类,之后按照所归类别将参数放到寄存器中,参数可以分成三类: ●数据指针(int *, long *, 等) ●16位数据(char, short, int) ●32位数据(long, float, double, 以及函数指针) 如果参数是指向数据类型的指针,则该参数就是数据指针;如果一个参数能够放入一个16位寄存器,则被看成一个16位数据;否则该参数被看成一个32位数据。 null第4章 C55x处理器的软件设计 2. 函数调用规则⑶ 一个32位(两个字)或小于32位的结构被当作一个32位数据通过寄存器传送。⑷ 如果结构的长度大于2个字,则通过索引传送,即编译器把该结构的地址作为一个数据指针传送。⑸ 如果子函数返回的值是一个结构或一个联合,则父函数在本地堆栈为结构分配相应的大小。父函数将该空间的地址作为第一个隐含参数送给子函数,这个参数被看作一个数据指针。 ⑸下面的例子说明了这一情况。 struct s result = fn(x,y); 这个例子是被调用子函数返回一个结构的例子,实际调用是该函数做了如下转化: fn(&result, x, y);null第4章 C55x处理器的软件设计 2. 函数调用规则⑹ 参数在函数声明中的排列位置是与其所分配的寄存器有直接关系的,它们按照表中所列顺序排列。 null第4章 C55x处理器的软件设计 2. 函数调用规则 如果参数的数量超过可使用寄存器数量,多余的参数会被压入堆栈,子函数通过堆栈得到剩余参数。 子函数的返回参数也将根据返回参数的类型使用不同的寄存器,表给出了这一对应关系。 null第4章 C55x处理器的软件设计 2. 函数调用规则 给出参数传递的例子: 首先声明两个结构,其中big的长度大于两个字节,small的长度等于两个字节。 struct big { long x[10]; }; struct small { int x; }; int fn(int i1, long l2, int *p3); //参数返回T0,传递参数分别占用 T0、AC0、AR0寄存器 long fn(int *p1, int i2, int i3, int i4); //返回AC0,参数通过AR0、T0、T1、AR1传递 struct big fn(int *p1); //返回AR0,参数通过AR1传递 int fn(struct big b, int *p1); //返回T0,参数通过AR0、AR1传递 struct small fn(int *p1); //参数返回AC0,参数通过AR0传递 int fn(struct small b, int *p1); //参数返回T0,参数通过AC0、AR0传递 int printf(char *fmt, ...); //参数返回T0,其余参数通过堆栈传递,并通过fmt的地址进行索引 void fn(long l1, long l2, long l3, long l4, int i5); //参数通过AC0、AC1、AC2、堆栈和T0传递 void fn(long l1, long l2, long l3, int *p4, int *p5, int *p6, int *p7, int *p8, int i9, int i10); //参数通过AC0、AC1、AC2、AR0、AR1、AR2、AR3、AR4、T0、T1传递null第4章 C55x处理器的软件设计 3.被调用函数的响应 被调用函数需要完成如下工作: ⑴ 子函数为本地变量、暂存空间以及函数本身可能调用函数的参数分配足够的空间,这些工作要在函数调用之初完成。 ⑵ 如果子函数修改一些寄存器,如T2、T3、AR5~AR7,需要子函数将这些数压栈或把它们存储到一个没有使用的寄存器中。如果子函数修改其他寄存器则不需要预先存储这些数。null第4章 C55x处理器的软件设计 3.被调用函数的响应⑶ 如果子函数的参数是一个结构,它所收到的是指向这个结构的指针。 如果在被调用函数中需要对结构进行写操作,就需要把这个结构复制到本地空间中,如果不进行写操作,则可以直接通过指针访问这个结构。 ⑷ 子函数执行代码。 null第4章 C55x处理器的软件设计 3.被调用函数的响应⑸ 函数按照表4-5的规则返回参数,如果子函数返回一个结构,父函数为这个结构分配空间,并传递指针到(X)AR0中。如果父函数没有使用这个结构,则在(X)AR0中返回的地址为0。 ⑹ 子函数将先前存储的寄存器值重新放到寄存器中。 ⑺ 子函数使堆栈返回调用前状态。 ⑻ 函数返回。null第4章 C55x处理器的软件设计 C/C++与汇编语言可以通过多种方式联系在一起,其中包括在C/C++中引用汇编语言中的常量或变量,并可以在C语言模块中调用汇编代码模块。 C/C++调用汇编语言模块时需要符合前面所述的寄存器规则和函数调用规则。在调用汇编模块时还应注意如下问题:4.C/C++与汇编语言的接口⑴ 调用C54x汇编函数时,应使用C54X_CALL或C54X_FAR_CALL关键字。 ⑵ 如果用汇编语言编写中断例程,则需要保存在中断例程中使用的所有寄存器。 ⑶ 如果在汇编程序中调用C/C++函数,则只有特定的寄存器在C/C++中被保存,而其他寄存器则可能被C/C++函数改变。 ⑷ 在定义汇编函数名和变量时,需要在函数名前加上下划线“ _ ”来让编译器识别。 null第4章 C55x处理器的软件设计 下面分别给出定义汇编函数和变量,以及在C语言中调用这些函数和变量的例子。 调用汇编函数的例子如下: 4.C/C++与汇编语言的接口C语言程序: /* 声明外部汇编函数 */ extern int asmfunc(int, int *); int gvar; /* 定义全局变量 */ main() { int i; i = asmfunc(i, &gvar); /* 调用 函数 */ }汇编程序: _asmfunc: ADD *AR0, T0, T0 ; gvar + T0 => i ,i= T0 RETURN ; 返回null第4章 C55x处理器的软件设计 4.C/C++与汇编语言的接口 调用汇编模块中所定义变量的例子如下: 汇编程序: .bss _var,1 ; 定义变量 .global _var ; 定义其为外部引用 C语言程序: extern int var; /* 外部变量 */ var = 1; /* 使用变量 */null第4章 C55x处理器的软件设计 4.C/C++与汇编语言的接口⑸ 如果C/C++中的变量要在汇编语言中访问,则该变量应用.global声明。 ⑹ 编译器所默认的CPL值为1,即采用间接绝对方式寻址,如果在汇编函数中CPL被设置为0,在函数返回时应当把这个值改为1。下面的例子是对应CPL=1或=0时所使用的不同汇编语句: MOV *(#global_var),AR3 ; CPL = = 1 MOV global_var, AR3 ; CPL = = 0 null⑺ 在汇编语言中可以通过.set、.global命令声明全局常量,这些常量在C/C++中可以通过特殊的方式访问。例如试图访问常量X,则在该常量名前需要加上“&”操作符,即在C/C++中该常量名为&X。例如: 第4章 C55x处理器的软件设计 4.C/C++与汇编语言的接口汇编语言: _table_size .set 10000 ; 定义常量 .global _table_size ; 定义的变量可以被全局访问C语言程序: extern int table_size; /*外部参数 */ #define TABLE_SIZE ((int) (&table_size)) …… …… …… for (i–0; i -o -m lnk.cmd * cl55x -z -o -m lnk.cmd /****************************************************************/ -c /*不区分大小写 */ -m a1.map /*生成.map文件*/ null第4章 C55x处理器的软件设计 -stack 0x1800 /*主堆栈
/
本文档为【第4章 C55x处理器的软件设计】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索