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

news2024/12/23 18:01:13

在这里插入图片描述

  • 博主简介:努力学习的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判断有里往外写的,这个是很难理解的一点,因为拿到这个输入,我们很自然而然的就会想到它是由外往里进行逻辑判断的。但实际上并不是这样,因为其实越靠外面越会直接得到最终结果,就应该更靠逻辑图的右边(距离输出更近)

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2082601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【精选】基于B_S架构的智慧校园系统的设计与实现(全网独一无二,阿龙原创开发)

博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…

5分钟搞定!最好用的6款写论文专用神器APP软件

在当今学术研究和写作领域,AI论文写作工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿,还能进行内容优化、查重和排版等操作。以下是8款推荐的AI论文写作工具,包括千笔-AIPassPaper,帮助你更…

AOP自定义注解防重

Spring Boot 防重提交注解实现与实战示例 在Web开发中,防止用户重复提交表单是一个常见的需求。本文将详细介绍如何在Spring Boot中通过自定义注解和AOP技术实现防重提交功能,并提供一个完整的示例。 一、背景介绍 重复提交问题通常出现在用户在短时间…

来自OpenAI官网的Function calling介绍与最佳实践

学习如何将大型语言模型连接到外部工具。 介绍 函数调用允许您将模型如gpt-4o与外部工具和系统连接起来。这对于许多事情都很有用,比如为AI助手赋能,或者在你的应用程序与模型之间建立深度集成。 在2024年8月,我们推出了结构化输出功能。当…

8月27日笔记

活动目录的访问 AD Explorer LDAP( Lightweight Directory Access Protocol,轻量目录访问协议)是一种基于TCP/IP的应用层协议,用于访问和维护分布式目录信息服务。它允许用户在一个网络中查找和管理存储在目录服务中的信息。是在…

SCADA 系统开启车间智能可视化

在当今高速发展的工业时代,车间的高效运作与精准管理至关重要。然而在自动化设备、仪表、传感器等应用的现今,其产生的数据越来越庞大,要想将这些数据充分利用起来,并且形成更易分析的信息,则需要SCADA 系统来进行采集…

参数高效的迁移学习在自然语言处理中的应用

人工智能咨询培训老师叶梓 转载标明出处 迁移学习技术,尤其是针对大型预训练模型的微调(fine-tuning),在诸多下游任务中展现出了卓越的性能。然而,当面临众多任务时,传统的微调方法存在参数效率低下的问题…

鸿蒙开发:深入浅出Stage模型(UIAbility组件)

🚀一、UIAbility组件 🔎1.概述 HarmonyOS中的Stage模型是一种基于UIAbility组件的应用程序架构。UIAbility是HarmonyOS系统中用于构建用户界面的基本组件之一。它负责处理应用程序界面的显示和交互。 在Stage模型中,每个应用程序都有一个或…

【Qt笔记】QCommandLinkButton控件详解

目录 引言 一、概述 二、特性与属性 1. 属性 2. 样式 三、基本用法 1. 引入必要的头文件 2. 创建和配置 QCommandLinkButton 3. 布局管理 四、高级用法 1. 自定义绘制 2. 动态内容更新 五、代码解析示例 注意 总结 引言 QCommandLinkButton 是 Qt 框架中 QtWi…

招生简章如何制作为在线版的网址链接?

​随着互联网的高速发展,越来越多的学校和企业选择通过在线方式发布招生简章。这种趋势不仅方便了大量用户,还大大降低了传统纸质招生简章的制造成本。那么,如何制作一份吸引眼球的在线招生简章呢? 1.要制作电子杂志,首先需要选择…

leetcode_001_两数之和解析

两数之和解析 题目: 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。你可以按任意顺序…

【解压即玩】使命de召唤4

《使命de召唤4》 立即下载:【chumenx.com】【解压即玩】使命de召唤4

Leetcode 51. 皇后 回溯 C++实现

Leetcode 51. 皇后 问题:按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上,并且使皇后彼此之间不能相互攻击。 给你一个整数 n ,返回所有不…

Spring框架基础

前言 本文将讲解spring框架的基础内容 Spring 首先,我们需要了解,spring是什么? spring是一个轻量级的IOC和AOP的一站式java开发框架 作用是简化企业级开发 轻量级:框架体积小(核心模块) 其中 IOC: Inversion of Control 控制反转 IOC的作用是可以把创建对象的控制权,反转给s…

学习区块链?看我就够了!

写在前面,本文提到的所有书籍资源,都提供免费下载地址 内含pdf,epub,mobi等格式 一.区块链:定义未来金融与经济新格局 以区块链技术为核心构建的价值互联网 将深刻改变未来的金融与经济格局 文明向前发展,有些成果的…

Linux基础软件-共享存储nfs

作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux进阶部分又分了很多小的部分,我们刚讲完了Linux日常运维。讲的那些东西都算是系统自带的,但是Linux作为一个…

大模型之二十七-语音识别Whisper实例浅析

Whisper简介 Whisper是OpenAI于2022年9月开源的一个多语种识别模型,目前支持99种语言,是目前性能最好的开源多语种识别ASR大模型,第一版版使用了68万小时标注好的语料预训练模型,而large-v3的标注数据超过了500万小时&#xff0c…

QL5010-16-ASEMI逆变焊机专用整流桥QL5010

编辑:ll QL5010-16-ASEMI逆变焊机专用整流桥QL5010 型号:QL5010 品牌:ASEMI 封装:KBPC-4 批号:2024 类型:整流模块 电流:50A 电压:1600V 安装方式:直插式封装 …

(2)Studio 5000 Logix Emulate仿真使用方法

Studio 5000 Logix Emulate仿真使用方法 引言:首先要安装好Studio 5000 logix emulate,这个软件也是需要授权的。还需要注意仿真器与studio 5000之间版本的对应,studio5000的版本需要小于仿真器版本。 打开Studio 5000 logix emulate&#x…

Lombok组件的使用

什么是Lombok Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量。 Lombok的使用 使用Lombok需要的开发环境JavaMavenIntelliJ IDEA或…