3.2 机器语言和汇编语言
请看代码清单3.1中列出的机器语言程序,这段程序在第2章中已经介绍过了,功能是把由指拨开关输入的数据输入CPU,然后CPU再把这些数据原封不动地输出到LED。也就是说,可以通过指拨开关控制LED的亮或灭
代码清单3.1 点亮LED的机器语言程序
地址 机器语言
00000000 00111110
00000001 11001111
00000010 11010011
00000011 00000010
00000100 00111110
00000101 11111111
00000110 11010011
00000111 00000010
00001000 00111110
00001001 11001111
00001010 11010011
00001011 00000011
00001100 00111110
00001101 00000000
00001110 11010011
00001111 00000011
00010000 11011011
00010001 00000000
00010010 11010011
00010011 00000001
00010100 11000011
00010101 00010000
00010110 00000000
这段由8比特二进制数构成的机器语言程序总共23个字节。若把这些字节一个接一个地依次写入内存中,所占据的内存空间就是00000000-00010110。一旦重置了CPU,CPU就会从0号地址开始顺序执行这段程序
在机器语言程序中,虽然都是0和1的组合,但每个组合都是有特定含义的指令或数据。可是对人类来说,如果只看0和1的话,恐怕很难判断各个组合都表示什么
于是就有人发明了一种编程方法,根据表示指令功能的英语单词起一个相似的昵称,并将这个昵称赋予给0和1的组合。这种类似英语单词的昵称叫做“助记符”,使用助记符的编程语言叫做“汇编语言”。无论是使用机器语言还是汇编语言,所实现的功能都一样的,区别只在于程序是用数字表示,还是用助记符表示。也就是说,如果理解了汇编语言,也就理解了机器语言,更进一步也就理解了计算机的原始工作方式
代码清单3.1中的机器语言可以转换成如代码清单3.2所示的汇编语言。汇编语言的语法十分简单,以至于语法只有一个,即把“标签”“操作码(指令)”和“操作数(指令的对象)”并排写在一行上,仅此而已
代码清单3.2 用汇编语言的代码表示代码清单3.1中的机器语言
标签 操作码 操作数
LD A,207
OUT (2),A
LD A,255
OUT (2),A
LD A,207
OUT (3),A
LD A,0
OUT (3),A
LOOP: IN A,(0)
OUT (1),A
JP LOOP
标签的作用是为该行代码对应的内存地址起一个名字。编程时如果总要考虑“这一行的内存地址是什么来着?”就会很不方便,所以在汇编语言中用标签来代替地址。用汇编语言编程时可以在任何需要的标签的地方“贴上”名称任意的标签。在代码清单3.2所示的程序中,使用了名为LOOP:的标签
操作码就是表示“做什么”的指令。因为用助记符表示的指令是英语单词的缩写,比如LD是Load(加载)的缩写,所以多少能猜出其含义。汇编语言中提供子多少种助记符,CPU就有多少种功能。Z80 CPU的指令全部加起来有70条左右,这里先把主要的指令列在表3.1中,请大家粗略浏览一下。在浏览的过程中请注意这些指令的分类,按功能这些指令可以分成运算、与内存的输入输出和与I/O的输入输出三类。这是因为计算机能做的事也只有输入、运算、输出这三种了
操作数表示的是指令执行的对象。CPU的寄存器、内存地址、I/O地址或直接给出的数字都可以作为操作数。如果某条指令需要多个操作数,那么它们之间就要用逗号分隔。操作数的个数取决于指令的种类。也有不需要操作数的指令,比如用于停止CPU运转的HALT指令
汇编语言的语法和英语祈使句的语法很像。若对比英语的祈使句Give me money和汇编语言的语句,就可以看出在英语的祈使句中,一开头放置了一个表示“做什么”的动词,这个动词就相当于汇编语言中的操作码。在动词后面放置了一个表示“动作作用到什么上”的宾语,这个宾语就相当于汇编语言中的操作数。因为程序的作用是向CPU发出指令,而且编程语言又是由说英语的人发明的,所以编程语言与英语祈使句类似也就不足为奇了
构成机器语言的是二进制数,而在汇编语言中,则使用十进制数和十六进制数记录数据。若仅仅写出123这样的数字,表示的就是十进制数;而像123H这样在数字末尾加一个H(H表示Hexadecimal,即十六进制数),表示的就是十六进制数。在代码清单3.2所示的程序中,使用的都是十进制数
表3.1 Z80 CPU中的主要指令
指令的种类 助记符 功能
运算指令
ADD A,num 把数值num加到寄存器A的值上
ADD A,reg 把寄存器reg的值加到寄存器A的值上
SUB num 把寄存器A的值中减去数值num
SUB reg 把寄存器A的值中减去寄存器reg的值
INC reg 将寄存器reg的值加1
DEC reg 将寄存器reg的值减1
AND num 计算寄存器A的值和数值num的逻辑积
AND reg 计算寄存器A的值和寄存器reg的值的逻辑积
OR num 计算寄存器A的值和数值num的逻辑和
OR reg 计算寄存器A的值和寄存器reg的值的逻辑和
XOR num 计算寄存器A的值和数值num的逻辑异或
XOR reg 计算寄存器A的值和寄存器reg的值的逻辑异或
SLA reg 对寄存器reg的值进行算数左移运算
SRA reg 对寄存器reg的值进行算数右移运算
SRL reg 对寄存器reg的值进行逻辑右移运算
CP num 比较寄存器A的值和数值num的大小
CP reg 比较寄存器A的值和寄存器reg的值的大小
内存与CPU之间的输入输出指令
LD reg,num 把数值num写入到寄存器reg中
LD reg1,reg2 把数值reg2的值写入到寄存器reg1中
LD (num),reg 把寄存器reg的值写入到地址num上
LD (reg),reg 把寄存器reg2的值写入到存放在寄存器reg1中的地址上
PUSH reg 把寄存器reg的值写入到栈中
POP reg 把由栈顶读出的数据存放到寄存器reg中
I/O与CPU之间的输入输出指令
IN A,(num) 从地址num中读出数据,存放到寄存器A中
IN reg,(c) 从存储在寄存器C中的地址读出数据,存放到寄存器reg中
OUT(num),A 把寄存器A的值写入到地址num上
OUT(c),reg 把寄存器reg的值写入到存储在寄存器C中的地址上
程序流程控制指令
JP num 使程序的流程跳转到地址num,接下来从那个地址的指令开始执行
CALL num 调用存放在地址num上的子进程
RET 从子例程中返回
HALT 终止CPU的运行
num:表示1个数值;
(num):表示值为num的地址
reg、reg1、reg2:名为reg、reg1、reg2的寄存器
(reg):存储在名为reg的寄存器中的地址
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论