3.6 汇编语言以及汇编语句 2
1 本单元目标 了解什么是汇编语言 掌握汇编语句格式 掌握源程序框架结构
2 机器语言 & 汇编语言 机器语言:芯片的存储单元只有0和1两种状态,而芯片也只会判断0和1这两种状态,因此一串代码要让芯片“读懂” ,这串代码只能由数字0和1组成。像这种由数字0和1按照一定的规律组成的代码就叫机器码,也叫二进制编码。一定长度的机器码组成了机器指令,用这些机器指令所编写的程序就称为机器语言。 1010011000000001 表示1A 011011100000000100000000 表示1$00
2 机器语言 & 汇编语言 1001010100000001011011100000000100000000这串机器码表示:1A,1$00 机器语言的缺陷: 代码长,不好记忆,不易看懂,容易写错。 汇编语言:为了解决机器语言的缺陷,人们发明了另外一种语言——汇编语言。这种语言用符号(助记符,标号,数值)来代替冗长的、难以记忆的0、1代码串。 LDA #1T 表示1A MOV #1T,$00 表示1$00
2 机器语言 & 汇编语言 汇编:汇编语言写成的源程序,我们人类看得懂,但是芯片看不懂,它只认得机器语言,汇编源程序必须翻译成机器语言,才能在芯片上运行。利用专用的汇编工具(例如ICS08、CodeWarrior、Keil)把汇编语言写成的源程序翻译成机器语言的过程就叫汇编。 现今,人们普遍采用汇编语言和C语言来编写单片机源程序。
3 汇编语言源程序的格式 用户的汇编源程序由一条条汇编语句组成,每条最完整的语句可包括以下4个部分:标号、操作码、操作数和注释。汇编语句不区分大小写。 例如:Again: MOV #$01,RamData ;主循环的开始 标号 操作数 注释 操作码
3.1 汇编语言源程序的格式:标号 标号:实际上是代表了某行语句存放的起始地址。 标号不是必须的,绝大多数语句都没有标号,它通常只用在子函数或转移目的语句处。 一般来说,标号的前面不能有空格,在CodeWarrior中允许标号前面有空格,但是这时必须在标号的后面跟上帽号“:”;当标号的前面没有空格时,标号后面的冒号“:”可有可无。 标号只能以字母或下划线开头,后面可以跟字母、数字和下划线。 标号在标号部分只能出现一次,不能重复。 判断这些标号,找出不合法的:Init_Pro, _Init_Pro, 3Init_Pro, Again1。 (不合法:3Init_Pro)
3.2 汇编语言源程序的格式:操作码 操作码:表示某种计算或者控制,例如表示加法、跳转等等。它可以是伪指令,也可以是助记符。 操作码位于标号之后,两者用至少一个空格或Tab符隔开。对于没有标号的语句,操作符不能从一行的第一列开始写,前面应该至少有一个空格或Tab符。 操作码是必须的,在一条语句中一定存在操作码。 例ORG,EQU,ADD,MOV,INC,LDA,STA,CLR等等。
3.3 汇编语言源程序的格式:操作数 操作数:是操作码操作的对象,可以是地址、标号、数值或表达式。 操作数位于操作码之后,两者用至少一个空格或Tab符隔开。 多个操作数之间用逗号“,”隔开。 大多数指令需要操作数,但是有些隐含寻址的指令(针对CPU寄存器的操作)没有操作数,如CLRA, STX,RSP等等。
3.4 汇编语言源程序的格式:注释 注释:在一行语句中,分号“;”后面的内容为注释部分;另外,如果“*”在一行语句的第一列,也表示该行是注释。 它应由一个以上的空格或制表符与操作数或操作码(无操作数时)分开。 它可包含任何可打印的ASCII字符。 注释不是必须的,但是对于初学者,建议给每条语句写注释。
3.5 汇编语言源程序的格式:其他说明 语句中出现的标点符号“:”、“;”、“,”、“_”都必须是在“英文标点模式”下输入,而不能在“中文标点模式”下输入为“:”、“;”、“,”、“——”。 注释中出现的标点符号则不受上面的限制。 不要把数字0和字母o混淆。 不要把数字1和字母l混淆。 不同语句的标号、操作码、操作数、注释最好对齐,这样的程序美观且容易阅读。
3.6 汇编语言源程序的格式:仿真体验 运行”学生练习(找错)_汇编语言程序设计1.mcp “,对照汇编语言源程序的格式中的各个要点,找出问题并改正它们。
4 常量 常量是指那些在汇编时已经有确定数值的量。分为数值常量(也叫常数)和符号常量。 常数:以数值的形式出现在符号指令中。常数可以是二进制、十进制、十六进制和ASCII码,其中二进制、十进制、十六进制分别加前缀%、!、$或者后缀Q、T、H,ASCII码用单引号‘’表示。 如10010111Q=%10010111=97H=$97=151T ‘A’ ;等同于41H 符号常量:经常使用的地址或者数值预先用伪指令EQU定义为一个名字,然后用该名字来表示该地址或数值,这个名字就成为了符号常量。例如 PTAD EQU $0000 ;将$0000地址单元定义为符号 ;常量PTAD Ram_Start EQU 0070H ;将数值0070H定义为符号常量 ;Ram_Start
5.1 伪指令:定位伪指令ORG ORG:定位伪指令 格式:ORG <表达式> (注释) 例如:ORG $EC00 ORG伪指令把由表达式决定的值($EC00)赋给程序计数器。在其后面的指令汇编后应放在从该值($EC00)开始的存储单元中。 如果一个源程序中没有ORG伪指令,程序计数器初始值为$0000,即从0号单元开始汇编。
5.2 伪指令:赋值伪指令EQU EQU:赋值伪指令 格式:标号 EQU <表达式> (注释) RomStart EQU $C000 ;FLASH的起始地址 EQU伪指令把表达式的值赋给前面的标号。该标号不能在程序的其他地方再定义。表达式中不能使用后面定义或没有定义的符号,否则将出错。下例将出错 ORG RomStart RomStart EQU $C000 下例则是正确的: RamStart EQU $0070 ORG RamStart
5.3 伪指令:块定义DS(RMB) 格式:标号 DS(或RMB) n_ds DS(或RMB)伪指令用于在RAM存储区内定义n_ds个字节的连续存储空间,该空间不进行初始化(即定义后这些空间里面的值是不确定的)。例: ORG $0070 Data_Ds DS(或RMB) 4 上例表示从$0070开始,定义了一块了大小为4个字节的空间,且它们的值是不确定的,即($0070)=××, ($0071)=××, ($0072)=××, ($0073)=××。
执行上例后,从$0074开始的存储空间的内容为:$0074 12 34 38 61 41(a、A的ASCII值分别为61H、41H)。 5.4 伪指令:字节定义DC.B(FCB) 格式:标号 DC.B(或FCB) n1_db<,n2_db>…<,nn_db> DC.B(或FCB)伪指令用于把后面的数据n1_db<,n2_db>…<,nn_db>按字节依次连续存放在以标号作为首地址的RAM存储单元中。例: ORG $0074 Data_Db DC.B(或FCB) 12H,34H,56T,’a’,’A’ 执行上例后,从$0074开始的存储空间的内容为:$0074 12 34 38 61 41(a、A的ASCII值分别为61H、41H)。
执行上例后,从$0078开始的存储空间的内容为:$0078 00 12 00 34 00 38 00 61 00 41。 5.5 伪指令:字定义DC.W(FDB) 格式:标号 DC.W(或FDB) n1_db<,n2_db>…<,nn_db> DC.W(或FDB)伪指令用于把后面的数据n1_dw<,n2_dw>…<,nn_dw>按字依次连续存放在以标号作为首地址的RAM存储单元中。例: ORG $0078 Data_Dw DC.W(或FDB) 12H,34H,56T,’a’,’A’ 执行上例后,从$0078开始的存储空间的内容为:$0078 00 12 00 34 00 38 00 61 00 41。 汇编语言程序设计1-伪指令综合练习.MCP
6 本任务所涉及的语句介绍
6.1 INCLUDE 格式: INCLUDE '文件名' 解释: INCLUDE是汇编伪指令。INCLUDE的作用是把单引号‘’中表示的文件引入到INCLUDE语句所在的地方。 举例: 语句“INCLUDE 'derivative.inc' ;”表示把文件derivative.inc的内容嵌入到本语句所在地方。 由于derivative.inc包含以下的代码(注意,这里省略了注释信息): INCLUDE 'MC9S08AC16.inc' feed_watchdog: MACRO STA SRS ENDM INCLUDE 'derivative.inc' 的作用相当于把以上的4行语句插入到该语句所在的地方。
6.2 EQU 格式: 标号 EQU <表达式> (注释) 解释: EQU是一条伪指令,语句的作用是用标号来表示表达式的内容。 举例: ROMStart EQU $C000 ; ROMStart相当于$C000 RAMStart: EQU $0100 ; RAMStart相当于$0100 RAMEnd: EQU $046F ; RAMEnd相当于$046F
6.3 ORG 格式: ORG <表达式> (注释) 解释: 举例: ORG RAMStart ; 定位变量/数据区的起始地址 LightNum: DS.B 1 ; LightNum所在的存储单元的 ; 地址为RAMStart(即$0100)
6.4 SEI 格式: SEI 解释: SEI是一条汇编指令,表示把条件码寄存器中的I标志置为1,具体作用是禁止单片机所有的可屏蔽的中断。 举例: SEI ; 关中断
6.5 LDA 格式: LDA <操作数> 解释: LDA是一条汇编指令,表示把操作数所表示的8位立即数(数值)或操作数所表示的地址中的数值存放到累加器A中。 举例: LDA #7FH ; 7FHA, (A) =7FH LDA SOPT ; (SOPT)A, ; (A)= (SOPT)
6.6 LDHX 格式: LDHX <操作数> 解释: LDHX是一条汇编指令,表示把操作数所表示的16位立即数(数值)或操作数所表示的地址以及下一个地址所存放的数值存放到H:X中,数值的高字节给H,低字节给X。 举例: LDHX #RAMEnd+1 由于#RAMEnd+1=$046F+1=$0470,所以(H)=$04,(X)=$70。
6.7 TXS 格式: TXS 解释: TXS是一条无操作数的指令,表示把H:X中的值减去1后赋给SP,(H:X)-1SP。
6.8 INCA 格式: INCA 解释: INCA是一条无操作数的指令,使累加器A的值自增1。
6.9 DECA 格式: DECA 解释: DECA是一条无操作数的指令,使累加器A的值自减1。
6.10 AIX 格式: AIX #opr16i 解释:AIX是一条单操作数的指令,使H:X中的值增加opr16i。 举例: AIX #1 ; 使H:X中的值加1
6.11 LSR 格式: LSR <操作数> 解释: LSR是一条单操作数的指令,表示逻辑右移,使操作数所表示的数值的值向右移动1位,原来的第0位移到了条件码寄存器的C标志中,最高位补零。逻辑右移示意图如上图所示。 举例: CLC ; (C) = 0 LDA #%10100101 ; (A) = %10100101 STA PTBD ; (PTBD) = %10100101 LSR PTBD ; (PTBD) = %01010010, (C) = 1
6.12 ROL 格式: ROL <操作数> 解释: ROL是一条单操作数的指令,使操作数所表示的数值的值循环向左移动1位,原来的第7位移到第0位,原来的第0位移到第7位,条件码寄存器中的C标志的值和原来的第7位相同。循环左移示意图如上图所示。 举例: CLC ; (C) = 0 LDA #%10100101 ; (A) = %10100101 STA PTBD ; (PTBD) = %10100101 ROL PTBD ; (PTBD) = %01001011, (C) = 1
6.13 CPHX 格式: CPHX <操作数> 解释: CPHX是一条单操作数或双操作数的指令,根据H:X中的值减去操作数所表示的16位数值的结果更新条件码寄存器中的V、N、Z、C标志,H:X和操作数本身的值没有改变。 举例: CPHX #50000T ; (H:X)-50000,并更新条 ; 件码寄存器中的V、N、Z、 ; C标志
6.14 CMP 格式: CMP <操作数> 解释: CMP是一条单操作数或双操作数的指令,根据A中的值-操作数所表示的8位数值的结果更新条件码寄存器中的V、N、Z、C标志,A和操作数本身的值没有改变。 举例: CMP #4T ; (A)-4,并更新条件码寄存 ; 器中的V、N、Z、C标志
6.15 BNE 格式: BNE <操作数> 解释: BNE是一条单操作数的指令,表示不相等则跳到操作数所表示的地址,具体来说是判断条件寄存器中的Z标志,如果(Z)=0则跳到操作数所表示的地址,否则顺序执行下一条指令。 举例: AIX #1 ; 使H:X中的值加1 CPHX #50000T ; (H:X)-50000,更新条件码寄存器 ; 中的V、N、Z、C标志 BNE Delay ; 如果H:X中的值还没有达到50000, ; 则转到Delay
6.16 BRA 格式: BRA <操作数> 解释: BRA是一条单操作数的指令,表示直接跳转到操作数所表示的地址。 举例: BRA mainLoop ; 跳转到mainLoop所 ; 表示的地址
6.17 NOP 格式: NOP 解释: NOP是一条无操作数的指令,除了消耗1个指令周期的时间之外,什么事情都没有做,一般用来产生延时。