Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1530794
  • 博文数量: 226
  • 博客积分: 3997
  • 博客等级: 少校
  • 技术积分: 2369
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-19 17:26
个人简介

Never save something for a special occasion. Every day in your life is a special occasion.

文章分类

全部博文(226)

文章存档

2018年(5)

2017年(11)

2016年(1)

2015年(17)

2014年(14)

2013年(30)

2012年(5)

2011年(52)

2010年(107)

分类: C/C++

2011-01-22 13:06:47

目录:
第二章  混合语言.............................. 31
Little Endian.................................31
函数与参数的命名规则..........................32
 全局变量................................32
 局部变量................................32
 函数..................................33
 函数的参数..............................34
参数的传递................................34
返回值....................................34
寄存器内容的保存............................34
在 C程序调用汇编语言函数.......................35
在汇编程序调用 C函数.........................36
使用汇编语言撰写 ISR函数........................38


正文:

第二章 混合语言
Holtek C&ASM混合编程相关议题:
  Little endian
  函数与参数的命名规则
  参数的传递
  返回值
  寄存器内容的保存
  在 C程序中调用汇编语言函数
  在汇编程序中调用C 函数
  使用汇编语言编写 ISR函数


Little Endian
HT-MCU采用 little-Endian 的数据格式。
例如:
  long var @ 0x40;
  var = 0x1234;
  地址 0x40 存放数据 0x34,地址 0x41存放数据 0x12。

函数与参数的命名规则

大小写
HT-Assembler 在处理符号名称时不分大小写。(事实上,所有的符号名称不管原来的形式为何,都将被译成大写字母。)而 HT-CCompiler 区分大小。因此,凡在 C 中定义被 ASM 程序引用的变量及函数,都必须以大写字母来命名。

前缀下划线:
当 CCompiler 将 C 编译为 ASM 时,会在全局变量与 C 语言函数的名称前加上前缀下划线(underscore)。
至于局部变量,可查看C编译器所生成的汇编语言文件,以找出 C局部变量在编译后的名称(如 CR3[1] 等~)。
提示:
如果只是宣告但未使用的局部变量,C编译器不会为其保留存储器空间。

例如1:全局变量
 TimerCt
 TMP
编译后
  _TimerCt
  _TMP

例如2:局部变量
void main(){
  int i, j, k;    ; k 未被使用
  long m;
  char c;
  i = j = m = c = 2;
  #asm
    set CR3[1].2    ; set bit 10 of m, i.e. m︱= 0x400
  #endasm
}
 
汇编语言文件中对应的部分如下:
  #line 2 “C:\Holtek IDE\SAMPLE\NAME.C”
  LOCAL CR1 DB ? ; i
  #pragma debug variable 2 CR1 i
  #line 2 “C:\Holtek IDE\SAMPLE\NAME.C”
  LOCAL CR2 DB ? ; j
  #pragma debug variable 2 CR2 j
  #line 3 “C:\Holtek IDE\SAMPLE\NAME.C”
  LOCAL CR3 DB 2 DUP (?) ; m
  #pragma debug variable 2 CR3 m
  #line 4 “C:\Holtek IDE\SAMPLE\NAME.C”
  LOCAL CR4 DB ? ; c
  #pragma debug variable 2 CR4 c
第二与第三行表示 i 被译成汇编语言中的 CR1,同理 j、m、c,但k没有被使用所以没有被编译。
注意:  如果加入新的局部变量或调整局部变量的顺序,那么编译后的名称会有所改变。


例如3:函数
 GetKey
 IsBusy
译成
  _GetKey
  _IsBusy

函数的参数:
C 函数的参数被译为函数名加后缀序号。
例如:
 GetKey (int row, long col)
 row 被译为 GetKey0
 col 被译为 GetKey1


参数的传递
由于单片机的资源限制,盛群C 编译器通过RAM存储器取代堆栈传递参数至函数。
函数参数的命名是以函数名称附加由 0开始的后缀序号(前面刚讲过)。
就像局部变量一样,函数参数也是配置在数据存储器的区块 0。
例如:
  void function (int a, int b)
参数 a 将被译成为 function0,参数 b 将被译为 function1。

BYTE!
混合编程时,即使函数参数的数据类型超过一个字节,在汇编语言中仍应该把它宣告为 BYTE的数据类型。
例如:
参数为 WORD (2 个字节) 的数据类型时,应该使用“DB 2 DUP(?)”来宣告。

返回值
C 函数的返回值会被存于 A 寄存器或 RH 系统变量。
如果返回值的大小是一个字节(例如 char、unsigned char、int、unsigned int、short、unsigned short) ,
则返回值被储存于 A 寄存器,如果返回值的大小是二个字节(例如 long、unsigned long、pointer)则高字节被储存于RH而低字节被储存于 A寄存器。 
注意: RH变量位于RAM 存储器的区块0。

寄存器内容的保存
除了 ISR 函数, 在所有使用汇编语言设计的函数中, 不需要保存寄存器的内容(CCompiler已经帮我们做了?)。
如果要用汇编语言设计 ISR 函数, 则使用者有责任将 ISR 中所用到的寄存器的内容保存起来,当 ISR 函数执行完毕回到被中断之处前,将原先的数据回存给这些寄存器。

在C程序中调用汇编语言函数
分为2部分:
→  ASM文件中:
  如果返回值为二个字节,则将RH宣告为 外部(external)字节变量(BYTE)。
  将以下划线为前缀的函数名称宣告为 公用函数(public)。
  如果函数有参数,将这些参数宣告在数据存储器的区块 0,以及宣告为公用的参数。注意参数的命名。
  将返回值放入A 寄存器或RH系统变量。

→  C文件中:
  将以大写字母命名的函数宣告为外部函数(external)。
  调用此函数。

例如:
在C程序调用汇编函数 long KEYIN( int row, long col )

ASM文件:
  ;; 将变量 RH 宣告为外部变量
 EXTERN RH:BYTE
 ;; 将函数与参数宣告为公用的
  PUBLIC _KEYIN, KEYIN0, KEYIN1
 ;; 将函数参数安排在存储器的区块0 ; 假设单片机具有多个ram 区块(bank)  
  RAMBANK0 KEYINDATA
  KEYINDATA .section ‘data’
  KEYIN0 DB        ?   ;row
  KEYIN1 DB 2 DUP (?)  ;col, 注意不是‘KEYIN1 DW ?’哦
 ;function body
  CODE .section ‘code’
 _KEYIN:
 ...
  MOV A, KEYIN0      ;取得参数 row 值
 ...
  MOV A, KEYIN1      ;取得参数 col 的低字节
 ...
  MOV A, KEYIN1[ 1 ]  ;取得参数 col 的高字节
 ...
 ;;将返回值放入寄存器 A 及系统变量RH 中
  MOV A, 0A0H       ; 假设返回值是 0xA010
  MOV RH, A        ; 将高字节 0xA0 存入变量 RH
  MOV A, 10H        ; 将低字节 0x10 存入寄存器 A
 RET

C文件:
  // 将被调用的函数宣告为外部函数,同时以大写字母对此函数命名
  extern long KEYIN(int row, long col);
  long rc;
  ...
  // 调用外部函数
  rc = KEYIN(10, 20L);


在汇编程序中调用C函数

和前面的C调ASM一样,也分2部分:

→  C文件中:
  宣告以大写字母命名的函数。
→  ASM文件中:
  如果返回值是二个字节,则宣告 RH为外部的(external)字节变量(BYTE)。
  宣告以下划线为前缀命名的函数为外部函数(external)。
  如果函数需要参数,则将这些参数宣告为外部参数(external),要注意参数的命名规则。
  如果函数有参数,将输入值设定给参数。
  调用C 函数。
对于单RomBank的单片机直接Call即可。
对于多RomBank的单片机在Call前必须先设置 BP 寄存器(BankPointer)为函数所在Bank。
  从 A寄存器或系统变量 RH中取出返回值。

例如:
在ASM程序调用C函数 long KEYIN( int row, long col )
 
假设单片机具有多个RomBank。

C文件:
long KEYIN(int row, long col){
 ...
 }

ASM文件:
; 宣告 RH 为外部变量
 EXTERN RH:BYTE
 ; 宣告以下划线为前缀的函数名为外部函数 
 extern_KEYIN:near  
;; 将函数的参数宣告为外部变量
 extern_KEYIN0:byte ; 参数 row
 extern_KEYIN1:byte ; 参数 col, 虽然它是 long(2 bytes)但是仍要宣告为 BYTE
code_ki  .section  ‘code’
 ;; 设定参数的输入值, 准备调用函数 KEYIN(0x10, 0x200L)
  mov a, 10
 mov KEYIN0,a    ; 参数 row
  mov a, 2
  mov KEYIN1[ 1 ],a  ; 参数 col 的高字节
 clr KEYIN1          ; 参数 col 的低字节
 ;;调用位于多个 ROM 存储器区块的函数
 ;;先要将 BP 寄存器设定为函数所在的存储器区块编号
  mov a, bank _KEYIN
  mov bp, a        ; 更改区块编号 bank number
  call _KEYIN      ; 调用函数
  ;; 从寄存器 A 或系统变量RH 中取得返回值(低高字节分别在 寄存器A 和系统变量RH 中)
  ...


使用汇编语言撰写ISR函数
ISR(中断服务程序)是由硬件中断所调用,不可由程序自行调用,因此不会有参数的输入,也不会有值返回。
如果用汇编语言撰写 ISR函数,则不会与C语言的程序有关系,只需要将此汇编语言文件加入项目即可。
不论 ISR是由汇编语言或C 语言所撰写,都不要从 ISR中调用 C函数。

阅读(1847) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~