770 likes | 905 Views
一个非常简单的 CPU 的设计. 1 、组合逻辑控制器 2 、微程序控制器. 1. cpu 定义. 我们按照应用的需求来定义计算机,本文介绍一个非常简单的 CPU 的设计,它仅仅用来教学使用的。我们规定它可以存取的存储器为 64byte ,其中 1byte=8bits 。所以这个 CPU 就有 6 位的地址线 A[5 : 0] ,和 8 位的数据线 D[7 : 0] 。. 我们仅定义一个通用寄存器 AC ( 8bits 寄存器), 它仅仅执行 4 条指令如下:. 除了寄存器 AC 外,我们还需要以下几个寄存器: 地址寄存器 A[5 : 0] , 保存 6 位地址。
E N D
一个非常简单的CPU的设计 1、组合逻辑控制器 2、微程序控制器
1. cpu定义 我们按照应用的需求来定义计算机,本文介绍一个非常简单的CPU的设计,它仅仅用来教学使用的。我们规定它可以存取的存储器为64byte,其中1byte=8bits。所以这个CPU就有6位的地址线A[5:0],和8位的数据线D[7:0]。
我们仅定义一个通用寄存器AC(8bits寄存器),它仅仅执行4条指令如下:我们仅定义一个通用寄存器AC(8bits寄存器),它仅仅执行4条指令如下:
除了寄存器AC外,我们还需要以下几个寄存器:除了寄存器AC外,我们还需要以下几个寄存器: • 地址寄存器 A[5:0], 保存6位地址。 • 程序计数器 PC[5:0],保存下一条指令的地址。 • 数据寄存器 D[7:0],接受指令和存储器来的数据。 • 指令寄存器 IR[1:0],存储指令操作码。
2 .取指设计 在处理器执行指令之前,必须从存储器取出指令。其中取指执行以下操作: • 通过地址端口A[5:0]从地址到存储器 • 等待存储器准备好数据后,读入数据。 由于地址端口数据A[5:0]是从地址寄存器中读出的,所以取指第一个执行的状态是 Fetch1: AR<—PC 接下来cpu发出read信号,并把数据从存储器M中读入数据寄存器DR中。同时pc加一。 Fetch2: DR<—M,PC<—PC+1 接下来把DR[7:6]送IR,把DR[5:0]送AR Fetch3: IR<—DR[7:6],AR<—DR[5:0]
3.指令译码 Cpu在取指后进行译码后才知道执行什么指令,对于本文中的CPU来说只有4条指令也就是只有4个执行例程,状态图如下:
4. 指令执行 对译码中调用的4个例程我们分别讨论: 4.1 ADD指令 ADD指令需要CPU做以下两件事情: • 从存储器取一个操作数 • 把这个操作数加到AC上,并把结果存到AC,所以需要以下操作: ADD1: DR<—M ADD2: AC<—AC+DR
4.2 AND指令 AND指令执行过程和ADD相似,需要以下操作: AND1: DR<—M AND2: AC<—AC^DR 4.3 JMP指令 JMP指令把CPU要跳转的指令地址送PC,执行以下操作: JMP1: PC<—DR[5:0] 4.4INC指令 INC指令执行AC+1操作: INC1: AC<—AC+1
5. 建立数据路径 这一步我们来实现状态图和相应的寄存器传输。首先看下面的状态及对应的寄存器传输: Fetch1: AR<—PC Fetch2: DR<—M,PC<—PC+1 Fetch3: IR<—DR[7:6],AR<—DR[5:0] ADD1: DR<—M ADD2: AC<—AC+DR AND1: DR<—M AND2: AC<—AC^DR JMP1: PC<—DR[5:0] INC1: AC<—AC+1
为了设计数据路径,我们可以采用两种办法: • 创造直接的两个要传输组件之间的直接路径 • 在CPU内部创造总线来传输不同组件之间的数据 首先我们回顾一下可能发生的数据传输,以便确定各个组件的功能。特别的我们要注意把数据载入组件的各个操作。首先我们按照他们改变了那个寄存器的数据来重组这些操作。得到如下的结果:
AR: AR<—PC;AR<—DR[5:0] • PC: PC<—PC+1;PC<—DR[5:0] • DR: DR<—M • IR: IR<—DR[7:6] • AC: AC<—AC+DR;AC<—AC^DR;AC<—AC+1 现在我们来看每个操作来决定每个组件执行什么样的功能,AR,DR,IR三个组件经常从其他的组件载入数据(从总线),所以只需要执行一个并行输入的操作。PC和AC能够载入数据同时也能够自动加一操作。下一步我们把这些组件连接到总线上来,如图所示:
现在我们来看以下者写数据传输中有没有不必要的传输:现在我们来看以下者写数据传输中有没有不必要的传输: • AR仅仅提供数据给存储器,所以他不需要连接到总线上。 • IR不通过总线提供数据给任何组件,所以他可以直接输出到控制单元。 • AC不提供数据到任何的组件,可以不连接到总线上。 • 总线是8bit宽度的,但是有些传输是6bit或者2bit的,我们必须制定寄存器的那几位送到总线的那几位。 • AC要可以载入AC和DR的和或者逻辑与的值,数据路径中还需要进行运算的ALU。
由此我们做以下工作: • 去掉AR,IR, AC与总线的连接。 • 我们约定寄存器连接是从总线的低位开始的。AR,PC连接到Bus[5:0],由于IR是接受DR[7:6]的,所以可以连接到总线的Bus[7:6]。 • 我们设定,AC作为ALU的一个输入,另一个输入来自总线Bus。 • 下面我们检查是否有争用总线的情况,幸运的是这里没有。修改后的CPU内部组织图如下:
6. ALU设计 • 这个CPU的ALU执行的功能就是两个操作数相加、逻辑与。这里不作详细介绍。电路如如下:
7. 控制单元 现在我们来考虑如何产生数据路径所需的控制信号,有两种方法:硬布线逻辑和微程序控制。这里我们用硬布线逻辑来实现。 这个简单的CPU需要的控制逻辑由三个部件组成: • 计数器: 用于保存现在的状态 • 译码器: 生成各个状态的控制信号 • 其他的组合逻辑来产生控制信号 一个通用的控制单元原理图如下:
对于这个CPU来说,一共有9个状态。所以需要一个4bit的计数器和一个4-16的译码器。接下来的工作就是按照前面的状态转换图来对状态进行赋值。对于这个CPU来说,一共有9个状态。所以需要一个4bit的计数器和一个4-16的译码器。接下来的工作就是按照前面的状态转换图来对状态进行赋值。 首先考虑如何的对译码输出状态进行赋值才能达到最佳状态。我们按照以下规则: 1〉给Fetch1赋计数器的0值,并用计数器的清零端来达到这个状态。由这个CPU的状态图可以看出,除了Fetch1状态外的其他状态都只能由一个状态转化而来,Fetch1需要从4个分支而来,这4个分支就可以发出清零信号(CLR)来转移到Fetch1。如图
2〉把连续的状态赋连续的计数器值,这样就可以用计数器的INC输入来达到状态的转移。2〉把连续的状态赋连续的计数器值,这样就可以用计数器的INC输入来达到状态的转移。 3〉给每个例程的开始状态赋值时,要基于指令的操作码和这个例程的最大状态数。这样就可以用操作码来生成计数器的LD信号达到正确的状态转移。首先,在Fetch3状态发出LD信号,然后要把正确的例程地址放到计数器的输入端。对这个CPU来说,我们考虑以地址1 [IR] 0作为计数器的预置输入。则得到状态编码如下:
这样就可以用操作码来生成计数器的LD信号达到正确的状态转移。首先,在Fetch3状态发出LD信号,然后要把正确的例程地址放到计数器的输入端。对这个CPU来说,我们考虑以地址1 [IR] 0作为计数器的预置输入。则得到状态编码如下:
下面我们用这些译码信号来产生数据路径控制所必需的AR、PC、DR、IR、M和ALU的控制信号。首先考虑寄存器AR,他在Fetch1状态取PC的值,并在Fetch3状态取DR[5:0]的值,所以我们得到下面我们用这些译码信号来产生数据路径控制所必需的AR、PC、DR、IR、M和ALU的控制信号。首先考虑寄存器AR,他在Fetch1状态取PC的值,并在Fetch3状态取DR[5:0]的值,所以我们得到 • ARLOAD=Fetch1 or Fetch3。 以此类推我们可以得到如下结果: • PCLOAD=JMP1 • PCINC=Fetch2 • DRLOAD=Fetch1 or ADD1 or AND1 • ACLOAD=ADD2 or AND2 • IRLOAD=Fetch3
对于ALU的控制信号ALUSEL是用来控制ALU做逻辑或者算数运算的,所以有:对于ALU的控制信号ALUSEL是用来控制ALU做逻辑或者算数运算的,所以有: ALUSEL=AND2 对于片内总线的控制较为复杂,我们先来看DR,对于DR他只在Fetch3、AND2 、ADD2和JMP1状态占用总线进行相信的数据传输,所以有: DRBUS=Fetch3 or AND2 or ADD2 or JMP1
其他类似有: • MEMBUS=Fetch2 or ADD1 or AND1 • PCBUS=Fetch1 最后,控制单元需要产生存储器的读信号(READ),它发生在Fetch2、ADD1、AND1三个状态: READ=Fetch2 or ADD1 or AND1 这样我们得到了总的控制逻辑,完成了整个CPU的设计。
8设计验证 我们执行如下指令进行设计验证, 0: ADD 4 1: AND 5 2: INC 3: JMP 0 4: 27H 5: 39H 指令执行过程如下(初始化所有寄存器为全零态):
1基本的微程序设计 • 当我们设计一个CPU的控制单元的时候我们往往是先给出一个CPU的状态图,然后设计一个有限状态机。硬布线逻辑是根据CPU的现态和输入(包括操作码和标志寄存器的内容)来进行状态转移,同时输出数据路径个组件的控制信号。 • 1.1微序列操作 • 一个微程序控制器也是一个有限状态机,一个通用的微程序控制器如下图:
说明: • 图中寄存器用来存储CPU状态图中的一个状态,把它作为微代码存储器的地址访问微代码存储器。 • 微代码存储器输出微指令,可以分成两个部分:一个部分是微操作,这些信号被输出到CPU的其他部分用以产生CPU数据路径中的控制信号。另一部分被用来产生下一个访问微代码存储器的地址。这一部分加上操作码、标志寄存器以及CPU现在的状态(也就是Register中的内容)一起产生下一次访问微代码存储器的地址。
3. 下一个地址产生单元接受操作码、标志寄存器内容和微代码存储器的输出,然后根据现在CPU所处的状态决定产生下一次访问微代码存储器的地址。它生成所有可能的转移地址,然后选择正确的输出到寄存器中。 • 一个可能的地址就是微代码存储器现在地址加一。 • 另一个可能的地址是要跳转的绝对地址。
每个微程序控制其还需要能够正确地访问执行例程,这就需要用到影射逻辑。把取指得到的操作码影射到执行子例程的第一条微指令的地址上。这个影射操作时在每个取指周期结束时进行的。每个微程序控制其还需要能够正确地访问执行例程,这就需要用到影射逻辑。把取指得到的操作码影射到执行子例程的第一条微指令的地址上。这个影射操作时在每个取指周期结束时进行的。
像所有高级语言编程一样,微代码也可以有子程序。当几条指令执行同一段微代码时,这段微代码就可以用一个子程序来实现。当调用此子程序时,这个子程序的微代码地址就被作为一个跳转的绝对地址赋给寄存器,而当前地址加一的地址则被保存为返回地址。(需要硬件的寄存器或者堆栈来实现)像所有高级语言编程一样,微代码也可以有子程序。当几条指令执行同一段微代码时,这段微代码就可以用一个子程序来实现。当调用此子程序时,这个子程序的微代码地址就被作为一个跳转的绝对地址赋给寄存器,而当前地址加一的地址则被保存为返回地址。(需要硬件的寄存器或者堆栈来实现)
4.一个微程序控制器最基本的四个部分就是: • 现在地址加一 • 绝对地址 • 影射逻辑地址 • 子例程返回地址 1.2微指令格式 每个微程序控制器可以有它自己的微指令格式。但是每条微指令必须包含以下几个部分的内容:
下面我们分别介绍这几个部分的内容: • SELECT域SELECT域用于指名下条指令地址的来源。它仅仅是指名下条指令地址的来源,而不直接给出下条指令的地址。例如:取指例程最后一条指令时,它的SELECT域会指名下一条地址将来自影射逻辑。 对于条件转移指令,执行子例程的执行需要根据标志为的判断来进行。对于这样的指令SELECT域要有相应的标志寄存器的选择。然后根据所选择的标志寄存器以及SELECT域的内容来决定下一地址的来源。 • ADDR域ADDR域就是来指名下一条指令执行的绝对地址的。例如当执行完一个例程需要进入取指例程时,对指明了下一个地址来源的微指令来说,ADDR域是无用的。例如:影射逻辑地址。
3.MICOR-OPERATION域 MICRO-OPERATION域用来描述要执行的微操作,有三种描述方法: 3.1水平微代码 为了实现水平微代码,我们先列出CPU执行的所有微操作。然后我们给每个微操作赋MICRO-OPERATION域中的1bit。这将导致MICRO-OPERATION域的位数很多。而且这种编码方法将使很多的MICRO-OPERATION域中的位在大多数时间无用。
3.2垂直微代码 为了实现垂直微代码,CPU可以执行的微操作被分组,然后每个微操作被赋予一个组合的二进制数,例如:16个微操作可以用4bit的MICRO-OPERATION域来描述(0000~1111)。事实上我们用4bit只能表示15个微操作,因为我们必须空出一个状态来描述空操作。垂直微代码的编码方式需要很少的MICRO-OPERATION域的位数,但是它需要一个译码器来产生真正的微操作信号。
3.3直接生成控制信号 在以上两种方法中,CPU都必须要把微操作信号转换成控制信号来进行数据路径的载入(LOAD)、清零(CLR)、加一(INC)、ALU控制以及总线上各个Buffers的开关等操作。第三种微代码的编码方法就是把控制信号直接存储到微指令中,这种方法不需要另外的组合逻辑,但是它可读性差,不宜于调试。
2、设计和实现A Very Simple CPU的微程序控制单元 • 为了验证一个微程序控制器的设计过程,我们首先来考虑前一章中的Very Simple CPU的控制单元的设计。本节将用微程序控制器重新设计其控制单元。我们将不在重新讲述指令集、有限状态机、数据路径以及ALU的设计。我们只讲述控制信号的产生过程。 • 2.1基本流程 • 这个Very Simple CPU的微程序控制器的基本框图如下:
在这个Very Simple CPU中只有两种可能的地址,一个是操作码影射地址另一个是绝对跳转地址。参看前面的Very Simple CPU的状态图,我们可以知道: • 从Fetch3到执行子例程需要一个地址影射逻辑,影射到要执行指令的地址处。 • 地址加一可以用Microde memory 产生ADDR作为绝对地址跳转实现,每个执行子例程结束后还需要一个地址跳转回到取指Fetch1微操作。 因为有两种地址输入,所以可以用一个2选1逻辑 来实现下一地址生成模块。选择控制信号是由微代码存储器产生的。
接下来我们考虑用多少位来表示Microde memory(控制存储器)输出的绝对地址? • 这个CPU一共有9个状态,每个状态用一个微指令表示。需要的最少的数据位数是4位。而IR译码后的影射逻辑地址也是4bit,所以用4bit来表示地址。
2.2生成微程序并且设计影射逻辑 现在我们通过有限状态机的状态来设计微代码序列。首先我们给每个状态赋予一个微代码的地址。与硬布线逻辑不同的是,它不是必须直接的把连续的地址赋给取指或者执行的各个状态,然而那样赋值能够使微代码易于阅读调试。赋值中考虑的首要问题是:执行子例程的第一个状态的地址赋值,因为它决定了影射逻辑的实现。对这个CPU来说,我们用和硬布线逻辑实现时同样的影射逻辑,也就是IR译码的影射逻辑是{1,IR[1:0],0}。这样产生了ADD1、AND1、JMP1、INC1的地址分别为1000、1010、1100、1110。相应的影射逻辑也就可以简单的如下表示: