为了正常的体验网站,请在浏览器设置里面开启Javascript功能!
首页 > 6.4 简单RISC处理器设计

6.4 简单RISC处理器设计

2017-10-14 50页 doc 270KB 25阅读

用户头像

is_477730

暂无简介

举报
6.4 简单RISC处理器设计6.4 简单RISC处理器设计 现代电子系统设计,课堂讲义, 6.4 简单RISC处理器设计 前面我们已经学习了现代电子系统设计的基本方法~学习了使用Verilog HDL语言设计简单组合逻辑和简单时序逻辑模块~学习了自顶向下的设计方法~同时还学习了状态机的设计。在这里~将综合运用以上所学的知识~设计一个简化的处理器。“麻雀虽小~五脏俱全”~这里设计的处理器虽然是经过简化的~但是能对其进行综合、适配~最终可以在硬件上运行。 这里介绍的处理器由于主要用于教学~只是一个简单的教学模型~设计不一定合理~只是从原理上说明了一个...
6.4 简单RISC处理器设计
6.4 简单RISC处理器 现代电子系统设计,课堂讲义, 6.4 简单RISC处理器设计 前面我们已经学习了现代电子系统设计的基本~学习了使用Verilog HDL语言设计简单组合逻辑和简单时序逻辑模块~学习了自顶向下的设计方法~同时还学习了状态机的设计。在这里~将综合运用以上所学的知识~设计一个简化的处理器。“麻雀虽小~五脏俱全”~这里设计的处理器虽然是经过简化的~但是能对其进行综合、适配~最终可以在硬件上运行。 这里介绍的处理器由于主要用于教学~只是一个简单的教学模型~设计不一定合理~只是从原理上说明了一个简单的处理器是如何构成的。 6.4.1 RISC处理器简介 中央处理器,CPU~Central Processing Unit,是计算机的核心部件。计算机进行信息处理可分为两个步骤: ,1,将数据和程序,即指令序列,输入到计算机的存储器中, ,2,从第一条指令的地址起开始执行该程序~得到所需结果~结束运行。CPU的作用是协调并控制计算机的各个部件并执行程序的指令序列~使其有条不紊地进行。因此它必须具有以下基本功能: ? 取指令——当程序已在存储器中时~首先根据程序入口地址取出一条程序~为此要发出指令地址和控制信号。 ? 指令——即指令译码~这是对当前取得的指令进行分析~指出它要求什么操作~并产生相应的操作控制命令。 ? 执行指令——根据分析指令时产生的“操作命令”形成相应的操作控制信号序列~通过运算器、存储器及输入/输出设备的执行~实现每条指令的功能~其中包括对运算结果的处理及下条指令地址的形成。 将CPU的功能进一步细化~可概括如下: ,1,能对指令进行译码并执行规定的动作, - 1 - 现代电子系统设计,课堂讲义, ,2,可以进行算术和逻辑运算, ,3,能与存储器和外设交换数据, ,4,提供整个系统所需要的控制。 尽管各种CPU的性能指标和结构细节各不相同~但它们所能完成的基本功能相同。由功能分析可知~任何一种CPU内部结构至少应包含下面这些部件: ,1,算术逻辑运算部件,ALU,, ,2,累加器或寄存器, ,3,程序计数器, ,4,指令寄存器和译码器, ,5,时序和控制部件。 精简指令计算机,RISC~Reduced Instruction Set Computer,是一种20世纪80年代才出现的CPU~它与一般CPU相比不仅只是简化了指令系统~而且还通过简化指令系统使计算机的结构更加简单合理~从而提高了运算速度。从实现的途径看~RISC处理器与一般的CPU的不同之处在于:它的时序控制信号形成部件是用硬布线逻辑实现的而不是采用微程序控制的方式。所谓硬布线逻辑也就是用触发器和逻辑门直接连线所构成的状态机和相应的组合逻辑~故产生控制序列的速度比用微程序控制方式快得多~因为这样做省去了读取微程序指令的时间。下面就详细介绍一个简化的、用于教学目的的RISC处理器SimpleRISC~它是采用硬布线逻辑实现的控制~是一个可综合的CPU模型。 6.4.2 SimpleRISC处理器结构介绍 一、处理器结构 这里首先对我们即将要进行设计的SimpleRISC处理器硬件结构作一个简要介绍。这里所介绍的处理器结构只是SimpleRISC芯片的内部结构~或者说只是SimpleRISC的CPU核~所以不包括存储器单元和外设等。SimpleRISC处理器的内核结构如图6-54所示。 - 2 - 现代电子系统设计,课堂讲义, 图6-54 SimpleRISC处理器内核结构 从图6-54中可以看出~SimpleRISC处理器内核包括以下功能单元:控制器、程序计数器、通用寄存器、算术逻辑单元,ALU~Arithmetic Logic Unit,和总线接口单元,BIU~Bus Interface Unit,。以下的内容将依次讨论这些模块。 二、处理器内部子模块 1、控制器 控制器用于进行指令译码、产生ALU运算控制信号、产生通用寄存器读写控制信号以及协调处理器工作时序工作。 2、程序计数器 程序计数器用于指向下一条将要执行的指令的地址~它可以自动增值或是通过分支指令来设臵其内容。 3、通用寄存器 SimpleRISC处理器内部有32个32 位通用寄存器~ALU运算的源操作数、目的操作数大都来自这个通用寄存器堆。 4、算术逻辑单元 算术逻辑单元用于进行算术运算、移位操作、比较设臵操作以及逻辑运算。对于其他未能实现的运算~例如乘法、浮点运算等~可以使用软件来实现。 - 3 - 现代电子系统设计,课堂讲义, 5、总线接口单元 总线接口单元用于SimpleRISC处理器与外部存储器和I/O口的连接~为了简单起见~SimpleRISC系统的存储器和I/O采用统一编址的方式进行组织~并且采用程序存储器和数据存储器分开的哈佛结构。 从图6-54可以看出~SimpleRISC处理器并没有实现中断处理以及Cache等功能~虽然如此~但是SimpleRISC处理器已经能进行一些简单的工作了。下面将继续讨论有关SimpleRISC的一些细节。 6.4.3 SimpleRISC处理器的指令集和寻址方式 一、SimpleRISC处理器的指令集 SimpleRISC处理器的指令集中包括以下指令: ,1,算术运算指令 算术运算指令包括加法,add,和减法,sub,指令。 ,2,比较指令 比较指令只有小于则设臵,slt,指令。 ,3,移位指令 移位指令包括左移,ls,和右移,rs,指令。 ,4,逻辑运算指令 逻辑运算指令包括与,and,、或,or,和非,not,指令。这里的逻辑运算都是按位进行的。 ,5,数据存储器访问指令 数据存储器访问指令包括存储器数据加载,load,和数据存储,store,两条指令。数据存储器的访问都必须通过这两条指令来进行。 ,6,分支指令 分支指令分为无条件分支和条件分支两类。无条件分支指令只有一条:branch,而条件分支只实现相等则分支,beq,指令。 - 4 - 现代电子系统设计,课堂讲义, 二、SimpleRISC处理器的寻址方式 CPU的寻址方式指的是CPU在进行操作时如何找到操作数的方法。一般来说~操作数可以存储在CPU内部寄存器中~也可以由指令提供~还可以存储在数据存储器中。对于RISC处理器来说~操作数一般都由指令提供或存储在CPU内部寄存器中~而RISC处理器一般不直接使用数据存储器中的数据作为操作数。 这里的SimpleRISC处理器~其操作数也由指令提供或存储在CPU内部寄存器中~相应的寻址方式为立即寻址,操作数由指令提供,和寄存器寻址,操作数存储在CPU内部寄存器中,。 6.4.4 SimpleRISC处理器的指令与编码 一、指令格式 这里假设设计的SimpleRISC处理器是32位的~由于它有32个32位寄存器~所以每个寄存器需要使用5位编码来寻址。将以上讨论的指令分为三种类型的指令:R,类型指令、I,类型指令和J,类型指令。 R,类型指令指的是操作数全部来自通用寄存器~包括寄存器操作数的算术运算指令、比较指令和逻辑运算指令。由于这些指令的操作数都来自于通用寄存器~而一般的操作都有三个操作数:两个源操作数和一个目的操作数~所以R,类型指令中需要使用5×3,15位来对寄存器进行编址~对于32位指令~使用了15位以后~还剩余17位~其余的17位都可用于指令的编码~所以一共可 17以有2,131072条R,类型的指令。 I,类型指令指的是操作数中有部分来自于通用寄存器~而另一部分是来自于指令本身的立即数~包括带有立即数的算术运算指令、比较指令、逻辑运算指令、移位指令、数据存储器访问指令和条件分支指令。除移位指令外~立即数都是16位的~而另外还需要两个寄存器操作数~所以共需要16,5×2,26 6位编码~还剩余6位编码~所以可以有2,64条I,类型的指令。对于移位指令~由于操作数是32位的~所以移位位数最多为32位~则只需要5位立即数 - 5 - 现代电子系统设计,课堂讲义, 即可~因此共需要5,5×2,15位编码~剩余17位可用于指令编码。 J,类型指令只有一条:无条件分支指令Branch~它采用6位指令编码,为了与I,类型指令格式对齐,~剩余的26位用于指明分支的目的地址到当前程序 2525计数器的偏移量。假设采用补码示法~则最大偏移量在,2,,,2-1,之间~即,0x02000000,,0x01FFFFFF之间。而前面讨论的条件分支使用16位偏 1515移量~所以最大偏移量在,2,,,2-1,之间~即,0x00008000,,0x00007FFF之间。 通过以上讨论~可以定义出以下指令格式。 对于R,类型指令~指令中包括三个5位的通用寄存器地址域和一个17位的指令编码域~为了与I,类型及J,类型指令保持格式一致~将指令编码域分成了11位和6位两个部分~参见图6-55。 图6-55 R,类型指令格式 图中的A、B、C为通用寄存器地址~OPX位11位指令编码~OP位6位指令编码。 对于I,类型指令~指令中包括四个域:两个5位的通用寄存器地址、6位指令编码和16位地址偏移量~可以表示为图6-56所示的格式。 图6-56 I,类型指令格式 图中的A、B为通用寄存器地址~IMM16为16位立即数,对于移位指令~只用最低5位,~OP为指令编码。 对于J,类型指令~指令中包括两个域:6位指令编码和26位地址偏移量~可以表示为图6-57所示的格式。 图6-57 J,类型指令格式 - 6 - 现代电子系统设计,课堂讲义, 图中的OP部分即为指令编码~而IMMED26是地址偏移量。 从以上三种类型指令的编码格式可以看出~SimpleRISC处理器的格式比较统一~设计起来也就会比较简单。实际上~几乎所有的RISC处理器的指令格式都采用这里的设计思想~使得设计简单~译码逻辑也简单~从而提高处理器性能。更重要的是~这种简单的设计有利于使用流水线来实现~能更进一步提高处理器性能。 二、SimpleRISC处理器的指令编码 1、加法 这里实现的是有符号数的加法~不考虑溢出。 ,1,寄存器操作数相加 汇编语言表示形式:add rt, rs1, rs2 操作说明:rt = rs1 + rs2 编码: ,2,寄存器操作数与立即数相加 汇编语言表示形式:addi rt, rs, imm16 操作说明:rt = rs + imm16~对imm16进行符号扩展 编码: 2、减法 这里实现的是有符号数的减法~不考虑溢出。 ,1,寄存器操作数相减 汇编语言表示形式:sub rt, rs1, rs2 操作说明:rt = rs1 - rs2 编码: ,2,寄存器操作数与立即数相减 汇编语言表示形式:subi rt, rs, imm16 - 7 - 现代电子系统设计,课堂讲义, 操作说明:rt = rs – imm16~对imm16进行符号扩展 编码: 3、小于则臵一 这里实现的是无符号数的比较。 ,1,寄存器操作数比较 汇编语言表示形式:slt rt, rs1, rs2 操作说明:rt = ,rs1 < rs2, 编码: ,2,寄存器操作数与立即数比较 汇编语言表示形式:slti rt, rs, imm16 操作说明:rt = ,rs < imm16,~对imm16进行零扩展 编码: 4、左移 汇编语言表示形式:sl rt, rs, imm5 操作说明:rt = rs << imm5 编码: 5、右移 汇编语言表示形式:rl rt, rs, imm5 操作说明:rt = rs >> imm5 编码: 6、逻辑与 这里实现的是无符号数的逻辑与。 ,1,寄存器操作数的逻辑与 汇编语言表示形式:andl rt, rs1, rs2 - 8 - 现代电子系统设计,课堂讲义, 操作说明:rt = rs1 & rs2 编码: ,2,寄存器操作数与立即数的逻辑与 汇编语言表示形式:andli rt, rs, imm16 操作说明:rt = rs & imm16~对imm16进行零扩展 编码: 7、逻辑或 这里实现的是无符号数的逻辑或。 ,1,寄存器操作数的逻辑或 汇编语言表示形式:orl rt, rs1, 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 = memory[rs + imm16]~对imm16进行符号扩展 - 9 - 现代电子系统设计,课堂讲义, 编码: 10、存储数据到存储器 汇编语言表示形式:store rs1, rs2, imm16 操作说明:memory[rs2 + imm16] = rs1~对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.4.5 数据通路的建立 前面我们讨论了将要设计的SimpleRISC处理器的指令集和编码~包括算术逻辑运算指令、存储访问指令和分支指令。这些指令的实现过程大致相同~而与具体的指令类型无关。实现每条指令的前两步是一样的: ,1,程序计数器,PC,指向指令所在的存储单元~并从中取出指令, ,2,通过指令字段的内容~选择读取一个或两个寄存器。对于取字,load,指令~只需读取一个寄存器~而其他大多数指令要求读取两个。 这两步之后~为完成指令而进行的步骤则取决于具体的指令类型。然而~ - 10 - 现代电子系统设计,课堂讲义, 对三种指令类型,存储访问、算术逻辑和分支,的每一种而言~其动作大致相同~与具体操作码无关。 即使是不同类型的指令~也有一定的共性。例如~所有类型的指令在读取寄存器后~都要使用算术逻辑单元,ALU,。存储访问指令用ALU计算地址~算术逻辑指令用来执行运算~分支指令用ALU进行比较。可以看出~指令的简洁和规整使许多指令的执行很相似~因而简化了实现过程。 使用ALU计算完成之后~不同类型指令需要进行不同的操作。存储访问指令需要对存储单元进行读出或写入,算术逻辑指令需要将ALU产生的数据写回寄存器中,而分支指令会根据比较的结果~决定是否需要更改下条指令的地址。 图6-58概括地描述了 SimpleRISC的实现方式。以下将介绍其细节。这里需要加入更多的功能部件~以及功能部件间的连接~当然还要有控制单元以控制不同类型指令需要执行的操作。 Data Register # AddressPCInstructionRegistersALUAddress Register #Instruction Data memory memoryRegister # Data 图6-58 SimpleRISC实现,包括主要的功能部件和它们之间的主要联系 开始设计数据通路比较合理的方法是先看看每种SimpleRISC处理器指令执行时所需的主要部件。先来看看每条指令需要什么数据通路部件~再用这些部件为每种指令类型建立其数据通路。在指出数据通路部件的同时~我们也会指出它们的控制信号。 首先需要的部件是一个存储程序指令的地方。一个存储单元是一个状态单元~它用来存储指令~并根据所给地址提供指令~如图6-59所示。指令的地址也必须存放在一个状态单元中~我们称之为程序计数器,PC,~也在图6-59中示出。最后~需要一个加法器增加PC的值以指向下条指令的地址。 - 11 - 现代电子系统设计,课堂讲义, Instruction address PC InstructionAddSum Instruction memory a. Instruction memoryb. Program counterc. Adder 图6-59 存取指令需要两个状态单元,计算下条指令需要一个加法器 要执行任何一条指令~首先要从存储单元中将指令取出。为准备执行下一条指令~也必须把程序计数器加到指向下条指令~即向后移动4个字节。此时的数据通路~如图6-60所示~使用了图6-59中的3个部件。 图6-60 用于取指和程序计数器增值的数据通路的一部分 现在讨论R型指令,参见图6-55,。这种指令读两个寄存器~对它们的内容进行ALU操作~再写出结果。我们将这类指令称为R型指令或算术逻辑指令,因为它们进行数学或逻辑运算,。这个指令集合包括前面介绍的add、sub、slt、and、or和not指令。这类指令的典型形式是add rt~rs1~rs2~它将读取rs1和rs2~并将结果写回到rt。 处理器的32个寄存器位于一个叫做寄存器堆,register file,的结构中。寄存器堆即是寄存器集合~其中的寄存器都可通过指定相应的寄存器号来进行读写。寄存器堆包含了计算机的寄存器状态。另外~还需要一个ALU来对从寄存器读出的数值进行运算。 - 12 - 现代电子系统设计,课堂讲义, 由于R型指令有3个寄存器操作数~对每条指令~都要从寄存器堆读出两个数据字~再写入一个。为读出一个数据字~寄存器堆需要一个输入信号指定要读的寄存器号和输出信号指示从寄存器堆读出的结果。为写入一个数据字~寄存器堆要有两个输入:一个指定要写的寄存器号~另一个提供要写的数据。寄存器堆总是根据输入的寄存器号输出相应的寄存器内容~而写操作由写控制信号控制~在写操作发生的时钟边沿~写控制信号必须是有效的。这样~我们一共需要4个输入,3个寄存器号和1个数据,和两个输出,两个数据,~如图 56-61所示。输入的寄存器号为5位~可指示32个寄存器中的某一个,2=32,~一条输入总线和两条输出总线宽度均为32位。 图6-61中的ALU由3位控制信号控制~该ALU有两个32位输入~一个32位输出。 ALU control53Read register 1Read data 15Register Read Zeroregister 2numbersRegistersDataALUALU 5Write resultregisterRead data 2Write Datadata RegWrite a. Registersb. ALU 图6-61 实现R型指令的ALU操作所需的两个状态单元:寄存器堆和ALU 使用寄存器堆和图6-61中的ALU的R型指令的数据通路如图6-62所示。因为寄存器号来自指令字段~我们将图6-60输出的指令与寄存器堆的寄存器号输入连在一起。 ALU operation3Read register 1Read data 1Read Zeroregister 2InstructionRegistersALUALU Write resultregisterRead data 2Write data RegWrite 图6-62 R型指令的数据通路 - 13 - 现代电子系统设计,课堂讲义, 下面考虑SimpleRISC取数据指令和存储数据指令~其一般形式为: load rt~rs~imm16或store rs1~rs2~imm16 在这类指令中~通过将基址寄存器rs或rs2的内容与指令中的16位带符号偏移地址相加~得到存储器地址。如果是存储数据指令~要从寄存器rs1中读出要存储的数据,如果是取数据指令~则要将从存储器中读出的数存入指定的寄存器rt中。所以~图6-61中的寄存器堆和ALU都将被用到。 另外~还需要一个单元将16位的偏移地址符号扩展为32位的带符号值~以及一个存储读出和写入数据的单元。存储单元在存储指令时被写入~所以它有读、写控制信号~地址输入和要被写入存储器的数据输入。图6-63给出了这两个单元。 MemWrite Read Addressdata1632Sign extendData Write memorydata MemRead a. Data memory unitb. Sign-extension unit 图6-63 取数据指令和存储数据指令所需的两个单元:数据存储器和符号扩展单元 图6-64显示了取指操作之后~所有上述单元如何构成取数据和存储数据指令的数据通路。寄存器堆的寄存器号输入由指令提供~偏移量也是这样。经过符号扩展~偏移量成为ALU的另一个输入。 ALU operation3Read register 1MemWriteRead data 1Read Zeroregister 2InstructionALURegistersALU Read Write resultAddressdataregisterRead data 2Write Data datamemoryWrite RegWritedata 1632Sign MemReadextend 图6-64 加入取数据和存储数据指令之后的数据通路 - 14 - 现代电子系统设计,课堂讲义, beq指令有2个操作数~其中两个为寄存器~用于比较是否相等~另一个是16位偏移量~用以计算相对于分支指令所在地址的分支目标地址。除了计算分支目标地址~还必须确定是顺序执行下一条指令~还是去执行分支目标地址处的指令。当分支条件为真,即操作数相等,时~分支目标地址成为新的PC~我们就说实现了分支,若操作数不等~增值后的PC将取代当前PC,就像其他一般指令一样,~这时就说没有实现分支。 所以~分支数据通路需要进行两个操作:计算分支目标地址和比较操作数。图6-65所示为分支数据通路。 PC + 4 from instruction datapath AddSumBranch target Shift left 2 ALU operation3Read register 1InstructionRead data 1Read register 2To branch RegistersALUZerocontrol logicWrite registerRead data 2Write data RegWrite 1632Sign extend 图6-65 分支指令的数据通路 为计算分支目标地址~分值目标通路包含了一个如图6-63所示的符号扩展单元和一个加法器。为进行比较操作~要由图6-61的寄存器堆提供两个寄存器操作数,但不需要向寄存器堆写入数据,。另外~比较操作由ALU完成。 无条件跳转指令将偏移地址的低26位左移两位后~以之代替PC的低28位,由于这里讨论的指令地址是字节地址~而实际的一条指令有4个字节~所以低两位指令地址无效,。 到此为止~我们已经讨论过单独的每种类型指令所需的数据通路~可以将它们合并成一个简单的数据通路~并且加上控制部分~以达到完整的实现。 - 15 - 现代电子系统设计,课堂讲义, 6.4.6 完整的数据通路 两个不同类型指令共享一个数据通路部件时~需要给部件连接多个输入~并设臵控制信号以便在输入中进行选择。这种选择通常由数据选择器来实现。 首先将图6-62所示的算术逻辑指令数据通路和图6-64所示的存储器指令的数据通路进行合并~得到如图6-66所示的数据通路。 ALU operation3Read register 1MemWriteRead data 1MemtoRegRead ALUSrcZeroregister 2InstructionRegistersALURead ALU Read Write data 2AddressresultdataregisterM M u u Write xData xdatamemoryWrite RegWritedata 1632Sign MemReadextend 图6-66 算术逻辑指令和存储器指令的数据通路合并 图中~加入了一些数据选择器及相应的控制信号。图6-67所示的是加入的取指部分的数据通路。 Add 4 RegistersRead ALU operation3MemWriteregister 1Read PCRead MemtoRegRead addressdata 1register 2ALUSrcZeroInstructionALURead ALU Read Write Addressresultdata 2registerdataM M u Instruction u Write xData xmemorydatamemoryWrite RegWritedata 1632Sign MemReadextend 图6-67 加入取指部分的数据通路 现在~加上图6-65所示的分支指令的数据通路~我们可以把所有部件加在 - 16 - 现代电子系统设计,课堂讲义, 一起建立起SimpleRISC处理器的一个简单数据通路。图6-68给出了把独立部件连在一起之后得到的数据通路。 PCSrc M Addu xALU Add4resultShift left 2 RegistersALU operation3Read MemWriteALUSrcRead register 1PCRead addressRead MemtoRegdata 1Zeroregister 2InstructionALUALU Read Write Read Address resultM dataregister data 2M u Instruction u xWrite memoryData xdatamemoryWrite RegWritedata3216Sign MemReadextend 图6-68 SimpleRISC处理器的数据通路 图中的指令和数据存储器使用总线接口单元BIU来进行连接。在完成这个数据通路之后~可以加上控制单元。控制单元接受指令输入~并产生每个状态单元的同步信号~每个数据选择器和ALU的控制信号。加入控制单元后的数据通路如图6-69所示。 0 M u xALU Add1resultAddShift PCSrcleft 2RegDst4BranchMemReadMemtoRegInstruction [31 26]ControlALUOpMemWriteALUSrcRegWrite Instruction [25 21]Read Read register 1PCRead addressdata 1Instruction [20 16]Read Zeroregister 2Instruction 0RegistersALURead ALU [31–0]0Read Write AddressM data 2result1dataInstruction registerM u M u memoryxu Instruction [15 11]Write xData 1xdata1memory0Write data1632Instruction [15 0]Sign extendALU control Instruction [5 0] 图6-69 有控制单元的完整数据通路 - 17 - 现代电子系统设计,课堂讲义, 6.4.7 SimpleRISC处理器的实现 通过前面的介绍~我们知道SimpleRISC处理器需要设计如下子模块: ,1,算术逻辑单元, ,2,寄存器堆, ,3,程序计数器, ,4,总线接口单元, ,5,控制器。 以下分别介绍各个模块的设计。 一、算术运算单元 算术逻辑单元根据输入的操作码~对两个源操作数进行算术逻辑运算~并 产生相应的输出。 程序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; - 18 - 现代电子系统设计,课堂讲义, parameter ADD = 4'd0, SUB = 4'd1, SLT = 4'd2, SL = 4'd3, SR = 4'd4, AND = 4'd5, OR = 4'd6, NOT = 4'd7, CMP = 4'd8; reg [31:0] Destination; always @(negedge nReset or posedge Clock) begin if(!nReset) Destination <= 32'd0; else begin case(OperationCode) ADD : Destination <= Source1 + Source2; SUB : Destination <= Source1 - Source2; SLT : Destination <= (Source1 < Source2) ? 32'd1 : 32'd0; SL : Destination <= Source1 << Source2[4:0]; SR : Destination <= Source1 >> Source2[4:0]; AND : Destination <= Source1 & Source2; OR : Destination <= Source1 | Source2; NOT : Destination <= ~ Source1; CMP : Destination <= (Source1 == Source2) ? 32'd1 : 32'd0; - 19 - 现代电子系统设计,课堂讲义, default : Destination <= 32'hxxxxxxxx; endcase end end endmodule 二、寄存器堆 寄存器堆具有三个地址输入端口~一个数据总线输入和两个数据总线输出 端口。内部结构可以用图6-70和图6-71~其中~图6-70表示寄存器堆的读端 口~而图6-71表示写端口。 Read register number 1 Register 0 Register 1M u Read data 1xRegister n – 1 Register n Read register number 2 M u Read data 2x 图6-70 寄存器堆读端口 Write C0Register 01D n-to-1 CRegister numberdecoderRegister 1 Dn – 1 n CRegister n – 1 D CRegister n DRegister data 图6-71 寄存器堆写端口 由此可以得到寄存器堆的Verilog HDL描述~参见程序6-7。寄存器堆设计 - 20 - 现代电子系统设计,课堂讲义, 中~假定0号寄存器总是0值~且不能写入。 【程序6-7】 `timescale 1 ns / 1 ns module GeneralPurposeRegister( nReset, 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] GPRs[31:1]; integer i; always @(negedge nReset or posedge Write) begin if(!nReset) for(i = 1; i <= 31; i = i + 1) GPRs[i] <= 32'd0; else if(WriteAddress != 5'd0) GPRs[WriteAddress] <= WriteData; end assign ReadData1 = (| ReadAddress1) ? GPRs[ReadAddress1] : 32'd0; assign ReadData2 = (| ReadAddress2) ? GPRs[ReadAddress2] : 32'd0; endmodule - 21 - 现代电子系统设计,课堂讲义, 三、程序计数器 程序计数器输入一个Branch用于判断是否发生跳转~如果发生跳转时~将程序计数器当前值加上输入的偏移量PCBias作为下一条指令的地址,而如果没有跳转发生时~直接将程序计数器加1。这里需要注意~这里的程序计数器设计时考虑采用的是存储器的字地址~所以增值是1~而不是前面图6-65中的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(!nReset) PCValue <= 32'd0; else if(Branch) PCValue <= PCValue + PCBias; else PCValue <= PCValue + 1; end endmodule 四、总线接口单元 总线接口单元只是一些三态缓冲器~所以直接在SimpleRISC处理器的顶层设计中实现~而这里就不专门进行设计。 五、控制器 控制器需要根据不同的指令~产生不同的控制信号~以控制数据通路中的部件能同步工作~并且使得数据通路中相应的数据选择器作出正确的选择。 - 22 - 现代电子系统设计,课堂讲义, 这里的控制器比较复杂~使用一个有限状态机来实现~图6-72给出了控制器的状态转移图。 图6-72 控制器状态转移图 从图中可以看出~SimpleRISC处理器的控制器具有5个状态。起始状态是取指状态Fetch~ Fetch状态使得指令存储器的读控制信号有效~从而取到要执行的指令。取到指令之后~要对其进行译码~所以进入了第二个指令译码状态Decode~Decode根据前一状态取到的指令进行译码操作~产生相应的数据选择器选择信号等控制信号。指令译码之后~进入指令执行状态Execute~这一步大多数指令使用ALU进行运算~然后根据指令类型选择是进行存储器操作还是直接将运算结果写回寄存器堆。对于存储器访问指令~执行状态之后计算出进行存储器访问的地址~之后进入存储器访问状态Memory进行相应的存储器操作。对于其他不需要进行存储器访问的指令~直接进入寄存器回写状态Write~将计算结果写回寄存器。 程序6-9是控制器的Verilog实现。 【程序6-9】 `timescale 1 ns / 1 ns module Controller( nReset, Clock, Instruction, ALUClock, GPRClock, PCClock, - 23 - 现代电子系统设计,课堂讲义, ALUCode, ALUSourceSelect, MemToReg, RegToMem, Branch, UnconditionalBranch, RegSrc, RegDst, i_Read, d_Read, d_Write ); input nReset, Clock; input [16:0] Instruction; 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, UnconditionalBranch; reg RegSrc, RegDst; reg i_Read, d_Read, d_Write; parameter ADD = 4'd0, SUB = 4'd1, SLT = 4'd2, SL = 4'd3, SR = 4'd4, AND = 4'd5, - 24 - 现代电子系统设计,课堂讲义, OR = 4'd6, NOT = 4'd7, CMP = 4'd8; parameter Fetch = 5'b00001, Decode = 5'b00010, Execute = 5'b00100, Memory = 5'b01000, Write = 5'b10000; reg [5:0] OperationCode; reg [4:0] State; always @(negedge nReset or posedge Clock) begin if(!nReset) begin ALUClock <= 1'b0; GPRClock <= 1'b0; PCClock <= 1'b0; ALUCode <= 4'b0000; ALUSourceSelect <= 2'b00; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b0; i_Read <= 1'b0; - 25 - 现代电子系统设计,课堂讲义, d_Read <= 1'b0; d_Write <= 1'b0; OperationCode <= 6'b000000; State <= Fetch; end else begin case(State) Fetch : begin ALUClock <= 1'b0; GPRClock <= 1'b0; PCClock <= 1'b0; ALUCode <= 4'b0000; ALUSourceSelect <= 2'b00; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b0; i_Read <= 1'b1; d_Read <= 1'b0; d_Write <= 1'b0; OperationCode <= 6'b000000; State <= Decode; - 26 - 现代电子系统设计,课堂讲义, end Decode : begin if(Instruction[5:0] == 6'b000000) // R-Type begin if(Instruction[16:6] == 11'h001) // add begin ALUCode <= ADD; ALUSourceSelect <= 2'b00; RegDst <= 1'b1; end else if(Instruction[16:6] == 11'h002) // sub begin ALUCode <= SUB; ALUSourceSelect <= 2'b00; RegDst <= 1'b1; end else if(Instruction[16:6] == 11'h003) // slt begin ALUCode <= SLT; ALUSourceSelect <= 2'b00; RegDst <= 1'b1; end else if(Instruction[16:6] == 11'h004) // and begin ALUCode <= AND; - 27 - 现代电子系统设计,课堂讲义, ALUSourceSelect <= 2'b00; RegDst <= 1'b1; end else if(Instruction[16:6] == 11'h005) // or begin ALUCode <= OR; ALUSourceSelect <= 2'b00; RegDst <= 1'b1; end else if(Instruction[16:6] == 11'h006) // not begin ALUCode <= NOT; ALUSourceSelect <= 2'b11; RegDst <= 1'b1; end else // unimplement begin ALUCode <= ADD; ALUSourceSelect <= 2'b11; RegDst <= 1'b0; end MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; - 28 - 现代电子系统设计,课堂讲义, end else begin if(Instruction[5:0] == 6'b000001) // addi begin ALUCode <= ADD; ALUSourceSelect <= 2'b10; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else if(Instruction[5:0] == 6'b000010) // subi begin ALUCode <= SUB; ALUSourceSelect <= 2'b10; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else if(Instruction[5:0] == 6'b000011) // slti - 29 - 现代电子系统设计,课堂讲义, begin ALUCode <= SLT; ALUSourceSelect <= 2'b01; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else if(Instruction[5:0] == 6'b000100) // andi begin ALUCode <= AND; ALUSourceSelect <= 2'b01; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else if(Instruction[5:0] == 6'b000101) // ori begin ALUCode <= OR; ALUSourceSelect <= 2'b01; MemToReg <= 1'b0; - 30 - 现代电子系统设计,课堂讲义, RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else if(Instruction[5:0] == 6'b000111) // load begin ALUCode <= ADD; ALUSourceSelect <= 2'b10; MemToReg <= 1'b1; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else if(Instruction[5:0] == 6'b001000) // store begin ALUCode <= ADD; ALUSourceSelect <= 2'b10; MemToReg <= 1'b0; RegToMem <= 1'b1; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b1; - 31 - 现代电子系统设计,课堂讲义, RegDst <= 1'b0; end else if(Instruction[5:0] == 6'b001001) // branch begin ALUCode <= ADD; ALUSourceSelect <= 2'b11; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b1; UnconditionalBranch <= 1'b1; RegSrc <= 1'b0; RegDst <= 1'b0; end else if(Instruction[5:0] == 6'b001010) // beq begin ALUCode <= CMP; ALUSourceSelect <= 2'b00; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b1; UnconditionalBranch <= 1'b0; RegSrc <= 1'b1; RegDst <= 1'b0; end else if(Instruction[5:0] == 6'b001011) // sl begin - 32 - 现代电子系统设计,课堂讲义, ALUCode <= SL; ALUSourceSelect <= 2'b01; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else if(Instruction[5:0] == 6'b001100) // sr begin ALUCode <= SR; ALUSourceSelect <= 2'b01; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b1; end else // unimplement begin ALUCode <= ADD; ALUSourceSelect <= 2'b11; MemToReg <= 1'b0; RegToMem <= 1'b0; - 33 - 现代电子系统设计,课堂讲义, Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b0; end end i_Read <= 1'b0; OperationCode <= Instruction[5:0]; State <= Execute; end Execute : begin ALUClock <= 1'b1; if(OperationCode == 6'b000111) // load State <= Memory; else if(OperationCode == 6'b001000) // store State <= Memory; else // others State <= Write; end Memory : begin ALUClock <= 1'b0; if(OperationCode == 6'b000111) // load d_Read <= 1'b1; else if(OperationCode == 6'b001000) // store - 34 - 现代电子系统设计,课堂讲义, d_Write <= 1'b1; State <= Write; end Write : begin PCClock <= 1'b1; GPRClock <= 1'b1; d_Write <= 1'b0; State <= Fetch; end default : begin ALUClock <= 1'b0; GPRClock <= 1'b0; PCClock <= 1'b0; ALUCode <= 3'd0; ALUSourceSelect <= 2'd0; MemToReg <= 1'b0; RegToMem <= 1'b0; Branch <= 1'b0; UnconditionalBranch <= 1'b0; RegSrc <= 1'b0; RegDst <= 1'b0; i_Read <= 1'b0; d_Read <= 1'b0; d_Write <= 1'b0; - 35 - 现代电子系统设计,课堂讲义, OperationCode <= 6'd0; State <= Fetch; end endcase end end endmodule 下面针对控制器的Verilog程序~详细介绍各个状态的工作过程。在介绍控制器各个状态之前~首先需要了解控制器程序外部信号接口和内部信号。 输入端口: ? nReset——复位输入端~连接到系统复位上~低电平有效。 ? Clock——时钟输入端~连接到系统时钟上~上升沿有效。 ? Instruction——指令输入端~只连接到指令输入的低16位~因为根据指令编码格式~只有指令的低16位参与控制~而高16位是作为寄存器地址或立即数等~并没有参与控制。 输出端口: ? ALUClock——ALU操作控制信号~当产生ALUClock的上升沿时~ALU将计算结果输出。 ? GPRClock——寄存器堆写控制信号。 ? PCClock——程序计数器增值控制信号。 ? ALUCode——ALU操作码~ALU根据这个操作码执行相应的操作。 ? ALUSourceSelect——ALU的第二个源操作数选择控制信号。 ? MemToReg——数据存储器到寄存器加载控制信号。 ? RegToMem——寄存器到数据存储器总线控制信号。 ? Branch——指示是否为分支指令~包括无条件分支指令和相等则分支指令都会使Branch信号有效。 - 36 - 现代电子系统设计,课堂讲义, ? UnconditionalBranch——指示是否为无条件分支指令。 ? RegSrc——寄存器堆读端口地址的选择。 ? RegDst——寄存器堆写端口地址的选择。 ? i_Read——指令存储器读控制信号。 ? d_Read——数据存储器读控制信号。 ? d_Write——数据存储器写控制信号。 内部信号: ? 与输出端口相应的reg型信号分别对应相应的输出端口。 ? OperationCode——指令的最低六位~对于所有指令~这六位都作为有效的控制信号。 ? State——状态信号~用于保存控制器的当前操作状态。 1、复位操作 复位信号nReset有效时~内部各寄存器都进行复位~同时将控制器的状态设臵为第一个状态——取指令Fetch。这样~复位结束后~控制器就开始取出指令~然后进行后面的操作。 2、取指令Fetch 控制器首先进行的第一步操作就是取指令操作。取指令这一步只需要将指令寄存器读控制信号i_Read设臵为有效即可~这时读出的指令是当前PC所指地址处的指令。取指令结束后~就可以开始进行指令译码操作~所以状态转移到Decode状态。 3、指令译码Decode 在指令译码状态~控制器状态机根据前面取到的指令~对其进行译码。译码的结果用于产生寄存器堆的读、写地址的选择~ALU的源操作数选择和操作代码~存储器端口控制以及分支控制。对于不同的指令~这些控制信号各不相同~下面分别进行说明。 ? RegSrc:用于寄存器堆读端口2地址的选择。根据指令编码格式~只有 - 37 - 现代电子系统设计,课堂讲义, store指令和beq指令使用指令的第27位到第31位作为寄存器堆读端口2的地址~而其余的指令都使用指令的第17位到第21位作为寄存器堆读端口2的地址。 ? RegDst:用于寄存器堆写端口地址的选择。同样~根据指令编码格式~只有store指令、branch指令和beq指令不需要写回~这时设臵其寄存器堆写端口地址为零,而且对所有的未定义指令~为了避免产生误操作~也将其寄存器堆写端口地址设臵为零,其余指令的寄存器堆写端口地址使用指令的第27位到第31位。 ? MemToReg:数据存储器到寄存器加载控制信号~用于选择寄存器堆的写数据来源~只有load指令选择来自存储器的数据~而其余指令都选择来自ALU的输出。 ? ALUCode:这个信号用于控制ALU进行操作~对于加法指令、取数据指令、存储数据指令、无条件分支指令以及其他指令集外的未定义指令~ALUCode都设臵为进行加法操作。而对于这些指令以外的指令集中的指令~则设臵为相应的操作~需要注意~对于相等则分支指令ALUCode需要设臵为CMP~以进行相等比较。 ? ALUSourceSelect:ALU的第二个源操作数选择控制信号~ALU的第二个源操作数可以有四种选择~分别是寄存器堆的数据、指令中16位立即数符号扩展的结果、指令中16位立即数或5位立即数无符号扩展的结果或是全零。除了not指令以外的寄存器指令和beq指令都使用寄存器堆的数据,addi指令、subi指令、load指令和store指令都使用符号扩展的结果,slti指令、andi指令、ori指令、sl指令和sr指令使用的是无符号扩展的结果,not指令、branch指令以及所有的未定义指令都使用零作为ALU的第二个源操作数。 ? Branch:无条件分支及条件分支指令的Branch都输出有效~而其余指令输出Branch无效。 ? UnconditionalBranch:只有无条件分支指令的UnconditionalBranch - 38 - 现代电子系统设计,课堂讲义, 输出有效~而其余指令输出UnconditionalBranch无效。 除了以上控制信号外~还需要将指令存储器的读控制信号i_Read撤销~同时要将指令的低6位保存起来~下面的状态还会用到。指令译码之后~就进入到执行状态。 4、执行指令Execute 由于指令译码时已经做好了大部分的准备工作~所以执行指令变得很简单~直接产生一个ALU的输出时钟即可。实际上~在刚才译码的过程中~ALU已经将运算结果计算出来了~只是没有输出到ALU的输出端口。在执行阶段~还将根据译码状态保存的操作码,指令的低6位,来决定下一步是进行存储器操作还是直接进行写回操作。只有load和store指令需要进行存储器操作~而其余指令直接进入写回操作状态。需要注意~下面将会看到~写回操作还涉及到PC的修改~所以即使是分支指令,不需要写寄存器堆,也需要进行写回操作。 5、存储器操作Memory 存储器操作状态根据是load指令还是store指令~来决定是让数据存储器的读控制信号d_Read还是让数据存储器的写控制信号d_Write有效。存储器操作后~不论是load指令还是store指令都进入写回状态。 6、寄存器写回Write 写回状态主要产生寄存器堆写控制信号和程序计数器的写控制信号。 设计好前面这些功能模块后~就可以根据SimpleRISC处理器的数据通路~将这些部件连接起来~实现SimpleRISC处理器。程序6-10是SimpleRISC处理器的顶层设计模块。 【程序6-10】 `timescale 1 ns / 1 ns module SimpleRISC( nReset, Clock, i_Address, i_Data, i_Read, - 39 - 现代电子系统设计,课堂讲义, d_Address, d_Data, d_Read, d_Write ); input nReset, Clock; input [31:0] i_Data; output [31:0] i_Address, d_Address; output i_Read, d_Read, d_Write; inout [31:0] d_Data; wire [31:0] instruction; wire [15:0] imm16; wire [25:0] imm26; assign instruction = i_Data; assign imm16 = instruction[21:6]; assign imm26 = instruction[31:6]; wire PCClock, Branch; wire [31:0] PCBias; ProgramCounter PC( .nReset(nReset), .Clock(PCClock), .Branch(Branch), .PCBias(PCBias), .PCValue(i_Address) ); wire GPRClock; wire [4:0] GPRWriteAddr, GPRReadAddr1, GPRReadAddr2; - 40 - 现代电子系统设计,课堂讲义, wire [31:0] GPRWriteData, GPRReadData1, GPRReadData2; assign GPRReadAddr1 = instruction[26:22]; GeneralPurposeRegister GPR( .nReset(nReset), .Write(GPRClock), .WriteAddress(GPRWriteAddr), .WriteData(GPRWriteData), .ReadAddress1(GPRReadAddr1), .ReadAddress2(GPRReadAddr2), .ReadData1(GPRReadData1), .ReadData2(GPRReadData2) ); wire ALUClock; wire [3:0] ALUCode; wire [1:0] ALUSourceSelect; wire [31:0] ALUSource2; wire [31:0] ALUOut; ArithmeticLogicUnit ALU( .nReset(nReset), .Clock(ALUClock), .OperationCode(ALUCode), .Source1(GPRReadData1), .Source2(ALUSource2), .Destination(ALUOut) ); wire [31:0] UnsignedImm32; UnsignExtend U1(.Din(imm16), .Dout(UnsignedImm32)); wire [31:0] SignedImm32; SignExtend #(16) U2(.Din(imm16), .Dout(SignedImm32)); - 41 - 现代电子系统设计,课堂讲义, assign ALUSource2 = (ALUSourceSelect == 2'b00) ? GPRReadData2 : ((ALUSourceSelect == 2'b01) ? UnsignedImm32 : ((ALUSourceSelect == 2'b10) ? SignedImm32 : 32'd0)); wire [31:0] PCBias32; SignExtend #(26) U3(.Din(imm26), .Dout(PCBias32)); wire MemToReg; wire RegToMem; assign d_Data = RegToMem ? GPRReadData2 : 32'hzzzzzzzz; assign GPRWriteData = MemToReg ? d_Data : ALUOut; assign d_Address = ALUOut; wire RegSrc, RegDst; wire UnconditionalBranch; wire BranchEnable; Controller CU( .nReset(nReset), .Clock(Clock), .Instruction(instruction[16:0]), .ALUCode(ALUCode), .PCClock(PCClock), .MemToReg(MemToReg), .RegToMem(RegToMem), .Branch(BranchEnable), .UnconditionalBranch(UnconditionalBranch), .ALUClock(ALUClock), .ALUSourceSelect(ALUSourceSelect), .GPRClock(GPRClock), .RegSrc(RegSrc), .RegDst(RegDst), .i_Read(i_Read), .d_Read(d_Read), .d_Write(d_Write) - 42 - 现代电子系统设计,课堂讲义, ); assign PCBias = UnconditionalBranch ? PCBias32 : SignedImm32; assign Branch = (UnconditionalBranch || (BranchEnable && ALUOut[0])); assign GPRReadAddr2 = RegSrc ? instruction[31:27] : instruction[21:17]; assign GPRWriteAddr = RegDst ? instruction[31:27] : 5'd0; endmodule 6.4.8 SimpleRISC应用系统 前面已经设计好了SimpleRISC处理器~这里需要使用SimpleRISC处理器 来设计一个处理器系统。一个完整的处理器系统应该包括至少中央处理器和存 储器~这里的中央处理器就是我们刚才设计的SimpleRISC处理器~而还需要设 计存储器~包括程序存储器和数据存储器,在我们设计的处理器系统中~还包 含一个用于输出的端口~SimpleRISC处理器把这个输出端口作为数据存储器来 访问。 在设计我们的SimpleRISC处理器系统之前~首先应该确保前面设计的 SimpleRISC处理器能正常工作~所以下面要做的第一项工作就是测试我们刚设 计的SimpleRISC处理器。 一、SimpleRISC处理器测试 SimpleRISC处理器测试应该包括所有指令的测试~这里选取几条指令进行 测试。首先让SimpleRISC处理器执行以下指令序列: 【SimpleRISC指令序列1】 - 43 - 现代电子系统设计,课堂讲义, ?addi r1~r0~0x4000 ?addi r2~r0~0x2000 ?add r3~r1~r2 here: ?branch here 以上指令序列中~第?条指令是将立即数0x4000的值保存在1号寄存器,r1,中,同样~第?条令是将立即数0x2000的值保存在2号寄存器,r2,中,而第?条指令是将1号寄存器的值和2号寄存器的值相加~和存放在3号寄存器,r3,中,第?条指令相当于让处理器停机,当前位臵跳转,。 根据指令的编码格式及寄存器编号的原则~上述指令序列可以用以下的十六进制代码表示~这些十六进制代码即是以上指令序列的机器码。 ?0x08100001~?0x10080001~?0x18440040~?0x00000009 将这些机器码作为指令输入~并将上面设计的SimpleRISC处理器进行综合、适配~然后在Quartus II中进行仿真~得到如图6-73所示的仿真结果。 图6-73 SimpleRISC指令序列1仿真结果 图中的最后三行的信号分别是寄存器堆中的r1、r2和r3。 上面的指令序列主要测试了寄存器指令和立即数指令的操作~以下再对移位指令、逻辑运算指令和存储器访问指令进行测试。为此~让SimpleRISC处理器执行以下指令序列: 【SimpleRISC指令序列2】 ?ori r1~r0~0x2000 - 44 - 现代电子系统设计,课堂讲义, ?store r1~r0~0x80 ?sl r2~r1~8 ?load r3~r1~0 ?and r1~r2~r3 here: ?branch here 以上指令序列中~第?条指令使用立即数或操作给寄存器r1设臵初始值0x2000,第?条指令将r1的值存储到数据存储器的0x80单元,第?条指令对寄存器r1左移8位~并把左移的结果存放在寄存器r2中,第?条指令读取寄存器r1所指向的数据存储器单元的数据~并将这个数据存放在寄存器r3中,第?条指令对寄存器r2和r3的值进行逻辑与操作~与的结果存放在寄存器r1中,第?条指令同样是停机指令。 将以上指令序列翻译成机器码以后~结果如下: ?0x08080005~?0x08002008~?0x1040020B~?0x18400007~?0x08860100~?0x00000009。 在Quartus II中进行仿真~得到如图6-74所示的仿真结果。 图6-74 SimpleRISC指令序列2仿真结果 对于其他指令~也可以采用同样的方式进行仿真。 二、存储器模块设计 SimpleRISC处理器系统的存储器模块包括数据存储器和程序存储器~程序6-11和程序6-12分别是SimpleRISC处理器的数据存储器和程序存储器的 - 45 - 现代电子系统设计,课堂讲义, Verilog HDL程序。 【程序6-11】 `timescale 1 ns / 1 ns module Memory(Enable, Read, Write, Address, Data); input Enable, Read, Write; input [3:0] Address; inout [31:0] Data; reg [31:0] RAM[0:15]; assign Data = (Enable & Read) ? RAM[Address] : 32'hzzzzzzzz; always @(posedge Write) if(Enable) RAM[Address] <= Data; endmodule 【程序6-12】 `timescale 1 ns / 1 ns module Program(Clock, Address, Data); input Clock; input [31:0] Address; output [31:0] Data; reg [31:0] Data; always @(posedge Clock) begin case(Address) 32'h00000000 : Data <= 32'h000000C9; // branch 0x03 32'h00000001 : Data <= 32'hAAAAAAAA; // unimplement 32'h00000002 : Data <= 32'h55555555; // unimplement 32'h00000003 : Data <= 32'h08000001; // addi r1, r0, 0x40 - 46 - 现代电子系统设计,课堂讲义, 32'h00000004 : Data <= 32'h0840040B; // sl r1, r1, 16 32'h00000005 : Data <= 32'h10003FC1; // addi r2, r0, 0xff 32'h00000006 : Data <= 32'h18000281; // addi r3, r0, 10 32'h00000007 : Data <= 32'h10400008; // store r2, r1, 0 32'h00000008 : Data <= 32'h18C00042; // subi r3, r3, 1 32'h00000009 : Data <= 32'h00000009; // branch 0x09 …… default : Data <= 32'h00000000; endcase end endmodule 三、输出端口设计 输出端口作为SimpleRISC处理器的外部数据存储器来访问~所以具有一个 参数:端口地址~即是SimpleRISC处理器访问时所使用的地址。输出端口的设 计比较简单~参见程序6-13。 【程序6-13】 `timescale 1 ns / 1 ns module OutputPort(Clock, Address, Din, Dout); parameter base = 32'h40000000; input Clock; input [31:0] Address; input [31:0] Din; output [31:0] Dout; reg [31:0] Dout; always @(posedge Clock) if(Address == base) Dout <= Din; - 47 - 现代电子系统设计,课堂讲义, endmodule 四、SimpleRISC处理器系统设计 将以上设计好的SimpleRISC处理器、数据和程序存储器以及输出端口连接 在一起~即可实现简单的SimpleRISC处理器系统。该系统只能通过端口输出数 据~可以用于一些只需要输出的系统~比如状态显示等。设计好的SimpleRISC 处理器系统参见程序6-14~其综合后的RTL电路见图6-75。 【程序6-14】 `timescale 1 ns / 1 ns module System(nReset, Clock, GPOA, GPOB, GPOC, GPOD); input nReset, Clock; output [7:0] GPOA, GPOB, GPOC, GPOD; wire [31:0] i_Address, d_Address, i_Data, d_Data; wire i_Read, d_Read, d_Write; SimpleRISC cpu( .nReset(nReset), .Clock(Clock), .i_Address(i_Address), .i_Data(i_Data), .i_Read(i_Read), .d_Address(d_Address), .d_Data(d_Data), .d_Read(d_Read), .d_Write(d_Write) ); - 48 - 现代电子系统设计,课堂讲义, Program rom( .Clock(i_Read), .Address(i_Address[7:0]), .Data(i_Data) ); Memory ram( .Enable(d_Address[4]), .Read(d_Read), .Write(d_Write), .Address(d_Address[3:0]), .Data(d_Data) ); wire [31:0] GPO; OutputPort io( .Clock(d_Write), .Address(d_Address), .Din(d_Data), .Dout(GPO) ); assign GPOA = GPO[7:0]; assign GPOB = GPO[15:8]; assign GPOC = GPO[23:16]; - 49 - 现代电子系统设计,课堂讲义, assign GPOD = GPO[31:24]; endmodule 图6-75 SimpleRISC处理器系统RTL电路 选用EP1C6Q240C8芯片~将设计好的系统使用Quartus II综合、适配后~占用逻辑资源数目为2874个LE和8704 bits存储器资源~最大运行速度为41.37MHz。 五、测试程序设计 综合、适配结束后~需要对设计好的SimpleRISC处理器系统进行全面的测试~所以需要编写SimpleRISC处理器系统的测试程序。测试程序中应包含对几乎所有指令的测试~还应包含对端口及存储器的测试。由于该处理器系统只有一个输出端口~所以只需要编写一个简单的跑马灯程序即可测试所有功能。 由于我们设计的SimpleRISC处理器没有相应的编译器或汇编器~所以测试程序只能使用机器语言来进行编写。为了简单起见~我们首先采用C语言来编写测试程序~然后将编写好的C程序手工汇编成汇编程序~最后再根据指令编码格式将汇编代码转化成机器代码。 以下程序是跑马灯的C程序代码: 【跑马灯的C程序代码】 void main(void) { int delay; PORTA = 0x00; PORTA = 0xFF; - 50 - 现代电子系统设计,课堂讲义, delay = 100; while(delay--); PORTA = 0x00; while(1) { for(i = 0; i < 8; i++) { PORTA = 1 << i; delay = 50; while(delay--); } } return 0; } 将其使用SimpleRISC的汇编语言进行手工编译~得到以下的汇编代码: 【跑马灯的SimpleRISC汇编代码】 // 加载端口地址 addi $1, $0, 0x4000 sl $1, $1, 16 // 端口A输出全0 store $0, $1, 0x0 // 端口A输出全1 addi $2, $0, 0xff store $2, $1, 0x0 // 设臵延时变量delay = 100 = 0x64 addi $2, $0, 0x64 - 51 - 现代电子系统设计,课堂讲义, // 进行延时 rpt1: subi $2, $2, 0x1 beq $2, $0, end_delay1 branch rpt1 end_delay1: // 端口A输出全0 store $0, $1, 0x0 // 开始主循环 main_loop: // 初始化for循环变量 addi $2, $0, 0x1 addi $3, $0, 0x100 // 开始for循环 for_loop: // 判断循环条件 beq $2, $3, main_loop // 端口输出 store $2, $1, 0x0 // 设臵延时变量delay = 50 = 0x32 addi $4, $0, 0x32 // 进行延时 rpt2: subi $4, $4, 0x1 beq $4, $0, end_delay2 branch rpt2 - 52 - 现代电子系统设计,课堂讲义, end_delay2: // 更新循环变量 sl $2, $2, 0x1 // 继续循环 branch for_loop 汇编代码中的$1表示寄存器r1~相应的$2表示寄存器r2~其余的依此类推。 得到汇编代码后~就可以根据SimpleRISC处理器的指令编码格式~以及寄存器的编号方式等~将汇编代码转化成SimpleRISC处理器可以直接执行的机器码。以下指令序列即为跑马灯的SimpleRISC处理器的二进制机器码~前面的数值表示指令的地址~用两位十六进制表示~地址后的数字是该地址处的指令~使用8位十六进制表示~“—”后的内容为注释~注释中将对应的汇编代码也写上了。 【跑马灯的SimpleRISC机器码】 -- start: 00 : 08100001; -- addi $1, $0, 0x4000 01 : 0840040B; -- sl $1, $1, 16 02 : 00400008; -- store $0, $1, 0x0 03 : 10003FC1; -- addi $2, $0, 0xFF 04 : 10400008; -- store $2, $1, 0x0 05 : 10001901; -- addi $2, $0, 0x64 -- rpt1: 06 : 10800042; -- subi $2, $2, 0x1 07 : 1000008A; -- beq $2, $0, end_delay1 08 : FFFFFF89; -- branch rpt1 -- end_delay1: - 53 - 现代电子系统设计,课堂讲义, 09 : 00400008; -- store $0, $1, 0x0 -- main_loop: 0A : 10000041; -- addi $2, $0, 0x1 0B : 18004001; -- addi $3, $0, 0x100 -- for_loop: 0C : 10FFFF8A; -- beq $2, $3, main_loop 0D : 10400008; -- store $2, $1, 0x0 0E : 20000C81; -- addi $4, $0, 0x32 -- rpt2: 0F : 21000042; -- subi $4, $4, 0x1 10 : 2000008A; -- beq $4, $0, end_delay2 11 : FFFFFF89; -- branch rpt2 -- end_delay2: 12 : 1080004B; -- sl $2, $2, 0x1 13 : FFFFFE49; -- branch for_loop 14 : FFFFFB09; -- branch start 15 : 00000009; -- branch . 其中最后一行的“branch .”表示停机。 得到机器码以后~将其设计成为SimpleRISC处理器的程序存储器~然后连接到系统中~重新进行综合、适配。综合、适配完成后~就可以开始进行测试了。 六、测试结果 测试时~由于代码已经存放在程序存储器中~所以只需要加入时钟和复位信号即可进行仿真。仿真结果参见图6-76。 这里为了提高仿真效率~使用了ModelSim来进行仿真。仿真测试文件的编写比较简单~只需要输出复位和时钟两个信号~这里略去。需要主要的是~由 - 54 - 现代电子系统设计,课堂讲义, 于进行的是时序仿真~时钟必须要满足时序分析的结果~即最大时钟频率不能超过41.37MHz。 图6-76 跑马灯程序在SimpleRISC处理器系统上的运行结果 - 55 -
/
本文档为【6&#46;4 简单RISC处理器设计】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索