《简单RISC处理器设计解析13441.pdf》由会员分享,可在线阅读,更多相关《简单RISC处理器设计解析13441.pdf(43页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、 简单 RISC 处理器设计 6.3 简单 RISC 处理器设计 前面我们已经学习了现代电子系统设计的基本方法,学习了使用 Verilog HDL 语言设计简单组合逻辑和简单时序逻辑模块,学习了自顶向下的设计方法,同时还学习了状态机的设计。在这里,将综合运用以上所学的知识,设计一个简化的处理器。“麻雀虽小,五脏俱全”,这里设计的处理器虽然是经过简化的,但是能对其进行综合、适配,最终可以在硬件上运行。这里介绍的处理器由于主要用于教学,只是一个简单的教学模型,设计不一定合理,只是从原理上说明了一个简单的处理器是如何构成的。6.3.1 RISC 处理器简介 中央处理器(CPU,Central Pro
2、cessing Unit)是计算机的核心部件。计算机进行信息处理可分为两个步骤:(1)将数据和程序(即指令序列)输入到计算机的存储器中;(2)从第一条指令的地址起开始执行该程序,得到所需结果,结束运行。CPU 的作用是协调并控制计算机的各个部件并执行程序的指令序列,使其有条不紊地进行。因此它必须具有以下基本功能:取指令当程序已在存储器中时,首先根据程序入口地址取出一条程序,为此要发出指令地址和控制信号。分析指令即指令译码,这是对当前取得的指令进行分析,指出它要求什么操作,并产生相应的操作控制命令。执行指令根据分析指令时产生的“操作命令”形成相应的操作控制信号序列,通过运算器、存储器及输入/输出
3、设备的执行,实现每条指令的功能,其中包括对运算结果的处理及下条指令地址的形成。将 CPU 的功能进一步细化,可概括如下:(1)能对指令进行译码并执行规定的动作;(2)可以进行算术和逻辑运算;(3)能与存储器和外设交换数据;(4)提供整个系统所需要的控制。尽管各种 CPU 的性能指标和结构细节各不相同,但它们所能完成的基本功能相同。由功能分析可知,任何一种 CPU 内部结构至少应包含下面这些部件:(1)算术逻辑运算部件(ALU);(2)累加器或寄存器;(3)程序计数器;(4)指令寄存器和译码器;(5)时序和控制部件。精简指令计算机(RISC,Reduced Instruction Set Com
4、puter)是一种 20世纪 80 年代才出现的 CPU,它与一般 CPU 相比不仅只是简化了指令系统,而且还通过简化指令系统使计算机的结构更加简单合理,从而提高了运算速度。从实现的途径看,RISC 处理器与一般的 CPU 的不同之处在于:它的时序控制信号形成部件是用硬布线逻辑实现的而不是采用微程序控制的方式。所谓硬布线逻辑也就是用触发器和逻辑门直接连线所构成的状态机和相应的组合逻辑,故产生控制序列的速度比用微程序控制方式快得多,因为这样做省去了读取微程序指令的时间。下面就详细介绍一个简化的、用于教学目的的 RISC 处理器 SimpleRISC,它是采用硬布线逻辑实现的控制,是一个可综合的C
5、PU 模型。6.3.2 SimpleRISC 处理器结构介绍 一、处理器结构 这里首先对我们即将要进行设计的 SimpleRISC 处理器硬件结构作一个简要介绍。这里所介绍的处理器结构只是 SimpleRISC 芯片的内部结构,或者说只是SimpleRISC 的 CPU 核,所以不包括存储器单元和外设等。SimpleRISC 处理器的内核结构如图 6-48 所示。图 6-48 SimpleRISC 处理器内核结构 从图 6-48 中可以看出,SimpleRISC 处理器内核包括以下功能单元:控制器、程序计数器、通用寄存器、算术逻辑单元(ALU,Arithmetic Logic Unit)和总线
6、接口单元(BIU,Bus Interface Unit)。以下的内容将依次讨论这些模块。二、处理器内部子模块 1、控制器 控制器用于进行指令译码、产生 ALU 运算控制信号、产生通用寄存器读写控制信号以及协调处理器工作时序工作。2、程序计数器 程序计数器用于指向下一条将要执行的指令的地址,它可以自动增值或是通过分支指令来设置其内容。3、通用寄存器 SimpleRISC 处理器内部有 32 个 32 位通用寄存器,ALU 运算的源操作数、目的操作数大都来自这个通用寄存器堆。4、算术逻辑单元 算术逻辑单元用于进行算术运算、移位操作、比较设置操作以及逻辑运算。对于其他未能实现的运算,例如乘法、浮点运
7、算等,可以使用软件来实现。5、总线接口单元 总线接口单元用于 SimpleRISC 处理器与外部存储器和 I/O 口的连接,为了简单起见,SimpleRISC 系统的存储器和 I/O 采用统一编址的方式进行组织,并且采用程序存储器和数据存储器分开的哈佛结构。从图 6-48 可以看出,SimpleRISC 处理器并没有实现中断处理以及 Cache 等功能,虽然如此,但是 SimpleRISC 处理器已经能进行一些简单的工作了。下面将继续讨论有关 SimpleRISC 的一些细节。6.3.3 SimpleRISC 处理器的指令集和寻址方式 一、SimpleRISC 处理器的指令集 SimpleRI
8、SC 处理器的指令集中包括以下指令:(1)算术运算指令 算术运算指令包括加法(add)和减法(sub)指令。(2)比较指令 比较指令只有小于则设置(slt)指令。(3)移位指令 移位指令包括左移(ls)和右移(rs)指令。(4)逻辑运算指令 逻辑运算指令包括与(and)、或(or)和非(not)指令。这里的逻辑运算都是按位进行的。(5)数据存储器访问指令 数据存储器访问指令包括存储器数据加载(load)和数据存储(store)两条指令。数据存储器的访问都必须通过这两条指令来进行。(6)分支指令 分支指令分为无条件分支和条件分支两类。无条件分支指令只有一条:branch;而条件分支只实现相等则分
9、支(beq)指令。二、SimpleRISC 处理器的寻址方式 CPU的寻址方式指的是CPU在进行操作时如何找到操作数的方法。一般来说,操作数可以存储在 CPU 内部寄存器中,也可以由指令提供,还可以存储在数据存储器中。对于 RISC 处理器来说,操作数一般都由指令提供或存储在 CPU 内部寄存器中,而 RISC 处理器一般不直接使用数据存储器中的数据作为操作数。这里的 SimpleRISC 处理器,其操作数也由指令提供或存储在 CPU 内部寄存器中,相应的寻址方式为立即寻址(操作数由指令提供)和寄存器寻址(操作数存储在 CPU 内部寄存器中)。6.3.4 SimpleRISC 处理器的指令格式
10、与编码 一、指令格式 这里假设设计的SimpleRISC处理器是32位的,由于它有32个 32位寄存器,所以每个寄存器需要使用 5 位编码来寻址。将以上讨论的指令分为三种类型的指令:R类型指令、I类型指令和 J类型指令。R类型指令指的是操作数全部来自通用寄存器,包括寄存器操作数的算术运算指令、比较指令和逻辑运算指令。由于这些指令的操作数都来自于通用寄存器,而一般的操作都有三个操作数:两个源操作数和一个目的操作数,所以 R类型指令中需要使用 5315 位来对寄存器进行编址,对于 32 位指令,使用了15 位以后,还剩余 17 位,其余的 17 位都可用于指令的编码,所以一共可以有21713107
11、2 条 R类型的指令。I类型指令指的是操作数中有部分来自于通用寄存器,而另一部分是来自于指令本身的立即数,包括带有立即数的算术运算指令、比较指令、逻辑运算指令、移位指令、数据存储器访问指令和条件分支指令。除移位指令外,立即数都是 16 位的,而另外还需要两个寄存器操作数,所以共需要 165226 位编码,还剩余 6 位编码,所以可以有 2664 条 I类型的指令。对于移位指令,由于操作数是 32 位的,所以移位位数最多为 32 位,则只需要 5 位立即数即可,因此共需要 55215 位编码,剩余 17 位可用于指令编码。J类型指令只有一条:无条件分支指令 Branch,它采用 6 位指令编码(
12、为了与 I类型指令格式对齐),剩余的 26 位用于指明分支的目的地址到当前程序计数器的偏移量。假设采用补码表示法,则最大偏移量在225(225-1)之间,即0 x020000000 x01FFFFFF 之间。而前面讨论的条件分支使用 16 位偏移量,所以最大偏移量在215(215-1)之间,即0 x000080000 x00007FFF 之间。通过以上讨论,可以定义出以下指令格式。对于 R类型指令,指令中包括三个 5 位的通用寄存器地址域和一个 17 位的指令编码域,为了与 I类型及 J类型指令保持格式一致,将指令编码域分成了 11 位和 6 位两个部分,参见图 6-49。图 6-49 R类型
13、指令格式 图中的 A、B、C 为通用寄存器地址,OPX 位 11 位指令编码,OP 位 6 位指令编码。对于 I类型指令,指令中包括四个域:两个5 位的通用寄存器地址、6 位指令编码和 16 位地址偏移量,可以表示为图 6-50 所示的格式。图 6-50 I类型指令格式 图中的 A、B 为通用寄存器地址,IMM16 为 16 位立即数(对于移位指令,只用最低 5 位),OP 为指令编码。对于 J类型指令,指令中包括两个域:6 位指令编码和 26 位地址偏移量,可以表示为图 6-51 所示的格式。图 6-51 J类型指令格式 图中的 OP 部分即为指令编码,而 IMMED26 是地址偏移量。从以
14、上三种类型指令的编码格式可以看出,SimpleRISC 处理器的格式比较统一,设计起来也就会比较简单。实际上,几乎所有的 RISC 处理器的指令格式都采用这里的设计思想,使得设计简单,译码逻辑也简单,从而提高处理器性能。更重要的是,这种简单的设计有利于使用流水线来实现,能更进一步提高处理器性能。二、SimpleRISC 处理器的指令编码 1、加法 这里实现的是有符号数的加法,不考虑溢出。(1)寄存器操作数相加 汇编语言表示形式:add rt,rs1,rs2 操作说明:rt=rs1+rs2 编码:(2)寄存器操作数与立即数相加 汇编语言表示形式:addi rt,rs,imm16 操作说明:rt=
15、rs+imm16,对 imm16 进行符号扩展 编码:2、减法 这里实现的是有符号数的减法,不考虑溢出。(1)寄存器操作数相减 汇编语言表示形式:sub rt,rs1,rs2 操作说明:rt=rs1-rs2 编码:(2)寄存器操作数与立即数相减 汇编语言表示形式:subi rt,rs,imm16 操作说明:rt=rs imm16,对 imm16 进行符号扩展 编码:3、小于则置一 这里实现的是无符号数的比较。(1)寄存器操作数比较 汇编语言表示形式:slt rt,rs1,rs2 操作说明:rt=(rs1 rs2)编码:(2)寄存器操作数与立即数比较 汇编语言表示形式:slti rt,rs,im
16、m16 操作说明:rt=(rs imm16),对 imm16 进行零扩展 编码:4、左移 汇编语言表示形式:sl rt,rs,imm5 操作说明:rt=rs imm5 编码:6、逻辑与 这里实现的是无符号数的逻辑与。(1)寄存器操作数的逻辑与 汇编语言表示形式:andl rt,rs1,rs2 操作说明:rt=rs1&rs2 编码:(2)寄存器操作数与立即数的逻辑与 汇编语言表示形式:andli rt,rs,imm16 操作说明:rt=rs&imm16,对 imm16 进行零扩展 编码:7、逻辑或 这里实现的是无符号数的逻辑或。(1)寄存器操作数的逻辑或 汇编语言表示形式:orl rt,rs1,
17、rs2 操作说明:rt=rs1|rs2 编码:(2)寄存器操作数与立即数的逻辑或 汇编语言表示形式:orli rt,rs,imm16 操作说明:rt=rs|imm16,对 imm16 进行零扩展 编码:8、逻辑非 这里只实现了寄存器操作数的逻辑非。汇编语言表示形式:notl rt,rs 操作说明:rt=rs 编码:9、从存储器取数据 汇编语言表示形式:load rt,rs,imm16 操作说明:rt=memoryrs+imm16,对 imm16 进行符号扩展 编码:10、存储数据到存储器 汇编语言表示形式:store rs1,rs2,imm16 操作说明:memoryrs2+imm16=rs1
18、,对 imm16 进行符号扩展 编码:11、无条件分支 汇编语言表示形式:branch imm26 操作说明:PC=PC+imm26,对 imm26 进行符号扩展 编码:12、相等则分支 汇编语言表示形式:beq rs1,rs2,imm16 操作说明:if(rs1=rs2)PC=PC+imm16;else PC=PC+1;对 imm16 进行符号扩展 编码:6.3.5 数据通路的建立 前面我们讨论了将要设计的 SimpleRISC 处理器的指令集和编码,包括算术逻辑运算指令、存储访问指令和分支指令。这些指令的实现过程大致相同,而与具体的指令类型无关。实现每条指令的前两步是一样的:(1)程序计数
19、器(PC)指向指令所在的存储单元,并从中取出指令;(2)通过指令字段的内容,选择读取一个或两个寄存器。对于取字(load)指令,只需读取一个寄存器,而其他大多数指令要求读取两个。这两步之后,为完成指令而进行的步骤则取决于具体的指令类型。然而,对三种指令类型(存储访问、算术逻辑和分支)的每一种而言,其动作大致相同,与具体操作码无关。即使是不同类型的指令,也有一定的共性。例如,所有类型的指令在读取寄 存器后,都要使用算术逻辑单元(ALU)。存储访问指令用 ALU 计算地址,算术逻辑指令用来执行运算,分支指令用 ALU 进行比较。可以看出,指令的简洁和规整使许多指令的执行很相似,因而简化了实现过程。
20、使用 ALU 计算完成之后,不同类型指令需要进行不同的操作。存储访问指令需要对存储单元进行读出或写入;算术逻辑指令需要将 ALU 产生的数据写回寄存器中;而分支指令会根据比较的结果,决定是否需要更改下条指令的地址。图 6-52 概括地描述了 SimpleRISC 的实现方式。以下将介绍其细节。这里需要加入更多的功能部件,以及功能部件间的连接,当然还要有控制单元以控制不同类型指令需要执行的操作。程 程 程 程 程地址指令寄存器指令寄存器堆数据1#寄存器2#寄存器3#寄存器ALU数据地址数据寄存器 图 6-52 SimpleRISC 实现,包括主要的功能部件和它们之间的主要联系 开始设计数据通路比
21、较合理的方法是先看看每种 SimpleRISC 处理器指令执行时所需的主要部件。先来看看每条指令需要什么数据通路部件,再用这些部件为每种指令类型建立其数据通路。在指出数据通路部件的同时,我们也会指出它们的控制信号。首先需要的部件是一个存储程序指令的地方。一个存储单元是一个状态单元,它用来存储指令,并根据所给地址提供指令,如图6-53 所示。指令的地址也必须存放在一个状态单元中,我们称之为程序计数器(PC),也在图 6-53 中示出。最后,需要一个加法器增加 PC 的值以指向下条指令的地址。程序计数器相加和指令地址指令寄存器指令指令寄存器程序计数器加法器 图 6-53 存取指令需要两个状态单元,
22、计算下条指令需要一个加法器 要执行任何一条指令,首先要从存储单元中将指令取出。为准备执行下一条指令,也必须把程序计数器加到指向下条指令,即向后移动 4 个字节。此时的数 据通路,如图 6-54 所示,使用了图 6-53 中的 3 个部件。相加和程 程 程 程 程读地址指令寄存器指令 图 6-54 用于取指和程序计数器增值的数据通路的一部分 现在讨论 R 型指令(参见图 6-49)。这种指令读两个寄存器,对它们的内容进行 ALU 操作,再写出结果。我们将这类指令称为 R 型指令或算术逻辑指令(因为它们进行数学或逻辑运算)。这个指令集合包括前面介绍的 add、sub、slt、and、or 和 no
23、t 指令。这类指令的典型形式是add rt,rs1,rs2,它将读取 rs1和 rs2,并将结果写回到 rt。处理器的 32 个寄存器位于一个叫做寄存器堆(register file)的结构中。寄存器堆即是寄存器集合,其中的寄存器都可通过指定相应的寄存器号来进行读写。寄存器堆包含了计算机的寄存器状态。另外,还需要一个 ALU 来对从寄存器读出的数值进行运算。由于 R 型指令有 3 个寄存器操作数,对每条指令,都要从寄存器堆读出两个数据字,再写入一个。为读出一个数据字,寄存器堆需要一个输入信号指定要读的寄存器号和输出信号指示从寄存器堆读出的结果。为写入一个数据字,寄存器堆要有两个输入:一个指定要
24、写的寄存器号,另一个提供要写的数据。寄存器堆总是根据输入的寄存器号输出相应的寄存器内容,而写操作由写控制信号控制,在写操作发生的时钟边沿,写控制信号必须是有效的。这样,我们一共需要 4个输入(3 个寄存器号和1 个数据)和两个输出(两个数据),如图 6-55所示。输入的寄存器号为5 位,可指示 32 个寄存器中的某一个(25=32),一条输入总线和两条输出总线宽度均为 32 位。图 6-55 中的 ALU 由 3 位控制信号控制,该 ALU 有两个 32 位输入,一个 32位输出。ALU零ALU 结果3ALU 控制读寄存器2寄存器读数据1读数据2读寄存器1写寄存器写数据寄存器号码数据数据寄存器
25、写入555 图 6-55 实现 R 型指令的 ALU 操作所需的两个状态单元:寄存器堆和 ALU 使用寄存器堆和图 6-55 中的 ALU 的 R 型指令的数据通路如图 6-56 所示。因为寄存器号来自指令字段,我们将图 6-54 输出的指令与寄存器堆的寄存器号输入连在一起。ALU零ALU 结果3ALU 控制读寄存器2寄存器读数据1读数据2读寄存器1写寄存器写数据写寄存器指令 图 6-56 R 型指令的数据通路 下面考虑 SimpleRISC 取数据指令和存储数据指令,其一般形式为:load rt,rs,imm16 或 store rs1,rs2,imm16 在这类指令中,通过将基址寄存器 r
26、s 或 rs2 的内容与指令中的 16 位带符号偏移地址相加,得到存储器地址。如果是存储数据指令,要从寄存器 rs1 中读出要存储的数据;如果是取数据指令,则要将从存储器中读出的数存入指定的寄存器 rt 中。所以,图 6-55 中的寄存器堆和 ALU 都将被用到。另外,还需要一个单元将 16 位的偏移地址符号扩展为 32 位的带符号值,以及一个存储读出和写入数据的单元。存储单元在存储指令时被写入,所以它有读、写控制信号,地址输入和要被写入存储器的数据输入。图 6-57 给出了这两个单元。1632符号扩展单元读数据数据存储器地址写数据读存储器写存储器 图 6-57 取数据指令和存储数据指令所需的
27、两个单元:数据存储器和符号扩展单元 图 6-58 显示了取指操作之后,所有上述单元如何构成取数据和存储数据指令的数据通路。寄存器堆的寄存器号输入由指令提供,偏移量也是这样。经过符号扩展,偏移量成为 ALU 的另一个输入。ALU零ALU 结果3ALU 控制读寄存器2寄存器读数据1读数据2读寄存器1写寄存器写数据写寄存器地址写数据写存贮器1632读数据数据存储器地址写数据读存储器符号扩展单元 图 6-58 加入取数据和存储数据指令之后的数据通路 beq 指令有 2 个操作数,其中两个为寄存器,用于比较是否相等,另一个是16 位偏移量,用以计算相对于分支指令所在地址的分支目标地址。除了计算分支目标地
28、址,还必须确定是顺序执行下一条指令,还是去执行分支目标地址处的指令。当分支条件为真(即操作数相等)时,分支目标地址成为新的 PC,我们就说实现了分支;若操作数不等,增值后的 PC 将取代当前 PC(就像其他一般指令一样),这时就说没有实现分支。所以,分支数据通路需要进行两个操作:计算分支目标地址和比较操作数。图 6-59 所示为分支数据通路。指令相加和符号扩展单元PC当前值加4读数据1读数据2写寄存器ALU零3ALU 控制读寄存器2寄存器读数据1读数据2读寄存器1写寄存器写数据写寄存器1632地址分支目标至控制逻辑分支左移2位 图 6-59 分支指令的数据通路 为计算分支目标地址,分支目标通路
29、包含了一个如图 6-57 所示的符号扩展单元和一个加法器。为进行比较操作,要由图 6-55 的寄存器堆提供两个寄存器操作数(但不需要向寄存器堆写入数据)。另外,比较操作由 ALU 完成。无条件跳转指令将偏移地址的低 26 位左移两位后,以之代替 PC 的低 28 位(由于这里讨论的指令地址是字节地址,而实际的一条指令有 4 个字节,所以低两位指令地址无效)。到此为止,我们已经讨论过单独的每种类型指令所需的数据通路,可以将它们合并成一个简单的数据通路,并且加上控制部分,以达到完整的实现。6.3.6 完整的数据通路 两个不同类型指令共享一个数据通路部件时,需要给部件连接多个输入,并设置控制信号以便
30、在输入中进行选择。这种选择通常由数据选择器来实现。首先将图6-56所示的算术逻辑指令数据通路和图 6-58所示的存储器指令的数据通路进行合并,得到如图 6-60 所示的数据通路。A L U 存储器至寄存器1632 多路选择器符号扩展单元ALUAL U3读存储器ALU指令读寄存器1读寄存器2写寄存器写数据寄存器堆读数据1读数据2结果零地址写数据数据存储器读数据写寄存器写存储器操作多路选择器源数据选择 图 6-60 算术逻辑指令和存储器指令的数据通路合并 图中,加入了一些数据选择器及相应的控制信号。图 6-61 所示的是加入的取指部分的数据通路。程序计数器1632 ALU4相加ALUALU 3读存
31、储器写存储器ALU 读地址指令指令存储器读寄存器1读寄存器2写寄存器写数据寄存器堆读数据1读数据2写寄存器符号扩展单元多路选择器操作零结果地址写数据数据存储器读数据多路选择器存储器至寄存器源数据选择 图 6-61 加入取指部分的数据通路 现在,加上图 6-59 所示的分支指令的数据通路,我们可以把所有部件加在一起建立起 SimpleRISC 处理器的一个简单数据通路。图 6-62 给出了把独立部件连在一起之后得到的数据通路。1632ALURegisters 4ALU 3PCALUALUALU程序计数器读地址相加指令指令存储器读寄存器 1读寄存器 2写寄存器写数据读数据1读数据2写寄存器符号扩展
32、单元多路选择器左移2位相加结果多路选择器操作零结果地址写数据读数据数据存储器写存储器读存储器多路选择器存储器至寄存器源数据选择源数据选择 图 6-62 SimpleRISC 处理器的数据通路 图中的指令和数据存储器使用总线接口单元 BIU 来进行连接。在完成这个数据通路之后,可以加上控制单元。控制单元接受指令输入,并产生每个状态单元的同步信号,每个数据选择器和 ALU 的控制信号。加入控制单元后的数据通路如图 6-63 所示。310 20 16 25 21 5 0ALUALU 31 2641632 15 00001A LU01 1ALUPC1 15 11ALU ALU 程序计数器相加读地址指令
33、存储器指令指令指令指令指令指令控制寄存器目的分支读存储器存储器至寄存器操作控制写存储器源数据选择写寄存器多路选择器读寄存器 1读寄存器 2写寄存器写数据寄存器堆读数据 1读数据 2 指令符号扩展单元控制多路选族器结果零左移2位相加结果多路选择器源数据选择地址写数据数据存储器读数据多路选择器 图 6-63 有控制单元的完整数据通路 6.3.7 SimpleRISC 处理器的实现 通过前面的介绍,我们知道 SimpleRISC 处理器需要设计如下子模块:(1)算术逻辑单元;(2)寄存器堆;(3)程序计数器;(4)总线接口单元;(5)控制器。以下分别介绍各个模块的设计。一、算术运算单元 算术逻辑单元
34、根据输入的操作码,对两个源操作数进行算术逻辑运算,并产生相应的输出。程序 6-6 是算术逻辑单元 ALU 的设计。【程序 6-6】timescale 1 ns/1 ns module ArithmeticLogicUnit(nReset,Clock,OperationCode,Source1,Source2,Destination);input nReset,Clock;input 3:0 OperationCode;input 31:0 Source1,Source2;output 31:0 Destination;parameter ADD=4d0,SUB=4d1,SLT=4d2,SL =
35、4d3,SR =4d4,AND=4d5,OR =4d6,NOT=4d7,CMP=4d8;reg 31:0 Destination;always (negedge nReset or posedge Clock)begin if(!nReset)Destination=32d0;else begin case(OperationCode)ADD:Destination=Source1+Source2;SUB:Destination=Source1-Source2;SLT:Destination=(Source1 Source2)?32d1:32d0;SL:Destination=Source1
36、Source24:0;SR:Destination Source24:0;AND:Destination=Source1&Source2;OR:Destination=Source1|Source2;NOT:Destination=Source1;CMP:Destination=(Source1=Source2)?32d1:32d0;default :Destination=32hxxxxxxxx;endcase end end endmodule 二、寄存器堆 寄存器堆具有三个地址输入端口,一个数据总线输入和两个数据总线输出端口。内部结构可以用图 6-64 和图 6-65,其中,图 6-64
37、 表示寄存器堆的读端口,而图 6-65 表示写端口。读1#寄存器 读2#寄存器 多路选择器寄存器 0寄存器 n-1寄存器 1寄存器 n.多路选择器读数据 1读数据 2 图 6-64 寄存器堆读端口 n-to-1 0 1 n 1CCDD CCDD01n 1n 写入寄存器号码解码器寄存器寄存器寄存器寄存器 n 寄存器数据 图 6-65 寄存器堆写端口 由此可以得到寄存器堆的 Verilog HDL 描述,参见程序 6-7。寄存器堆设计中,假定 0 号寄存器总是 0 值,且不能写入。【程序 6-7】timescale 1 ns/1 ns module GeneralPurposeRegister(n
38、Reset,Write,WriteAddress,WriteData,ReadAddress1,ReadAddress2,ReadData1,ReadData2);input nReset,Write;input 4:0 WriteAddress,ReadAddress1,ReadAddress2;input 31:0 WriteData;output 31:0 ReadData1,ReadData2;reg 31:0 GPRs31:1;integer i;always (negedge nReset or posedge Write)begin if(!nReset)for(i=1;i=31
39、;i=i+1)GPRsi=32d0;else if(WriteAddress!=5d0)GPRsWriteAddress=WriteData;end assign ReadData1=(|ReadAddress1)?GPRsReadAddress1:32d0;assign ReadData2=(|ReadAddress2)?GPRsReadAddress2:32d0;endmodule 三、程序计数器 程序计数器输入一个 Branch 用于判断是否发生跳转,如果发生跳转时,将程序计数器当前值加上输入的偏移量 PCBias 作为下一条指令的地址;而如果没有跳转发生时,直接将程序计数器加 1。这里
40、需要注意,这里的程序计数器设计时考虑采用的是存储器的字地址,所以增值是 1,而不是前面图 6-59 中的 4。程序计数器的 Verilog 程序参见程序 6-8。【程序 6-8】timescale 1 ns/1 ns module ProgramCounter(nReset,Clock,Branch,PCBias,PCValue);input nReset,Clock,Branch;input 31:0 PCBias;output 31:0 PCValue;reg 31:0 PCValue;always (negedge nReset or posedge Clock)begin if(!nR
41、eset)PCValue=32d0;else if(Branch)PCValue=PCValue+PCBias;else PCValue=PCValue+1;end endmodule 四、总线接口单元 总线接口单元只是一些三态缓冲器,所以直接在 SimpleRISC 处理器的顶层设计中实现,而这里就不专门进行设计。五、控制器 控制器需要根据不同的指令,产生不同的控制信号,以控制数据通路中的部件能同步工作,并且使得数据通路中相应的数据选择器作出正确的选择。这里的控制器比较复杂,使用一个有限状态机来实现,图6-66 给出了控制器的状态转移图。图 6-66 控制器状态转移图 从图中可以看出,Sim
42、pleRISC 处理器的控制器具有 5 个状态。起始状态是取指状态 Fetch,Fetch 状态使得指令存储器的读控制信号有效,从而取到要执行的指令。取到指令之后,要对其进行译码,所以进入了第二个指令译码状态Decode,Decode 根据前一状态取到的指令进行译码操作,产生相应的数据选择器选择信号等控制信号。指令译码之后,进入指令执行状态 Execute,这一步大多数指令使用 ALU 进行运算,然后根据指令类型选择是进行存储器操作还是直接将运算结果写回寄存器堆。对于存储器访问指令,执行状态之后计算出进行存储器访问的地址,之后进入存储器访问状态 Memory 进行相应的存储器操作。对于其他不需
43、要进行存储器访问的指令,直接进入寄存器回写状态 Write,将计算结果写回寄存器。程序 6-9 是控制器的 Verilog 实现。【程序 6-9】timescale 1 ns/1 ns module Controller(nReset,Clock,Instruction,ALUClock,GPRClock,PCClock,ALUCode,ALUSourceSelect,MemToReg,RegToMem,Branch,UnconditionalBranch,RegSrc,RegDst,i_Read,d_Read,d_Write);input nReset,Clock;input 16:0 In
44、struction;output ALUClock,GPRClock,PCClock;output 3:0 ALUCode;output 1:0 ALUSourceSelect;output MemToReg,RegToMem;output Branch,UnconditionalBranch;output RegSrc,RegDst;output i_Read,d_Read,d_Write;reg ALUClock,GPRClock,PCClock;reg 3:0 ALUCode;reg 1:0 ALUSourceSelect;reg MemToReg,RegToMem;reg Branch
45、,UnconditionalBranch;reg RegSrc,RegDst;reg i_Read,d_Read,d_Write;parameter ADD=4d0,SUB=4d1,SLT=4d2,SL =4d3,SR =4d4,AND=4d5,OR =4d6,NOT=4d7,CMP=4d8;parameter Fetch =5b00001,Decode =5b00010,Execute =5b00100,Memory =5b01000,Write =5b10000;reg 5:0 OperationCode;reg 4:0 State;always (negedge nReset or po
46、sedge Clock)begin if(!nReset)begin ALUClock=1b0;GPRClock=1b0;PCClock=1b0;ALUCode=4b0000;ALUSourceSelect=2b00;MemToReg=1b0;RegToMem=1b0;Branch=1b0;UnconditionalBranch=1b0;RegSrc=1b0;RegDst=1b0;i_Read=1b0;d_Read=1b0;d_Write=1b0;OperationCode=6b000000;State=Fetch;end else begin case(State)Fetch:begin A
47、LUClock=1b0;GPRClock=1b0;PCClock=1b0;ALUCode=4b0000;ALUSourceSelect=2b00;MemToReg=1b0;RegToMem=1b0;Branch=1b0;UnconditionalBranch=1b0;RegSrc=1b0;RegDst=1b0;i_Read=1b1;d_Read=1b0;d_Write=1b0;OperationCode=6b000000;State=Decode;end Decode:begin if(Instruction5:0=6b000000)/R-Type begin if(Instruction16
48、:6=11h001)/add begin ALUCode=ADD;ALUSourceSelect=2b00;RegDst=1b1;end else if(Instruction16:6=11h002)/sub begin ALUCode=SUB;ALUSourceSelect=2b00;RegDst=1b1;end else if(Instruction16:6=11h003)/slt begin ALUCode=SLT;ALUSourceSelect=2b00;RegDst=1b1;end else if(Instruction16:6=11h004)/and begin ALUCode=A
49、ND;ALUSourceSelect=2b00;RegDst=1b1;end else if(Instruction16:6=11h005)/or begin ALUCode=OR;ALUSourceSelect=2b00;RegDst=1b1;end else if(Instruction16:6=11h006)/not begin ALUCode=NOT;ALUSourceSelect=2b11;RegDst=1b1;end else /unimplement begin ALUCode=ADD;ALUSourceSelect=2b11;RegDst=1b0;end MemToReg=1b
50、0;RegToMem=1b0;Branch=1b0;UnconditionalBranch=1b0;RegSrc=1b0;end else begin if(Instruction5:0=6b000001)/addi begin ALUCode=ADD;ALUSourceSelect=2b10;MemToReg=1b0;RegToMem=1b0;Branch=1b0;UnconditionalBranch=1b0;RegSrc=1b0;RegDst=1b1;end else if(Instruction5:0=6b000010)/subi begin ALUCode=SUB;ALUSource