簡介
項目1的要求是用Nand門搭建15個基本芯片.其理論基礎是:
- 用And, Or和Not三種Boolean操作符就可以表示所有的Boolean函數
- 用德摩根定律可以證明Or可以用And和Not表示
- And和Not可以僅用Nand表示
- 用德摩根定律可以證明Or可以用And和Not表示
根據以上結論,只需要使用Nand操作符,就可以表示所有的Boolean函數.
講師在整個課程中"扮演"系統架構師(System architect)的角色,他們提供需要實現芯片的框架文件(stub file),測試文件和比較文件. 框架文件包含了需要實現的芯片的名稱,該芯片引脚的名稱,以及簡單的注釋 (其中不包含具體的實現). 測試文件和比較文件則是相當於定義了這個芯片的接口表現, 具體來説就是輸入和輸出的表現.
學員"充當"開發者的角色,根據講師提供的框架和輸入輸出表現,來搭建相應的芯片,完成整個課程大致需要實現30多個芯片,最基本的組件只有Nand門(内部可以由晶體管實現,唯一不需要學員自己實現的部分).最終將這些芯片組合在一起,便可以構建出一個Hack計算機.
在項目1中有個至關重要的概念,即Boolean Function和Digital Logic Circuit之間可以相互表示. 另外,根據真值表也可以設計出對應的數字邏輯電路(通過sum of product或者product of sum方法), 或者寫出相應的Boolean Function. Boolean Algebra也是一種代數, 對代數而言, 有三個要素(常數/變量/運算),在Boolean Algebra中具體表現為: constants(0/1), variable(用來代表0/1的字母)和operation(AND,OR,NOT).
項目1需要實現的15個芯片分類
Elementary logic gates | 16-bit variants | Multi-way variants |
---|---|---|
Not | Not16 | |
And | And16 | |
Or | Or16 | Or8way |
Xor | ||
Mux | Mux16 | Mux4Way16, Mux8Way16 |
DMux | DMux4Way, DMux8Way |
Mux簡介:
最簡情況有三個輸入端a,b,和Sel,以及一個輸出端out. 其邏輯的效果是:
if sel = 0
// 此時無論b為何值,均不影響out的結果,只和a相關
if a = 0
out = 0
else if a = 1
out = 1
else if sel = 1
// 此時無論a為何值,均不影響out的結果,只和b相關
if b = 0
out = 0
else if b = 1
out = 1
具體實現 (Implementation)
Not
And (Not Nand)
Or
Xor
Mux
a | b | sel | out |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 0 | 1 | 0 |
0 | 1 | 0 | 0 |
0 | 1 | 1 | 1 |
1 | 0 | 0 | 1 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
1 | 1 | 1 | 1 |
if (sel = 0)
out = a
else
out = b
DMux
if (sel = 0)
{a,b}={in,0}
else
{a,b}={0,in}
in | sel | a | b |
---|---|---|---|
0 | 0 | 0 | 0 |
0 | 1 | 0 | 0 |
1 | 0 | 1 | 0 |
1 | 1 | 0 | 1 |
Not16, And16, Or16, Mux16
Example
CHIP Foo {
IN in[8] // 8-bit input
OUT out[8] // 8-bit output
// Foo's body (irrelevant to the example)
}
The implementation of Not16, And16,Or16,and Mux16 is similar.
// ...
PARTS:
// Put your code here:
Not(in=in[0],out=out[0]);
// ...
Not(in=in[15],out=out[15]);
Or8Way
Ref:And4way
/*
* Ands together all 4 bits of the input
*/
CHIP And4way{
IN a[4];
OUT out;
PARTS:
AND(a = a[0], b = a[1], out = t01);
AND(a = t01, b = a[2], out = t012);
AND(a = t012,b = a[3], out = out);
// ...
}
Mux4Way16, Mux8Way16
Example
/*
* Adds three 16-bit values
*/
CHIP Add3Way16{
IN first[16], second[16], third[16];
OUT out[16];
PARTS:
Add16(a = first, b = second, out = temp);
Add16(a = temp, b = third, out = out);
// ...
}
// ...
Mux16(...,sel=sel[0],...);
Mux16(...,sel=sel[0],...);
Mux16(...,sel=sel[1],...);
Mux4Way16 can be implemented by three Mux16 chips and Mux8Way16 can be implemented by two Mux4Way16 chips and one Mux16 chip.
DMux4Way, DMux8Way
DMux4Way
in | sel | a | b | c | d |
---|---|---|---|---|---|
0 | 00 | 0 | 0 | 0 | 0 |
0 | 01 | 0 | 0 | 0 | 0 |
0 | 10 | 0 | 0 | 0 | 0 |
0 | 11 | 0 | 0 | 0 | 0 |
1 | 00 | 1 | 0 | 0 | 0 |
1 | 01 | 0 | 1 | 0 | 0 |
1 | 10 | 0 | 0 | 1 | 0 |
1 | 11 | 0 | 0 | 0 | 1 |
After sel[0] works, sel[0]=0 choose a,c; sel[0]=1 choose b,d
We need to further choose one of a and c, and one of b and d by using sel[1].
DMux8Way
After sel[0..1] works, we need to use sel[2] to separate a/e,b/f,c/g,d/h. (recursively apply the rule of DMux4Way)
In comparison, we only need to separate a/c and b/d in the situation of DMux4Way.
Coursera課程部分筆記
All chips can be made from the same building blocks: elementary logic gates and these gates can further be made from one primitive gate: Nand. The mathematical foundation of logic gates is Boolean algebra so that in this chapter, professors first present Boolean functions and their basic rules and then introduce how to implement Boolean gates in a hardware description language.
Unit 1.1: Boolean Logic
Boolean functions can be represented by either formulas or truth tables.
1." Every Boolean function, no matter how complex, can be expressed using three Boolean operators only: And, Or, and Not."
2." Every Boolean function can be expressed using at least one Boolean expression called the canonical representation."
There are some laws associated with boolean logic as follows.
- commutative laws
- associative laws
- distributive laws
- De Morgan laws
Unit 1.2: Boolean Functions Synthesis
Truth table to Boolean Expression
"Just with ANDs and NOTs, we can construct any Boolean function."
Proof:
"Any Boolean Functions can be represented using an expression containing only NAND operations."
Nand (Not And) x NAND y = Not(x AND y)
x | y | Nand |
---|---|---|
0 | 0 | 1 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
Proof: NOT and AND can be represented just by NAND
Not(X) = (X NAND X)
(X AND Y) = NOT(X NAND Y)
Unit 1.3: Logic Gates
Gate: A gate is a physical device that implements a Boolean function.
"The chip interface tells us What the chip is doing, and chip implementation tells us How the chip is doing it. There are many possible implementations for every interface. The builders of a chip need to worry about the implementation and the users only need to know the interface."
Primitive and Composite Gates: Composite gates are composed of more elementary gates.
Unit 1.4: Hardware Description Language
XOR gate
Steps:
- Understand what the interface does (focus on inputs and outputs)
- Draw a diagram in mind or physically
- Name the connections(a,b,in,out)
- Common HDLs
- Verilog
- VHDL
This course provides a simple and minimal HDL language and there are 2 useful documents for us to nail it.
Appendix A: Hardware Description Language (HDL)
HDL Survival Guide
Unit 1.5: Hardware Simulation
- Simulation options
- interactive
- Script-based
- with/without output and compare files
- Process:
- load the HDL file into the hardware simulator
- enter 0/1 into the chip's input pins
- evaluate the logic of the chip (whether the logic is correct or not)
- inspect the values of
- output pins
- internal pins
Interactive simulation
Script-Based simulation
The advantage of script-based simulation is that we do not need to do tedious interactive works (play with input pins and inspect the output) and things can be done automatically with the test scripts.
Script-Based simulation with compare files
Compare our output with a well-behaved output file to see if there is a difference. If two lines in Xor.out and Xor.cmp are not the same, then the simulator will throw a comparison error.
Alternative HDL software
Icarus Verilog for Windows
Icarus Verilog和GTKwave使用简析
Unit 1.6: Multi-Bit Buses
Buses in HDL
/*
* Adds two 16-bit values
*/
CHIP Add16{
IN a[16], b[16];
OUT out[16];
PARTS:
// ...
}
Using Buses
/*
* Adds three 16-bit values
*/
CHIP Add3Way16{
IN first[16], second[16], third[16];
OUT out[16];
PARTS:
Add16(a = first, b = second, out = temp);
Add16(a = temp, b = third, out = out);
// ...
}
Working with Bits in Buses
/*
* Ands together all 4 bits of the input
*/
CHIP And4way{
IN a[4];
OUT out;
PARTS:
AND(a = a[0], b = a[1], out = t01);
AND(a = t01, b = a[2], out = t012);
AND(a = t012,b = a[3], out = out);
// ...
}
/*
* Computes a bit-wise and of its two 4-bit input buses
*/
CHIP And4{
IN a[4], b[4];
OUT out[4];
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]);
// ...
}
Sub-buses
// ...
IN lsb[8], msb[8] // least significant bytes and most significant bytes
// ...
Add16(a[0..7]=lsb, a[8..15]=msb, b=..., out=...);
Add16(..., out[0..3]=t1, out[4..15]=t2);
Example
IN c, Bus1[16], Bus2[16];
OUT out, out2[16];
PARTS:
Add16(a=Bus1[0..15], b=Bus2[0..15], out[0..14]=out2[0..14]); // ✔
Add16(a=true, b=false, out=out2); // ✔
And(a=c, b=Bus2[7], out=out); // ✔
Unit 1.7: Project 1 Overview
Chip Name | Description |
---|---|
Nand | Nand gate (primitive) |
Not | Not gate |
And | And gate |
Or | Or gate |
Xor | Xor gate |
Mux | Multiplexer |
DMux | Demultiplexer |
Not16 | 16-bit Not |
And16 | 16-bit And |
Or16 | 16-bit Or |
Mux16 | 16-bit Multiplexer |
Or8Way | Or (in0,in1,in2,...in7) |
Mux4Way16 | 16-bit, 4-way mux |
Mux8Way16 | 16-bit, 8-way mux |
DMux4Way | 4-way demultiplexer |
DMux8Way | 8-way demultiplexer |
Multiplexer
Demultiplexer
It looks like the inverse of a multiplexer.
The Hack chip-set API
Add16(a= ,b= ,out= );
ALU(x= ,y= ,zx= ,nx= ,zy= ,ny= ,f= ,no= ,out= ,zr= ,ng= );
And16(a= ,b= ,out= );
And(a= ,b= ,out= );
ARegister(in= ,load= ,out= );
Bit(in= ,load= ,out= );
CPU(inM= ,instruction= ,reset= ,outM= ,writeM= ,addressM= ,pc= );
DFF(in= ,out= );
DMux4Way(in= ,sel= ,a= ,b= ,c= ,d= );
DMux8Way(in= ,sel= ,a= ,b= ,c= ,d= ,e= ,f= ,g= ,h= );
DMux(in= ,sel= ,a= ,b= );
DRegister(in= ,load= ,out= );
FullAdder(a= ,b= ,c= ,sum= ,carry= );
HalfAdder(a= ,b= ,sum= , carry= );
Inc16(in= ,out= );
Keyboard(out= );
Memory(in= ,load= ,address= ,out= );
Mux16(a= ,b= ,sel= ,out= );
Mux4Way16(a= ,b= ,c= ,d= ,sel= ,out= );
Mux8Way16(a= ,b= ,c= ,d= ,e= ,f= ,g= ,h= ,sel= ,out= );
Mux(a= ,b= ,sel= ,out= );
Nand(a= ,b= ,out= );
Not16(in= ,out= );
Not(in= ,out= );
Or16(a= ,b= ,out= );
Or8Way(in= ,out= );
Or(a= ,b= ,out= );
PC(in= ,load= ,inc= ,reset= ,out= );
RAM16K(in= ,load= ,address= ,out= );
RAM4K(in= ,load= ,address= ,out= );
RAM512(in= ,load= ,address= ,out= );
RAM64(in= ,load= ,address= ,out= );
RAM8(in= ,load= ,address= ,out= );
Register(in= ,load= ,out= );
ROM32K(address= ,out= );
Screen(in= ,load= ,address= ,out= );
Xor(a= ,b= ,out= );