From Nand To Tetris 从与非门到俄罗斯方块

21、P1 W3 U3.6 总结、作业3答案(待深入)

2019-08-06  本文已影响0人  shazizm

视频:
如果本次课程对应的 Coursera 的视频打不开,可以点击下面链接
P1W3U3.6 - Perspectives

  1. DFF没有实现,在实际中是怎么回事呢?
    没太明白,视频 00:40 到 5:45 (待深入研究)

  2. 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 和一个 dff

2、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实现方式嘛?

不,你不满足。

上一篇下一篇

猜你喜欢

热点阅读