hcs08 c 语言语言语言语言 之之之之 混和编程混和编程混和编程混和编程
混和编程
1)内嵌汇编内嵌汇编内嵌汇编内嵌汇编
HCS08 C 语言提供一个很有用的功能语言提供一个很有用的功能语言提供一个很有用的功能语言提供一个很有用的功能,,,,内嵌汇编内嵌汇编内嵌汇编内嵌汇编。。。。凡是凡是凡是凡是 C 语言程序段能出现的地方汇编语言程序段能出现的地方汇编语言程序段能出现的地方汇编语言程序段能出现的地方汇编
语言源程序都可以出现语言源程序都可以出现语言源程序都可以出现语言源程序都可以出现,,,,但是汇编语言源程序必需位于一个但是汇编语言源程序必需位于一个但是汇编语言源程序必需位于一个但是汇编语言源程序必需位于一个 C 语言函数中语言函数中语言函数中语言函数中。。。。
语法格式语法格式语法格式语法格式
1) "asm" <汇编指令> ";" ["/*" 注释 "*/"]
双引号中的内容为关键字双引号中的内容为关键字双引号中的内容为关键字双引号中的内容为关键字,,,,方括号中的内容为可选项方括号中的内容为可选项方括号中的内容为可选项方括号中的内容为可选项。。。。
例如例如例如例如::::
asm sta COPCTL; /* 喂狗喂狗喂狗喂狗 */
2) "asm" "{"
<汇编指令 1> [";" 注释]
<汇编指令 2> [";" 注释]
"}"
要求要求要求::::大括号内每条汇编指令占一行大括号内每条汇编指令占一行大括号内每条汇编指令占一行大括号内每条汇编指令占一行;;;;标号以标号以标号以标号以“:”结尾占一行结尾占一行结尾占一行结尾占一行;;;;注释以注释以注释以注释以“;”开始开始开始开始;;;;可以用变可以用变可以用变可以用变
量名访问全局变量和量名访问全局变量和量名访问全局变量和量名访问全局变量和 C 函数中的局部变量函数中的局部变量函数中的局部变量函数中的局部变量。。。。汇编语言结束前要保证堆栈内容与汇编开始前汇编语言结束前要保证堆栈内容与汇编开始前汇编语言结束前要保证堆栈内容与汇编开始前汇编语言结束前要保证堆栈内容与汇编开始前
一致一致一致一致。。。。
例如例如例如例如::::用内嵌汇编方法实现统计字符串中字符的个数用内嵌汇编方法实现统计字符串中字符的个数用内嵌汇编方法实现统计字符串中字符的个数用内嵌汇编方法实现统计字符串中字符的个数。。。。
int strlen (char *str)
/*** 'str' 参数由堆栈传递. 函数返回字符串'str'的长度
假定字符串的长度小于 256!
*/
{
asm {
LDHX str ; 装入指针
CLRA ; 初始化计数器
BRA test ; 跳到 test
loop:
AIX #1 ; 指针加 1
INCA ; 计数器加 1
test:
TST 0,X ; 字符串是否结束?
BNE loop ; 下一字符
CLRX ; 返回值在 X:A(参见后文)
};
/* 这里可以继续写 C 语言程序段 */
}
2)混和调用混和调用混和调用混和调用
混和调用指的是混和调用指的是混和调用指的是混和调用指的是 C 语言函数调用汇编语言函数和汇编语言函数调用语言函数调用汇编语言函数和汇编语言函数调用语言函数调用汇编语言函数和汇编语言函数调用语言函数调用汇编语言函数和汇编语言函数调用 C 语言函数语言函数语言函数语言函数。。。。实现混和实现混和实现混和实现混和
调用要解决两个问题调用要解决两个问题调用要解决两个问题调用要解决两个问题 1::::常量和变量的相互访问常量和变量的相互访问常量和变量的相互访问常量和变量的相互访问;;;;2 调用
调用协议调用协议调用协议
1 常量和变量的相互访问常量和变量的相互访问常量和变量的相互访问常量和变量的相互访问
C 语言函语言函语言函语言函数访问汇编语言常量数访问汇编语言常量数访问汇编语言常量数访问汇编语言常量、、、、变量变量变量变量
在汇编语言源程序中采用汇编语法定义变量和常量在汇编语言源程序中采用汇编语法定义变量和常量在汇编语言源程序中采用汇编语法定义变量和常量在汇编语言源程序中采用汇编语法定义变量和常量;;;;在在在在 C 语言中把这些变量语言中把这些变量语言中把这些变量语言中把这些变量、、、、常量声明为常量声明为常量声明为常量声明为
外部常量变量外部常量变量外部常量变量外部常量变量,,,,即可以用变量即可以用变量即可以用变量即可以用变量、、、、常量名来访问常量名来访问常量名来访问常量名来访问。。。。汇编器和编译器敏感段名的大小写汇编器和编译器敏感段名的大小写汇编器和编译器敏感段名的大小写汇编器和编译器敏感段名的大小写。。。。
例如例如例如例如::::
汇编源程序中汇编源程序中汇编源程序中汇编源程序中
XDEF ASMData, ASMConst ;声明声明声明声明 ASMData, ASMConst 可以在模块外访问可以在模块外访问可以在模块外访问可以在模块外访问
MyData: SECTION
ASMData: DS.W 1 ; 定义变量定义变量定义变量定义变量
MyConst: SECTION
ASMConst: DC.W $44A6 ; 定义常量定义常量定义常量定义常量
在 C 语言源程序中
#pragma DATA_SEG MyData /* 定义变量段定义变量段定义变量段定义变量段 */
extern int ASMData; /* 变量变量变量变量 ASMData 是外部模块声明的是外部模块声明的是外部模块声明的是外部模块声明的 */
#pragma DATA_SEG DEFAULT /* 返回默认变量段返回默认变量段返回默认变量段返回默认变量段 */
#pragma CONST_SEG MyConst /* 定义常数段定义常数段定义常数段定义常数段 */
extern const int ASMConst; /* 常量常量常量常量 ASMConst 是外部模块声明的是外部模块声明的是外部模块声明的是外部模块声明的*/
#pragma CONST_SEG DEFAULT /*返回默认常数段返回默认常数段返回默认常数段返回默认常数段 */
汇编语言访问汇编语言访问汇编语言访问汇编语言访问 C 语言语言语言语言变量变量变量变量、、、、常量常量常量常量
在 C语言中用
格式定义常量、变量,在汇编语言中声明这些常量变量是外部定义即可。
例如:
在 C语言源文件中:
unsigned int CData; /* 定义变量定义变量定义变量定义变量 */
unsigned const int CConst; /* 定义常量定义常量定义常量定义常量 */
在汇编语言源文件中在汇编语言源文件中在汇编语言源文件中在汇编语言源文件中::::
XREF CData ; 外部声明的变量外部声明的变量外部声明的变量外部声明的变量
XREF CConst; 外部声明的常量外部声明的常量外部声明的常量外部声明的常量
使用:
LDD CConst
STD CData
2)调用协议调用协议调用协议调用协议
调用协议调用协议调用协议调用协议,,,,即函数参数传递和返回值的协议即函数参数传递和返回值的协议即函数参数传递和返回值的协议即函数参数传递和返回值的协议。。。。对于对于对于对于 HC08 和和和和 HCS08 调用协议是不同的调用协议是不同的调用协议是不同的调用协议是不同的。。。。
HC08 参数传递参数传递参数传递参数传递::::调用者函数把所需参数从左到右依次入栈调用者函数把所需参数从左到右依次入栈调用者函数把所需参数从左到右依次入栈调用者函数把所需参数从左到右依次入栈,,,,调用结束后由调用者函数从调用结束后由调用者函数从调用结束后由调用者函数从调用结束后由调用者函数从
堆栈中清除传递的参数堆栈中清除传递的参数堆栈中清除传递的参数堆栈中清除传递的参数。。。。在函数传递的是值参数的情况下在函数传递的是值参数的情况下在函数传递的是值参数的情况下在函数传递的是值参数的情况下,,,,如果最后一个参数长度为如果最后一个参数长度为如果最后一个参数长度为如果最后一个参数长度为 2 字字字字
节节节节,,,,则用则用则用则用 X:A 寄存器对传递寄存器对传递寄存器对传递寄存器对传递;;;;如果最后一个参数长度为如果最后一个参数长度为如果最后一个参数长度为如果最后一个参数长度为 1 字节且倒数第字节且倒数第字节且倒数第字节且倒数第 2 个参数长度超过个参数长度超过个参数长度超过个参数长度超过
1 字节字节字节字节,,,,则最后一个参数用寄存器则最后一个参数用寄存器则最后一个参数用寄存器则最后一个参数用寄存器 A 传递传递传递传递;;;;如果最后一个参数长度为如果最后一个参数长度为如果最后一个参数长度为如果最后一个参数长度为 1 字节且倒数第字节且倒数第字节且倒数第字节且倒数第 2 个个个个
参数长度也是参数长度也是参数长度也是参数长度也是 1 字节字节字节字节,,,,则最后一个参数用寄存器则最后一个参数用寄存器则最后一个参数用寄存器则最后一个参数用寄存器 X 传递传递传递传递,,,,倒数第倒数第倒数第倒数第 2 个参数用寄存器个参数用寄存器个参数用寄存器个参数用寄存器 A 传传传传
递递递递;;;;
HCS08返回值:函数返回值总是在寄存器中,根据返回值的类型不同,而采用不同的寄存
器
返回值类型返回值类型返回值类型返回值类型 寄存器寄存器寄存器寄存器
char (signed 或 unsigned) A
int (signed 或 unsigned) H:X
pointers/arrays(指针/数组) H:X
function pointers(函数指针) H:X
如果返回值的长度超过如果返回值的长度超过如果返回值的长度超过如果返回值的长度超过 2 字节字节字节字节,,,,则在则在则在则在 H:X 存放返回值的地址存放返回值的地址存放返回值的地址存放返回值的地址。。。。
例如例如例如例如::::写一段写一段写一段写一段 C 语言源程序语言源程序语言源程序语言源程序,,,,然后把它编译为汇编语言然后把它编译为汇编语言然后把它编译为汇编语言然后把它编译为汇编语言,,,,观察调用规则观察调用规则观察调用规则观察调用规则
#include /* 为了包含中断允许宏定义为了包含中断允许宏定义为了包含中断允许宏定义为了包含中断允许宏定义*/
#include
unsigned char r;
unsigned char f1(unsigned char v1,unsigned char v2,unsigned char
v3,unsigned char v4) {
v1+=1;
v2+=1;
v3+=1;
v4+=1;
return(v4);
}
void f0(void) {
r=f1(4,9,6,3);
}
void main(void) {
EnableInterrupts; /*中断允许中断允许中断允许中断允许 */
f0();
for(;;) {
__RESET_WATCHDOG(); /* 喂狗喂狗喂狗喂狗 */
}
}
在 C语言源程序中 f0函数调用 f1函数,传递参数并有返回值
函数 f1编译后的汇编语言
PSHA ; 有参数用 X、A传递,入栈保存防止破坏
PSHX
TSX ; X=SP+1
INC 5,X ; v1+=1,参数 v1在 sp+6处
INC 4,X ; v2+=1; 参数 v2在 sp+5处
INC 1,X ; v3+=1; 参数 v3在 A中,被本函数入栈
INC ,X ; v4+=1; 参数 v4在 X中,被本函数入栈
LDA ,X ; return(v4);返回值在 A中
AIS #2 ; 调整堆栈指针,指向返回地址
RTS ; 返回 f0函数
函数 f0编译后的汇编语言
LDA #4
PSHA ; 参数 v1入栈
LDA #9
PSHA ; 参数 v2入栈
LDA #6 ; 参数 v3用 A传递
LDX #3 ; 参数 v4用 X传递
BSR f1 ; 调用函数 f1
AIS #2 ; 清除传递的参数
STA r ; 保存返回值
RTS ; 返回main函数
Main函数编译后的汇编语言
CLI
BSR f0
L3:
STA _COPCTL
BRA L3
只要遵循以上调用规则,就可以实现用 C函数和汇编函数的相互调用。调用时使用对方定
义的函数名。
16.2.5 启动代码启动代码启动代码启动代码
在启动main函数之前 HCS08 C 语言会自动运行一段启动代码,进行硬件初始化和建立 C
语言的运行环境。起动代码一般由编译器自动生成,也可以由用户自写的启动代码替代自动
生成的启动代码。启动代码的名字为 start08.c,它的主要工作是:
l 禁止中断
l 从 ROM到 RAM复制并初始化数据
l 未初始化的数据区域清零
l 为堆栈分配并初始化堆栈
l 如果用到堆,创建并初始化堆
l 允许中断
l 调用main()函数