Nand2Tetris_Part1
最后更新时间:
文章总字数:
预计阅读时间:
mini版数电+计组+汇编,像搭积木一样了解计算机体系结构。
注意:计算机系统要素 从零开始构建现代计算机 ((美)NOAM NISAN,SHIMON SCHOCKEN著) (Z-Library).pdf
官网给出的课程PPT,补充了不少课本上没有的内容。
Project walkthrough
接口
1 |
|
不难
值得一提的是 Mux 和 DMux 的设计:每位的0,1都会将输入值分为两半,两者的运算方向相反,每次都处理一半的输入,例如从16->8->4->2->1+1。
1 |
|
学东西就留下具体实践解决生活问题这才是技术之根本 。
ALU 完成
1 |
|
本ALU没有涉及时序逻辑中的shift功能。
2024/10/16
Project 3 时序逻辑
It’s a poor sort of memory that only works backward.
记忆如此悲怜,只能回溯过去。
—- Lewis Carroll (1832 ~ 1898 ) , 英国作家
接口
1 |
|
还得绕一下,把输出接到输入,所有第一步其实在第二步的后面。
1 |
|
内存的设计也很巧妙,将load信号进行分配。
1 |
|
RAM64: 地址线高三位先选择某片内存,低三位在raw内选存储器
PC: 可以置零,加一,输入新值,频繁更改。注意标志位的处理顺序
1 |
|
2024/10/19
Project 4 汇编
我写汇编?真的假的?
Before the porject…
These files should be stored in your browser’s local storage by the web IDE.
这些文件应该通过Web IDE存储在浏览器的本地存储中。Add.asm, Max.asm, Rect.asm, and Pong.asm should be in the Project 6 folder.
Add.asm、Max.asm、Pong.asm和Pong.asm应位于Project 6文件夹中。They can be accessed through the “Load file” button in either the CPU emulator or the assembler, as depicted here:
它们可以通过CPU模拟器或汇编器中的“加载文件”按钮访问,如下所示:
If you don’t see the folders for projects 4 and 6 in there, please try resetting your files (Settings > Reset) and let me know if this fixes the issue.
如果你没有在那里看到项目4和6的文件夹,请尝试重置你的文件(设置 > 重置),并让我知道这是否解决了问题。(Note that this will clear the browser’s local storage, deleting your saved files, so make sure you back everything up before doing that!)
(Note这将清除浏览器的本地存储,删除您保存的文件,所以请确保您备份一切之前这样做!)
来自:从第一原理构建现代计算机:从 Nand 到俄罗斯方块(以项目为中心的课程) - 讨论 | Coursera
从这一章开始该仔细读project文档了,项目 4:机器语言。
在开始汇编之前,文档推荐先去proj6文件夹下感受一下汇编代码,给出了几个示例文件:加法,求max,经典弹球游戏之类的。将文件load进汇编器里,然后translate all将汇编转为机器码,完成后在binary code板块将其加载到cpu模拟器中运行。
注意:如果你编写的汇编代码需要使用目的地 DM=… 或 ADM=…,请改用 MD=… 或 AMD=…。
Hack 语言是区分大小写的。
另一个常见错误是在编写指令时使用小写字母或空格。例如,m=1 或 M = 1 都会导致语法错误。正确的语法是 M=1
。
最佳实践:
- 使用大写字母为标签,如 LOOP,使用小写字母为变量,如 sum。
- 缩进你的代码:将所有不是标签声明的行向右缩进几个字符。
- 根据需要编写注释,以使你的代码清晰。
- 查看讲座或书籍中的程序,并遵循它们的示例。
- 像往常一样,努力编写优雅、高效且自解释的程序。
简单理解一下:Hacker计算机内部有A,D(a.k.a. address data)两个寄存器和可按地址访问的内存M[address]。将数或地址写入A寄存器的语法为@value
,与M配合使用可进行访存,也可当作存储数字的寄存器使用,例如:
1 |
|
闹麻了,卡了好几天了,让我看看怎么个事:
分析一下给出的汇编代码:主要是跳转指令有些模糊,使用了标志作为语法糖辅助跳转,思想与C中的goto一致,避免调用JMP指令时还需要程序员数行号进行跳转。跳转语句结构形如D;JMP
,D为放入ALU计算的值,JMP指令根据ALU计算后的返回值按需跳转。
标志的结构为 (SYMBOL)
括号括助,内部一般使用全大写表示,JMP语句调用前使用@SYMBOL
将标志地址导入A寄存器,跳转语句将跳转至A寄存器所指的指令位置(行号)
完成后的程序需要将其卡住在程序的底部,防止PC增长,越界执行非法代码。
部分代码
1 |
|
IO部分更为有趣,从print到屏幕上对应hello world的像素亮起中间到底发生了什么,我很好奇。其实没有什么难的,内存中除了保存数据的部分,也有专门划分的用于保存显示器每个像素颜色的区域,调整这一小块内存的值就能改变对应像素的颜色,键盘输入也有一个专门的地址保存,CPU按需读取。
下一章将完成从CPU到computer的实现,激动人心。
Project 5 计算机体系结构
已给接口
1 |
|
主要目标是完成CPU的设计,考虑到复杂性,已经给出大致设计:
指令或上一步输出经选择存入A寄存器,分两支处理
1 指令存入A寄存器
A指令:[0 value*15]
C指令:[111 acccccc ddd jjj]分别按指令位执行计算,存入目的地,是否跳转 。 a-位域决定ALU是把A寄存器的输入当作操作数,还是把内存单元的输入当作 操作数
由下图可见,c是ALU的参数,d和j需要单独处理,图中未标出。
把流程理一下:指令内存传入指令instruction,Memory out端传入inM信号,通过ins[15]的值判断Areg存入指令还是上次计算的结果。c指令,接下来将ALU标志位传入ALU,d位分别传入A,Dreg和最终输出位writeM决定是否写入A,D,M中。然后是j位是跳转条件,根据ALU两个输入之差的正负判断大于小于情况,与JMP要求相符则同意PC的下一时刻的值为Areg中的目标地址。否则PC自律(自增,重置…)。最终CPU输出out写入内存中(如果d位同意的话)
1 |
|
a位域0表示将A reg作为数值计算,1表示作为内存读取
以汇编代码@5 D=A
为例解析:
A指令传入,Mux选择指令写入Areg,A指令结束。
C指令从Areg与inM中选择Areg的值传入ALU,不进行计算直接输出,途径load态Dreg将数值写入,跳转码为000,不执行。Areg,Memory为非load态,不写入数据。C指令结束。
还需处理JMP指令,通过ALU的输出进行判断大于小于条件是否成立,作为PC的load条件,in为A reg的值,当load成立,则PC转入A指向的值;否则PC正常自增。
注意:ALU及其他c位域必须在c指令时才生效(And检验instruction[15] & instruction[c])
至此CPU的运行逻辑就很清晰了,务必自行设计汇编案例通过人脑模拟CPU。
来自fkgkdfgy的HDL代码,太优雅了
1 |
|
Computer
汇编代码烧录到ROM指令内存后由ROM和CPU交互,接受PC的地址,将对应地址的指令传入CPU。计算过程与数据内存进行读写。
1 |
|
代码稍微有一点点绕,把输出变量名写清晰就好多了。
接下来的软件部分后续可能会抽时间慢慢做,先啃OS去了。