编程论坛
直播中

黄玫玫

7年用户 171经验值
私信 关注
[问答]

关于混合编程的基本知识都在这里

C语言和汇编语言的混合编程
混合编程的方法有哪些?
混合编程的实例有哪些?
混合编程的注意事项有哪些?

回帖(1)

王树林

2021-4-25 13:44:30
  1 引言
  CCS(Code Composer Studio)是TI公司的DSP集成开发环境。它提供了环境配置、源文件编辑、程序调试、跟踪和分析等工具,帮助用户在一个软件环境下完成编辑、编译链接、调试和数据分析等工作。与TI提供的早期软件开发工具相比,利用CCS能够加快软件开发进程,提高工作效率。CCS一般工作在两种模式下:软件仿真器和与硬件开发板相结合的在线编程。前者可以脱离DSP芯片,在PC机上模拟DSP指令集与工作机制,主要用于前期算法实现和调试。后者实时运行在DSP芯片上,可以在线编制和调试应用程序。
  2 C语言和汇编语言的混合编程
  TMS320 C5000系列的软件设计通常有三种方法:
  (1 ) 用C语言开发;
  (2) 用汇编语言开发;
  (3) C和汇编的混合开发。
  其中用C语言开发具有兼容性和可移植的优点,有利于缩短开发周期和减少开发难度,但是在运算量较大的情况下,C代码的效率还是无法和手工编写的汇编代码的效率相比,比如FFT运算,用汇编语言开发的效率高,程序执行速度快,而且可以合理利用芯片的硬件资源,但是开发难度较大,开发周期长,而且可读性和可移植性差。C和汇编的混合编程则可以充分利用前两者的优点,以达到最佳利用DSP资源的目的。但是,采用C和汇编语言混合编程必须遵循相关函数调用规则和寄存器调用规则,否则会给程序的开发带来意想不到的问题。
  2.1 C语言和汇编语言混合编程的四种方法
  (1) 独立编写汇编程序和C程序,分开编译或汇编成各自的目标代码模块,再用链接器将二者链接起来。这种方法比较灵活,但是设计者必须自己维护各汇编模块的入口和出口代码,自己计算传递的参数在堆栈中的偏移量,工作量较大,但是能做到对程序的绝对控制。
  (2) 在C程序中使用汇编程序中定义的变量和常数。
  (3) 在C程序中内嵌汇编语句。这种方法可以实现C语言无法实现的一些硬件控制功能,如修改中断控制寄存器。
  (4) 将C语言编译生成相应的汇编代码,手工修改和优化C编译器生成的汇编代码。采用这种方法可以控制C编译器,从而产生具有交叉列表的汇编程序,而设计者可以对其中的汇编语句进行修改,然后对汇编程序进行编译,产生目标文件。
  后3种方法由于在C中直接嵌入了汇编语言,易造成程序混乱,破坏C环境,甚至导致程序崩溃,而开发者又很难对不良结果进行预期和有效控制。而如果采用第一种方法,只要遵循有关C语言函数调用规则和寄存器规则,就能预见到程序运行的结果,保证程序正确。
  2.2 编程注意事项
  C编译器对函数调用制定了一组严格的规则。除了特殊的运行时间支持库函数外,任何调用函数和被C函数调用的函数都必须遵守这些规则。结合作者在编程中的实际情况和切身体会,提出在编程时要注意以下几点:
  (1) 必须保护任何被函数修正的专用寄存器。这些专用寄存器包括:AR1,AR6,AR72和堆栈指针(SP)。其中,如果对SP正常使用,则不必明显的保存。换句话说,只要汇编函数在调用返回时弹出压入的对象,实际上就已经保护了SP。
  (2) 中断函数必须保存其使用的所有寄存器。
  (3) 从汇编函数中调用C函数时,第一个参数(最左边的)必须放入累加器A中,剩下的参数按照自右向左的顺序压入堆栈。
  (4) 如果函数有返回值,则返回值存放在累加器A中。
  (5) 调用C函数时,注意C函数只保护了几个特定的寄存器,对于其他寄存器C函数是可以自由使用的。
  (6) 长整数和浮点数存储在存储器中的方法是最高有效字在低位地址。
  (7) 汇编语言模块不能改变由C模块产生的.cinit段,如果改变其中的内容将会引起不可预测的后果。
  (8) 在汇编语言模块中,对可以从C中访问的变量和函数名需加上前缀“_”。对于仅用于汇编语言模块中的标识符,不用加下划线。而且如果仅在汇编中使用,只要不加下划线,即使与C程序中定义的对象名相同,也不会造成冲突。
  (9) 任何在汇编语言模块中声明的将要从C访问或调用的对象或函数,都必须在汇编语言中用.global伪指令声明为全局变量。同样,任何在C程序中定义而将在汇编中访问或调用的对象或函数,在汇编中也必须用.global声明。
  (10) 在默认的情况下,编译器总是认为CPL为1。因此,若在汇编程序中将CPL清0,则在返回C环境时,必须将其恢复为1;在默认的情况下,编译器总是认为 OVM为0。因此,若在汇编程序中将OVM置为1,则返回C环境时,必须将其恢复为0;ARP在函数进入和返回时,必须为0,即当前辅助寄存器为AR0。函数执行时可以为其他值。
  3 编程实例
  3.1 FFT算法简介
  FFT是一种高效实现离散傅立叶变换的算法,在数字信号处理系统中,FFT作为一个非常重要的工具,甚至成为DSP运算能力的一个考核因素。如何将FFT算法很好的应用到DSP系统中对于DSP系统的设计具有重要的意义。
  一个优化的实数FFT算法是一个组合以后的算法。该算法主要分为以下几步,首先将输入的2N点实序列进行位倒序组合成一个N点的复序列,之后对复序列进行N 点的FFT运算,最后再由N点的复数输出拆散成2N点的复数序列,这2N点的复数序列与原始的2N点的实数输入序列的DFT输出一致。(详细的算法介绍可参考相关信号处理书籍)。
  3.2 C主程序
  #include “stdlib.h”
  extern void fft(); // FFT运算函数
  int DisData[256]; // 输出结果
  int SimData[256]={
  0,6270,11585,15137, 16384, 15137, 11585,6270,
  0, -6270, -11585,-15137,-16384,-15137,-11585,-6270,
  ……
  0,6270,11585,15137,16384,15137,11585,6270,
  0,-6270,-11585,-15137,-16384,-15137,-11585,-6270
  };
  // 输入数据
  int main()
  {
  rfft();
  // 调用FFT函数
  while(1) ;
  }
  本程序中FFT运算所用到的数据是通过matlab仿真产生的,然后通过全局数组进行传值,这种方式的优点是数据的通用性强,方便对数据进行其他相关处理; 也可通过其他C程序产生然后保存到一个文本文件中,再由汇编程序将该数据文件拷到数据存储器中参与FFT运算。这种方式的优点是程序的可读性强,缺点是当输入数据修改后,必须进行重新编译、汇编和链接。
  (4) 如果函数有返回值,则返回值存放在累加器A中。
  (5) 调用C函数时,注意C函数只保护了几个特定的寄存器,对于其他寄存器C函数是可以自由使用的。
  (6) 长整数和浮点数存储在存储器中的方法是最高有效字在低位地址。
  (7) 汇编语言模块不能改变由C模块产生的.cinit段,如果改变其中的内容将会引起不可预测的后果。
  (8) 在汇编语言模块中,对可以从C中访问的变量和函数名需加上前缀“_”。对于仅用于汇编语言模块中的标识符,不用加下划线。而且如果仅在汇编中使用,只要不加下划线,即使与C程序中定义的对象名相同,也不会造成冲突。
  (9) 任何在汇编语言模块中声明的将要从C访问或调用的对象或函数,都必须在汇编语言中用.global伪指令声明为全局变量。同样,任何在C程序中定义而将在汇编中访问或调用的对象或函数,在汇编中也必须用.global声明。
  (10) 在默认的情况下,编译器总是认为CPL为1。因此,若在汇编程序中将CPL清0,则在返回C环境时,必须将其恢复为1;在默认的情况下,编译器总是认为 OVM为0。因此,若在汇编程序中将OVM置为1,则返回C环境时,必须将其恢复为0;ARP在函数进入和返回时,必须为0,即当前辅助寄存器为AR0。函数执行时可以为其他值。
  3 编程实例
  3.1 FFT算法简介
  FFT是一种高效实现离散傅立叶变换的算法,在数字信号处理系统中,FFT作为一个非常重要的工具,甚至成为DSP运算能力的一个考核因素。如何将FFT算法很好的应用到DSP系统中对于DSP系统的设计具有重要的意义。
  一个优化的实数FFT算法是一个组合以后的算法。该算法主要分为以下几步,首先将输入的2N点实序列进行位倒序组合成一个N点的复序列,之后对复序列进行N 点的FFT运算,最后再由N点的复数输出拆散成2N点的复数序列,这2N点的复数序列与原始的2N点的实数输入序列的DFT输出一致。(详细的算法介绍可参考相关信号处理书籍)。
  3.2 C主程序
  #include “stdlib.h”
  extern void fft(); // FFT运算函数
  int DisData[256]; // 输出结果
  int SimData[256]={
  0,6270,11585,15137, 16384, 15137, 11585,6270,
  0, -6270, -11585,-15137,-16384,-15137,-11585,-6270,
  ……
  0,6270,11585,15137,16384,15137,11585,6270,
  0,-6270,-11585,-15137,-16384,-15137,-11585,-6270
  };
  // 输入数据
  int main()
  {
  rfft();
  // 调用FFT函数
  while(1) ;
  }
  本程序中FFT运算所用到的数据是通过matlab仿真产生的,然后通过全局数组进行传值,这种方式的优点是数据的通用性强,方便对数据进行其他相关处理; 也可通过其他C程序产生然后保存到一个文本文件中,再由汇编程序将该数据文件拷到数据存储器中参与FFT运算。这种方式的优点是程序的可读性强,缺点是当输入数据修改后,必须进行重新编译、汇编和链接。
  将输入信号通过Matlab仿真进行验证。输入信号的时域波形见图4。
  
  图4 输入信号的时域波形
  经FFT运算后得到的信号幅值谱图见图5。
  
  图5 信号幅值谱图
  通过比较CCS中的输出图形和Matlab中的仿真输出图形, 可以看到二者是一致的,说明本程序的结果是正确的。
  4 结束语
  本文通过实例,说明了TMS320 C5000系列DSP芯片的混合编程方法,利用混合编程达到了提高程序的可读性与编程效率的目的,是开发DSP软件的常用方法。本文介绍的混合编程方法不但适用于TI C5000系列DSP芯片,同样也适用于TI其他系列的DSP芯片,如C2000系列、C6000系列,甚至对其他芯片,如51系列单片机等,实现混合编程也有很大参考价值。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分