《计算机系统:系统架构与操作系统的高度集成》——3.5 控制单元设计-阿里云开发者社区

开发者社区> 华章出版社> 正文
登录阅读全文

《计算机系统:系统架构与操作系统的高度集成》——3.5 控制单元设计

简介:

本节书摘来自华章计算机《计算机系统:系统架构与操作系统的高度集成》一书中的第3章,第3.5节,作者:(美)拉姆阿堪德兰(Ramachandran, U.)(美)莱希(Leahy, W. D.)著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.5 控制单元设计

如图3-16所示。管弦乐队指挥的作用是告诉乐队什么时候谁需要演奏或演唱。乐队成员自己知道自己要演奏什么,所以指挥不需要管理演奏内容,只需要保持节奏和次序就可以了。如果说数据通路是乐队,那么控制单元就是指挥。控制单元为数据通路中的元件完成自己的工作提供一些提示。例如,如果DrALU线被断言(即,如果线上值为1),那么相应的驱动器门就会将ALU的输出放到总线上。
image

图3-16  一个管弦乐队的布置。指挥的作用近似于处理器中的控制单元。她为乐队中的每个成员给出“时间提示”
检查数据通路后,我们给出控制单元所需要的控制信号:
驱动信号:DrPC、DrALU、DrREG、DrMEM、DrOFF。
加载信号:LdPC、LdA、LdB、LdMAR、LdIR、LdZ。
写内存信号:WrMEM。
写寄存器信号:WrREG。
ALU功能选择器:func。
寄存器选择:regno。
如何产生这些控制信号有许多可能的实现,所有的实现都是对于处理器控制单元的FSM的硬件实现。
3.5.1 ROM加状态寄存器
我们来看一个非常简单的设计。首先,我们需要知道处理器处于什么状态。前面我们介绍了控制单元的FSM,它包含FETCH(取指)、DECODE(译码)和EXECUTE(执行)状态。这是FSM抽象中处理器宏的状态。在真实实现中,根据数据通路的功能,需要许多微状态来表示宏状态的细节。例如,我们假设需要3个微状态来实现FETCH宏状态。我们将这些为微状态进行编码:
image

现在我们引入状态寄存器,它的内容就是这些微状态的编码。所以,在任何情况下,这个寄存器的值都表示处理器的状态。
状态寄存器的引入让我们又从FSM抽象向硬件实现接近了一步。下面,为了在每个微状态下控制数据通路的各个元件,我们需要产生之前列出的控制信号。下面我们来讨论如何才能产生这些控制信号。
一种最简单的方法是,用状态寄存器作为表的索引。表中的每一项都包含该状态所需要的全部控制信号。用前面的乐队做比喻,指挥面前有整个音乐的乐谱。在演奏曲子时,指挥指导管弦乐队的演奏。指挥能从乐谱的每一行中看出,谁应该在哪一个时间点演奏哪一个音符。同理,我们能从控制单元表的表项看出,数据通路的元件在这个状态下应该做什么。每个演奏者都知道自己需要演奏什么。同样,每个数据通路元件也知道自己的功能。两者的相同之处是,他们都需要别人(别的东西)告诉他们现在该做什么。所以,指挥者和控制单元有着极其类似的工作,他们在时间上为演奏者和数据通路提供了必要的线索(解决了“什么时候”的问题),使其能够在正确的时间做相应的事情。这似乎很简单,所以表中的每个控制信号用1位表示。如果该位为1,则表示产生该控制信号;为0,则不产生。当然,func和regno字段的位数与它们在数据通路中的宽度有关(见图3-15,分别为2位和4位)。图3-17给出了控制信号表中的表项。
image

图3-17 控制信号表的表项
控制单元需要从一个状态转移到另一个状态。例如,FETCH宏状态需要3个微状态,那么就会存在下面的情况:
image

如果将下一个状态也写在表中,那么状态转移就变得相对简单。现在来看看图3-18中的表。
image

让我们来研究如在硬件上实现这个表。
这个表其实就是存储元件。这种存储元件的特性是,一旦我们决定了某个状态所需要的控制信号,该表项的内容就被冻结。我们称这种存储器为只读存储器,或ROM。
所以,控制单元的硬件实现看起来就像图3-19那样。在每过一个时钟周期上,状态寄存器就转移到使用当前时钟周期内ROM表项输出指定的下一个状态。这是驱动数据通路中所有边沿触发存储元件的同一个时钟(见图3-15)。从ROM发出的所有加载信号(LdPC、LdMAR等)充当时钟信号的掩码,决定它们控制的存储元件是否在该时钟周期内被驱动。
下一件要做的事情就是将数据通路和控制单元结合起来。只要简单地将数据通路(见图3-15)的相应命名的实体与对应的ROM输出连接起来。

image

图3-19  控制单元,使用状态寄存器和ROM。ROM的每一行都包含了当前时钟周期内需要产生供数据通路使用的控制信号(即“状态”)
控制单元的工作方式如下:
1)状态寄存器给出了本时钟周期内处理器的状态。
2)通过状态寄存器的值对ROM进行索引访问。
3)ROM的输出就是当前传送给数据通路的控制信号集合。
4)在本时钟周期内数据通路执行控制信号指定的功能。
5)将ROM给出的下一状态传送给状态寄存器的输入,使之在下一个时钟周期开始时能够转移到下一个状态。
每个时钟周期都重复上述5个步骤。
图3-13将处理器的控制单元描述为一个FSM。为了方便起见,我们再将它画在图3-20中。现在我们来检查图3-20中的每个宏状态需要发生什么,还有控制单元如何实现它们。对于每个微状态,我们在旁边标出了数据通路的操作。

image

3.5.2 FETCH宏状态
FETCH宏状态从程序计数器(PC)所指出的内存中取出一条指令到指令寄存器(IR)中,为了读取下一条指令,还会将PC递增。
现在我们列出实现FETCH宏状态需要做什么:
将PC发送给内存。
读出内存的内容。
将内存的内容发送到IR中。
递增PC。
很明显,如果使用单总线数据通路,那么这些步骤无法在一个时钟周期内完成。

image

稍加思索,我们就能在少于4个时钟周期内完成FETCH宏状态的工作。观察在ifetch1和ifetch3中发生了什么。PC的内容传递给了寄存器MAR和A。这两个状态可以合并为一个状态,因为一旦PC的值输出到总线上,在一个周期内这两个寄存器都可以取得这个值。所以,我们可以将上面的序列简化为:
image

既然我们已经知道实现FETCH宏状态需要数据通路在每个微状态时做些什么,那么可以给出每个微状态需要的控制信号。对于每个微状态,我们将用到的数据通路元件和控制线高亮表示。
image

下图显示了ifetch1微状态的数据通路活动。

image

下图显示ifetch2微状态的数据通路活动。
image

注意:根据数据通路的设计,对内存的默认操作为读操作(即WrMEM为0)。而且,内存隐式地读出了MAR指定地址的内存内容并在ifetch2中的Dout上给出了结果。
image

下图显示了ifetch3微状态的数据通路活动。
image

注意:如果func选择的信号为11,那么ALU执行的操作是A+1(见图3-15)。
现在我们可以给出与微状态ifetch1、ifetch2、ifetch3对应的ROM的内容(见图3-21,X表示无所谓)。ifetch3的下一状态字段临时标记为TBD(To Be Determined,未决定),很快我们会讨论这个字段。
这开始看起来像一个程序了,虽然它比我们第一节编程课上讲的程序要低层得多。每个ROM单元都包含驱动数据通路不同元件工作的命令集合。我们将每个表项称为一条微指令,并将ROM的整个内容称为一个微程序。每条微指令还包含下一条要执行的微指令的地址。现在,控制单元的设计变成了一个编程练习。它是一个最后的并发程序,因为我们在每条微指令中都利用了硬件的并行性。

image

注意每条微指令都是有结构的。例如,所有的驱动信号可以分成一组。类似地,所有加载信号也可以分成一组。这样的设计是为了节约表的空间需求。例如,可以将某些控制信号结合到一个编码字段中。因为我们知道任意时刻在总线上只有一个实体能够被驱动,所以我们可以将所有的驱动信号集成为3位宽的字段,这个字段的每个编码都唯一指定了总线上的一个应该被驱动的实体。这种方法在减少空间占用的同时,需要一个额外的解码环节,这会增加生成控制信号的延迟。我们无法将所有加载信号都集成在一起,因为可能会有多个存储元件在同一时钟周期内工作。
3.5.3 DECODE宏状态
一旦将指令取出,就准备好进行解码了。所以,我们需要从ifetch3微状态转移到DECODE宏状态。
在这个宏状态中,我们检查IR的内容(位28~31)以识别这是什么指令。知道是什么指令后,就需要找到实现这个指令的微程序。所有我们可以认为DECODE(解码)过程是基于指令OPCODE(操作码)的多路分支。为了更好地描述解码的多路分支特性,我们将控制单元的FSM重绘如下(见图3-22)。多路分支的每一路都将FSM引向某一条指令的具体执行,为了简单起见,我们只画出FSM转移到不同类型的指令。

image

很快我们将回到如何在控制单元中实现多路分支的问题。现在我们先讨论每种指令的一些简单实现。
3.5.4 EXECUTE宏状态:ADD指令(R型指令部分)
R型指令具有下面的格式:
image

ADD指令执行下面操作:
image

为了实现这个指令,我们需要从寄存器堆中读取两个寄存器并将结果写入第三个寄存器。需要读取的寄存器指定为指令的一部分,且保存在IR中,在数据通路中是可用的。然而,从数据通路中可以看到,从IR到寄存器堆之间没有通路。这个“疏忽”是有原因的。根据我们要读或写的寄存器,我们需要将IR中的不同部分作为寄存器堆的regno输入。正如我们所见,多路复用器是完成这类选择的逻辑元件。
所以,我们需要将这个元件加入图3-23的数据通路中。
image

图3-23  使用IR位字段对寄存器进行选择。多路复用器在IR中选择需要发送给寄存器堆regno地址的专用字段
RegSel控制输入(2位)来自于微指令。多路复用器的输入是IR中指明寄存器的3个字段(见第2章中LC-2200指令格式)。微指令从不直接对寄存器堆寻址。所以,我们在微指令中用2位RegSel字段来代替4位regno字段(见图3-24)。
image

现在我们写出实现ADD操作宏状态的微状态的数据通路活动和相应的控制信号。
image

下图显示了add1微状态的数据通路活动。

image

注意:寄存器堆的默认操作是将regno指定地址的寄存器的内容读出到Dout上。
image

下图显示了add2微状态的数据通路活动。
image

下图显示了add3微状态的数据通路活动。
ADD宏状态由控制单元通过将add1、add2、add3微状态串联起来实现,最终返回到FETCH宏状态(见图3-25)。

image

3.5.5 EXECUTE宏状态:NAND指令(R型指令部分)
NAND指令执行如下操作:
image

NAND宏状态与ADD宏状态的相似之处是,有nand1、nand2、nand3三个微状态。与ADD相比,NAND的三个微状态有哪些不同?我们将它作为练习留给读者。
3.5.6 EXECUTE宏状态:JALR指令(J型指令部分)
J型指令具有如下的格式:
image

将JALR指令引入LC-2200指令集中用于支持高级语言的过程调用机制。JALR将返回地址保存在寄存器中并将控制权交给子过程:
image

下面是JALR指令的微状态、数据通路活动和控制信号:

image

下图显示了jalr1微状态的数据通路活动。
image

注意:PC+1需要被保存到Ry中。我们在FETCH宏状态中已经递增了PC。
image

下图显示了jalr2微状态的数据通路活动。
image

3.5.7 EXECUTE宏状态:LW指令(I型指令部分)
I型指令有如下格式:
image

LW指令的语义是:
image

在I型指令中,带符号地址偏移量由指令的一部分作为立即值字段给出。立即值字段占据IR的0~19位。从数据通路中可以看出,有一个符号扩展硬件将这20位补码值转换为32位补码。DrOFF控制线使得IR中的经过符号扩展后的偏移地址可以被放到总线上。
下面是LW指令的微状态、数据通路活动和控制信号:
image

下图显示了lw1微状态的数据通路活动。
image

下图显示了lw2微状态的数据通路活动。
image
image

下图显示了lw3微状态的数据通路活动。
image

下图显示了lw4微状态的数据通路活动。
image

例3-4 我们现在要给LC-2200增加一种新的寻址模式,称为自动递增模式。该 模式对于LW/SW指令来说是有用的。采用此模式的LW指令语义为:
image

指令格式如下:
image

写出使用该寻址模式实现的LW指令的序列。(你需要写出该指令的EXECUTE宏状态的序列。)对于每个微状态,给出数据通路活动(寄存器传输形式为A←Ry),并在标出使能数据通路所需的控制信号(例如,DrPC)。
答:
image

3.5.8 EXECUTE宏状态:SW和ADDI指令(I型指令部分)
SW宏状态的实现与LW宏状态类似。ADDI宏状态的实现与ADD宏状态类似,唯一的区别是第二个操作数来自IR中的立即值而不是另一个寄存器。这两个宏状态的实现就留给读者作为练习。
3.5.9 EXECUTE宏状态:BEQ指令(I型指令部分)
BEQ指令有如下语义:
if (Rx == Ry) then PC ← PC + 1 + 符号地址偏移量
else 什么都不做
这条指令需要一些特殊处理。该指令的语义是,比较两个寄存器(Rx和Ry)中的内容,如果它们相等,则跳转到目的地址,而目的地址是符号扩展偏移量与PC+1的和(PC是这条BEQ指令的地址)。
数据通路中,有硬件用于检测总线上的值是否为零。BEQ的微状态使用这个逻辑根据两个寄存器的比较结果来设置Z寄存器的值。
下面是BEQ宏状态对应的微状态、数据通路活动以及控制信号:
image

下图显示了beq1微状态的数据通路活动。

image
image

下图显示了beq2微状态下的数据通路活动。
image

下图显示了beq3微状态下的数据通路活动。
image

注意:数据通路中的零检测逻辑元件一直在检测总线上的值是否为零。通过断言LdZ,Z寄存器(1位寄存器)捕获检测结果以备以后使用。
与其他指令的微状态相比,这个微状态的操作更具技巧性。对于其他指令,我们就是简单地按顺序走一遍各个微状态最后返回到FETCH宏状态。然而,BEQ指令根据比较的结果引起控制流转移。如果Z寄存器为0(即Rx!=Ry),那么我们就简单地返回到ifetch1并继续顺序执行下一条指令(PC已经指向了该条指令)。另一方面,如果Z寄存器为1,继续用BEQ微状态计算分支的目标地址。
首先让我们假设分支发生以完成BEQ的各微状态。
image

下图显示了beq4微状态下的数据通路活动。
image

下图显示了beq5微状态下的数据通路活动。
image

下图显示了beq6微状态下的数据通路活动。
image

注意:在FETCH宏状态中,PC已经递增了,所以这里我们可以将PC与符号扩展偏移量相加来计算目标地址。
3.5.10 设计微程序中的条件分支
图3-26展示了BEQ宏状态的状态转移。beq3微指令的下一状态(next-state)字段将包含beq4。但是微指令中只有一个下一状态字段,我们需要让beq3根据Z寄存器的状态转移到ifetch1或者beq4。一种时间上高效的办法是,在ROM上的其他单元复制一份与ifetch1有关的微指令。下面我们将解释这是如何做到的。
image

图3-26  BEQ宏状态的状态转移。我们可能会转移到ifetch1或beq4,这依赖于beq3中计算的结果,这个结果在beq3结束前被Z寄存器捕获
我们假设状态寄存器有5位,beq4的二进制编码为010000,beq3微指令的下一状态字段设置为beq4。我们将Z寄存器的内容作为前缀,得到6位的ROM地址。如果Z为0,则ROM地址为001000;如果Z为1,则地址为101000。后一个地址(101000)是我们要存储与beq4微状态有关的微指令的地方。而001000(称为ifetch-clone)则会保存与原始ifetch1一样的微指令。图3-27显示了这个设计。
image

图3-27 设计条件微分支。使用5位基地址(01000)并采用Z寄存器的输出作为地址前缀
我们还可以将这个想法(复制微指令)推广到任意需要在微程序中进行条件分支的情况。
3.5.11 再谈DECODE宏状态
我们回到DECODE宏状态。这是一个从ifetch3到IR指定的宏状态的一个多路分支。我们使用的技巧与之前根据Z寄存器内容为BEQ实现2路分支时的一样。
我们假设10000是通用的EXECUTE宏状态编码。
Ifetch3的下一状态字段包含这个通用值。我们用OPCODE的内容(IR的位28~31)作为通用值的前缀来产生9位的ROM地址。因此,ADD宏状态将从ROM地址000010000开始,NAND宏状态将从地址000110000开始,ADDI则从001010000开始,等等。如图3-28所示。
image

图3-28  为DECODE宏状态产生多路分支。使用5位基地址(10000),用IR中的OPCODE(4位)作为前缀
将所有这些集合到一起,我们发现处理器的控制逻辑具有10位地址:
最高4位是IR的28~31位。
下一位是Z寄存器的输出。
最低5位来自5位状态寄存器。
最高4位(来自IR的28~31位)应当为0,除非我们想在FETCH宏状态的末尾(即ifetch3微状态)进行多路选择。类似地,下一位(来自Z寄存器的输出)应该为0,除了在beq3微状态下需要做2路分支。为了确保能正确地按照我们的选择修改ROM地址的高5位,我们在ROM的每个表项中添加额外的两个1位字段,称为M和T。(见图3-29。)这些字段分别控制在这个时钟周期中是否要用来自IR的4位和来自Z寄存器的1位修改ROM地址。如何使用图3-30给出的修改控制电路来完成控制单元设计作为练习留给读者(见练习17)。
image

图3-29  ROM表项的最终设置。我们给ROM中的每一项添加了M和T“下一状态和修改者”位
图3-30中控制单元的输入/输出信号直接与图3-15中的对应信号相连。
image

图3-30  LC-2200控制单元。这展示了完整的ROM寻址机制,以及所有需要产生并发送给数据通路的控制信号

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享: