文章目录
一、前言
项目来源:
该项目是著名课程Nand2Tetris的课程项目,总共分12部分,从零开始构建属于自己的hack计算机。该文项目属于第二个子项目。
项目路线介绍:
在硬件部分,你将进入 01 的世界,用与非门构造出逻辑电路,并逐步搭建出一个 CPU 来运行一套课程作者定义的简易汇编代码。在软件部分,你将编写一个编译器,将作者开发的一个名为Jack的高级语言编译为可以运行在虚拟机上的字节码,然后进一步翻译为汇编代码。你还将开发一个简易的 OS,让你的计算机支持输入输出图形界面。至此,你可以用 Jack 开发一个俄罗斯方块的小游戏,将它编译为汇编代码,运行在你用与非门搭建出的 CPU 上,通过你开发的 OS 进行交互。
二、项目介绍
目标:实现HalfAdder、FullAdder、Add16、ALU、Inc总共5个芯片
要求:使用HDL语言实现,并且通过所有芯片在硬件模拟器的测试。
细节:
- 运算芯片的二进制编码格式为补码
- 在ALU芯片内,需要利用补码的加法和相反数特性实现二进制补码的减法操作——将加法操作的前提上,将加数取反加一,再进行加法。
- 对于全加器,一种普遍的、高效的实现方法是利用两个半加器进行耦合实现
三、项目展示
1.HDL文件图
2.实现代码
2.1HalfAdder——两位的半加芯片
// 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/02/HalfAdder.hdl
/**
* Computes the sum of two bits.
*/
CHIP HalfAdder {
IN a, b; // 1-bit inputs
OUT sum, // Right bit of a + b
carry; // Left bit of a + b
PARTS:
And(a=a,b=b,out=carry);
Xor(a=a,b=b,out=sum);
}
2.2FullAdder——两位的全加法芯片
// 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/02/FullAdder.hdl
/**
* Computes the sum of three bits.
*/
CHIP FullAdder {
IN a, b, c; // 1-bit inputs
OUT sum, // Right bit of a + b + c
carry; // Left bit of a + b + c
PARTS:
HalfAdder(a=a,b=b,sum=sum1,carry=carry1);
HalfAdder(a=sum1,b=c,sum=sum,carry=carry2);
Or(a=carry1,b=carry2,out=carry);
}
2.3Add16——16位加法器
// 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/02/Adder16.hdl
/**
* Adds two 16-bit values.
* The most significant carry bit is ignored.
*/
CHIP Add16 {
IN a[16], b[16];
OUT out[16];
PARTS:
HalfAdder(a=a[0],b=b[0],sum=out[0],carry=carry0);
FullAdder(a=a[1],b=b[1],c=carry0,sum=out[1],carry=carry1);
FullAdder(a=a[2],b=b[2],c=carry1,sum=out[2],carry=carry2);
FullAdder(a=a[3],b=b[3],c=carry2,sum=out[3],carry=carry3);
FullAdder(a=a[4],b=b[4],c=carry3,sum=out[4],carry=carry4);
FullAdder(a=a[5],b=b[5],c=carry4,sum=out[5],carry=carry5);
FullAdder(a=a[6],b=b[6],c=carry5,sum=out[6],carry=carry6);
FullAdder(a=a[7],b=b[7],c=carry6,sum=out[7],carry=carry7);
FullAdder(a=a[8],b=b[8],c=carry7,sum=out[8],carry=carry8);
FullAdder(a=a[9],b=b[9],c=carry8,sum=out[9],carry=carry9);
FullAdder(a=a[10],b=b[10],c=carry9,sum=out[10],carry=carry10);
FullAdder(a=a[11],b=b[11],c=carry10,sum=out[11],carry=carry11);
FullAdder(a=a[12],b=b[12],c=carry11,sum=out[12],carry=carry12);
FullAdder(a=a[13],b=b[13],c=carry12,sum=out[13],carry=carry13);
FullAdder(a=a[14],b=b[14],c=carry13,sum=out[14],carry=carry14);
FullAdder(a=a[15],b=b[15],c=carry14,sum=out[15],carry=carry15);
}
2.4Inc——累加器
// 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/02/Inc16.hdl
/**
* 16-bit incrementer:
* out = in + 1 (arithmetic addition)
*/
CHIP Inc16 {
IN in[16];
OUT out[16];
PARTS:
Add16(a=in,b[1..15]=false,b[0]=true,out=out);
}
2.5ALU——算术逻辑单元
// 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/02/ALU.hdl
/**
* The ALU (Arithmetic Logic Unit).
* Computes one of the following functions:
* x+y, x-y, y-x, 0, 1, -1, x, y, -x, -y, !x, !y,
* x+1, y+1, x-1, y-1, x&y, x|y on two 16-bit inputs,
* according to 6 input bits denoted zx,nx,zy,ny,f,no.
* In addition, the ALU computes two 1-bit outputs:
* if the ALU output == 0, zr is set to 1; otherwise zr is set to 0;
* if the ALU output < 0, ng is set to 1; otherwise ng is set to 0.
*/
// Implementation: the ALU logic manipulates the x and y inputs
// and operates on the resulting values, as follows:
// if (zx == 1) set x = 0 // 16-bit constant
// if (nx == 1) set x = !x // bitwise not
// if (zy == 1) set y = 0 // 16-bit constant
// if (ny == 1) set y = !y // bitwise not
// if (f == 1) set out = x + y // integer 2's complement addition
// if (f == 0) set out = x & y // bitwise and
// if (no == 1) set out = !out // bitwise not
// if (out == 0) set zr = 1
// if (out < 0) set ng = 1
CHIP ALU {
IN
x[16], y[16], // 16-bit inputs
zx, // zero the x input?
nx, // negate the x input?
zy, // zero the y input?
ny, // negate the y input?
f, // compute out = x + y (if 1) or x & y (if 0)
no; // negate the out output?
OUT
out[16], // 16-bit output
zr, // 1 if (out == 0), 0 otherwise
ng; // 1 if (out < 0), 0 otherwise
PARTS:
Mux16(a=x,b=false,sel=zx,out=zerox);
Not16(in=zerox,out=notx);
Mux16(a=zerox,b=notx,sel=nx,out=negatex);
Mux16(a=y,b=false,sel=zy,out=zeroy);
Not16(in=zeroy,out=noty);
Mux16(a=zeroy,b=noty,sel=ny,out=negatey);
Add16(a=negatex,b=negatey,out=xaddy);
And16(a=negatex,b=negatey,out=xandy);
Mux16(a=xandy,b=xaddy,sel=f,out=firstout);
Not16(in=firstout,out=notout);
Mux16(a=firstout,b=notout,sel=no,out[0..7]=aout,out[8..15]=bout);
Or8Way(in=aout,out=or1);
Or8Way(in=bout,out=or2);
Or(a=or1,b=or2,out=orout);
Not(in=orout,out=zr);
And16(a[0..7]=aout,a[8..15]=bout,b[15]=true,b[0..14]=false,out[8..15]=andout);
Or8Way(in=andout,out=ng);
Mux16(a=firstout,b=notout,sel=no,out=out);
}
四、项目经验分享
个人感觉这几个芯片的实现难度其实还好,其关键点就是明白硬件描述语言(HDL)的特性——完全函数描述型的语言。一个hdl程序的实现部分实际上就是显式的使用已有的芯片和隐式的进行线路连接,并且要好好利用抽象,或是说要用好接口。
对于project02的芯片,除了ALU芯片其他的都好说,只是简单的顺序实现——没用设计选择,而ALU的实现就不一样一点,因为它是很多功能的集合,就势必涉及功能选择问题上——6个控制位,与一些高级语言不同,HDL没有if…else,他不能让我们先判断再选择相关模块,不过我们可以使用C语言里条件传送的思想,让输入渗透芯片的每个部分,最后再在输出上进行筛选,将目标输出接到输出端。