nand2tetris课程中的hack汇编语言详解
nand2tetris课程中的hack汇编语言详解
本文是关于nand2tetris课程中hack汇编语言的详细讲解,内容包括计算机基础架构、指令集、汇编语言、内存和寄存器架构、指令集实现、符号编程、低级编程、输入输出等。文章结构清晰,内容详实,包含了大量示例代码和图示,适合对计算机体系结构和汇编语言感兴趣的读者。
计算机基础架构
计算机的基础架构可以追溯到图灵机的理论模型,后来发展成为冯·诺伊曼体系。在nand2tetris课程中,我们将实现一个简化的计算机架构,如下图所示:
这个架构图省略了总线和控制单元,主要展示了程序和数据如何在内存中存储,以及算术逻辑单元(ALU)如何从内存和寄存器中取值进行运算,并将结果输出到外部设备或内存和寄存器中。
指令集
在开始实现计算机之前,我们需要定义一个指令集,这个指令集需要能够完成以下功能:
- 指定计算机要执行的操作,比如取数或运算
- 控制硬件的执行流程,比如条件跳转
- 指定操作数的来源和结果的存储位置
在设计指令集时,需要在硬件实现和软件功能之间进行权衡。例如,这门课程没有在指令集层次支持乘法操作,而是通过软件算法来实现。
hack汇编语言
在介绍hack汇编语言之前,先来看一段标准的汇编语言代码:
相比于高级语言,汇编语言更接近计算机底层的执行机制,只提供基本的算术运算和逻辑运算。编写汇编代码时,思维模式会更加聚焦于数据的搬运和基本运算。
hack计算机的内存和寄存器架构
在通用计算机中,代码和数据通常存储在同一块内存中,但在hack计算机中为了简化处理,将代码和数据分别存储在两块独立的内存中。
hack计算机有两个主要寄存器:
- A寄存器:用于存放地址
- D寄存器:用于存放数据
此外,还有一个特殊的变量M,用于表示当前数据区选中的值,可以对其进行赋值和运算。
hack计算机指令集
hack计算机提供了两种基本指令集:A指令集和C指令集。
A指令集
A指令集用于取址操作,格式为@address
,其中address
可以是立即数或符号地址。执行时,地址值会被自动赋值给A寄存器。
C指令集
C指令集功能更为丰富,支持以下操作:
- A/D/M寄存器可以赋值立即数(常数),但可选值只有0、-1、1三种
- A/D/M寄存器之间可以互相赋值,支持取反操作
- 支持算术运算(+、-)和逻辑运算(&、|),并支持立即数1的操作
- 跳转指令,用于控制程序执行流程
hack计算机的Symbolic programming
为了提高代码的可读性和可维护性,hack汇编语言引入了以下符号编程特性:
分支
通过跳转指令实现条件分支和循环控制。例如:
变量
使用小写字母表示内存地址,从16号地址开始,前16个地址被保留给内置变量R0-R15。
标签
使用标签来简化跳转指令的编写,避免直接使用行号。
实战
编写汇编代码时,建议先用伪代码规划逻辑,再将其翻译成汇编语言。例如:
hack计算机低级编程
在这一部分,主要介绍了迭代和指针等低级编程概念,并通过具体示例展示了如何在hack汇编中实现这些功能。
hack计算机指令集补充
A指令集的两种用法
A指令集有两种主要用法:直接寻址和间接寻址。
C指令集的完整概述
C指令集的完整指令格式和编码规则如下:
输入与输出
hack计算机内置了显示器和键盘芯片,并将它们映射到内存的特定区域。
显示器
显示器的内存区域从@SCREEN
开始,可以通过写入16位的-1来快速设置一大块像素点为黑色。
键盘
键盘的输入值存储在@KBD
对应的内存位置,当没有键被按下时,该位置的值为0。
课程作业
课程提供了两个实践项目:
实现乘法
通过重复加法实现乘法运算:
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/4/Mult.asm
// Multiplies R0 and R1 and stores the result in R2.
// (R0, R1, R2 refer to RAM[0], RAM[1], and RAM[2], respectively.)
// The algorithm is based on repetitive addition.
@R2
M=0
@R0
D=M
@END
D;JEQ
@R1
D=M
@END
D;JEQ
@i
M=0
(LOOP)
@i
D=M
@R1
D=D-M
@END
D;JEQ
@R0
D=M
@R2
M=M+D
@i
M=M+1
@LOOP
0;JMP
(END)
@END
0;JMP
白屏/黑屏
这个程序展示了如何通过循环操作实现屏幕的清屏和填充:
// Runs an infinite loop that listens to the keyboard input.
// When a key is pressed (any key), the program blackens the screen,
// i.e. writes "black" in every pixel. When no key is pressed,
// the screen should be cleared.
(MAIN)
@KBD
D=M
@BLACK
D;JNE
@WHITE
0;JMP
@MAIN
0;JMP
(BLACK)
@i
M=0
@j
M=0
@head
M=0
(BLACK-LOOP1)
@i
D=M
@255
D=D-A
@MAIN
D;JGT
@j
M=0
(BLACK-LOOP2)
@j
D=M
@31
D=D-A
@BLACK-LOOP1-END
D;JGT
@head
D=M
@j
D=D+M
@SCREEN
A=A+D
M=-1
@j
M=M+1
@BLACK-LOOP2
0;JMP
(BLACK-LOOP1-END)
@32
D=A
@head
M=M+D
@i
M=M+1
@BLACK-LOOP1
0;JMP
(WHITE)
...
M=0
...
(END)
@END
0;JMP
总结
通过这门课程的学习,读者可以深入了解计算机体系结构和汇编语言的基础知识。虽然hack计算机的架构相对简单,但通过这个过程,可以建立起对计算机底层运行机制的深刻理解。