华科组成原理课程设计MIPS流水线CPU

时间:2022-12-26 08:00:02 浏览量:

计算机科学与技术学院 2014 计算机组成原理 课程设计报告 题 目:
支持流水线的简单计算机系统设计与实现 专 业:
计算机科学与技术 班 级:
学 号:
姓 名:
电 话:
邮 件:
实 验 台:
完成日期:
指导教师:
目录 一、课程设计概述 3 1 课设目的 3 2 实验环境 3 3 设计任务与要求 3 二、设计原理 3 1 MIPS概述 3 2 MIPS指令简介 3 3 经典5段RSIC流水线结构 4 三、设计内容 5 1 指令选取 5 2 非流水5段CPU模型 6 3 流水5段CPU模型 8 四、实现内容与测试结果 12 1 各模块功能 12 2 控制信号 12 3 指令操作流程 13 4 指令执行状态转换图 14 5 引脚绑定 15 6 测试程序 15 7 测试结果与仿真图 16 五、课设总结 17 1 课设中遇到的问题 17 2 课设经历 17 3 课设感想 18 4 小组分工 18 参考文献 18 一、 课程设计概述 1. 课设目的 ① 掌握硬件描述语言与开发环境,了解硬件开发地基本过程。

② 掌握流水线CPU设计方法。

③ 锻炼学生简单计算机系统的设计能力,并通过进行主机系统低层电路的实现、故障分析与定位、系统调试等环节的锻炼,进一步提高了学生分析和解决问题的能力。

2. 实验环境 ① Xilinx ISE 14.2 ② Spartan3E实验板一块 3. 设计任务与要求 课程设计的主要任务是设计一台支持流水线的简单计算机系统并调试通过。要求所设计的计算机系统能正确地执行存放在指令cache中的程序的功能。

本设计基于MIPS的32位流水线架构,设计过程中力图尽可能的遵循原有的MIPS的功能和指令集。基本做到与MIPS指令集的兼容。

具体要求包括:
① 支持算术运算,逻辑运算,存储器读写,寄存器间数据传送等几类指令。

② 支持立即数寻址,直接寻址,寄存器寻址等几种基本的数据寻址方式和顺序寻址、跳跃寻址两种指令的寻址方式。

③ 支持10条或以上的指令。

④ 能运行由自己所设计的指令系统构成的一段程序,程序执行功能正确。

⑤ 具有完整的五级流水线架构。采用独立的32位的数据总线和地址总线。

二、 设计原理 1. MIPS概述 MIPS是高效的RISC体系结构中最优雅的一种体系结构。其中文意思为“无内部互锁流水级的微处理器”,其机制是尽量利用软件办法避免流水线中的数据相关问题。它最早是在80年代初期由斯坦福大学Hennessy教授领导的研究小组研制出来的。MIPS公司的R系列就是在此基础上开发的RISC工业产品的微处理器。这些系列产品为很多计算机公司采用构成各种工作站和计算机系统。

本设计将参考MIPS的CPU设计以实现自己的五段流水线CPU设计,并部分实现MIPS32指令集 2. MIPS指令简介 2.1 MIPS指令集特点 MIPS指令集具有以下特点:
① 简单的LOAD/STORE结构。所有计算类型指令均从寄存器组中读取数据并把结果写入寄存器组中。只有LOAD和STORE指令访问存储器(数据cache)。

② 易于流水线CPU的设计。MIPS指令集的指令格式非常规整,所有的指令均为32位,而且指令操作码在固定的位置上。

③ 易于编译器的开发。一般情况下,编译器在编译高级语言程序时,很难用到复杂的指令。MIPS指令的寻址方式与操作非常简单,便于编译器的开发。

2.2 MIPS指令格式 在本次课程设计中,在数据类型上只支持整数类型,在指令格式上直接R、I和J型指令。以下是对三型指令的简介[1]:
① R(register)类型的指令从寄存器组中读取两个源操作数,计算结果写回寄存器组。

② I(immediate)类型的指令使用一个16位的立即数作为一个源操作数。

③ J(jump)类型的指令使用一个26位立即数作为跳转的目标地址。

三型指令的格式如图1所示,其中:
① op表示指令操作码。

② rs为源操作数的寄存器号。

③ rd为目的寄存器号,RT既可为源寄存器号,也可为目的寄存器号。

④ funct可认为是扩展的操作码。

⑤ shamte由移位指令使用,定义移位位数。

⑥ Immediate是16位立即数,根据指令需求进行无符号或有符号扩展。

⑦ Address是26位立即数,由J型指令使用,用于产生跳转的目的地址。

图1. MIPS的指令格式 3. 经典5段RSIC流水线结构 经典的5段RISC流水线如图2。

图2. 经典5段RISC流水线 在该结构中一条指令的执行过程分为以下5个时钟周期:
① 取指令周期(IF):以程序计数器PC中的内容作为地址,从存储器中取出指令并放入指令寄存器IR;
同时PC值加4(假设每条指令占4个字节),指向顺序的下一条指令。

② 指令译码/读寄存器周期(ID):对指令进行译码,并用IR中的寄存器地址去访问通用寄存器组,读出所需的操作数。

③ 执行/有效地址计算周期(EX):在这个周期,ALU对在上一个周期准备好的操作数进行运算或处理。不同指令所进行的操作不同。

④ 存储器访问/分支完成周期(MEM):load指令用上一个周期计算出的有效地址从存储器中读出相应的数据;
store指令把指定的数据写入这个有效地址所指出的存储器单元;
分支指令若分支成功就把钱一个周期中计算好的转移目标地址送入PC,否则不进行任何操作;
其他类型的指令在该周期不做任何操作。

⑤ 写回周期(WB):把结果写入通用寄存器组。

本设计基于该经典5端流水线结构完成了MIPS的一种简单实现,并在此基础上加入了对流水线冲突(数据冲突,控制冲突)的处理,以及对中断的处理。

三、 设计内容 1. 指令选取 本系统能执行16条MIPS指令,指令基本情况如表1所示。

MIPS指令 助记符 指令格式 操作 Bit # 31..26 25..21 20..16 15..11 10..6 5..0 R-type op rs rt rd shamt func add 000000 rs rt rd 00000 100000 Rd = rs + rt Sub 100010 Rd = rs - rt And 100100 Rd = rs & rt Or 100101 Rd = rs | rt Xor 100110 Rd = rs ^ rt Sllv 000100 Rd = rs << rt srlv 000110 Rd = rs >> rt slt 101010 If (rs < rt) rd=1 else rd=0; I-type op rs rt immdediate Addi 001000 rs rt imm Rt = rs + imm Andi 001100 Rt = rs & imm ori 001101 Rt = rs | imm Xori 001110 Rt = rs ^ imm Bne 000101 If (rs!=rt) pc=pc+1-imm Lw 100011 Rt = mem[rs + imm] sw 101011 Mem[rs + imm] = rt J-type op address j 000010 add Pc=add 表1. 系统支持的MIPS指令集 从指令类型来讲,这16条指令覆盖了算逻运算、访存、无条件跳转和有条件跳转,已基本覆盖一个指令集所需的所有基本指令。

从寻址方式来讲,这16条指令覆盖了寄存器寻址(R-TYPE指令),立即数寻址(I-TYPE指令),基址偏移量寻址(LW/SW),直接寻址(J)。

16条MIPS指令并不是本设计的极限,只是受到实验板资源的限制,我们仅仅完成了MIPS32指令集中的16条而已。本设计通过简单的拓展可以轻松实现整个MIPS32指令集。

2. 非流水5段CPU模型 2.1 初始数据通路 设计往往都是从简单到复杂,循序渐进。好高骛远则往往求之而不得。因此我们并没有从流水线模型直接下手,而是首先设计了一个类似经典5段RISC流水线结构的非流水5段CPU模型。由于不涉及流水,所以所有的指令周期均为单周期,数据通路见图3。

图3. 非流水5段CPU初始数据通路 2.2 5段具体操作 在这个数据通路上每条指令需要花费5个时钟周期,这5个时钟周期相应的操作如下:
2.2.1 取指令周期(IF)
IR←Mem[PC] NPC←PC+1 以PC中的值从指令cache中取出一条指令,放入指令寄存器IR;
同时PC值加1,然后放入NPC,这时NPC中的值为顺序的下调指令的地址。

2.2.2 指令译码/读寄存器周期(ID)
A←Regs[rs] B←Regs[rt] imm←((IR16)16##IR16..31) 对指令进行译码,并以指令中的rs和rt字段作为地址访问通用寄存器组,将读出的数据让如A和B寄存器中。同时IR的低16位进行有符号或者无符号扩展,然后存入Imm寄存器 2.2.3 执行/有效地址计算周期(EX)
① LW和SW指令 ALUo←A+Imm ALU将操作数相加形成有效地址,并存入临时寄存器ALUo ② R-TYPE ALUo←A funct B ALU根据funct字段指出的操作类型对A和B中的数据进行运算,并将结果存入ALUo ③ I-TYPE ALUo←A op Imm ALU根据操作码op指出的操作类型对A和Imm中的数据进行运算,并将结果存入ALUo ④ 分支指令 ALUo←NPC+Imm ALU将临时寄存器NPC和Imm中的值相加得到转移目标的地址,存入ALUo 2.2.4 存储器访问/分支完成周期(MEM)
① LW和SW指令 LW:LMD←Mem[ALUo] 即从存储器中读出相应数据,放入临时寄存器LMD中 SW:Mem[ALUo]←B 即把B中数据写入存储器 ② 分支指令 If (cond) PC←ALUo else PC←NPC 若cond中的内容为真,则将ALUo中的转移目标地址放入PC,否则PC+1。

2.2.5 写回周期(WB)
① R-TYPE Regs[rd]←ALUo ② I-TYPE Regs[rt]←ALUo ③ LW指令 Regs[rt]←LMD 2.3 模型优化与最终数据通路 在这部分设计的时候我们的跳转指令仅仅实现了JNZQ,因此我们对改分支指令进行了单独的优化。在图2的设计中若分支失败,则由于新的PC在EX段产生,因此会产生2个时钟周期的延迟。但实际上可以对这条指令进行单独的改进,将对PC的修改提前到IF段,以便PC值能够快速变化。经过这样优化后,分支失败则只会产生1个时钟周期的延迟。改进后的数据通路如图4所示。

图4. 非流水5段CPU最终数据通路 3. 5段流水CPU模型 3.1 初始数据通路 在实现了非流水的5段CPU模型后,5段流水CPU模型也就水到渠成了。只需要在各段之间加入相应的流水寄存器即可。数据通路如图5。

图5. 5段流水CPU初始数据通路 3.2 5段具体操作 这部分与非流水的具体操作大致相同,这里不加赘述。

3.3 流水线冲突及解决方案 3.3.1 数据冲突 如果上一条指令的结果还没有写入到寄存器中,而下一条指令的原操作数又恰恰是此寄存器的数据,那么它所获得的将是原来的数据,而不是更新后的数据,这样的相关问题称为数据相关。

根据在系统结构中学习到的相关知识,在我们的设计中,采用定向(forwarding)技术来解决此类相关问题。其关键思路是:在发生写后读相关的情况下,在计算结果尚未出来之前,后面等待使用该结果的指令并不见得是马上就要用该结果。如果能够将该计算结果从其产生的地方(ALU出口)直接送到其他指令需要它的地方(ALU的入口),那么就可以避免停顿,如图6。

图6. 定向技术 3.3.2 控制冲突 在流水线中,控制冲突可能会使数据冲突造成更大的性能损失。执行分支指令的结果有两种,一种是“成功”,PC值改变为分支转移的目标地址。另一种则是“失败”,这是PC的值保持正常递增。

本设计中采用预测分支失败的方法解决控制冲突,即允许分支指令后的指令继续在流水线中流动。当确定分支是失败时,可以将分支指令看做一条普通指令,流水线正常流动,如表2;
当确定分支是成功时,流水线就把在分支指令之后取出的指令转化为空操作,并按分支目标地址重新取指令执行,如表3。

分 支 失 败 分支指令i IF ID EX MEM WB 指令i+1 IF ID EX MEM WB 指令i+2 IF ID EX MEM WB 指令i+3 IF ID EX MEM WB 表2. 分支失败的流水线时空图 分 支 成 功 分支指令i IF ID EX MEM WB 指令i+1 IF Idle Idle Idle idle 分支目标指令 IF ID EX MEM WB 分支目标指令+1 IF ID EX MEM WB 表3. 分支成功的流水线时空图 3.4 模型中的问题与修正 3.4.1 指令周期数问题 若是指令周期和之前的设计一样,使用单周期的设计,那么会出现对流水寄存器的读写冲突。

例如对于通用寄存器组来说,在clk上升沿的时候需要从IF段的指令寄存器IR中取出指令,然后访问相应的寄存器并将数据写入ID段的A,B寄存器。试想,若是从IR中取指令,和对ID段的A,B寄存器的写入两个操作都是在clk上升沿触发,那么由于时延的存在,很有可能导致写入的值不是预期值。

因此我们将指令周期从单周期改为双周期。在前一周期完成对流水寄存器的读操作,并且完成各段的功能。后一周期,完成对流水寄存器的写操作。具体实现上我们舍弃了分频的方法而是采用前半周期为clk上升沿触发,后半周期为clk下降沿触发。

3.4.2 译码器问题 通过3.3.1可知,各段功能需要在前一周期内全部完成,但是ID段很特殊,因为有译码器的存在。

通用寄存器组和扩展部件都需要译码器提供控制信号,但是由于3.3.1的限制,译码器也会在clk上升沿触发。由于时延的存在,这可能会导致控制信号产生在需求之后。也即在寄存器组和扩展部件需要控制信号的时候,控制信号还未真正产生,导致这两部件使用了错误的控制信号。

除了这个隐患,还有一个问题就是若采用单独的译码器,那么会在ID段产生大量的控制信号,这些控制信号都需要通过流水线流向下一段,那么势必需要大量的流水寄存器,大幅增加硬件成本。

综合考虑这两个问题之后我们撤掉了译码器,而采用分段译码的方式。即给每个功能部件都提供完整的指令,由各个功能部件自己产生自己所需要的控制信号,这样就可以完美的解决上述两个问题。

3.4.3 针对JNZQ指令的优化问题 在非流水的CPU模型中我们针对JNZQ指令进行了专门的优化,将对分支条件的判断放在了ID段。但是这存在两个问题,一是我们认为这样影响了整体设计的一致性;
二是在流水线CPU的设计中我们加入了新的跳转指令,这使得判断变得更加复杂,ID段分担了太多EX段的功能,会影响整体流水的性能。

因此在流水CPU设计中我们将分支的条件改回在EX段判断。

3.4.4 寄存器组的读写顺序问题 在最初的设计中,我们将寄存器的写回操作放在后半周期,即和流水线寄存器的写操作一同完成。但是在后面的实际测试中我们发现若这样处理,我们在做重定向的时候必须做三次重定向。因此我们对此做了调整,将写回操作提前到前半周期完成,即对寄存器组实现先写后读策略。

3.4.5 写回段的取舍 在最初的设计中,由于我们将寄存器的写回操作放在后半周期,因此我们一度舍弃了写回段。因为写回段仅仅是前半周期读出写回数据,后半周期将数据写回寄存器组,这么简单的功能占据一个流水段显示实在是“奢侈”。因而在最初的设计中我们将其和MEM段合并。

但是3.3.4中对寄存器读写顺序做了调整,因此写回段中的写回操作和EX段的计算操作以及MEM的访存操作在同半个周期内,由于时延的存在很有可能导致写回数据错误。此时若舍弃了写回段则可能在计算结果出来前就写回了,这显然不合理。

因此我们重新加入了写回段。在加入访存段后,由于写回的结果依赖于访存结果,因此放在访存段之后。

3.4.6 特殊指令JNZ的问题 JNZ这条指令在整个指令集中是非常特殊的存在,在之前的设计中我们完全没有考虑到这个问题。

① 虽然JNZ是I-TYPE指令,但是RT却是源寄存器,也即JNZ不会修改RT的值。即它不符合I-TYPE指令在写回段的数据通路Regs[rt]←ALUo。这在做定向的时候会产生严重的问题,若不做特殊判断,那么很可能会产生错误的定向。

② JNZ指令是整个指令集中唯一一个需要4个输入(rega,regb,imm,pc)的指令,其他指令均最多只需要2个输入。这使得EX段的两个选择器完全是多余的,可以去掉。

在考虑到这两点之后我们对重定向进行了重新设计,并且去掉了EX段中的两个选择器。

3.5 硬软中断的实现 3.5.1 软中断的实现 对于软中断,我们实际上通过扩展指令集的方式来实现。即在指令集中加入两条指令,PUSH和POP,来实现软中断。具体指令表4。

R-type op rs rt rd shamt func Pop 111111 00000 00101 00000 00000 00000 J-type op address Push 111110 0000000000000000000001110 表4. Push和Pop指令 当ID段检测到PUSH指令时,将会把所有通用寄存器组的值以及当前PC值压入堆栈。当EX段检测到PUSH指令时,会无条件跳转至指令对对应的地址。

当ID段检测到POP指令时,将会把所有的通用寄存器组的值弹出。当EX段检测到POP指令时,会无条件跳转至堆栈中的PC值对应的地址。

3.5.2 硬中断的实现 对于硬中断我们仅实现了了溢出中断。当EX段出现溢出时,EX段将会向IF段传送相应的控制信号。此时IF段将会产生一条PUSH指令送到IR中,并且PC值维持一周期不变。

这样就相当于向流水线中插入了一条软中断指令,从而实现了用硬件来自动产生中断指令。

3.6 最终数据通路 在成功修改和完善3.4中的问题以及加入3.5中的内容后,我们得到了最后的数据通路图,如图7。

图7. 5段流水CPU最终数据通路图 四、 实现内容与测试结果 1. 各模块功能 模块例化名称 模块实现功能 U1 实现PC的存储与更新 U2 实现指令的存取 U3 实现对通用寄存器的读写 U4 实现对立即数的有符号与无符号扩展 U5 实现ALU U6 实现访存功能 表5. 各模块功能表 2. 控制信号 流水段 控制信号 功能 IF Update_Pc 控制PC更新为PC+1或ALUO ID Reg_Sign 控制通用寄存器组的压栈与弹出 Ex_Sign 控制有符号扩展和无符号扩展 EX Alu_Sign1 控制MUX2的选择 Alu_Sign2 控制MUX3的选择 Alu_Sign3 控制ALU的计算功能 Sel1 控制ALUA端的定向 Sel2 控制ALUB端的定向 MEM Mem_Write 控制MEM的读写 WB Mem_Read 表明MEM的读写状态,控制MUX4的选择 Wb_Sign 控制通用寄存器的写回 表6. 控制信号表 3. 指令操作流程 由于我组实现的指令较多,而很多指令具有较大的相似性,因此这里取ADD, BNE, J, SW四条指令,先做出其各周期的操作及控制信号表[2]。

指令阶段 操作流程 控制信号 IF IR←(M[PC]) Update_Pc = 0 PC←(PC)+1 ID A←(R[IR[25:21]]) Reg_Sign = 00, Ex_Sign = 1, Wb_Sign = 0 B←(R[IR[20:16]]) IR2←IR EX ALUO←(A)+(B) Alu_Sign1 = 0, Alu_Sign2 = 1, Alu_Sign3 = 0000, sel1 = 0, sel2 = 0 IR3←IR2 MEM ALUO2←ALUO Mem_Write = 0 IR4←IR3 WB R[IR4[15:11]]←(ALUO2) Mem_Read = 0, Wb_Sign = 1 表7. ADD指令操作流程及控制信号 指令阶段 操作流程 控制信号 IF IR←(M[PC]) Update_Pc = 0 NPC←(PC)+1 PC←(PC)+1 ID A←(R[IR[25:21]]) Reg_Sign = 00, Ex_Sign = 1 B←(R[IR[20:16]]) IMM←(Sign-extend(IR[15-0])) IR2←IR NPC2←NPC EX if (A!=B) PC←NPC2-IMM Alu_Sign1 = 1, Alu_Sign2 = 0, Alu_Sign3 = 0111, sel1 = 0, sel2 = 0 if (A!=B) Update_Pc = 1 else Update_Pc = 0 表8. BNE指令操作流程及控制信号 指令阶段 操作流程 控制信号 IF IR←(M[PC]) Update_Pc = 0 PC←(PC)+1 ID IMM←(Sign-extend(IR[15-0])) Reg_Sign = 00, Ex_Sign = 1 IR2←IR EX PC←(IMM) Alu_Sign1 = 0, Alu_Sign2 = 0, Alu_Sign3 = 1000, sel1 = 0, sel2 = 0, Update_Pc = 1 表9. J指令操作流程及控制信号 指令阶段 操作流程 控制信号 IF IR←(M[PC]) Update_Pc = 0 PC←(PC)+1 ID A←(R[IR[25:21]]) Reg_Sign = 00, Ex_Sign = 1 B←(R[IR[20:16]]) IMM←(Sign-extend(IR[15-0])) IR2←IR EX ALUO←(A)+(IMM) Alu_Sign1 = 0, Alu_Sign2 = 0, Alu_Sign3 = 0000, sel1 = 0, sel2 = 0 IR3←IR2 B2←B MEM Memory[ALUO] ←(B2) Mem_Write = 1 表10. SW指令操作流程及控制信号 4. 指令执行状态转换图 可画出其对应的状态转移图,如图9所示。

图9. 状态转移图 5. 引脚绑定表 名称 绑定引脚 功能 clk BTN3-A7 CPU时钟 reset SW7-N3 复位信号 sel_seg[0] SW4-G3 sel_seg控制七段显示的具体内容。

000:pc_now 001: id_rega 010:id_regb 011:ex_alua 100:ex_alub 101:ex_aluo 110: if_ins 111:wb_data sel_seg[1] SW5-F3 sel_seg[2] SW6-E2 L1 LD7(G1) clk对应的LED L2 LD6(P4) reset对应的LED L3 LD5(N4) of对应的LED L4 LD4(N5) cf对应的LED L5 LD3(P6) update_pc对应的LED L6 LD2(P7) sel_seg[0]对应的LED L7 LD1(M11) sel_seg[1]对应的LED L8 LD0(M5) sel_seg[2]对应的LED a_to_g[0] CG(M12) 控制七段码显示 a_to_g[1] CF(L13) a_to_g[2] CE(P12) a_to_g[3] CD(N11) a_to_g[4] CC(N14) a_to_g[5] CB(H12) a_to_g[6] CA(L14) an[0] AN0(K14) 控制七段码具体显示位 an[1] AN1(M13) an[2] AN2(J12) an[3] AN3(F12) clk1 MCLK(B8) 七段码显示的时钟 表11. 引脚绑定表 6. 测试程序 综合考虑到我们选择的指令集以及FPGA开发板的硬件资源情况,我们打算用下面三个程序来测试我们的设计方案。

程序1主要用来测试算逻运算和访存指令的正确性,程序如表12所示。

主存地址 指令 结果描述 机器指令的机器码 十六进制 二进制 00000000 addi reg0, reg1, #2 reg1 = reg0 + 2 20010002 0010000000000001 0000000000000010 00000001 andi reg1, reg2, #1 reg2 = reg1 & 1 30220001 0011000000100010 0000000000000001 00000002 ori reg1, reg2, #1 reg2 = reg1 | 1 34220001 0011010000100010 0000000000000001 00000003 sllv reg1, reg2, reg2 reg2 = reg1 << reg2 00221004 0000000000100010 0001000000000100 00000004 slt reg1, reg2, reg2 reg2 = (reg1 < reg2) 0022102A 0000000000100010 0001000000101010 00000005 sw reg0, reg1, #0 mem[reg0 + 0] = reg1 AC010000 1010110000000001 0000000000000000 00000006 lw reg0, reg3, #0 reg3 = mem[reg0 + 0] 8C030000 1000110000000011 0000000000000000 表12. 测试程序1 程序2主要用来测试软中断和硬中断功能,程序如表13所示。

主存地址 指令 结果描述 机器指令的机器码 十六进制 二进制 00000000 addi reg0, reg1, #2 reg1 = reg0 + 2 20010002 0010000000000001 0000000000000010 00000001 andi reg1, reg1, #FFFF reg1 = reg1 + FFFF 2021FFFF 001000000010000 11111111111111111 00000002 addi reg0, reg1, #1 reg1 = reg0 + 1 20010001 0010000000000001 0000000000000001 00000003 addi reg0, reg1, #2 reg1 = reg0 + 2 20010002 0010000000000001 0000000000000010 00000004 addi reg0, reg1, #3 reg1 = reg0 + 3 20010003 0010000000000001 0000000000000011 00000005 addi reg0, reg1, #4 reg1 = reg0 + 4 20010004 0010000000000001 0000000000000100 0000000A push 压PC、R6-1 F800000E 1111100000000000 0000000000001110 0000000E pop PC、R6-1出栈 FC050000 1111110000000101 0000000000000000 表13. 测试程序2 程序3主要用来测试跳转指令的正确性,由于push和pop指令中已经隐含了J指令,因此这里只对bne指令进行测试,程序如表14所示。

主存地址 指令 结果描述 机器指令的机器码 十六进制 二进制 00000000 addi reg0, reg1, #2 reg1 = reg0 + 2 20010002 0010000000000001 0000000000000010 00000001 addi reg0, reg2, #0 reg2 = reg0 + 0 20020000 0010000000000010 0000000000000000 00000002 addi reg2, reg2, #1 reg2 = reg2 + 1 20420001 0010000001000010 0000000000000001 00000003 bnz reg1, reg2, #2 if (reg1 != reg2) pc = pc + 1 - 2 14220002 0001010000100010 0000000000000010 表14. 测试程序3 7. 测试结果与仿真图 所有测试程序均在最终检查时验收,其在FPGA开发板上的实际的运行结果均在课设验收时得到了确认,三个测试程序的结果均符合预期,这里便不再赘述。

此外由于仿真图上通过缩放后已经无法看清32位寄存器具体的值,即使放在这里也根本无法看清其具体值,毫无意义。因此仿真图便不再放在报告里。

五、 课设总结 1. 课设中遇到的问题 这次课设中遇到的主要问题有如下这些:
指令周期数问题。(单周期与双周期的选择)
是否设立单独的译码器的问题。(集中译码与分布译码的选择)
① 是否保留非流水中针对跳转指令的优化问题。(结构一致性的取舍)
② 寄存器组读写顺序问题。(先读后写与先写后读的选择)
③ 写回段的取舍问题。(与问题④密切相关)
④ JNZ指令带来的结构问题。(唯一的四输入指令,以及不修改rt)
⑤ 同步复位或异步复位的选择。

⑥ 仿真与上板测试的区别。

其中①~⑥的问题与解决方案在3.4中都已经详细写明,这里便不加赘述。

对于问题⑦,最初我们的设计中选择了异步复位,仿真顺利通过。但是后来在编译中发现一个寄存器不能在两个always中赋值,因此我们改为了同步复位。

对于问题⑧,在中期检查时我们只做了仿真,并没有上板进行实际的测试。在那时,老师便一再强调仿真与上板测试的差异性,仿真结果正确只是上板测试结果的必要条件。在仔细斟酌老师的话后我认为,仿真与上板测试最大的区别就在于开发板上是存在时延的,而仿真确是在理想状态下的测试结果。因此在后面的设计中我充分考虑了时延的问题,尽量避免有前后相关关系的值在同一沿上变化,这也就有了双指令周期以及分布译码的设计。功夫不负有心人,我组是班上少有的在上板测试中没有出现任何问题的小组。

参考文献 [1] 张晨曦, 王志英, 沈立, 刘依. 计算机系统结构教程. 北京: 清华大学出版社, 2009: 53~90 [2] 秦磊华, 吴非, 莫正坤. 计算机组成原理. 北京: 清华大学出版社, 2011: 203~277

推荐访问:流水线 课程设计 原理

最新推荐
猜你喜欢