21、P1 W3 U3.6 总结、作业3答案(待深入)
视频:
如果本次课程对应的 Coursera 的视频打不开,可以点击下面链接
P1W3U3.6 - Perspectives
-
DFF没有实现,在实际中是怎么回事呢?
没太明白,视频 00:40 到 5:45 (待深入研究) -
RAM 在电脑是唯一的存储吗?
RAM是最重要的。存数据和命令。断电丢失存储。
ROM只读存储单元。断电不丢失存储。一般用来启动系统的程序存在这里。
Flash存储单元。集合了RAM和ROM的有点。
Cache存储。这里有一种取舍,更大更便宜更慢的存储(比如硬盘)。还有一种离CPU很近,不仅小而且贵不过速度奇快。Cache就是后者。
物理角度,各种存储的实现可能不同。但是从逻辑的角度来看。他们都是寻址,然后从寄存器里读数据。这个规律是不变的。
求:
1bit Register
16-bit Register
RAM8
RAM64
RAM512
RAM4k
RAM16k
PC
一、 Bit (1bit 寄存器)
1、分析
回顾17、P1 W3 U3.2 触发器(Flip-Flops)
DFF硬件模拟器已给,Mux第一周作业
利用一个mux 和一个 dff2、HDL
如上图DFF图标有倒三角,是一个时序电路,写法貌似软件模拟上跟普通写逻辑没啥区别。
//注:Mux里sel = 0,out = a。对应load = 0 ,输出上一步的dffout(读操作)
Mux(a = dffout, b = a, sel = load, out = muxout);
//这种out 多赋值的情况第二周作业里应该就见到了。
DFF(in = muxout, out = dffout, out = out);
完整的
// 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/03/a/Bit.hdl
/**
* 1-bit register:
* If load[t] == 1 then out[t+1] = in[t]
* else out does not change (out[t+1] = out[t])
*/
CHIP Bit {
IN in, load;
OUT out;
PARTS:
// Put your code here:
//注:Mux里sel = 0,out = a,对应load = 0 ,还是输出上一步的dffout(读操作)
Mux(a = dffout, b = in, sel = load, out = muxout);
//这种out 多赋值的情况第二周作业里应该就见到了。
DFF(in = muxout, out = dffout, out = out);
}
3、测试
测试成功
PS:第一周作业详情说了如何用 Hardware Simulator 硬件模拟器 进行测试。这里就贴一张图
Hardware_Simulator 本文最开始 软件处下载
二、Register(16-bit 寄存器)
1、分析
貌似就是串16个bit,类似第一周的And16.
2、HDL
// 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/03/a/Register.hdl
/**
* 16-bit register:
* If load[t] == 1 then out[t+1] = in[t]
* else out does not change
*/
CHIP Register {
IN in[16], load;
OUT out[16];
PARTS:
// Put your code here:
Bit(in=in[0], load=load, out=out[0]);
Bit(in=in[1], load=load, out=out[1]);
Bit(in=in[2], load=load, out=out[2]);
Bit(in=in[3], load=load, out=out[3]);
Bit(in=in[4], load=load, out=out[4]);
Bit(in=in[5], load=load, out=out[5]);
Bit(in=in[6], load=load, out=out[6]);
Bit(in=in[7], load=load, out=out[7]);
Bit(in=in[8], load=load, out=out[8]);
Bit(in=in[9], load=load, out=out[9]);
Bit(in=in[10], load=load, out=out[10]);
Bit(in=in[11], load=load, out=out[11]);
Bit(in=in[12], load=load, out=out[12]);
Bit(in=in[13], load=load, out=out[13]);
Bit(in=in[14], load=load, out=out[14]);
Bit(in=in[15], load=load, out=out[15]);
}
3、测试
测试成功
三、RAM8(8个 16-bit 寄存器)
1、分析
因为后面几个RAMxxx都类似,就在这一起分析了,后面就省略了
选 RAM8 里的 一个 Register 进行设置数据
load 为1 时,addr 给一个 sel[k],选择出一个寄存器,写
//伪代码
// in 输入 1bit、sel[3] 输入选项。
// 输出 8路1bit,被sel选中的路,输出in的状态。其它7路还输出之前的状态。
DMux8Way {
IN in=load, sel[3] = addr[k];
OUT a, b, c, d, e, f, g, h; // 输出决定哪个寄存器 进行 load操作
}
Register(in = in,load = DMux8Way输出的out ,out = outa)
Register(in = in, load = b, out = outb)
Register(in = in, load = c, out = outc)
...
选 RAM8 里的 一个 Register 进行读数据
8个 Register 需要用 address 来选择,选择就用Mux,有8路要选择来操作读。第一周作业貌似做过一个 Mux8Way16。
//伪代码
Mux8Way16(
a = 1路[16], // 代表第0个寄存器的状态,outa
b = 2路[16], // outb
c = 3路[16], // outc
d = ...,
e = ...,
f = ...,
g = ...,
h = 8路[16],
sel=addr[k],
out = out[16])
2、HDL
// 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/03/a/RAM8.hdl
/**
* Memory of 8 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM8 {
IN in[16], load, address[3];
OUT out[16];
PARTS:
// Put your code here:
DMux8Way(in=load, sel=address, a=loada, b=loadb, c=loadc, d=loadd,
e=loade, f=loadf, g=loadg, h=loadh);
Register(in=in, load=loada, out=outa);
Register(in=in, load=loadb, out=outb);
Register(in=in, load=loadc, out=outc);
Register(in=in, load=loadd, out=outd);
Register(in=in, load=loade, out=oute);
Register(in=in, load=loadf, out=outf);
Register(in=in, load=loadg, out=outg);
Register(in=in, load=loadh, out=outh);
Mux8Way16(a=outa, b=outb, c=outc, d=outd,
e=oute, f=outf, g=outg, h=outh, sel=address, out=out);
}
四、RAM64(8个 RAM8)
那以此类推,这个就把上一个的Register换成RAM8,不过RAM8上比Register多一个address[3],而RAM64也需要3位来选择8个RAM8。
这里需要把RAM64的 address[6],拆分一下
2、HDL
// 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/03/a/RAM64.hdl
/**
* Memory of 64 registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM64 {
IN in[16], load, address[6];
OUT out[16];
PARTS:
// Put your code here:
// RAM64 八选一 RAM8 ,用 address 的[0][1][2]
DMux8Way(in=load, sel=address[0..2], a=loada, b=loadb, c=loadc, d=loadd,
e=loade, f=loadf, g=loadg, h=loadh);
// RAM8 里的3位,用 address的[3][4][5]
RAM8(in=in, load=loada, address=address[3..5], out=outa);
RAM8(in=in, load=loadb, address=address[3..5], out=outb);
RAM8(in=in, load=loadc, address=address[3..5], out=outc);
RAM8(in=in, load=loadd, address=address[3..5], out=outd);
RAM8(in=in, load=loade, address=address[3..5], out=oute);
RAM8(in=in, load=loadf, address=address[3..5], out=outf);
RAM8(in=in, load=loadg, address=address[3..5], out=outg);
RAM8(in=in, load=loadh, address=address[3..5], out=outh);
Mux8Way16(a=outa, b=outb, c=outc, d=outd,
e=oute, f=outf, g=outg, h=outh, sel=address[0..2], out=out);
}
五、RAM512(8个 RAM64)
同理上面RAM64
2、HDL
// 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/03/b/RAM512.hdl
/**
* Memory of 512 registers, each 16-bit wide.
* The chip facilitates read and write operations, as follows:
* Read: out(t) = RAM512[address(t)](t)
* Write: If load(t-1) then RAM512[address(t-1)](t) = in(t-1)
* In words: the chip always outputs the value stored at the memory
* location specified by address. If load == 1, the in value is loaded
* into the memory location specified by address. This value becomes
* available through the out output starting from the next time step.
*/
CHIP RAM512 {
IN in[16], load, address[9];
OUT out[16];
PARTS:
DMux8Way(in=load, sel=address[0..2], a=loada, b=loadb, c=loadc, d=loadd,
e=loade, f=loadf, g=loadg, h=loadh);
RAM64(in=in, load=loada, address=address[3..8], out=outa);
RAM64(in=in, load=loadb, address=address[3..8], out=outb);
RAM64(in=in, load=loadc, address=address[3..8], out=outc);
RAM64(in=in, load=loadd, address=address[3..8], out=outd);
RAM64(in=in, load=loade, address=address[3..8], out=oute);
RAM64(in=in, load=loadf, address=address[3..8], out=outf);
RAM64(in=in, load=loadg, address=address[3..8], out=outg);
RAM64(in=in, load=loadh, address=address[3..8], out=outh);
Mux8Way16(a=outa, b=outb, c=outc, d=outd,
e=oute, f=outf, g=outg, h=outh, sel=address[0..2], out=out);
}
六、RAM4k(8个 RAM512)
同理上面
2、HDL
// 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/03/b/RAM4K.hdl
/**
* Memory of 4K registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM4K {
IN in[16], load, address[12];
OUT out[16];
PARTS:
// Put your code here:
DMux8Way(in=load, sel=address[0..2], a=loada, b=loadb, c=loadc, d=loadd,
e=loade, f=loadf, g=loadg, h=loadh);
RAM512(in=in, load=loada, address=address[3..11], out=outa);
RAM512(in=in, load=loadb, address=address[3..11], out=outb);
RAM512(in=in, load=loadc, address=address[3..11], out=outc);
RAM512(in=in, load=loadd, address=address[3..11], out=outd);
RAM512(in=in, load=loade, address=address[3..11], out=oute);
RAM512(in=in, load=loadf, address=address[3..11], out=outf);
RAM512(in=in, load=loadg, address=address[3..11], out=outg);
RAM512(in=in, load=loadh, address=address[3..11], out=outh);
Mux8Way16(a=outa, b=outb, c=outc, d=outd,
e=oute, f=outf, g=outg, h=outh, sel=address[0..2], out=out);
}
七、RAM16k(4个 RAM4k)
稍微有点小变化,其它同理上面
2、HDL
// 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/03/b/RAM16K.hdl
/**
* Memory of 16K registers, each 16 bit-wide. Out holds the value
* stored at the memory location specified by address. If load==1, then
* the in value is loaded into the memory location specified by address
* (the loaded value will be emitted to out from the next time step onward).
*/
CHIP RAM16K {
IN in[16], load, address[14];
OUT out[16];
PARTS:
// Put your code here:
DMux4Way(in=load, sel=address[0..1], a=loada, b=loadb, c=loadc, d=loadd);
RAM4K(in=in, load=loada, address=address[2..13], out=outa);
RAM4K(in=in, load=loadb, address=address[2..13], out=outb);
RAM4K(in=in, load=loadc, address=address[2..13], out=outc);
RAM4K(in=in, load=loadd, address=address[2..13], out=outd);
Mux4Way16(a=outa, b=outb, c=outc, d=outd, sel=address[0..1], out=out);
}
八、PC
1、分析
计数器的逻辑描述如下:
如果 reset[t] == 1 那么 PC 的 out[t+1] = 0 (out 重置到 0步)
如果 reset[t] !== 1
那么再判断
如果 load[t] ==1 那么 PC 的 out[t+1] = in[t] (out 跳转到 in步)
如果 load[t] !==1
那么再判断
如果 inc[t] == 1 那么 PC 的 out[t+1] = out[t] + 1 (out 下一步)
如果以上都不是 那么 out[t+1] = out[t] (out 保持不变)
解题思路:
可以想到依次用3 个 Mux 表示 reset、load、inc的选择
HDL的顺序可能得反着写。
先做 inc 自增1, Inc(in = feedback,out = outinc)
再做inc ,Mux(...)
再做load, Mux(a = outinc,b = in[16], sel = load ,out = outload )
最后判断清零reset Mux(...,out= feadback, out = out)
最后容易忽略的是要加入合适的时序逻辑。来使PC具有时序性。
2、HDL
// 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/03/a/PC.hdl
/**
* A 16-bit counter with load and reset control bits.
* if (reset[t] == 1) out[t+1] = 0
* else if (load[t] == 1) out[t+1] = in[t]
* else if (inc[t] == 1) out[t+1] = out[t] + 1 (integer addition)
* else out[t+1] = out[t]
*/
CHIP PC {
IN in[16],load,inc,reset;
OUT out[16];
PARTS:
// Put your code here:
Inc16(in=feedback, out=incout);
Mux16(a=feedback, b=incout, sel=inc, out=m1); //sel为1时,做加1操作
Mux16(a=m1, b=in, sel=load, out=m2); //sel(load)为1时,out = in
Mux16(a=m2, b=false, sel=reset, out=m3); //sel为0时,选a。reset=1,选b
//加寄存器的目的是为了引入时序,上面的Inc和Mux都是没有时序的。
//有了时序,feedback估计才能起作用。
Register(in=m3, load=true, out=feedback, out=out); //load =true时,out=in。反之out等于上一个clock的out
}
3、测试
测试成功。
这周课,引入了时序逻辑,由于老师隐藏了DFF和时钟脉冲这些影响学习的因素。使我们更容易理解。但同时这里的时序逻辑电路在物理上真正是如何的实现的,就有待之后去发现了。你满足这样虚拟的CPU实现方式嘛?
不,你不满足。