【计算机系统架构】从0开始构建一台现代计算机|时序逻辑、主存储器|第2章

本文主要是介绍【计算机系统架构】从0开始构建一台现代计算机|时序逻辑、主存储器|第2章,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

  • 博主简介:努力学习的22级计算机科学与技术本科生一枚🌸
  • 博主主页: @Yaoyao2024
  • 往期回顾: 【计算机系统架构】从0开始构建一台现代计算机|二进制、布尔运算和ALU|第2章
  • 每日一言🌼: 孤独和喧嚣都令人难以忍受。如果一定要忍受,我宁可选择孤独。
    —— 周国平

0、前言

  • 一言以蔽之: 在构建了计算机的 ALU 之后,本 Modulation 将转向构建计算机的主存储器单元,也称为随机存取存储器或RAM。这项工作将自下而上逐步完成,从初级触发器门到一位寄存器,再到 n 位寄存器,直至一系列 RAM 芯片。与基于组合逻辑的计算机处理芯片不同,计算机的存储逻辑需要基于时钟的顺序逻辑(时序逻辑电路)。我们将首先概述这一理论背景,然后构建我们的内存芯片组
  • 关键概念:组合逻辑与时序逻辑、时钟与周期、触发器、寄存器、RAM 单元、计数器。

1、时序逻辑(Sequential Logic)

1.0 前言

在前面两章中,我们学习到一些逻辑门,他们代表着输入和输出的映射关系。但是我们并没有“时间”的概念,更通俗来说,我们的概念中,并不是先有输入,然后才有了输出;而是在输入的同一时间即刻得到的输出,我们并没有“One thing after an other”的概念。

但是现实生活中我们必须关注“时间”,因为我们就是生活在时间当中的,我们的任何行动和行为都是具有时间概念的,计算机也必须拥有时间,也才能更好地像人一样工作,否则则是混乱的。

💁🏻‍♀️其实在本节学习计算机中的"时间"这个概念的时候,老师说我们之前几节学的组合逻辑,并不是先有输入,然后才有了输出(one after another);我其实比较纳闷,哪电流信号从输入信号流入,通过组合逻辑电路得到输出,肯定有时间的呀!!
但其实我这种想法是比较错误的,对于我们人来说,的确是有时间的,但是对于计算机来说,其实是没有时间的,因为你没有给它这个概念,时间也无法度量,对于它来说其实并不是`one thing after another"的。

要想计算机拥有时间的概念之前,我们再来深入地分析一下,时间的作用。

1.1 时间的作用

  • Use the same hardware over time(硬件的复用性)

    组合逻辑电路是可以复用的,但它的复用方式和时间的关系不同。我们先来理解组合逻辑电路和时间之间的关系。

    组合逻辑电路是一种不涉及存储的电路。它根据输入直接产生输出,输出完全由当前输入决定,和时间无关。所以,对于同样的输入,组合逻辑电路总是会立即产生相同的输出,不管什么时候输入是一样的,它都能立刻给出结果。

    但是,当我们说到需要“复用硬件”时,指的是计算机需要处理连续的、不同的计算任务,而这些任务不可能在同一时间内同时完成。时间在这里的作用是让计算机能够依次处理这些任务。例如,如果你有多个加法操作要进行,虽然组合逻辑电路可以同时处理多个加法,但硬件资源有限(例如一块特定的加法电路),计算机会按顺序利用这块电路来完成不同的加法任务。

    所以,组合逻辑电路本身是可以复用的,但复用它时依然需要时间。因为我们希望通过一个硬件单元(例如加法器)来处理不同的输入和任务,而不是为每个任务都配备独立的硬件。时间允许我们复用同一块硬件去完成多个操作,这样就可以节约资源。

    总的来说,复用硬件是指在不增加额外硬件的情况下,通过时间的控制,让一块硬件能够连续完成多个任务。

  • Remember state
    记录中间状态

    比如我们要计算一个数累加100次,如果不能记录每次中间得到的结果,就不可能得到正确答案

  • Deal with speed

    这段话主要讲了一个我们不想特别关心,但又必须考虑的关于时间的因素:计算机的速度有限

    具体来说,计算机处理任务的速度并不是无限的,它有一个固定的、有限的运行速度。因此,我们在设计程序或系统时,必须考虑到计算机的这个限制。我们不能要求计算机超出它的能力去完成任务,或者至少要知道计算机的运行速度是多少,这样才能合理地安排任务的执行。

    打个比方,就像我们不可能要求一个人每秒钟完成100件事一样,计算机也有它的极限。即使我们希望计算机能尽快完成任务,但实际上它的速度是受限的。因此,我们需要确保我们的程序不会让计算机超负荷工作,或者根据它的速度合理地安排计算任务,以避免程序崩溃或运行不稳定。

    总结一下:虽然我们更关注如何复用硬件和处理连续任务,但我们也必须注意到计算机的运行速度有限,不能让它超出能力范围工作。因为计算机不能超出其最大速度去处理任务,所以我们需要合理安排任务的顺序和执行时间。这也就是为什么我们说计算机的有限速度让时间变得重要。时间在这里的作用是分配和协调任务,确保计算机有足够的时间去完成每一项操作

1.2 时钟

时钟是计算机里来衡量和表示时间的方法。和现实世界中的时钟一样, 它的作用就算将连续的时间信号离散化,变为一个一个单位进行时间的衡量。

在这里插入图片描述

如上图,物理世界中的时间是连续的,而时钟的作用就是将时间离散化、量化,变成一个时间序列:time=1、time=2、time=3...。一个周期就是一个时间单位;在一个整数时间单位内,我们认为电路中不会有信号的改变。

在把时间量化后,输入输出的时间先后顺序是这样表示的:在t-1这个时间单位输出做出的改变,会在t时刻输出。这就完全不同于之前没有先后顺序的组合逻辑电路:在t-1这个时间单位输出做出的改变,会在t-1时刻l立刻输出。

👧🏻所以我个人认为拥有时钟来表示时间,就是量化时间,从而更好地更清晰的表示先后顺序,从而保证系统的稳定性,这点可以在下一节讲信号的延迟中可以看出。

1.3 信号的延迟

这点也进一步解释了我们为什么希望使用clock来将时间离散化,目的也是为了忽略不计这些信号的延迟!避免延迟带来的影响。对时钟时间周期选择的目的(不能太快,当然也不能太慢)的目的就是为了让硬件运行地更加稳定。

上面我们提到,虽然在组合电路中,对于计算里来说,是没有时间概念的;但是我们知道,在电路中,输入的物理信号用电信号表示,从输入到输出,是电子流动和聚集的过程,这在现实的物理世界中肯定是需要时间的,且在这段时间内的电信号变化是连续的而非条约的。即:从输入信号到输出信号存在延迟。
在这里插入图片描述
而在计算机内部建立起这种离散化的数字时间,其实也是为了避免信号的延迟!

为什么这么说呢?如下图,只要我们的时钟的速度不是太快,在连续的延迟之间流出足够多的时间等待信号达到稳定(即灰色区域后),当周期结束时,即可取得最终稳定的信号:

在这里插入图片描述
事实上,在选取时钟周期的前提也是确保所有的硬件都能稳定下来。

1.4 组合逻辑和时序逻辑的区别

∙ Combinatorial:  o u t [ t ] = f u n c t i o n ( i n [ t ] ) ∙ Sequential:  o u t [ t ] = f u n c t i o n ( i n [ t − 1 ] ) \bullet\text{Combinatorial: }out[t]=function(\:in[t]\:)\\\bullet\text{ Sequential: }out[t]=function(\:in[t-1]\:) Combinatorial: out[t]=function(in[t]) Sequential: out[t]=function(in[t1])

其实在上面的1.2小节已经讲到过了:

下面这个例子也是对组合逻辑和时序逻辑的比较:

  • 组合逻辑:
    在这里插入图片描述

  • 时序逻辑:
    在这里插入图片描述

2、时序逻辑的基本单元:D触发器 (D Flip-Flop)

D触发器是时序逻辑电路的基础,它可以保存一个bit的信息,这也为之后保存大量的字节内容奠定了基础

2.0 前言

在前面一小节我们讲解了时序逻辑电路,它的核心就是数字化和离散化了时间,让先后顺序更加量化和明确。这一小节,我们将从硬件实现 的角度出发,实现 s t a t e [ t ] = f u n c t i o n ( s t a t e [ t − 1 ] ) state[t]=function(state[t-1]) state[t]=function(state[t1]) 的时序逻辑。

2.1 状态的记忆:Remembering State

  • 首先,实现时序逻辑的关键就是记忆状态: 记住时刻的信息直到t时刻使用。Missing ingredient:remember one bit of information from time t-1 so it can be used at timet
  • 那么我们知道,这个记忆状态的元件肯定有两种状态:1 or 0; 并且根据t-1时刻的信号进行翻转flip01之间进行转换

上述实现这种在单位时间内进行信号状态记忆的元素称为 触发器(Clocked Data Flip Flop).

2.2 Clocked Data Flip Flop:D触发器

💜介绍:

如下图,D触发器有一个输入in和一个输出out;作用是记录上一个单位时间的输入,然后在下一个单位时间输出: o u t [ t ] = i n [ t − 1 ] out[t]=in[t-1] out[t]=in[t1]
在这里插入图片描述

注意:图中的正三角形🔺是【时钟脉冲沿】的意思,表示这个器件是时序逻辑下的芯片,与时钟有关;触发器输出的状态由该脉冲沿的状态来决定,三角符号下边有圆圈的表示时钟脉冲下降沿触发有效,无圆圈的则表示时钟脉冲上升沿触发有效。即,理解如下: 下一个周期的输出信号由上一个周期末尾结束的上升沿采样值确定。
在这里插入图片描述

🥗D触发器的实现:

  • 在这门课中,我们不会去关系它的内部地层实现,而是默认它是有记忆功能的原始器件即可。In this course:it is a primitive

  • In many physical implementations,it may be built from actual Nand gates:
    Step 1:create a"loop”achieving an“un-clocked”flip-flip
    Step 2:Isolation across time steps using a "master-slave"setup

  • Our Hardware Simulator forbids “combinatorial loops”

    • A cycle in the hardware connections is allowed only if it passesthrough a sequential gate

2.5 时序逻辑的实现

在这里插入图片描述

上图展示了我们将在计算机中构建的所有逻辑的架构:A combination of remembering information via this basic D Flip-Flops, and the manipulating them using combinational logics.

我们可以看到,在上述架构中可以看到,该芯片的输出状态不仅取决于当前时刻的输入,还取决于上一时刻的输出: s t a t e [ t ] = f ( i n p u t , s t a t e [ t − 1 ] ) state[t]=f(input,state[t-1]) state[t]=f(input,state[t1])

2.4 一位寄存器

💜目标(Goal):“永远”记住输入的1bit信息,直到被要求记住一个新的输入(remember an input bit “forever”:until requested to load a new value.)

`
在这里插入图片描述
在这里插入图片描述

🌺实现(Implementation):

寄存器和触发器的逻辑并不完全相同:

  • 触发器永远保存上一个单位时间的输入;如果上一个单位时间的输入改变,则该单位时间的输出也随之改变;
  • 寄存器:只有在load = 1时,才会不断加载上一个单位时间的输入,直至load = 0则会永远保存load = 0之前那个单位时间的输入。即: if load(t-1) then out(t)=in(t-1) else out(t)=out(t-1) \begin{aligned}&\text{if load(t-1) then out(t)=in(t-1)}\\&\text{else out(t)=out(t-1)}\end{aligned} if load(t-1) then out(t)=in(t-1)else out(t)=out(t-1)

要想实现上述1bit寄存器的功能,只需在DFF之前加上一个选择器即可,根据load进行选择如何输出:
在这里插入图片描述

3、内存单元:RAM

3.0 前言

如下图,当我们讲到存储器Memory时,它是冯诺依曼体系结构的五大组成部分之一。

在这里插入图片描述
同时存储器有按照在计算机中的作用or层次可以分为以下两种:

  • Main memory(主存储器or内存储器): 随机存储器(RAM)…
    主存储器是存储在计算机内部的并连接到主板上的,CPU可以直接访问。作用是用来存储计算机运行器件所需要的数据和指令(指令本身就是程序的组成部分)。
  • Secondary memory(辅助存储器):磁盘disks,…

按照信息的可保存性分类为:

  • Volatile(易失性存储器)
    eg: RAM
  • non-volatile(非易失性存储器)
    eg: ROM

在本门课课程中我们只关心打✔的以下几项:
在这里插入图片描述

3.1 RAM的基础存储元素:寄存器

在这里插入图片描述

2.4,我们学习了一位寄存器,我们不难想到可以将其扩展为多位寄存器;其中w表示位宽,可以为:16-bit, 32-bit...

16-bit的寄存器逻辑和输入输出接口如下:

/*** 16-bit register:* If load is asserted, the register's value is set to in;* Otherwise, the register maintains its current value:* if (load(t)) out(t+1) = int(t), else out(t+1) = out(t)*/
CHIP Register {IN in[16], load;OUT out[16];PARTS: Replace this comment with your code.
}

3.2 RAM unit

RAM的体系架构如下:

在这里插入图片描述

  • RAM的抽象概念:(RAM abstraction): 是一系列(n个)可寻址的寄存器组成,地址为 0~1(A sequence ofn addressable registers,with addresses 0 to n-1)
  • 在任意给定时间单位内: 只有一个寄存器可以被选中。(At any given point of time,only oneregister in the RAM is selected)
  • k(输入地址的位宽): k = l o g 2 n \mathrm{k=log_2n} k=log2n
  • w(输入数据的位宽)在本门课所构建的Hack计算机中,w = 16

RAM的逻辑如下:

//Let M stand for the state of
//the selected register
if load then {M = in//from the next cycle onward:out = M
}
else out = M
  • RAM的读取逻辑:
    在这里插入图片描述

  • RAM的写入逻辑:
    在这里插入图片描述

3.3 16输入位宽的RAM系列

在这里插入图片描述

如上图可以看到RAM nn表示这个内存有n个寄存器,且每个寄存器的输入位宽这里默认是16

到这里我们也知道RAM的含义: Ramdom Access Memory,因为我们只用确定好要访问的寄存器地址,就能在同等的时间内快速选取到该寄存器对其进行处理。

4、程序计数器PC: Program Counter

4.0 前言

CPU是由ALU+控制器组成:
在这里插入图片描述

其中控制器是整个系统的 指挥中枢,基本功能就是执行指令

其中程序计数器PC控制器的组成部分。用于指出将要执行的指令在主程序中存放的地址,CPU再根据地址去取出指令;由于指令在内存中通常都是顺序存放,它有自增 的功能。

🐣eg: 比如我写了一个程序给机器人如何做蛋糕,这个程序由49条指令组成,顺序存放。那么机器人做蛋糕就从第1条指令出发,顺次往下自增得到指令并执行即可;同时,可以随意从一个指令跳到另一个指令(比如完成了一个蛋糕后,再重新做一个蛋糕时不必从指令1开始,或许可以从指令17开始,因为前面的准备工作都已完成。

4.1 PC的作用

  • 首先,计算机必须要跟踪当前指令的执行以及即将执行的指令(The computer must keep track of which instruction should be fetched and executed next)
  • 上述这种控制可以被PC,即程序计数器实现。
  • 程序计数器包含下一个将要被取得和执行的指令地址(The PC contains the address of the instruction that will befetched and executed next)

同时,PC必须包含以下三个基本设置:

  1. Reset: fetch the first instruction (PC = 0)
  2. Next: fetch the next instruction (PC++)
  3. Goto: fetch instruction n (PC = n)

4.2 深入PC

PC的结构如下:
在这里插入图片描述

PC的逻辑如下:

/*** A 16-bit counter.* if      reset(t): out(t+1) = 0* else if load(t):  out(t+1) = in(t)* else if inc(t):   out(t+1) = out(t) + 1* else              out(t+1) = out(t)*/
CHIP PC {IN in[16], reset, load, inc;OUT out[16];PARTS: Replace this comment with your code.
}

5、Project 3

在这里插入图片描述

5.1 一位存储器

在这里插入图片描述

  • 🐣分析:1 bit寄存器的结构如下,由一个数据选择器mux和一个DFF组成:

在这里插入图片描述

  • 🪴HDL代码:

    /*** 1-bit register:* If load is asserted, the register's value is set to in;* Otherwise, the register maintains its current value:* if (load(t)) out(t+1) = in(t), else out(t+1) = out(t)*/
    CHIP Bit {IN in, load;OUT out;PARTS: Replace this comment with your code.Mux(a= outDFF, b= in, sel= load, out= o1);DFF(in= o1,  out = outDFF,out = out);
    }
    

    Tips:注意到DFFout有两个赋值,这是正确的,因为其输出确实连接了两个引脚,HDL本身也就是描述硬件的连接的。

5.2 16位寄存器

在这里插入图片描述

  • 🐣分析:16bit的寄存器本身就是将16个1bit的寄存器并接即可,load都由一位控制即可。

  • 🪴HDL代码:

    /*** 16-bit register:* If load is asserted, the register's value is set to in;* Otherwise, the register maintains its current value:* if (load(t)) out(t+1) = int(t), else out(t+1) = out(t)*/
    CHIP Register {IN in[16], load;OUT out[16];PARTS: Replace this comment with your code.// 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] );
    }
    

5.3 RAM8

在这里插入图片描述

  • 🐣分析:

    • 让输入in[16]与所有的寄存器连接
    • 反向选择器连接load,用address来选择判断让哪个寄存器来进行加载数据
    • 数据输出部分很简单,利用多路选择器并用address来判断读取哪个寄存器的数据
      在这里插入图片描述
  • 🪴HDL代码:

    /*** Memory of eight 16-bit registers.* If load is asserted, the value of the register selected by* address is set to in; Otherwise, the value does not change.* The value of the selected register is emitted by out.*/
    CHIP RAM8 {IN in[16], load, address[3];OUT out[16];PARTS: Replace this comment with your code.进行数据读取的判断,选择哪个寄存器来加载数据DMux8Way(in= load, sel= address, a= load0, b= load1, c= load2, d= load3, e= load4, f= load5, g= load6, h= load7);将输入与每个寄存器相连Register(in= in, load= load0, out= o0);Register(in= in, load= load1, out= o1);Register(in= in, load= load2, out= o2);Register(in= in, load= load3, out= o3);Register(in= in, load= load4, out= o4);Register(in= in, load= load5, out= o5);Register(in= in, load= load6, out= o6);Register(in= in, load= load7, out= o7);使用多路选择器来判断将哪个寄存器的结果输出Mux8Way16(a= o0, b= o1, c= o2, d= o3, e= o4, f= o5, g= o6, h= o7, sel= address, out= out);
    }
    

5.4 …->RAM16

在这里插入图片描述

现在我们要完成RAM64~RAM512,但这也是基于之前的RAM8RAM64…逐渐抽象的过程:

1 RAM64

  • 🐣分析:RAM64的本质是8RAM8
    其中address[3~5]负责选择哪一个RAM进行输入和输出。,address[0~2]负责选择这个RAM里面的哪个寄存器
    在这里插入图片描述

  • 🪴HDL代码:

    /*** Memory of sixty four 16-bit registers.* If load is asserted, the value of the register selected by* address is set to in; Otherwise, the value does not change.* The value of the selected register is emitted by out.*/
    CHIP RAM64 {IN in[16], load, address[6];OUT out[16];PARTS: Replace this comment with your code.DMux8Way(in= load, sel= address[3..5], a= load0, b= load1, c= load2, d= load3, e= load4, f= load5, g= load6, h= load7);RAM8(in= in, load= load0, address= address[0..2], out= o0);RAM8(in= in, load= load1, address= address[0..2], out= o1);RAM8(in= in, load= load2, address= address[0..2], out= o2);RAM8(in= in, load= load3, address= address[0..2], out= o3);RAM8(in= in, load= load4, address= address[0..2], out= o4);RAM8(in= in, load= load5, address= address[0..2], out= o5);RAM8(in= in, load= load6, address= address[0..2], out= o6);RAM8(in= in, load= load7, address= address[0..2], out= o7);Mux8Way16(a= o0, b= o1, c= o2, d= o3, e= o4, f= o5, g= o6, h= o7, sel= address[3..5], out= out);
    }
    

2 RAM512

在这里插入图片描述

这个和RAM64的思路完全一样:

/*** Memory of 512 16-bit registers.* If load is asserted, the value of the register selected by* address is set to in; Otherwise, the value does not change.* The value of the selected register is emitted by out.*/
CHIP RAM512 {IN in[16], load, address[9];OUT out[16];PARTS: Replace this comment with your code.DMux8Way(in= load, sel= address[6..8], a= load0, b= load1, c= load2, d= load3, e= load4, f= load5, g= load6, h= load7);RAM64(in= in, load= load0, address= address[0..5], out= o0);RAM64(in= in, load= load1, address= address[0..5], out= o1);RAM64(in= in, load= load2, address= address[0..5], out= o2);RAM64(in= in, load= load3, address= address[0..5], out= o3);RAM64(in= in, load= load4, address= address[0..5], out= o4);RAM64(in= in, load= load5, address= address[0..5], out= o5);RAM64(in= in, load= load6, address= address[0..5], out= o6);RAM64(in= in, load= load7, address= address[0..5], out= o7);Mux8Way16(a= o0, b= o1, c= o2, d= o3, e= o4, f= o5, g= o6, h= o7, sel= address[6..8], out= out);
}

3 RAM4k

/*** Memory of 4K 16-bit registers.* If load is asserted, the value of the register selected by* address is set to in; Otherwise, the value does not change.* The value of the selected register is emitted by out.*/
CHIP RAM4K {IN in[16], load, address[12];OUT out[16];PARTS: Replace this comment with your code.// Put your code here:DMux8Way(in=load ,sel=address[9..11] ,a=load0 ,b=load1 ,c=load2 ,d=load3 ,e=load4 ,f=load5 ,g=load6 ,h=load7 );RAM512(in=in ,load=load0 ,address=address[0..8] ,out=out0 );RAM512(in=in ,load=load1 ,address=address[0..8] ,out=out1 );RAM512(in=in ,load=load2 ,address=address[0..8] ,out=out2 );RAM512(in=in ,load=load3 ,address=address[0..8] ,out=out3 );RAM512(in=in ,load=load4 ,address=address[0..8] ,out=out4 );RAM512(in=in ,load=load5 ,address=address[0..8] ,out=out5 );RAM512(in=in ,load=load6 ,address=address[0..8] ,out=out6 );RAM512(in=in ,load=load7 ,address=address[0..8] ,out=out7 );Mux8Way16(a=out0 ,b=out1 ,c=out2 ,d=out3 ,e=out4 ,f=out5 ,g=out6 ,h=out7 ,sel=address[9..11] ,out=out );
}

4 RAM16k

/*** Memory of 16K 16-bit registers.* If load is asserted, the value of the register selected by* address is set to in; Otherwise, the value does not change.* The value of the selected register is emitted by out.*/
CHIP RAM16K {IN in[16], load, address[14];OUT out[16];PARTS:// Put your code here:DMux4Way(in=load ,sel=address[12..13] ,a=load0 ,b=load1 ,c=load2 ,d=load3);RAM4K(in=in ,load=load0 ,address=address[0..11] ,out=out0 );RAM4K(in=in ,load=load1 ,address=address[0..11] ,out=out1 );RAM4K(in=in ,load=load2 ,address=address[0..11] ,out=out2 );RAM4K(in=in ,load=load3 ,address=address[0..11] ,out=out3 );Mux4Way16(a=out0 ,b=out1 ,c=out2 ,d=out3 ,sel=address[12..13] ,out=out );
}

5.5 PC

在这里插入图片描述

  • 🐣分析:

    • 首先,这是一个时序电路,那么它的结构肯定是复合2.5 时序逻辑的实现那样,如下图:
      在这里插入图片描述
    • 由上图我们可以确定,组合逻辑在左边,而时序逻辑(寄存器)在右半部分。
    • 那么难点其实是组合逻辑的书写

    这里直接看最终代码:

/*** 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=state,out=inc16);Mux16(a=state ,b=inc16 ,sel=inc ,out=tmp1 );Mux16(a=tmp1 ,b=in ,sel=load ,out=tmp2 );Mux16(a=tmp2 ,b=false ,sel=reset ,out=newstate );Register(in=newstate ,load=true ,out=out,out=state );
}

可以看到,它其实是从几个多层if判断有里往外写的,这个是很难理解的一点,因为拿到这个输入,我们很自然而然的就会想到它是由外往里进行逻辑判断的。但实际上并不是这样,因为其实越靠外面越会直接得到最终结果,就应该更靠逻辑图的右边(距离输出更近)

在这里插入图片描述

这篇关于【计算机系统架构】从0开始构建一台现代计算机|时序逻辑、主存储器|第2章的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1115732

相关文章

mybatis的整体架构

mybatis的整体架构分为三层: 1.基础支持层 该层包括:数据源模块、事务管理模块、缓存模块、Binding模块、反射模块、类型转换模块、日志模块、资源加载模块、解析器模块 2.核心处理层 该层包括:配置解析、参数映射、SQL解析、SQL执行、结果集映射、插件 3.接口层 该层包括:SqlSession 基础支持层 该层保护mybatis的基础模块,它们为核心处理层提供了良好的支撑。

百度/小米/滴滴/京东,中台架构比较

小米中台建设实践 01 小米的三大中台建设:业务+数据+技术 业务中台--从业务说起 在中台建设中,需要规范化的服务接口、一致整合化的数据、容器化的技术组件以及弹性的基础设施。并结合业务情况,判定是否真的需要中台。 小米参考了业界优秀的案例包括移动中台、数据中台、业务中台、技术中台等,再结合其业务发展历程及业务现状,整理了中台架构的核心方法论,一是企业如何共享服务,二是如何为业务提供便利。

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

Retrieval-based-Voice-Conversion-WebUI模型构建指南

一、模型介绍 Retrieval-based-Voice-Conversion-WebUI(简称 RVC)模型是一个基于 VITS(Variational Inference with adversarial learning for end-to-end Text-to-Speech)的简单易用的语音转换框架。 具有以下特点 简单易用:RVC 模型通过简单易用的网页界面,使得用户无需深入了

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

maven 编译构建可以执行的jar包

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」👈,「stormsha的知识库」👈持续学习,不断总结,共同进步,为了踏实,做好当下事儿~ 专栏导航 Python系列: Python面试题合集,剑指大厂Git系列: Git操作技巧GO

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

系统架构设计师: 信息安全技术

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师: 信息安全技术前言信息安全的基本要素:信息安全的范围:安全措施的目标:访问控制技术要素:访问控制包括:等保

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor