77
个个个个个个 CPU 个个个 1 个个个个个个个 2 个个个个个个

一个非常简单的 CPU 的设计

  • Upload
    nerina

  • View
    70

  • Download
    5

Embed Size (px)

DESCRIPTION

一个非常简单的 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 位地址。 - PowerPoint PPT Presentation

Citation preview

Page 1: 一个非常简单的 CPU 的设计

一个非常简单的 CPU 的设计 1、组合逻辑控制器 2、微程序控制器

Page 2: 一个非常简单的 CPU 的设计

1. cpu 定义 我们按照应用的需求来定义计算机,本文介绍一个非常简单的 CPU 的设计,它仅仅用来教学使用的。我们规定它可以存取的存储器为 64byte ,其中 1

byte=8bits 。所以这个 CPU 就有 6 位的地址线 A[5 : 0] ,和 8 位的数据线D[7 : 0] 。

Page 3: 一个非常简单的 CPU 的设计

我们仅定义一个通用寄存器 AC ( 8bits 寄存器),它仅仅执行 4 条指令如下:

Instruction Instruction Code Operation

ADD 00AAAAAA AC<—AC+M[AAAAAA]

AND 01AAAAAA AC<—AC^M[AAAAAA]

JMP 10AAAAAA GOTO AAAAAA

INC 11XXXXXX AC<—AC+1

Page 4: 一个非常简单的 CPU 的设计

除了寄存器 AC 外,我们还需要以下几个寄存器: 地址寄存器 A[5 : 0] , 保存 6 位地址。 程序计数器 PC[5 : 0] ,保存下一条指令的地址。 数据寄存器 D[7 : 0] ,接受指令和存储器来的数据。 指令寄存器 IR[1 : 0] ,存储指令操作码。

Page 5: 一个非常简单的 CPU 的设计

2 . 取指设计 在处理器执行指令之前,必须从存储器取出指令。其中取指执行以下操作:1. 通过地址端口 A[5 : 0] 从地址到存储器2. 等待存储器准备好数据后,读入数据。 由于地址端口数据 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]

Page 6: 一个非常简单的 CPU 的设计
Page 7: 一个非常简单的 CPU 的设计

3. 指令译码 Cpu 在取指后进行译码后才知道执行什么指令,对于本文中的 C

PU 来说只有 4 条指令也就是只有4 个执行例程,状态图如下:

Page 8: 一个非常简单的 CPU 的设计
Page 9: 一个非常简单的 CPU 的设计

4. 指令执行 对译码中调用的 4 个例程我们分别讨论:4.1 ADD 指令 ADD 指令需要 CPU 做以下两件事情:1. 从存储器取一个操作数2. 把这个操作数加到 AC 上,并把结果存到

AC, 所以需要以下操作:ADD1 : DR<—MADD2 : AC<—AC+DR

Page 10: 一个非常简单的 CPU 的设计

4.2 AND 指令AND 指令执行过程和 ADD 相似,需要以下操作:AND1 : DR<—MAND2 : AC<—AC^DR4.3 JMP 指令JMP 指令把 CPU 要跳转的指令地址送 PC ,执行以下操作 :JMP1 : PC<—DR[5 : 0]4.4INC 指令INC 指令执行 AC+1 操作 :INC1 : AC<—AC+1

Page 11: 一个非常简单的 CPU 的设计
Page 12: 一个非常简单的 CPU 的设计

5. 建立数据路径 这一步我们来实现状态图和相应的寄存器传输。首先看下面的状态及对应的寄存器传输:Fetch1 : AR<—PCFetch2 : DR<—M , PC<—PC+1Fetch3 : IR<—DR[7 : 6] , AR<—DR[5 : 0]ADD1 : DR<—MADD2 : AC<—AC+DRAND1 : DR<—MAND2 : AC<—AC^DRJMP1 : PC<—DR[5 : 0]INC1 : AC<—AC+1

Page 13: 一个非常简单的 CPU 的设计

为了设计数据路径,我们可以采用两种办法:1. 创造直接的两个要传输组件之间的直接路径2. 在 CPU 内部创造总线来传输不同组件之间的数据 首先我们回顾一下可能发生的数据传输,以便确定各个组件的功能。特别的我们要注意把数据载入组件的各个操作。首先我们按照他们改变了那个寄存器的数据来重组这些操作。得到如下的结果:

Page 14: 一个非常简单的 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 能够载入数据同时也能够自动加一操作。下一步我们把这些组件连接到总线上来,如图所示:

Page 15: 一个非常简单的 CPU 的设计
Page 16: 一个非常简单的 CPU 的设计

如上图所示,各个组件与总线之间通过三态连接,防止出现总线竞争。 AR 寄存器送出存储器的地址, DR 寄存器用于暂存存数起来的数据。到现在为止我们还没有讨论有关的控制信号,我们现在只是保证了所有的数据传输能够产生,我们将在后面章节来使这些数据传输正确的产生 --- 控制逻辑。

Page 17: 一个非常简单的 CPU 的设计

现在我们来看以下者写数据传输中有没有不必要的传输:1. AR 仅仅提供数据给存储器,所以他不需要连接到总线上。2. IR 不通过总线提供数据给任何组件,所以他可以直接输出到控制单元。3. AC 不提供数据到任何的组件,可以不连接到总线上。4. 总线是 8bit 宽度的,但是有些传输是 6bit 或者

2bit 的,我们必须制定寄存器的那几位送到总线的那几位。5. AC 要可以载入 AC 和 DR 的和或者逻辑与的值,数据路径中还需要进行运算的 ALU 。

Page 18: 一个非常简单的 CPU 的设计

由此我们做以下工作:1.去掉 AR , IR , AC 与总线的连接。2.我们约定寄存器连接是从总线的低位开始的。 AR , PC 连接到 Bus[5 :

0] ,由于 IR 是接受 DR[7 : 6] 的,所以可以连接到总线的 Bus[7 : 6] 。3.我们设定, AC 作为 ALU 的一个输入,另一个输入来自总线 Bus 。 下面我们检查是否有争用总线的情况,幸运的是这里没有。修改后的 CP

U 内部组织图如下:

Page 19: 一个非常简单的 CPU 的设计
Page 20: 一个非常简单的 CPU 的设计

6. ALU 设计• 这个 CPU 的 ALU 执行的功能就是两个操作数相加、逻辑与。这里不作详细介绍。电路如如下:

Page 21: 一个非常简单的 CPU 的设计

7. 控制单元 现在我们来考虑如何产生数据路径所需的控制信号,有两种方法:硬布线逻辑和微程序控制。这里我们用硬布线逻辑来实现。 这个简单的 CPU 需要的控制逻辑由三个部件组成:1. 计数器: 用于保存现在的状态2. 译码器: 生成各个状态的控制信号3. 其他的组合逻辑来产生控制信号一个通用的控制单元原理图如下:

Page 22: 一个非常简单的 CPU 的设计
Page 23: 一个非常简单的 CPU 的设计

对于这个 CPU 来说,一共有 9 个状态。所以需要一个 4bit 的计数器和一个 4-16 的译码器。接下来的工作就是按照前面的状态转换图来对状态进行赋值。 首先考虑如何的对译码输出状态进行赋值才能达到最佳状态。我们按照以下规则:1〉给 Fetch1赋计数器的 0 值,并用计数器的清零端来达到这个状态。由这个 CPU 的状态图可以看出,除了 Fetch1 状态外的其他状态都只能由一个状态转化而来, Fetch1 需要从 4 个分支而来,这 4 个分支就可以发出清零信号( CL

R )来转移到 Fetch1 。如图

Page 24: 一个非常简单的 CPU 的设计

2〉把连续的状态赋连续的计数器值,这样就可以用计数器的 INC 输入来达到状态的转移。3〉给每个例程的开始状态赋值时,要基于指令的操作码和这个例程的最大状态数。这样就可以用操作码来生成计数器的 LD 信号达到正确的状态转移。首先,在 Fetch3状态发出 LD 信号,然后要把正确的例程地址放到计数器的输入端。对这个 CPU 来说,我们考虑以地址 1 [IR] 0 作为计数器的预置输入。则得到状态编码如下:

Page 25: 一个非常简单的 CPU 的设计

• 这样就可以用操作码来生成计数器的 LD 信号达到正确的状态转移。首先,在Fetch3 状态发出 LD 信号,然后要把正确的例程地址放到计数器的输入端。对这个 CPU 来说,我们考虑以地址 1 [IR] 0 作为计数器的预置输入。则得到状态编码如下:

Page 26: 一个非常简单的 CPU 的设计

Instruction State IR counterFetch Fetch1 0000

Fetch2 0001

Fetch3 0010

ADD ADD1 00 1000ADD2 00 1001

AND AND1 01 1010AND2 01 1011

INC INC1 10 1100JMP JMP1 11 1110

Page 27: 一个非常简单的 CPU 的设计

如上表所示,下面我们需要设计产生计数器的 LD 、 INC 、CLR 等信号,总的控制单元的逻辑如下图:

Page 28: 一个非常简单的 CPU 的设计
Page 29: 一个非常简单的 CPU 的设计

• 下面我们用这些译码信号来产生数据路径控制所必需的 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

Page 30: 一个非常简单的 CPU 的设计

对于 ALU 的控制信号 ALUSEL 是用来控制 ALU 做逻辑或者算数运算的,所以有: ALUSEL=AND2 对于片内总线的控制较为复杂,我们先来看 DR ,对于 DR 他只在 Fetch

3 、 AND2 、 ADD2 和 JMP1 状态占用总线进行相信的数据传输,所以有: DRBUS=Fetch3 or AND2 or ADD2 or

JMP1

Page 31: 一个非常简单的 CPU 的设计

其他类似有:• MEMBUS=Fetch2 or ADD1 or AND1• PCBUS=Fetch1

最后,控制单元需要产生存储器的读信号( READ ),它发生在 Fetch2 、 ADD1 、 AND1 三个状态:

READ=Fetch2 or ADD1 or AND1 这样我们得到了总的控制逻辑,完成了整个 CPU 的设计。

Page 32: 一个非常简单的 CPU 的设计

8 设计验证我们执行如下指令进行设计验证,0 : ADD 41 : AND 52 : INC3 : JMP 04 : 27H5 : 39H 指令执行过程如下(初始化所有寄存器为全零态):

Page 33: 一个非常简单的 CPU 的设计

Instruction State Active Signals Operations Next State

ADD 4 Fetch1 PCBUS、 ARLOAD

AR<—0 Fetch2

Fetch2 READ、MEMBUS

DRLOAD、 PCINC

DR<—04HPC<—PC+1

Fetch3

Fetch3 DRBUS、 ARLOAD

IRLOAD

IR<—00AR<—04H

ADD1

ADD1 READ、MEMBUS

DRLOAD

DR<—27H ADD2

ADD2 DRBUS、 ACLOAD

AC<—0+27H Fetch1

Page 34: 一个非常简单的 CPU 的设计

AND 5 Fetch1Fetch2Fetch3ADD1ADD2

INC Fetch1Fetch2Fetch3INC1

JMP 0 Fetch1Fetch2Fetch3JMP1

Page 35: 一个非常简单的 CPU 的设计

1基本的微程序设计• 当我们设计一个 CPU 的控制单元的时候我们往往是先给出一个 CPU 的状态图,然后设计一个有限状态机。硬布线逻辑是根据 C

PU 的现态和输入(包括操作码和标志寄存器的内容)来进行状态转移,同时输出数据路径个组件的控制信号。• 1.1微序列操作• 一个微程序控制器也是一个有限状态机,一个通用的微程序控制器如下图:

Page 36: 一个非常简单的 CPU 的设计
Page 37: 一个非常简单的 CPU 的设计

说明:1. 图中寄存器用来存储 CPU 状态图中的一个状态,把它作为微代码存储器的地址访问微代码存储器。2. 微代码存储器输出微指令,可以分成两个部分:一个部分是微操作,这些信号被输出到 CPU 的其他部分用以产生 CPU 数据路径中的控制信号。另一部分被用来产生下一个访问微代码存储器的地址。这一部分加上操作码、标志寄存器以及 CPU 现在的状态(也就是 Register 中的内容)一起产生下一次访问微代码存储器的地址。

Page 38: 一个非常简单的 CPU 的设计

3. 下一个地址产生单元接受操作码、标志寄存器内容和微代码存储器的输出,然后根据现在 CPU 所处的状态决定产生下一次访问微代码存储器的地址。它生成所有可能的转移地址,然后选择正确的输出到寄存器中。 一个可能的地址就是微代码存储器现在地址加一。 另一个可能的地址是要跳转的绝对地址。

Page 39: 一个非常简单的 CPU 的设计

每个微程序控制其还需要能够正确地访问执行例程,这就需要用到影射逻辑。把取指得到的操作码影射到执行子例程的第一条微指令的地址上。这个影射操作时在每个取指周期结束时进行的。

Page 40: 一个非常简单的 CPU 的设计

像所有高级语言编程一样,微代码也可以有子程序。当几条指令执行同一段微代码时,这段微代码就可以用一个子程序来实现。当调用此子程序时,这个子程序的微代码地址就被作为一个跳转的绝对地址赋给寄存器,而当前地址加一的地址则被保存为返回地址。(需要硬件的寄存器或者堆栈来实现)

Page 41: 一个非常简单的 CPU 的设计

4. 一个微程序控制器最基本的四个部分就是: 现在地址加一 绝对地址 影射逻辑地址 子例程返回地址

1.2微指令格式每个微程序控制器可以有它自己的微指令格式。但是每条微指令必须包含以下几个部分的内容:

Page 42: 一个非常简单的 CPU 的设计

下面我们分别介绍这几个部分的内容:1. SELECT域 SELECT域用于指名下条指令地址的来源。它仅仅是指名下条指令地址的来源,而不直接给出下条指令的地址。例如:取指例程最后一条指令时,它的 SEL

ECT域会指名下一条地址将来自影射逻辑。 对于条件转移指令,执行子例程的执行需要根据标志为的判断来进行。对于这样的指令 SELECT域要有相应的标志寄存器的选择。然后根据所选择的标志寄存器以及 SELECT域的内容来决定下一地址的来源。2. ADDR域 ADDR域就是来指名下一条指令执行的绝对地址的。例如当执行完一个例程需要进入取指例程时,对指明了下一个地址来源的微指令来说, ADDR域是无用的。例如:影射逻辑地址。

Page 43: 一个非常简单的 CPU 的设计

3.MICOR-OPERATION域 MICRO-OPERATION域用来描述要执行的微操作,有三种描述方法:

3.1水平微代码 为了实现水平微代码,我们先列出 CPU 执行的所有微操作。然后我们给每个微操作赋 MICRO-OPERATION域中的 1bit 。这将导致MICRO-OPERATION域的位数很多。而且这种编码方法将使很多的 MICRO-OPERATION域中的位在大多数时间无用。

Page 44: 一个非常简单的 CPU 的设计

3.2垂直微代码 为了实现垂直微代码, CPU 可以执行的微操作被分组,然后每个微操作被赋予一个组合的二进制数,例如: 16 个微操作可以用 4bit 的 MICRO-OPERATION域来描述( 0000~1111 )。事实上我们用 4bit只能表示 15 个微操作,因为我们必须空出一个状态来描述空操作。垂直微代码的编码方式需要很少的 MICRO-OPERATION域的位数,但是它需要一个译码器来产生真正的微操作信号。

Page 45: 一个非常简单的 CPU 的设计

3.3 直接生成控制信号 在以上两种方法中, CPU都必须要把微操作信号转换成控制信号来进行数据路径的载入( LOAD )、清零( CLR )、加一( INC )、 ALU 控制以及总线上各个 Buffers 的开关等操作。第三种微代码的编码方法就是把控制信号直接存储到微指令中,这种方法不需要另外的组合逻辑,但是它可读性差,不宜于调试。

Page 46: 一个非常简单的 CPU 的设计

2 、设计和实现 A Very Simple CPU 的微程序控制单元• 为了验证一个微程序控制器的设计过程,我们首先来考虑前一章中的 Very Simple CPU 的控制单元的设计。本节将用微程序控制器重新设计其控制单元。我们将不在重新讲述指令集、有限状态机、数据路径以及 ALU 的设计。我们只讲述控制信号的产生过程。• 2.1基本流程• 这个 Very Simple CPU 的微程序控制器的基本框图如下:

Page 47: 一个非常简单的 CPU 的设计
Page 48: 一个非常简单的 CPU 的设计

在这个 Very Simple CPU 中只有两种可能的地址,一个是操作码影射地址另一个是绝对跳转地址。参看前面的 Very Simple CPU 的状态图,我们可以知道:1. 从 Fetch3 到执行子例程需要一个地址影射逻辑,影射到要执行指令的地址处。2. 地址加一可以用 Microde memory 产生 ADD

R 作为绝对地址跳转实现,每个执行子例程结束后还需要一个地址跳转回到取指 Fetch1微操作。 因为有两种地址输入,所以可以用一个 2选 1 逻辑 来实现下一地址生成模块。选择控制信号是由微代码存储器产生的。

Page 49: 一个非常简单的 CPU 的设计

• 接下来我们考虑用多少位来表示 Microde memory( 控制存储器 ) 输出的绝对地址?

• 这个 CPU 一共有 9 个状态,每个状态用一个微指令表示。需要的最少的数据位数是 4位。而 IR 译码后的影射逻辑地址也是 4bit ,所以用 4bit 来表示地址。

Page 50: 一个非常简单的 CPU 的设计

2.2 生成微程序并且设计影射逻辑 现在我们通过有限状态机的状态来设计微代码序列。首先我们给每个状态赋予一个微代码的地址。与硬布线逻辑不同的是,它不是必须直接的把连续的地址赋给取指或者执行的各个状态,然而那样赋值能够使微代码易于阅读调试。赋值中考虑的首要问题是:执行子例程的第一个状态的地址赋值,因为它决定了影射逻辑的实现。对这个 CPU 来说,我们用和硬布线逻辑实现时同样的影射逻辑,也就是 IR 译码的影射逻辑是 {1 , IR[1 : 0] , 0} 。这样产生了 ADD1 、 AND1 、 JMP1 、 INC1 的地址分别为 1000 、 1010 、 1100 、 1110 。相应的影射逻辑也就可以简单的如下表示:

Page 51: 一个非常简单的 CPU 的设计
Page 52: 一个非常简单的 CPU 的设计

其余状态的地址赋值如下表:State Address State Address

Fetch1 0000 Fetch2 0001

Fetch3 0010 ADD1 1000

ADD2 1001 AND1 1010

AND2 1011 JUMP1 1100

INC1 1110  

Page 53: 一个非常简单的 CPU 的设计

现在我们来通过这些状态来建立微代码序列。为了实现状态的转移,为序列控制器在 ADDR域提供其要转移状态的地址,并且在 SELECT域选择它。例如:为了从 Fetch1 转移到 Fetch2 状态,微程序控制器需要设定 SEL=0 (选择 ADDR 作为输入,而不是 IR影射逻辑),ADDR=0001 ( Fetch2 的地址) --- 也就是微代码存储器 0000 处 ADDR域的内容存储的是0001 这个地址。除了 Fetch3 状态外其他的状态都可以这样得到微代码存储器中 SEL 和 ADDR 的值(微操作 uOP 的值后面再讲)。 Fetch3 状态需要选择影射逻辑作为访问微代码存储器的地址。此时 ADDR 中的值将是无用的,所以可以不用考虑,而 SEL=1 。总的微代码存储器内容如下表(除去微操作 uOP )

Page 54: 一个非常简单的 CPU 的设计

State Address SEL ADDRFetch1 0000 0 0001Fetch2 0001 0 0010Fetch3 0010 1 XxxxADD1 1000 0 1001ADD2 1001 0 0000AND1 1010 0 1011AND2 1011 0 0000JMP1 1100 0 0000INC1 1110 0 0000

Page 55: 一个非常简单的 CPU 的设计

2.3 用水平编码方式设计微操作 首先我们注意到一个微程序控制器有两个任务:1. 生成正确的微操作2. 正确的流动状态 上面我们已经考虑了怎么样正确的进行状态的流动,下面我们的任务就是生成正确的微操作和相关的控制信号。 在水平编码的微代码方式中,每一个微操作用 1bit表示。首先我们列出 CPU 所有的微操作,然后用助记忆符来进行表示如下:

Page 56: 一个非常简单的 CPU 的设计

助记符 微操作ARPC AR<—PCARDR AR<—DR[5:0]PCIN PC<—PC+1PCDR PC<—DR[5:0]DRM DR<—MIRDR IR<—DR[7:6]PLUS AC<—AC+DRAND AC<—AC^DRACIN AC<—AC+1

Page 57: 一个非常简单的 CPU 的设计

这个 CPU 一共有 9 个微操作,每个微代码字需要 9bit 来表示它们。用 1表示执行这个微操作,用 0表示不执行这个微操作。我们把这些表示微操作的值填入到上面的微代码存储器的表格中就得到了最后的微代码存储器的内容,如下表:

Page 58: 一个非常简单的 CPU 的设计

State Address SEL ARPC

ARDR

PCIN

PCDR

DRM

IRDR

PLUS

AND

ACIN

ADDR

Fetch1 0000 0 1 0 0 0 0 0 0 0 0 0001

Fetch2 0001 0 0 0 1 0 1 0 0 0 0 0010

Fetch3 0010 1 0 1 0 0 0 1 0 0 0 Xxxx

ADD1 1000 0 0 0 0 0 1 0 0 0 0 1001

ADD2 1001 0 0 0 0 0 0 0 1 0 0 0000

AND1 1010 0 0 0 0 0 1 0 0 0 0 1011

AND2 1011 0 0 0 0 0 0 0 0 1 0 0000

JMP1 1100 0 0 0 0 1 0 0 0 0 0 0000

INC1 1110 0 0 0 0 0 0 0 0 0 1 0000

Page 59: 一个非常简单的 CPU 的设计

在生成控制信号之前,我们先来对微代码存储器中的微代码进行优化。注意到:对于所有的状态来说,ARDR 和 IRDR都与相同的值,所以我们可以用 1bit ( AIDR )来表示这两个微操作。得到最后的结果如下表

Page 60: 一个非常简单的 CPU 的设计

State Address

SEL ARPC

AIDR

PCIN

PCDR

DRM

PLUS

AND

ACIN

ADDR

Fetch1 0000 0 0 1 0 0 0 0 0 0 0001

Fetch2 0001 0 0 0 1 0 1 0 0 0 0010

Fetch3 0010 1 0 1 0 0 0 0 0 0 Xxxx

ADD1 1000 0 0 0 0 0 1 0 0 0 1001

ADD2 1001 0 0 0 0 0 0 1 0 0 0000

AND1 1010 0 0 0 0 0 1 0 0 0 1011

AND2 1011 0 0 0 0 0 0 0 1 0 0000

JMP1 1100 0 0 0 0 1 0 0 0 0 0000

INC1 1110 0 0 0 0 0 0 0 0 1 0000

Page 61: 一个非常简单的 CPU 的设计

最后,我们用这些微操作信号来生成数据路径中相应的控制信号。例如,对于寄存器 AR 来说, ARLOAD 信号必须在 ARPC 和 AIDR 两个微操作有效时有效。于是就把这两个微操作进行 OR 操作产生 ARLOAD信号。其他的控制信号同理可得,最后的控制信号如下表:

Page 62: 一个非常简单的 CPU 的设计

Signal ValueARLOAD ARPC or AIDRPCLOAD PCDRPCINC PCINDRLOAD DRMACLOAD PLUS or ANDACINC ACINIRLOAD AIDRALUSEL ANDMEMBUS DRMPCBUS ARPCDRBUS AIDR or PCDR or PLUS or ANDREAD DRM

Page 63: 一个非常简单的 CPU 的设计

2.4 用垂直编码方法产生微操作码

由于水平编码方式代码利用率太低,所以考虑用垂直编码方式。垂直编码方式的微代码存储器输出的并不是直接的微操作的控制信号需要进行译码,其原理如下图:

Page 64: 一个非常简单的 CPU 的设计
Page 65: 一个非常简单的 CPU 的设计

现在我们来用垂直编码的方法来设计这个 Very Simple CPU 的控制单元。我们还是从指令集、状态图、数据路径和 ALU 等开始分析。数据路径和硬布线逻辑相同,微程序代码控制器的影射逻辑、以及微代码存储器中的 SEL 和 ADDR 的内容与水平编码的设计也相同。我们现在的任务就是给微操作分配不同的微操作码。我们按照以下规则进行:

Page 66: 一个非常简单的 CPU 的设计

1.当两个微操作在同各状态发生时,把它们分在不同的域。也就是要求每个域在一个状态只能够输出一个值。2. 如果需要的话每个域中都可以包含 N

OP 操作。当此域中没有操作要执行时输出空操作。3. 把其余的微操作分布到各个域中,尽可能的充分利用每个域能表示的状态。各个域的字长可以不同。4. 把在同一个域中修改同一个寄存器的微操作组成一组。因为两个微操作不能同时修改同一个寄存器。

Page 67: 一个非常简单的 CPU 的设计

首先我们检查同时进行的微操作有哪些,注意到 DRM 和 PCIN都在 Fetch2 发生,所以必须被分到两个不同的域中。所以这个 CPU至少需要两个域M1 和 M2 。在每个域中加上 NOP 操作得到: M1 M2 NOP NOP DRM PCIN

Page 68: 一个非常简单的 CPU 的设计

由于 PCIN 和 PCDR都修改 PC ,我们把 PCDR 加到 M2 中。接下来我们把修改同一个寄存器的操作放到同一个域中得到一个状态分配方案如下:M1 M2NOP NOPDRM PCINACIN PCDRPLUS ARPCAND AIDR

Page 69: 一个非常简单的 CPU 的设计

每个域中有 5 个微操作,所以每个域都需要 3bit 来表示。总共需要 6bit 来表示。我们对之进行优化,可以把 AIDR 从 M2移动到 M1 中,这样 M1 可以用 3bit表示 M2 只需要 2bit表示了。我们还可以进一步的优化把 ARPC 和PCDR 也从 M2移动到 M1 中,这样 M1 有 8 个状态, M2 有 2 个状态。所以一共可以用 4bit 来表示。最后结果如下表:

Page 70: 一个非常简单的 CPU 的设计

M1 M2

Value Micro-operation Value Micro-operation

000 NOP 0 NOP

001 DRM 1 PCIN

010 ARPC  

011 AIDR  

100 PCDR  

101 PLUS  

110 AND  

111 ACIN  

Page 71: 一个非常简单的 CPU 的设计

• 接下来我们用这些数值来生成最终的微代码存储器的内容,结果如下表:

Page 72: 一个非常简单的 CPU 的设计

State Address SEL M1 M2 ADDR

Fetch1 0000 0 0 010 0001

Fetch2 0001 0 0 001 0010

Fetch3 0010 1 1 011 Xxxx

ADD1 1000 0 0 001 1001

ADD2 1001 0 0 101 0000

AND1 1010 0 0 001 1011

AND2 1011 0 0 110 0000

JMP1 1100 0 0 100 0000

INC1 1110 0 0 111 0000

Page 73: 一个非常简单的 CPU 的设计

注意到 M1 中的 NOP 操作从来没有用到,我们可以把 M1 中的空操作去掉。 接下来我们要把 M1 和 M2 的输出进行译码得到相应的微操作信号,对

M1 用一个 3-8 译码器就可以,对 M2来说直接接到 PCIN 上即可。 最后再经过和水平编码方式相同的控制信号产生逻辑就可以的到整个微程序控制器的设计。

Page 74: 一个非常简单的 CPU 的设计

2.5 直接生成控制信号编码 这种方法微代码存储器不是生成微操作信号而是直接产生数据路径中的控制信号。设计中不同的部分就是微代码存储器中的微操作信号不同,而且省去了微代码存储器输出之后的译码逻辑而是直接输出数据路径所需要的控制信号。 例如看 Fetch2 中的控制信号, Fetch2 执行的微操作是: DR<—M , PC<—PC+1 我们需要的控制信号有: READ , MEMBUS , DR

LOADPCINC 同时所有其他的信号必须置 0 以保持没有总线争用。对每个微指令进行这样的分析最后得到下表:

Page 75: 一个非常简单的 CPU 的设计

State Address

SEL

ARLOAD

PCLOAD

PCINC

DRLOAD

ACLOAD

ACINC

IRLOAD

ALUSEL

MEMBUS

PCBUS

DRBUS

READ ADDR

Fetch1 0000 0 1 0 0 0 0 0 0 0 0 1 0 0 0001

Fetch2 0001 0 0 0 1 1 0 0 0 0 1 0 0 1 0010

Fetch3 0010 1 1 0 0 0 0 0 1 0 0 0 1 0 Xxxx

ADD1 1000 0 0 0 0 1 0 0 0 0 1 0 0 1 1001

ADD2 1001 0 0 0 0 0 1 0 0 0 0 0 1 0 0000

AND1 1010 0 0 0 0 1 0 0 0 0 1 0 0 1 1011

AND2 1011 0 0 0 0 0 1 0 0 1 0 0 1 0 0000

JMP1 1100 0 0 1 0 0 0 0 0 0 0 0 1 0 0000

INC1 1110 0 0 0 0 0 0 1 0 0 0 0 0 0 0000

Page 76: 一个非常简单的 CPU 的设计

我们注意到 DRLOAD 、 MEMBUS和 READ 总是有相同的值,所以可以用能够一个状态位来表示( DMR ),最后的倒微代码存储器的内容如下:

Page 77: 一个非常简单的 CPU 的设计

State Address SEL

ARLOAD

PCLOAD

PCINC

DMR

ACLOAD

ACINC

IRLOAD

ALUSEL

PCBUS

DRBUS

ADDR

Fetch1 0000 0 1 0 0 0 0 0 0 0 1 0 0001

Fetch2 0001 0 0 0 1 1 0 0 0 0 0 0 0010

Fetch3 0010 1 1 0 0 0 0 0 1 0 0 1 Xxxx

ADD1 1000 0 0 0 0 1 0 0 0 0 0 0 1001

ADD2 1001 0 0 0 0 0 1 0 0 0 0 1 0000

AND1 1010 0 0 0 0 1 0 0 0 0 0 0 1011

AND2 1011 0 0 0 0 0 1 0 0 1 0 1 0000

JMP1 1100 0 0 1 0 0 0 0 0 0 0 1 0000

INC1 1110 0 0 0 0 0 0 1 0 0 0 0 0000