背景
只用 Nand 运算符来表示任意的布尔函数 一文已经证明了只用 Nand 运算符就可以表示任意的布尔函数,让我们按照 From Nand to Tetris 里 Project 1 的要求,来完成下列的设计。
- 实现
Not - 实现
And - 实现
Or - 实现
Xor - 实现
Mux - 实现
DMux - 实现
Not16 - 实现
And16 - 实现
Or16 - 实现
Mux16 - 实现
Or8Way - 实现
Mux4Way16 - 实现
Mux8Way16 - 实现
DMux4Way - 实现
DMux8Way
说明
我是阅读了《计算机系统要素 (第2版)》 第 1 章的内容之后才去完成 Project 1 的。读者朋友在完成 Project 1 时,如果遇到不明白的地方,可以参考这本书中的描述。
正文
Project 1 中要求我们用内置的 Nand 来实现一些其他的门
1. 实现 Not
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Not,效果如下图所示 ⬇️
因为下面的转化成立,所以我们找到了一种用 Nand 来实现 Not 的方式。
基于上面的分析,可以写出如下的代码 ⬇️
CHIP Not {
IN in;
OUT out;
PARTS:
Nand(a= in, b= in, out= out);
//// Replace this comment with your code.
}
这样的代码可以通过仿真测试 ⬇️
其他方式
下面的转化成立,于是我们找到了另一种用 Nand 来实现 Not 的方式。
对应的代码如下 ⬇️
CHIP Not {
IN in;
OUT out;
PARTS:
Nand(a= in, b= true, out= out);
}
这样的代码可以通过仿真测试 ⬇️
2. 实现 And
前往 Nand to Tetris Online IDE,选择 Project 1 里的 And,效果如下图所示 ⬇️
因为下面的转化成立,所以已经找到了用 Nand 来实现 And 的方式(因为之前已经通过 Nand 实现了 Not,所以这里可以使用 Not)。
基于上面的分析,可以写出如下的代码 ⬇️
CHIP And {
IN a, b;
OUT out;
PARTS:
Nand(a= a, b= b, out= out1);
Not(in= out1, out= out);
}
这样的代码可以通过仿真测试 ⬇️
其他方式(只用 Nand 来实现 And)
考虑到以下两式成立
令 ,就可以得到 ⬇️
基于上面的分析,可以写出如下的代码 ⬇️
CHIP And {
IN a, b;
OUT out;
PARTS:
Nand(a= a, b= b, out= temp);
Nand(a= temp, b= true, out= out);
}
这样的代码可以通过仿真测试 ⬇️
3. 实现 Or
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Or。
根据德摩根定律
我们用真值表也可以证明上式 ⬇️ (, 两列是输入,其他列是计算结果)
所以已经找到了用 Nand 来实现 Or 的方式(因为之前已经通过 Nand 实现了 Not,所以这里可以使用 Not)。
填写我们的代码 ⬇️ 后,应该就可以通过仿真测试了。
CHIP Or {
IN a, b;
OUT out;
PARTS:
Not(in= a, out= notA);
Not(in= b, out= notB);
Nand(a= notA, b= notB, out= out);
}
效果如下图所示 ⬇️
其他方式(只用 Nand 来实现 Or)
因为以下两式成立
所以
基于上面的分析,可以写出如下的代码 ⬇️
CHIP Or {
IN a, b;
OUT out;
PARTS:
Nand(a= a, b= true, out= nota);
Nand(a= b, b= true, out= notb);
Nand(a= nota, b= notb, out= out);
}
这样的代码可以通过仿真测试 ⬇️
4. 实现 Xor
在前面 步中,我们已经实现了 Not/And/Or,那么对任意的布尔函数,我们只要先找到其对应的析取范式(DNF),然后就可以用 Not/And/Or 来实现它了。
Xor 的真值表如下
基于以上真值表,可以将 Xor 转化成对应的析取范式(DNF)。
这样我们找到了一种用 Nand 来实现 Xor 的方式。
前往 Nand to Tetris Online IDE 后,选择 Project 1 里的 Xor,效果如下图所示 ⬇️
填写我们的代码 ⬇️ 后,应该就可以通过仿真测试了。
CHIP Xor {
IN a, b;
OUT out;
PARTS:
Not(in= a, out= notA);
Not(in= b, out= notB);
And(a= a, b= notB, out= out1);
And(a= notA, b= b, out= out2);
Or(a= out1, b= out2, out= out);
}
效果如下图所示 ⬇️
其他方式 1
也有其他方式可以实现 Xor。注意到 Xor 和 Or 的真值表只有一行不同 ⬇️
所以我们可以对 Or 得到的结果进行微调,
对应的代码如下 ⬇️
CHIP Xor {
IN a, b;
OUT out;
PARTS:
Or(a= a, b= b, out= out1);
Nand(a= a, b= b, out=out2);
And(a= out1, b= out2, out= out);
}
这样的代码也可以通过仿真测试,效果如下图所示 ⬇️
其他方式 2(只用 Nand 来实现 Xor)
还有有其他方式可以实现 Xor。注意到 Xor 和 Nand 的真值表只有一行不同 ⬇️
所以我们可以对 Nand 得到的结果进行微调 ⬇️
考虑到 成立,令
则 。
那么
再令
则 。
那么
考虑到 成立
令
可以得出
CHIP Xor {
IN a, b;
OUT out;
PARTS:
Nand(a= a, b= b, out= x);
Nand(a= a, b= true, out= nota);
Nand(a= b, b= true, out= notb);
Nand(a= nota, b= notb, out= y);
Nand(a= x, b= y, out= temp);
Nand(a= temp, b= true, out= out);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
5. 实现 Mux
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Mux,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Multiplexer。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
if (sel = 0) out = a, else out = b
从题目的描述来看,应该可以这样实现 ⬇️
如果一时想不出上面这个式子也无妨,我们也可以从真值表入手。这个 Mux 的真值表如下 ⬇️
从真值表入手,我们可以写出这个 Mux 的析取范式(DNF)如下
下面对其进行化简
将前两个最小项(minterm)合并,可以得到
再将最后两个最小项(minterm)合并,可以得到
这和直接分析题意而得到的 是一样的。于是可以写出对应的代码 ⬇️
CHIP Mux {
IN a, b, sel;
OUT out;
PARTS:
Not(in= sel, out= notSel);
And(a= notSel, b= a, out= out1);
And(a= sel, b= b, out= out2);
Or(a= out1, b= out2, out= out);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
6. 实现 DMux
前往 Nand to Tetris Online IDE,选择 Project 1 里的 DMux,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Demultiplexer。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
[a, b] = [in, 0] if sel = 0
[0, in] if sel = 1
我们可以把 , 分开来看。 先看
if (sel = 0) a = in, else a = 0
所以
再看
if (sel = 0) b = 0, else b = in
将两个式子写在一起 ⬇️
如果一时想不出上面这两个式子也无妨,我们也可以从真值表入手。这个 DMux 的真值表如下 ⬇️
先看 ,从上面的真值表可以得出 的析取范式(DNF)如下
再看 ,从上面的真值表可以得出 的析取范式(DNF)如下
我们从真值表出发,得到的结果和刚才是一样的。现在可以写出对应的代码了 ⬇️
CHIP DMux {
IN in, sel;
OUT a, b;
PARTS:
Not(in= sel, out= notSel);
And(a= in, b= notSel, out= a);
And(a= in, b= sel, out= b);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
7. 实现 Not16
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Not16,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Not16。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
16-bit Not gate:
for i = 0, ..., 15:
out[i] = Not(in[i])
在第 步中,我们已经实现了 Not,所以现在可以直接使用 Not。我们要写的代码会长这个样子 ⬇️
Not(in= in[0], out= out[0]);
Not(in= in[1], out= out[1]);
...
由于 Not(in= in[?], out= out[?]); 这样的代码一共要写 遍,用程序来生成它比较好。我写了以下的 java 代码来生成对应的 hdl 代码。请将以下代码保存为 Not16HdlCodeGenerator.java ⬇️
import java.util.StringJoiner;
public class Not16HdlCodeGenerator {
public static void main(String[] args) {
String template = """
CHIP Not16 {
IN in[16];
OUT out[16];
PARTS:
%s
}""";
StringJoiner joiner = new StringJoiner(System.lineSeparator());
for (int i = 0; i < 16; i++) {
String line = String.format(" Not(in= in[%s], out= out[%s]);", i, i);
joiner.add(line);
}
System.out.printf(template, joiner);
}
}
用如下命令可以编译 Not16HdlCodeGenerator.java 并运行其中的 main 方法。
javac Not16HdlCodeGenerator.java
java Not16HdlCodeGenerator
运行结果如下
CHIP Not16 {
IN in[16];
OUT out[16];
PARTS:
Not(in= in[0], out= out[0]);
Not(in= in[1], out= out[1]);
Not(in= in[2], out= out[2]);
Not(in= in[3], out= out[3]);
Not(in= in[4], out= out[4]);
Not(in= in[5], out= out[5]);
Not(in= in[6], out= out[6]);
Not(in= in[7], out= out[7]);
Not(in= in[8], out= out[8]);
Not(in= in[9], out= out[9]);
Not(in= in[10], out= out[10]);
Not(in= in[11], out= out[11]);
Not(in= in[12], out= out[12]);
Not(in= in[13], out= out[13]);
Not(in= in[14], out= out[14]);
Not(in= in[15], out= out[15]);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
8. 实现 And16
前往 Nand to Tetris Online IDE,选择 Project 1 里的 And16,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 And16。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
16-bit And gate:
for i = 0, ..., 15:
out[i] = a[i] And b[i]
在第 步中,我们已经实现了 And,所以现在可以直接使用 And。我们要写的代码会长这个样子 ⬇️
And(a= a[0], b= b[0], out= out[0]);
And(a= a[1], b= b[1], out= out[1]);
...
由于 And(a= a[?], b= b[?], out= out[?]); 这样的代码一共要写 遍,用程序来生成它比较好。我写了以下的 java 代码来生成对应的 hdl 代码。请将以下代码保存为 And16HdlCodeGenerator.java ⬇️
import java.util.StringJoiner;
public class And16HdlCodeGenerator {
public static void main(String[] args) {
String template = """
CHIP And16 {
IN a[16], b[16];
OUT out[16];
PARTS:
%s
}
""";
StringJoiner joiner = new StringJoiner(System.lineSeparator());
for (int i = 0; i < 16; i++) {
String line = String.format(" And(a= a[%s], b= b[%s], out= out[%s]);", i, i, i);
joiner.add(line);
}
System.out.printf(template, joiner);
}
}
用如下命令可以编译 And16HdlCodeGenerator.java 并运行其中的 main 方法。
javac And16HdlCodeGenerator.java
java And16HdlCodeGenerator
运行结果如下
CHIP And16 {
IN a[16], b[16];
OUT out[16];
PARTS:
And(a= a[0], b= b[0], out= out[0]);
And(a= a[1], b= b[1], out= out[1]);
And(a= a[2], b= b[2], out= out[2]);
And(a= a[3], b= b[3], out= out[3]);
And(a= a[4], b= b[4], out= out[4]);
And(a= a[5], b= b[5], out= out[5]);
And(a= a[6], b= b[6], out= out[6]);
And(a= a[7], b= b[7], out= out[7]);
And(a= a[8], b= b[8], out= out[8]);
And(a= a[9], b= b[9], out= out[9]);
And(a= a[10], b= b[10], out= out[10]);
And(a= a[11], b= b[11], out= out[11]);
And(a= a[12], b= b[12], out= out[12]);
And(a= a[13], b= b[13], out= out[13]);
And(a= a[14], b= b[14], out= out[14]);
And(a= a[15], b= b[15], out= out[15]);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
9. 实现 Or16
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Or16,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Or16。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
16-bit Or gate:
for i = 0, ..., 15:
out[i] = a[i] Or b[i]
在第 步中,我们已经实现了 Or,所以现在可以直接使用 Or。我们要写的代码会长这个样子 ⬇️
Or(a= a[0], b= b[0], out= out[0]);
Or(a= a[1], b= b[1], out= out[1]);
...
由于 Or(a= a[?], b= b[?], out= out[?]); 这样的代码一共要写 遍,用程序来生成它比较好。我写了以下的 java 代码来生成对应的 hdl 代码。请将以下代码保存为 Or16HdlCodeGenerator.java ⬇️
import java.util.StringJoiner;
public class Or16HdlCodeGenerator {
public static void main(String[] args) {
String template = """
CHIP Or16 {
IN a[16], b[16];
OUT out[16];
PARTS:
%s
}
""";
StringJoiner joiner = new StringJoiner(System.lineSeparator());
for (int i = 0; i < 16; i++) {
String line = String.format(" Or(a= a[%s], b= b[%s], out= out[%s]);", i, i, i);
joiner.add(line);
}
System.out.printf(template, joiner);
}
}
用如下命令可以编译 Or16HdlCodeGenerator.java 并运行其中的 main 方法。
javac Or16HdlCodeGenerator.java
java Or16HdlCodeGenerator
运行结果如下
CHIP Or16 {
IN a[16], b[16];
OUT out[16];
PARTS:
Or(a= a[0], b= b[0], out= out[0]);
Or(a= a[1], b= b[1], out= out[1]);
Or(a= a[2], b= b[2], out= out[2]);
Or(a= a[3], b= b[3], out= out[3]);
Or(a= a[4], b= b[4], out= out[4]);
Or(a= a[5], b= b[5], out= out[5]);
Or(a= a[6], b= b[6], out= out[6]);
Or(a= a[7], b= b[7], out= out[7]);
Or(a= a[8], b= b[8], out= out[8]);
Or(a= a[9], b= b[9], out= out[9]);
Or(a= a[10], b= b[10], out= out[10]);
Or(a= a[11], b= b[11], out= out[11]);
Or(a= a[12], b= b[12], out= out[12]);
Or(a= a[13], b= b[13], out= out[13]);
Or(a= a[14], b= b[14], out= out[14]);
Or(a= a[15], b= b[15], out= out[15]);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
10. 实现 Mux16
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Mux16,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Mux16。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
16-bit multiplexor:
for i = 0, ..., 15:
if (sel = 0) out[i] = a[i], else out[i] = b[i]
在第 步中,我们已经实现了 Mux,所以现在可以直接使用 Mux。我们要写的代码会长这个样子 ⬇️
Mux(a= a[0], b= b[0], sel= sel, out= out[0]);
Mux(a= a[1], b= b[1], sel= sel, out= out[1]);
...
由于 Mux(a= a[?], b= b[?], sel= sel, out= out[?]); 这样的代码一共要写 遍,用程序来生成它比较好。我写了以下的 java 代码来生成对应的 hdl 代码。请将以下代码保存为 Mux16HdlCodeGenerator.java ⬇️
import java.util.StringJoiner;
public class Mux16HdlCodeGenerator {
public static void main(String[] args) {
String template = """
CHIP Mux16 {
IN a[16], b[16], sel;
OUT out[16];
PARTS:
%s
}
""";
StringJoiner joiner = new StringJoiner(System.lineSeparator());
for (int i = 0; i < 16; i++) {
String line = String.format(" Mux(a= a[%s], b= b[%s], sel= sel, out= out[%s]);", i, i, i);
joiner.add(line);
}
System.out.printf(template, joiner);
}
}
用如下命令可以编译 Mux16HdlCodeGenerator.java 并运行其中的 main 方法。
javac Mux16HdlCodeGenerator.java
java Mux16HdlCodeGenerator
运行结果如下
CHIP Mux16 {
IN a[16], b[16], sel;
OUT out[16];
PARTS:
Mux(a= a[0], b= b[0], sel= sel, out= out[0]);
Mux(a= a[1], b= b[1], sel= sel, out= out[1]);
Mux(a= a[2], b= b[2], sel= sel, out= out[2]);
Mux(a= a[3], b= b[3], sel= sel, out= out[3]);
Mux(a= a[4], b= b[4], sel= sel, out= out[4]);
Mux(a= a[5], b= b[5], sel= sel, out= out[5]);
Mux(a= a[6], b= b[6], sel= sel, out= out[6]);
Mux(a= a[7], b= b[7], sel= sel, out= out[7]);
Mux(a= a[8], b= b[8], sel= sel, out= out[8]);
Mux(a= a[9], b= b[9], sel= sel, out= out[9]);
Mux(a= a[10], b= b[10], sel= sel, out= out[10]);
Mux(a= a[11], b= b[11], sel= sel, out= out[11]);
Mux(a= a[12], b= b[12], sel= sel, out= out[12]);
Mux(a= a[13], b= b[13], sel= sel, out= out[13]);
Mux(a= a[14], b= b[14], sel= sel, out= out[14]);
Mux(a= a[15], b= b[15], sel= sel, out= out[15]);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
11. 实现 Or8Way
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Or8Way,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Or8Way。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
8-way Or gate:
out = in[0] Or in[1] Or ... Or in[7]
在第 步中,我们已经实现了 Or,所以现在可以直接使用 Or。一个容易想到的做法是对 , 进行 Or 运算,得到 ,然后再对 , 进行 Or 运算,得到 ,等等,直到将 中的所有位都用上。
对应的代码会长这个样子 ⬇️
Or(a= in[0], b= in[1], out= out1);
Or(a= in1, b= in[2], out= out2);
...
由于 Or(a= ?, b= ?, out= ?); 这样的代码一共要写 遍,用程序来生成它比较好。我写了以下的 java 代码来生成对应的 hdl 代码。请将以下代码保存为 Or8WayHdlCodeGenerator.java ⬇️
import java.util.StringJoiner;
public class Or8WayHdlCodeGenerator {
public static void main(String[] args) {
String template = """
CHIP Or8Way {
IN in[8];
OUT out;
PARTS:
%s
}
""";
StringJoiner joiner = new StringJoiner(System.lineSeparator());
joiner.add(" Or(a= in[0], b= in[1], out= out1);");
for (int i = 2; i < 7; i++) {
String line = String.format(" Or(a= out%s, b= in[%s], out= out%s);", i - 1, i, i);
joiner.add(line);
}
joiner.add(" Or(a= out6, b= in[7], out= out);");
System.out.printf(template, joiner);
}
}
用如下命令可以编译 Or8WayHdlCodeGenerator.java 并运行其中的 main 方法。
javac Or8WayHdlCodeGenerator.java
java Or8WayHdlCodeGenerator
运行结果如下
CHIP Or8Way {
IN in[8];
OUT out;
PARTS:
Or(a= in[0], b= in[1], out= out1);
Or(a= out1, b= in[2], out= out2);
Or(a= out2, b= in[3], out= out3);
Or(a= out3, b= in[4], out= out4);
Or(a= out4, b= in[5], out= out5);
Or(a= out5, b= in[6], out= out6);
Or(a= out6, b= in[7], out= out);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
其他方式
由于 Or 运算满足结合律和交换律,所以下面的等式成立(详细的说明请参考 当一个二元运算符同时满足 交换律 和 结合律 时 一文,或者从“只有 中的 个数全都是 时,它们进行 Or 运算的结果才会是 ”这个角度来论证也可以)
这样的转化可以用如下的代码来表示 ⬇️
CHIP Or8Way {
IN in[8];
OUT out;
PARTS:
Or(a= in[0], b= in[1], out= in01);
Or(a= in[2], b= in[3], out= in23);
Or(a= in[4], b= in[5], out= in45);
Or(a= in[6], b= in[7], out= in67);
Or(a= in01, b= in23, out= in03);
Or(a= in45, b= in67, out= in47);
Or(a= in03, b= in47, out= out);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
12. 实现 Mux4Way16
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Mux4Way16,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Mux4Way16。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
4-way 16-bit multiplexor:
out = a if sel = 00
b if sel = 01
c if sel = 10
d if sel = 11
在第 步中,我们已经实现了 Mux16,所以现在可以直接使用 Mux16。一种做法是
- 用 决定从 中选择谁(注意 都是 位的),选择结果为
- 用 决定从 中选择谁(注意 都是 位的),选择结果为
- 用 决定从 中选择谁(注意 都是 位的),选择结果为
具体的代码如下 ⬇️
CHIP Mux4Way16 {
IN a[16], b[16], c[16], d[16], sel[2];
OUT out[16];
PARTS:
Mux16(a= a, b= b, sel= sel[0], out= abOut);
Mux16(a= c, b= d, sel= sel[0], out= cdOut);
Mux16(a= abOut, b= cdOut, sel= sel[1], out= out);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
13. 实现 Mux8Way16
前往 Nand to Tetris Online IDE,选择 Project 1 里的 Mux8Way16,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 Mux8Way16。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
8-way 16-bit multiplexor:
out = a if sel = 000
b if sel = 001
c if sel = 010
d if sel = 011
e if sel = 100
f if sel = 101
g if sel = 110
h if sel = 111
- 在第 步,我们实现了
Mux16 - 在第 步,我们实现了
Mux4Way16
所以现在可以直接使用 Mux16 和 Mux4Way16。一种做法是
- 用 和 共同决定从 中选择谁(注意 都是 位的),选择结果为
- 用 和 共同决定从 中选择谁(注意 都是 位的),选择结果为
- 用 决定从 中选择谁(注意 都是 位的),选择结果为
具体的代码如下 ⬇️
CHIP Mux8Way16 {
IN a[16], b[16], c[16], d[16],
e[16], f[16], g[16], h[16],
sel[3];
OUT out[16];
PARTS:
Mux4Way16(a= a, b= b, c= c, d= d, sel= sel[0..1], out= choice1);
Mux4Way16(a= e, b= f, c= g, d= h, sel= sel[0..1], out= choice2);
Mux16(a= choice1, b= choice2, sel= sel[2], out= out);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
14. 实现 DMux4Way
前往 Nand to Tetris Online IDE,选择 Project 1 里的 DMux4Way,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 DMux4Way。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
4-way demultiplexor:
[a, b, c, d] = [in, 0, 0, 0] if sel = 00
[0, in, 0, 0] if sel = 01
[0, 0, in, 0] if sel = 10
[0, 0, 0, in] if sel = 11
我们先看看 的真值表 ⬇️
| (注意: 在前, 在后) | |||||
|---|---|---|---|---|---|
可以得出
和 可以写成如下形式
记
则
所以如果我们能通过某种方式得到 ,那么在 的基础上,用一个 DMux 就能得到 和 了。 类似地
记
则
如果我们能通过某种方式得到 ,那么在 的基础上,用一个 DMux 就能得到 和 了。仔细看看 和 ,会发现它们可以用一个 DMux 来实现,具体的代码如下 ⬇️
CHIP DMux4Way {
IN in, sel[2];
OUT a, b, c, d;
PARTS:
DMux(in= in, sel= sel[1], a= x, b= y);
DMux(in= x, sel= sel[0], a= a, b= b);
DMux(in= y, sel= sel[0], a= c, b= d);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
15. 实现 DMux8Way
前往 Nand to Tetris Online IDE,选择 Project 1 里的 DMux8Way,效果如下图所示 ⬇️
我们的目标是用 Nand(以及前文提到的可以用 Nand 实现的各种门)来实现一个 DMux8Way。
- 输入是
- 输出是
要实现的逻辑是这样的 ⬇️
8-way demultiplexor:
[a, b, c, d, e, f, g, h] = [in, 0, 0, 0, 0, 0, 0, 0] if sel = 000
[0, in, 0, 0, 0, 0, 0, 0] if sel = 001
[0, 0, in, 0, 0, 0, 0, 0] if sel = 010
[0, 0, 0, in, 0, 0, 0, 0] if sel = 011
[0, 0, 0, 0, in, 0, 0, 0] if sel = 100
[0, 0, 0, 0, 0, in, 0, 0] if sel = 101
[0, 0, 0, 0, 0, 0, in, 0] if sel = 110
[0, 0, 0, 0, 0, 0, 0, in] if sel = 111
- 在第 步中,我们已经实现了
DMux - 在第 步中,我们已经实现了
DMux4Way
所以我们可以考虑用 DMux 和 DMux4Way 来实现 DMux8Way
CHIP DMux8Way {
IN in, sel[3];
OUT a, b, c, d, e, f, g, h;
PARTS:
DMux(in= in, sel= sel[2], a= x, b= y);
DMux4Way(in= x, sel= sel[0..1], a= a, b= b, c= c, d= d);
DMux4Way(in= y, sel= sel[0..1], a= e, b= f, c= g, d= h);
}
这样的代码可以通过仿真测试,效果如下图所示 ⬇️
完成了 Project 1 之后,我们可以去做 Project 2。我在 From Nand to Tetris 里的 Project 2 一文中记录了自己对 Project 2 的理解。