建站之星用做什么网站,大连做网站的,镇江网站建设策划,企业网络营销的推广方法5 段流水 CPU 设计
1 课程设计概述
1.1 课设目的
计算机组成原理是计算机专业的核心基础课。该课程力图以“培养学生现代计算机系统设计能力”为目标#xff0c;贯彻“强调软/硬件关联与协同、以 CPU 设计为核心/层次化系统设计的组织思路#xff0c;有效地增强对学生的计…5 段流水 CPU 设计
1 课程设计概述
1.1 课设目的
计算机组成原理是计算机专业的核心基础课。该课程力图以“培养学生现代计算机系统设计能力”为目标贯彻“强调软/硬件关联与协同、以 CPU 设计为核心/层次化系统设计的组织思路有效地增强对学生的计算机系统设计与实现能力的培养”。课程设计是完成该课程并进行了多个单元实验后综合利用所学的理论知识并结合在单元实验中所积累的计算机部件设计和调试方法设计出一台具有一定规模的指令系统的简单计算机系统。所设计的系统能在 LOGISIM 仿真平台和 FPGA 实验平台上正确运行通过检查程序结果的正确性来判断所设计计算机系统正确性。
课程设计属于设计型实验不仅锻炼学生简单计算机系统的设计能力而且通过进行中央处理器底层电路的实现、故障分析与定位、系统调试等环节的综合锻炼进一步提高学生分析和解决问题的能力。
1.2 设计任务
本课程设计的总体目标是利用 FPGA 以及相关外围器件在课程实验中完成的单周期 CPU 基础上完成单周期 CPU 在 FPGA 开发板上的正确运行并改造设计五段流水 CPU要求所设计的流水 CPU 系统能支持自动和单步运行方式能正确地执行存放在主存中的程序的功能对主要的数据流和控制流通过 LED、数码管等适时的进行显示方便监控和调试。对于五段流水要求分别使用气泡、重定向、分支预测等方式处理数据冲突和控制冲突等此外还要求支持中断请求。尽可能利用 EDA 软件或仿真软件对模型机系统中各部件进行仿真分析和功能验证。在学有余力的前提下可进一步扩展相关功能。
1.3 设计要求
1 根据课程设计指导书的要求制定出设计方案
2 分析指令系统格式指令系统功能。
3 根据指令系统构建基本功能部件主要数据通路。
4 根据功能部件及数据通路连接分析所需要的控制信号以及这些控制信号的有效形式
5 设计出实现指令功能的硬布线控制器
6 调试、数据分析、验收检查
7 课程设计报告和总结。
1.4 技术指标
1 支持表 1.1 的 27 条基本 32 位 MIPS 指令
2 支持教师指定的 4 条扩展指令即表 1.1 中的最后四条指令分别任 blez、xori、sltiu 和 lbu
3 支持多级嵌套中断利用中断触发扩展指令集测试程序
4 支持 5 段流水机制可处理数据冒险结构冒险分支冒险
5 能运行由自己所设计的指令系统构成的一段测试程序测试程序应能涵盖所有指令程序执行功能正确。
6 能运行教师提供的标准测试程序并自动统计执行周期数。
7 对于基本指令测试程序一次性运行对于扩展指令要求单步手动执行一次执行一段。
8 能自动统计各类分支指令数目如不同种类指令的条数、冒险冲突次数、插入气泡数目、load-use 冲突次数、动态分支预测流水线能自动统计预测成功与失败次数。
表 1.1 指令集 # 指令助记符 简单功能描述 备注 1 ADD 加法 指令格式参考 MIPS32 指令集最终功能以 MARS 模拟器为准。 2 ADDI 立即数加 3 ADDIU 无符号立即数加 4 ADDU 无符号数加 5 AND 与 6 ANDI 立即数与 7 SLL 逻辑左移 8 SRA 算数右移 9 SRL 逻辑右移 10 SUb 减 11 OR 或 12 ORI 立即数或 13 NOR 或非 14 LW 加载字 15 SW 存字 16 BEQ 相等跳转 17 BNE 不相等跳转 18 SLT 小于置数 19 STI 小于立即数置数 20 SLTU 小于无符号数置数 21 J 无条件转移 22 JAL 转移并链接 23 JR 转移到指定寄存器 If $v010 halt(停机指令)else 数码管显示$a0 值 24 SYSCALL 系统调用 25 MFC0 访问 CP0 26 MTC0 访问 CP0 27 ERET 中断返回 28 BLEZ 小于或等于 0 跳转 29 XORI 异或立即数 30 SLTIU 小于立即数置 1无符号 31 LBU 加载字节地址无符号
2 总体方案设计
2.1 单周期 CPU 设计
本次我们采用的方案是硬布线控制。将系统分成指令存储器 IM、操作控制器、寄存器文件、运算器 ALU、数据存储器 DM、地址转移逻辑 NPC 等几大模块。从指令存储器中取出一条指令操作控制器根据指令解析出各模块间的数据通路控制信号寄存器文件的输出作为 ALU 的操作数ALU 的运算结构送到数据存储器或者寄存器文件地址转移逻辑决定下一条指令的地址。以上所有操作都在一个周期内完成不需要考虑各种数据冲突。实际上取指令和取数据存储器的值都涉及到访存可能会有冲突为此需要另加控制信号为了简化系统的实现我们把指令存储器和数据存储器分开用增加硬件的方式解决了这一冲突。
在 logisim 平台上模拟的单周期 CPU 已经在课程实验中完成了现在需要用 Verilog 代码来描述该系统使之能够在 FPGA 开发板上完成相同的功能这个过程不需要修改系统的设计只需要根据电路图划分模块将各模块的输入输出作为 Verilog 模块的接口即可完成转换。理论上用 Verilog 生成的结构图与 Logisim 的结构图基本相同。总体结构图如图 2.1 所示。 图 2.1 单周期总体结构图
2.1.1 主要功能部件
1. 程序计数器 PC
程序计数器决定取指令的地址接收地址转移逻辑的输出作为输入在每个时钟上升沿到来时输出一个地址送到指令存储器应该用一个寄存器来实现。该寄存器需要时钟信号、清零信号使能端接停机信号当停机信号到来时 PC 值不再改变系统也就停止运转。输入输出引脚描述如表 2.1。
表 2.1 程序计数器引脚与功能描述 引脚 输入/输出 位宽 功能描述 Clk 输入 1 时钟 Rst 输入 1 清零 En 输入 1 使能端为 0 时忽略时钟输入 PC_in 输入 32 加载到寄存器输入端的值 PC_out 输出 32 寄存器输出端的值
2. 指令存储器 IM
为简化实现将 IM 和 DM 分开实现。指令是只读的应该用 ROM 存储器来存储MIPS 指令都为定长 32 位所以数据位宽设为 32 位程序计数器 PC 输出的是字节地址一条指令有 4 个字节所以指令存储器应该以字寻址将 PC 截去低 2 位作为 ROM 的输入。考虑到我们实现的只是一个模拟的 CPU可以不用全部的 30 位字地址取 10 位即可也就是 PC 的第 2 到第 11 位。输入输出引脚描述如表 2.2。
表 2.2 指令存储器引脚与功能描述 引脚 输入/输出 位宽 功能描述 PC 输入 10 程序地址 Instru 输出 32 待解析指令
3. 数据存储器 DM
数据存储器要求可读可写用 RAM 实现。sw、lw 指令要读写字lbu 指令则要求读取字节所以要能够以不同的模式进行访问。通过两位的访问模式信号决定是字、字节或半字访问写使能信号决定读数据或写数据时钟上升沿控制写入而读数据则是组合逻辑随时可读。读写的地址有 32 位与指令存储器同理我们不需要使用那么大的空间所以可以截取低 12 位作为读写地址。输入输出引脚描述如表 2.3。
表 2.3 数据存储器引脚与功能描述 引脚 输入/输出 位宽 功能描述 Clk 输入 1 时钟 Rst 输入 1 清零 Mode 输入 2 访问模式00 表示字访问01 字节访问 We 输入 1 写使能信号 Din 输入 32 待写入的数据 addr 输入 12 读写的字节地址 Dout 输出 32 读出的数据
4. 运算器
运算器接受两个 32 位的操作数根据操作码决定对两个数进行何种运算输出一个 32 位的结果并输出一位数表示两个操作数是否相等。除此之外还有有符号溢出、无符号溢出等多种输出由于在这里不需要使用所以忽略这些输出。输入输出引脚描述如表 2.4。
表 2.4 ALU 引脚与功能描述 引脚 输入/输出 位宽 功能描述 aluX 输入 32 操作数 X aluY 输入 32 操作数 Y Aluop 输入 4 操作码决定运算方式 Result 输出 4 计算结果 Equal 输出 32 两操作数是否相等的标志
各操作码对应的运算方式如表 2.5。
表 2.5 操作码功能描述 Aluop 运算 0000 逻辑左移 0001 算术右移 0010 逻辑右移 0011 相乘 0100 相除 0101 相加 0110 相减 0111 按位与 1000 按位或 1001 按位异或 1010 按位或非 1011 符号比较 1100 无符号比较
5. 寄存器堆 RF
寄存器文件包含 MIPS 中的 32 个 32 位寄存器一次可以读取 ra 和 rb 两个寄存器一次可写一个寄存器用 rw 表示用时钟控制一位写使能信号用来标识当前周期是否需要写数据写入和读出的数据都是 32 位的。输入输出引脚描述如表 2.6。
表 2.6 寄存器堆引脚与功能描述 引脚 输入/输出 位宽 功能描述 Clk 输入 1 时钟 Rw 输入 5 写寄存器号 Ra 输入 5 读寄存器号 1 Rb 输入 5 读寄存器号 2 We 输入 1 写使能 W 输入 32 写入数据 A 输出 32 读出数据 1 B 输出 32 读出数据 2
2.1.2 数据通路的设计
对于电路中的各大部件记录其输入端数据来源忽略控制类信号仅保留数据类信号得到数据通路框架如表 2.7。
表 2.7 指令系统数据通路框架 2.1.3 控制器的设计
首先对于控制信号进行统计包括各个主要部件所需要输入的控制信号以及数据通路合并表中所示的具有多输入的主要部件需要进行输入选择的控制信号并且对各个统计信号的各种取值情况进行定义。统计得到的控制信号以及说明如表 2.8。
表 2.8 主控制器控制信号的作用说明 控制信号 取值 说明 Jal 1 函数调用写寄存器的编号选择 31 号 0 写寄存器编号选择指令解析器解析出的 rd、rt RegDst 1 写寄存器编号为 rt 0 写寄存器编号为 rd Syscall 1 读寄存器编号 1 为 2读寄存器编号 2 为 4 0 读寄存器编号 1 为 rs读寄存器编号 2 为 rt Jump 1 无条件跳转npc 取 26 位立即数 0 不跳转npc 取其他值 Branch 1 有条件跳转成功npc 选择 16 位立即数 0 Npc 为其他值 Return 1 Jr 指令函数调用返回npc 为 31 号寄存器的值 0 Npc 为其他值 Regdin 1 写入寄存器的值为数据存储器的输出 0 写入寄存器的值为 alu 的输出 Shift 1 移位标志立即数扩展器输出 5 位移位值的 32 位扩展结果 0 立即数扩展器输出 16 位立即数的扩展结果 Unsigned 1 无符号扩展标记16 位立即数做无符号扩展 0 16 位立即数做有符号扩展 regW 1 写寄存器使能信号允许将寄存器的输入加载到输出 0 不允许写寄存器寄存器输出值不变 aluB 1 Alu 操作数 Y 的选择选择立即数扩展的结果 0 选择寄存器文件的第二个输出 DMWrite 1 数据存储器写使能信号允许向 DM 写数据 0 从 DM 读数据 Mode 00 对 DM 进行字访问 01 对 DM 进行字节访问 10 对 DM 进行半字访问 Aluop 0000-110 功能过多详见表 2.5
对照所有控制信号依次分析各条指令分析该指令执行过程中需要哪些控制信号。该控制信号表的框架如表 2.9 所示其中为空的表项表示取值为 0 或者取任意值均可。
表 2.9 主控制器控制信号框架 2.2 单周期多级中断机制设计
2.2.1 总体设计
中断响应的执行流程如图 2.2 所示。 图 2.2 多级中断响应流程
用独立请求的方式响应中断每个中断对应一个中断号。根据中断号确定执行哪段中断程序用类似于中断向量表的方式存放中断程序入口可以事先获取中断入口地址以常量形式进行选择。
为了在中断执行后能够正常返回主程序要将跳转前的地址保存下来就像 jal 指令将返回地址保存在 31 号寄存器中一样。每级中断在执行过程中都需要动态地改变中断优先级所以需要若干个中断屏蔽寄存器。在执行某些操作时不允许任何外部事件中断需要完全关中断所以还需要添加中断使能寄存器 IE。
对 EPC、IE 和中断屏蔽寄存器的操作需要增加指令才能实现具体为 MFC0 和 MTC0以及中断返回指令 ERET所以还需要修改操作控制器和数据通路。
2.2.2 硬件设计
① 中断屏蔽寄存器
用 D 触发器实现数量与中断的数量相同为 3 个。时钟上升沿触发正常执行时写入 0不屏蔽任何中断中断程序执行前向屏蔽寄存器写入 1。寄存器输出取反和中断请求信号进行与操作。
② 中断识别
三个中断按钮都可能被按下但是一次只能响应一个应该有限响应优先级高的应该用优先编码器对中断请求信号进行编码。
③ 中断使能寄存器
用 D 触发器实现输出 1 时允许中断输出 0 时屏蔽所有中断。
④ EPC 寄存器
用 32 位寄存器实现上升沿触发当有中断请求时使能端置 1写入当前 PC4 的值作为返回地址。中断执行过程中使能端一直为 0不许写入新的值。
⑤ 操作控制器修改
为了支持新的三条指令增加三个比较器根据操作码判断是否为 eret、mfc0 或者 mtc0 指令。Mfc0 和 mtc0 需要读写通用寄存器和 IE、EPC 寄存器所以需要将 mfc 和 mtc 指令作为寄存器的使能信号。
⑥ 硬件关中断
在中断请求发出的一个周期中断信号为 1系统响应中断但是一个周期之后应立马关中断防止后续中断继续响应这应该由硬件实现可以将中断信号反馈到 D 触发器的清零端。
2.2.3 软件设计
依靠硬件只能实现单级中断不能在中断执行过程中将其打断因为新的 EPC 值会覆盖原有的值为此要用软件方法实现。
在中断程序的最开始需要将通用寄存器都压栈保存。用数据存储器 DM 作为堆栈用 sw 指令完成即可。然后依次用 mfc0 指令读取 IE、EPC 和中断屏蔽寄存器的值存入通用寄存器。再将新的中断屏蔽字写回屏蔽寄存器并将 IE 写入 1实现软件开中断在此之前实现的操作都是不可打断的在此之后中断可以被嵌套打断。
执行完中断处理程序后按照原来入栈顺序的倒序依次出栈各寄存器的值恢复 IE、EPC 和中断屏蔽字。
2.3 流水 CPU 设计
2.3.1 总体设计
在指令的实际执行过程中取指、译码、执行等操作都是有先后顺序的有的操作必须使用另一操作的结果所以很多部件需要等待其他部件运算完毕才能接着计算系统效率极低。为了充分利用各部件需要设计五段流水线。一条指令的操作可以细分为五个阶段如图 2.3 所示。 图 2.3 指令流水线逻辑架构
2.3.2 流水接口部件设计
流水接口部件的作用是将上一段中的数据和控制信号锁存一个周期供下一段使用应该用寄存器实现。时钟上升沿触发使能端接停机信号将清零信号作为多路选择器的选择信号正常情况下选择输入信号清零时选择常数 0。各段的流水接口结构大体相同只是传输的数据不同。
2.3.3 理想流水线设计
将单周期 CPU 中的各部件依次划分到五个段中。
① 取指程序计数器 PC指令存储器 IM。
② 译码指令解析器有符号、无符号扩展器操作控制器寄存器堆。
③ 执行运算器 ALU。
④ 访存数据存储器 DM。
⑤ 写回与译码段一样使用寄存器堆不过这里是写寄存器为了防止数据冲突需用下降沿写入保证下一个上升沿到来时译码阶段能取到最新的寄存器值。
2.4 气泡式流水线设计
2.4.1 总体设计
理想流水线只能顺序执行无法解决跳转问题此外相邻指令间还存在着读写数据的冲突读寄存器指令读取的寄存器值还未被及时写回会导致读取错误。
reducer.py
import syscurr_label None
curr_count 0
curr_encod 0
label Nonefor line in sys.stdin:label, encod line.strip().split(\t, 1)label, encod int(label), eval(encod)dim len(encod)
# 如果当前类别与之前的类别不同则上一个类别计数完成
if curr_label ! label:if curr_label is not None:# 求平均数print(f{curr_label}\t{[curr_encod[i] / curr_count for i in range(dim)]})curr_label labelcurr_count 0curr_encod [0] * dim
curr_count 1
curr_encod [curr_encod[i] encod[i] for i in range(dim)]
最后一类
if curr_label label:
# 求平均数
print(f{curr_label}\t{[curr_encod[i] / curr_count for i in range(dim)]})
2.4.2 控制冲突处理设计
无条件跳转在译码段就能得到目标地址有条件跳转要等到执行段利用 alu 的运算结果才能确定。为统一管理将 j 型指令的控制信号也向后传送一个周期与 b 指令同等处理。在执行段判断当前指令是否为 j 指令或者为 b 指令且成功跳转满足条件时将目标地址送到 pc 寄存器完成跳转同时还要将 IF-ID 和 ID-EX 流水部件完成误取指令的清除。
2.4.3 数据冲突处理设计
要判断一条指令与其前面两条指令的关系应该在译码、执行、访存段判断将执行段和访存段的写寄存器编号和写使能送回译码段与译码段要读的寄存器编号相比较假如两者相同则冲突在 ID-EX 流水部件中插入一个气泡。读写 0 号寄存器不算冲突所以要排除这种情况。生成的插气泡信号接到 ID-EX 的清零端清零实现插入气泡此外还要接到 IF-ID 和 PC 寄存器的使能端在插入气泡的同时将前两段锁住。
2.5 数据转发流水线设计
2.5.1 总体设计
数据冲突中要读的寄存器值没有及时写回寄存器它已经存在于访存段和写回段的流水部件中重定向的思路就是把这些数据送到需要寄存器最新值的地方。重定向检测放在执行段判断执行段读寄存器与访存段、写回段写寄存器之间是否冲突。 图 2.4 Load-Use 相关
若相邻两条指令数据相关且前一条是访存指令不能采用重定向。如图 2.4EX 段读寄存器与 MEM 段目的寄存器相同此时寄存器的值没有锁存在 EX/MEM 中等 DM 读操作完成后才会出现在 Readdata 上若将其直接重定向到 EX 段会使得 EX 段的延迟变成了访存延迟 运算器延迟。所以应在 ID 段就检出并插入一个气泡。
2.5.2 Load-Use 相关处理设计
Load-Use 相关要在 ID 段检出在 ID 段增加检测逻辑当 ID 段为读寄存器指令、EX 段为 lw 或 lbu 指令、ID 段读寄存器编号与 EX 段目的寄存器编号相同条件均满足时即为 load-use 相关需要生成气泡插入信号。
2.5.3 重定向设计
重定向是从访存段和写回段定向到 alu 的两个输入端两段的数据均可能定向到两个输入端所以共有四种定向可能需要四个控制信号。
四个控制信号的生成逻辑基本相同只是控制的数据来源和去向不同。重定向要满足三个条件执行段读寄存器、执行段读寄存器编号与访存段/写回段写的寄存器编号相同、访存段/写回段的寄存器写使能信号为 1表示该段需要写寄存器。上述条件中包含了 Load-Use 相关不过 Load-Use 相关已经在 ID 段检测出并且插入了气泡所以在执行段不会再检测出。理论上还要求读写寄存器的编号不为 0但是没有哪一条指令会写零号寄存器所以这里也省去了这一逻辑。
2.6 动态分支预测机制
2.6.1 总体设计 图 2.5 动态分支预测流程
重定向流水线相比气泡流水线已经有了极大的优化但是仍然因为跳转清空时误取指令而浪费了很多时钟周期为了继续优化我们要能够尽早判断出跳转使误取深度将为 0这就是动态分支预测需要完成的工作。
分支预测最核心的部件是分支历史表 BHT原理类似于广泛使用的 cache将最近出现过的数据进行缓存下次使用时如果命中就能够直接使用。动态分支预测流程如图 2.5 所示。
2.6.2 BHT 设计
BHT 的所有表项均用寄存器实现设置 8 个表项增大命中概率。BHT 表主要包含有效位、指令地址、分支目标地址、预测历史和 LRU。
有效位标记该表项是否被使用初值为 0一旦存入数据则永远为 1指令地址是跳转指令在指令存储器中的地址分支目标地址是指令成功跳转时的目标地址预测历史用双预测位高位为 1 时预测跳转否则预测不跳转状态转移图如图 2.6转移条件为实际跳转情况而不是预测跳转情况。 图 2.6 采用双预测位的 BHT 状态转换
在 8 个表项还未被填满时用优先编码器获取当前为空的表项的编号将该表项使能端置 1写入分支地址值将该项的有效位置 1表示该表项已经被使用。若 8 个表项都被填满了而当前又有以前没有出现过的跳转情况出现则需要涉及到表项的替换。替换算法采用 LRU 算法要从 8 个表项中选取 lru 值最大的一项用比较器两两比较各表项的值两者中较大者继续比较最终选出最大者将该表项的使能端置 1写入新的分支指令地址和目标地址并将 lru 值置 0表示该项刚使用过。
2 详细设计与实现
2.7 单周期 CPU 实现
2.7.1 主要功能部件实现
程序计数器PC
① Logism 实现
用一个 32 位寄存器 PC上升沿触发输入来自于地址转移逻辑的输出输出送到指令存储器。Halt 为停机信号取反后接在寄存器的使能端。如图 3.1 所示。 图 3.1 程序计数器PC
② FPGA 实现
程序计数器 PC 的 Verilog 代码如下
always(posedge clk) begin
if(0rst) pc 0;
else if(halt) pc pcout;
else pc pc;
end
指令存储器IM
① Logism 实现 图 3.2 指令存储器IM
用一个只读存储器 ROM 实现。设置地址位宽为 10 位数据位宽为 32 位。因为 PC 中存储的指令地址有 32 位而 ROM 地址线宽度有限仅为 10 位故使用分线器只取 32 位指令地址的 2-11 位作为指令存储器的输入地址。如图 3.2 所示。
数据存储器DM
① Logism 实现
使用 4 个数据位宽为 8 的随机存储器 RAM 实现从 32 位地址中截取低 12 位作为 DM 的字节地址字节地址中的高 10 位为字地址低两位为字节片选信号。具体选择电路很复杂这里只展示 RAM 的部分结构如图 3.3 所示。 图 3.3 数据存储器DM
② FPGA 实现
写数据用用 always 行为描述读数据用 assign 赋值。DM 的 Verilog 代码如下
always (posedge clk) begin
if(DMwrite) memory[addr1] Din;
else memory[addr1] memory[addr1];
end
assign Dout (mode0) ? data :
(mode1) ? {24h000000, bytes} :
(mode2) ? {16h0000, half} : 0;
寄存器文件
① Logism 实现 图 3.4 寄存器文件
使用 CS3410 库中提供的寄存器堆实现寄存器文件。如图 3.4 所示。
② FPGA 实现
用 reg 类型实现寄存器用 always 行为描述时钟上升沿时加载输入0 号寄存器永远位 0。输出为组合逻辑随时读出不需要时钟。Verilog 代码如下
reg [31:0]memory[31:0];;
always (posedge clk) begin
memory[0]0;
if(WE1) memory[rw]w;
end
assign Amemory[rA];
assign Bmemory[rB];
③ RTL 电路图Vivado 生成的 RTL 电路图如图 3.5 所示。 图 3.5 寄存器文件 RTL 图
2.7.2 数据通路的实现
采用工程化设计模式一次构建所有数据通路。将每条指令改成 RTL仅保留数据类信号记录各部件输入端数据来源数据通路表已在 2.1.2 中给出不再重复。
根据数据通路表进行多指令数据通路的合并将各个主要功能部件进行连接根据数据通路合并表的最终结果对于所有的多输入部件使用多路选择器进行输入选择。最终便可以完成数据通路的搭建。数据通路如图 3.6 所示。 图 3.6 单周期 CPU 数据通路Logism
在 Vivado 中使用 Verilog 语言搭建的数据通路的原理图如图 3.7 所示。 图 3.7 单周期 CPU 数据通路FPGA
2.7.3 控制器的实现
① Logisim 实现
根据指令 op 和 func 字段判断指令类型用比较器实现部分电路如图 3.8 所示。 图 3.8 解析指令类型
得到指令类型信号以后结合表 2.9 中给出的控制信号根据每种控制信号对应的指令类型用或门将这些指令生成各控制信号部分电路如图 3.9 所示。 图 3.9 控制信号生成
② FPGA 实现
Logisim 中的比较逻辑在 Verilog 中可以用“”操作符实现逻辑门可以用“|”、“”等操作实现整个操作控制器都是组合逻辑所以全部使用 assign 赋值虽然代码量大但是逻辑简单部分代码如下
assign ret (func6h08) r;
assign syscall (func6h0c) r;
assign tmpsys r (~(ret | syscall));
assign tmpbr equal | (alur32h00000001); 图 3.10 主控制器原理图
用 RTL 分析得到主控制器原理图如图 3.10 所示。
2.8 中断机制实现
2.8.1 硬件实现
① 中断等待信号产生
如图 3.11 所示用两个 D 触发器实现中断按键信号接到第一个触发器的时钟端D 触发器 1 的输出和复位信号取反相与作为第二个触发器的输入。 图 3.11 中断等待信号产生电路
② 中断屏蔽寄存器
用四个 D 触发器来实现级别为 0、1、2、3依次增加。触发器输出的补值与中断请求相与得到中断信号。当 mtc0 指令执行时选择信号选择待写入的值进行写入改变中断优先级。电路实现如图 3.12 所示。 图 3.12 中断屏蔽寄存器电路
③ 中断入口地址选择
如图 3.13将中断请求信号接入优先编码器输出编码代表当前优先级最高的中断将各中断的入口地址用常数形式接到多路选择器的输入用中断编号作为选择信号选出的地址即为当前需要响应的中断的入口地址。 图 3.13 中断入口地址选择
④ 等待信号清零
与入口地址选择一样也用优先编码器实现将当前中断请求信号接到优先编码器上输出编码再用解码器解码就生成了同步清零信号。这里接入的是原始中断请求信号编码结果表示当前执行的中断而图 3.14 中接入的是经过屏蔽字处理后的信号。电路如图 3.14 所示。 图 3.14 等待信号清零信号产生电路
⑤ IE 和 CP0 寄存器实现
IE 寄存器用 D 触发器实现CP0 寄存器用 32 位宽的寄存器实现。 图 3.15 中断寄存器实现
电路启动时IE 写入 1硬件关中断时IE 写入 0mtc0 执行时IE 写入通用寄存器的值所以 IE 输入端需要多路选择器进行选择选择信号由控制电路生成。IE 使能端接一个或门的输出当有中断请求、返回指令以及其他两个控制信号时允许写入其他情况锁死。
CP0 寄存器正常时写入当前 PC4 值mtc0 执行时写入通用寄存器值用二路选择器选择后送入输入端控制信号由控制电路产生。使能端接控制信号与中断使能信号相或的结果。电路如图 3.15 所示。
⑥ 中断控制信号生成
原单周期 CPU 不支持中断指令需增加控制逻辑。三条中断指令的 op 字段均为 0x10这还不足以区分三条指令但这三条指令的 rs 寄存器字段各不相同所以可以作为判断依据。如图 3.16 所示通过比较器对 op 字段和 rs 字段综合判断得出三条指令的控制信号。 图 3.16 中断指令识别
2.8.2 软件实现
中断程序执行前先将 32 个通用寄存器中需要用到的寄存器压栈堆栈在数据存储器中选取一段实现用 sw 指令实现压栈每次对 sp 寄存器减 4。紧接着读取屏蔽字、CP0 寄存器的值为了方便用 MFC0$1,$1 表示将屏蔽字送入 1 号通用寄存器MFC0 $2,$2 表示将 CP0 送入 2 号通用寄存器。然后用 MTC0 向寄存器写入 1实现软件开中断。执行中断程序体执行完成后出栈恢复各寄存器的值顺序与压栈顺序相反。压栈部分代码如下出栈部分与之类似
addi $sp,$sp,-4 #通用寄存器压栈
sw $25,0($sp)
MFC0 $1,$1 #读屏蔽寄存器并压栈
addi $sp,$sp,-4
sw $1,0($sp)
MFC0 $2,$2 #读 CP0 寄存器并压栈
addi $sp,$sp,-4
sw $2,0($sp)
addi $1,$0,0x3 #写屏蔽寄存器该变中断优先级
MTC0 $1,$1
addi $3,$0,0x1 #软件开中断
MTC0 $3,$3
2.9 流水 CPU 实现
2.9.1 流水接口部件实现
以 EX-MEM 接口为例如图 3.17 所示所有输入信号都用对应位宽的寄存器进行输出时钟上升沿触发使能端接停机信号 halt清零信号接多路选择器的选择端正常情况下选择输入信号清零信号到来时选择 0实现同步清零。 图 3.17 流水接口部件实现
2.9.2 理想流水线实现
理想流水线数据通路如图 3.18 所示。 图 3.18 理想流水线实现
取指段PC 的输出送 IM 的输入取出的指令通过 IF-ID 接口部件传输到译码段PC4 的值也向后传输。译码段指令解析器解析出指令各字段并送到操作控制器和立即数扩展器操作控制器输出的控制信号有部分就作用在本段其他不需要用到的信号用集线器整合送往下一段寄存器输出值、立即数扩展器的输出也向后传输。
执行段用分线器分出本段需要用到的控制信号剩下的用集线器打包后继续向后传送。alu 的运算结果、寄存器输出和 PC4 向后传送。访存段寄存器的第二个输出作为 DM 的输入alu 运算结果作为访存地址用分线器从控制信号中分出访问模式和写使能信号剩下的信号继续向后传送。访存输出继续向后传送。
写回段alu 输出、寄存器输出、PC4 的值均送回到寄存器的输入端选择信号从第五段的控制信号中用分线器分出。此外停机信号也在此段生成并起作用如果在其他段起作用那么系统会提前几个周期停机。
2.10 气泡式流水线实现
2.10.1 控制冲突处理实现
如图 3.19 所示“”表示 alu 的相等输出alur 为 alu 的运算结果。Beq 信号和相等信号相与表示 beq 成功跳转同理bne 信号和相等信号的非相与表示 bne 跳转成功blez 相对复杂在寄存器值小于或者等于 0 时跳转小于 0 的判断用的是 alu 的小于 0 置 1 功能所以要判断 alu 的结果是否等于 1用比较器比较在和相等信号相或表示二者满足其一即可跳转。将生成的信号接到 ID-EX 和 IF-ID 流水接口部件的清零端即可。 图 3.19 有条件成功跳转信号生成电路
2.10.2 数据冲突处理实现 图 3.20 读寄存器使能信号
如图 3.20在操作控制器中增加读寄存器控制信号生成电路inst1 表示同时读 rs 和 rt 寄存器的指令inst2 表示只读 rs 的指令inst3 表示只读 rt 寄存器的指令将三者两两相或得到读 rs 和 rt 寄存器的控制信号。
气泡生成需满足译码段访问 rs/rt 寄存器中的至少一个译码段读寄存器的编号与执行段写寄存器编号之一相同用比较器比较执行段写寄存器编号不为 0也用比较器执行段写寄存器使能信号为 1表示该指令需要写寄存器。将这四个条件用与门与起来得到气泡逻辑。上述是译码段与执行段的数据冲突译码段与访存段的处理方式完全相同只是写寄存器编号要从访存段送回。具体电路如图 3.21 所示。 图 3.21 气泡生成电路
2.11 数据转发流水线实现
2.11.1 Load-Use 相关处理实现 图 3.22 Load-Use 相关处理电路
如图 3.22 所示为 load-use 相关时插入气泡的逻辑电路用比较器判断 ID 段的读寄存器编号 ra、rb 是否与执行段的写寄存器编号 rw3 相同rs_r、rt_r 是 ID 段的读寄存器标志由控制器生成在气泡流水线中已经介绍过RegDin3 是执行段的 load 指令标志是控制器中原本存在的一个控制信号仅当 lw 和 lbu 指令时为 1所以刚好可以用来作为 load 标志。当 ID 段读至少一个寄存器且该寄存器编号与 EX 段写寄存器相同且 EX 段为 load 指令则生成气泡在 ID-EX 流水接口部件插入。
2.11.2 重定向实现
① Logisim 实现
如图 3.23 所示为重定向的四个控制信号的生成电路。四个信号生成逻辑基本相同仅说明 sel1 的生成rs_r、regWrite4 和比较器的比较结果用逻辑门相与结果为选择信号其中 rs_r 为 EX 段读 rs 寄存器的标志regWrite4 是访存段写寄存器使能比较器比较访存段写寄存器编号与执行段读寄存器编号 ra 是否相同。 图 3.23 重定向控制信号生成电路 图 3.24 重定向电路
图 3.23 中生成的重定向信号最终作用在 alu 的输入端如图 3.24 所示选择电路极为复杂其中右半部分为单周期中已经存在的控制逻辑左半部分的四个多路选择器是新增的。alur4 是访存段的 alu 结果是 ex 段与 mem 段数据冲突时需要重定向的数据regD 是写回段写寄存器的值是 ex 段与 wb 段数据冲突时需要重定向的数据。
② FPGA 实现
将 logisim 中实现的重定向流水线转换成 Verilog 代码转换过程比起单周期 CPU 复杂很多因为流水线的连线更复杂所以需要实现对每一根线进行命名所有的模块严格按照命名规范来定义输入输出接口。代码量太大不予展示最终生成的 RTL 电路图如图 3.25 所示。 图 3.25 重定向流水线 RTL 图
2.12 动态分支预测机制实现
2.12.1 BHT 实现
列出预测历史位状态转移图的真值表用 logisim 自动生成电路结果如图 3.26 所示。 图 3.26 预测历史状态转移逻辑
如图 3.27 所示8 个表项一共 8 行每行 5 个寄存器分别为有效位、指令地址、目标地址、预测历史位和 lru 值时钟上升沿触发。 图 3.27 分支历史表
如图 3.28是淘汰表项所需的最大数选择电路将8个lru值分成四组进程比较选出4个最大值继续比较用三次二分法选出最大数的编号。 图 3.28 最大数选择电路
如图 3.29 是 BHT 各寄存器的使能信号产生电路。Bignum 是图 3.27 中选出的最大数表项编号invalid 是用优先编码器生成的未使用表项编号当有表项为空时选择 invalid否则需要发生替换选择 bignum。Hitpos_3 是在取指段命中的表项传到执行段以后再传回的值hit3 也是传回的命中标志作为选择器的控制信号。当 hit3 为 0未命中需要写入新表项所以选择 bignum/invalidhit3 为 1 表示命中选择命中的表项编号。将编号传入解码器输出为 1 的一路表示当前激活的表项。Jb3 是执行段传回的信号表示指令是跳转指令通过与门和译码器的输出相与得到 en0-en7作为有效位、预测历史位的使能信号en0-en7 进一步与 hit3 取反后的信号相与得到 en0addr-en7addr作为指令地址、目标地址寄存器的使能信号。 图 3.29 使能信号生成电路
2.12.2 地址转移逻辑实现 图 3.30 地址转移逻辑
重定向流水线中的跳转指令周期与分支预测中不相同所以地址转移逻辑也需要修改。如图 3.30从最左侧的多路选择器开始选择信号 jump 为无条件分支标志为 1 时选择 26 位立即数生成的目标地址为 0 时表示有条件分支选择 16 位立即数生成的目标地址多路选择器的输出 destaddr 输出到 BHT 中写入分支目标地址寄存器。Jumpsuc 表示实际跳转成功为 0 时选择 pc4_3也就是按照重定向流水线中的方式在执行段跳转否则选择 destaddratt_fail 是分支预测失败的标志为 0 表示预测成功选择从 BHT 输出的 pc_att也就是命中的表项取出的分支目标地址否则选择上一个选择器的输出最后一个多路选择器选择信号 return 为 jr 指令标志为 1 时选择 31 号寄存器的值否则选择上一个寄存器的输出。
3 实验过程与调试
3.1 功能测试和性能分析
对各个任务分别单独测试除多级中断要执行中断服务程序外其他任务都用 benchmark 标准程序进行测试。在 benchmark 程序的最后还添加了四条扩展指令的测试程序每执行一条暂停一次手动按键继续执行。
3.1.1 单周期 CPU
用 benchmark_ccmb 标准程序进行测试。
① Logisim 测试
运行完 benchmark 的基础指令后的四个周期数如图 4.1 所示符合预期。 图 4.1 单周期 logisim 测试周期数 图 4.2 blez 指令测试输出 图 4.3 lbu 指令测试输出
继续执行 ccmb 指令该过程重在观察数码管输出此处无法演示动态过程只截取部分中间结果如图 4.2 到图 4.5 所示。 图 4.4 sltiu 指令测试输出 图 4.5 xori 指令测试输出
② FPGA 测试
在 FPGA 开发板上运行标准测试程序最终显示结果如图 4.6 所示与 logisim 结果相同。 图 4.6 单周期 CPU 上板测试结果
3.1.2 多级嵌套中断
使用中断服务程序 正常执行程序的方式进行测试。中断服务程序分别是 1、2、3 的循环左移正常执行程序从 0x200 递减。
先正常执行输出如图 4.6所示紧接着依次按下中断按钮2、3、1依次执行的中断程序为2、3、2、1分别如图 4.7到图 4.10所示。执行完成后再次回到主程序如图 4.11所示。 图 4.7 主程序执行 图 4.8 中断服务程序 2 图 4.9 中断服务程序 3 图 4.10 再次回到中断服务程序 2 图 4.11 中断服务程序 1 图 4.12 再次回到主程序
3.1.3 理想流水线
用几条简单的顺序执行指令进行测试理想周期数应为 21如图 4.12 所示实测总周期数为 21。运行完毕后数据存储器中存储的数据如图 4.13 所示前四个字节分别存有 0、1、2、3。 图 4.13 理想流水线总周期数 图 4.14 数据存储器内容
3.1.4 气泡流水线
① 测试用 benchmark-ccmb 测试程序进行测试运行完毕后各周期数如图 4.14 所示。
② 性能分析
总周期数 3624与单周期 CPU 的 1546 相比增加了一倍多。虽然每个周期的时间比单周期要短但是有大量时钟周期 CPU 在空转插入了多大 1447 个气泡性能不好。 图 4.15 气泡流水线运行结果
3.1.5 重定向流水线
① Logisim 测试用 benchmark-ccmb 测试程序进行测试运行完毕后各周期数如图 4.15 所示。 图 4.16 重定向流水线运行结果
② FPGA 测试
在 FPGA 开发板上运行标准测试程序跑马灯效果和各周期数均与 logisim 中相同load-use 数如图 4.17 所示。 图 4.17 重定向流水线上板测试结果
③ 性能分析
总周期数 2298气泡数为 120比气泡流水线减少了 1000 多个周期性能极大提升不过分支跳转时浪费的周期达到了38338-276*2仍然可以继续优化。
3.1.6 动态分支预测
① 测试用 benchmark-ccmb 测试程序进行测试运行完毕后各周期数如图 4.16 所示。 图 4.18 动态分支预测运行结果
② 性能分析
总周期数 1762气泡数 120跳转指令浪费的周期数为 90相较于重定向流水线减少了很多。1762 与单周期的 1546 已经比较接近再考虑到流水线中每个周期的时间更短所以分支预测流水线的性能比原来的单周期 CPU 要好很多基本上达到了极限。如果需要继续优化则需要在指令级并行的软硬件优化上着手增加硬件编译时优化这已经不是本课程要考虑的问题。
3.2 主要故障与调试
3.2.1 数据存储器综合故障
单周期 CPU 顶层模块综合问题。
故障现象执行顶层模块的综合时在进行到 DM数据存储器模块时会停滞既没有报错也没有综合成功无论等待多久都没有效果vivado 可能进入了某种死循环。如图 4.17 所示前面模块的综合都成功在 DM 的仿真处停滞不前。 图 4.19 数据存储器综合报错信息
原因分析综合过程的提示信息如图 4.18这一类的报错信息还有很多这里只截取了部分。小组讨论后认为是存储器的分配的空间太大询问老师后排除了这一可能。然后对 DM 模块的语句逐一注释再次综合以确定故障模块的位置。在将其中的一个 for 循环注释以后综合成功因此可以锁定是 for 循环的使用不当导致了故障。 图 4.20 数据存储器综合报错示意图
解决方案for 循环是用来对数据存储器进行初始化赋值的也就是将所有的存储单元存入 0这一功能是可有可无的因为数据存储器的初值非 0 即 1不会有不确定状态而且对内存的操作都是先写后读所以可以不用初始化直接删去初始化语句即可。
3.2.2 总周期数故障
单周期 CPUbenchmark 程序运行总周期数与预期不符。
故障现象上板运行跑马灯效果符合预期但总周期数显示为 1556有条件成功跳转次数位 271这两者的正确值分别为 1546 和 276。
原因分析实测周期与理想周期相差不是很大应该某几条指令的逻辑不正确导致少数情况下计数错误而且跑马效果正确。为了确定是哪些指令有误对 j 指令、b 指令、跑马测试、排序等小程序分别单独测试结果 j 指令、b 指令和跑马测试的运行结果和周期计数均与 logisim 上的结果一致而排序测试的总周期多了 10有条件分支成功少了 5这与 benchmark 的错误相同所以可以断定 benchmark 的错误全部发生在排序程序段中。对比发现排序程序中的 lw、sw 指令较多所以可能是访存错误。
解决方案数据存储器读取数据部分的 Verilog 代码如下程序逻辑看起来正确仔细观察才意识到使用了时序逻辑而存储器读数据应该是组合逻辑只要送入地址就应该立马得到数据。将 always 行为描述模块改用 assign 语句赋值即可实现组合逻辑读取数据。同样在寄存器文件中也存在着类似的问题所以一并对寄存器文件也进行了读数据的组合逻辑修改。
always (posedge clk) begin if(mode[3]) Dout[31:24]memory3[addr1][7:0];else Dout[31:24]8b00000000;if(mode[2]) Dout[23:16]memory2[addr1][7:0];else Dout[23:16]8b00000000;if(mode[1]) Dout[15:8]memory1[addr1][7:0];else Dout[15:8]8b00000000;if(mode[0]) Dout[7:0]memory0[addr1][7:0];else Dout[7:0]8b00000000;end
3.2.3 气泡流水线分支故障
气泡流水线 跑马效果不正确分支跳转错误。
故障现象对气泡流水线进行 benchmark 程序测试前一段时间跑马灯执行正常到移位测试阶段如图 4.19 所示本该一直向右移动的数字 2 没有移动执行到数字 3 的移位时显示效果如图 4.20也没有移动后续的数字显示效果与之类似。 图 4.21 移位测试跑马故障 1 图 4.22 移位测试跑马故障 2
原因分析程序能够按顺序显示程序的跑马输出说明程序在有序执行跳转指令的逻辑没有问题但是输出的结果没有移位说明是移位指令出了错或者根本没有被执行也就是跳转的位置不对这导致了每次循环时有两条语句没有执行而这两条语句中恰好有移位指令所以导致跑马效果没有移位。 图 4.23 地址转移逻辑
解决方案对移位测试程序进行单步执行其中涉及到循环当循环判断条件不成立时往回跳转发现跳转的位置不正确总是在正确位置的下下条指令处也就是 pc 值比正确值大 8问题一定出在 npc 地址转移逻辑。Npc 转移逻辑电路如图 4.21当 b 指令成功跳转时选择的目标地址是 pc4 加上 16 位立即数扩展的值理论上没有问题但是该电路调用时传入的 pc4 是从 IF 段接入的而 b 指令跳转发生在 ex 段两者相差两个周期所以 pc4 的值差了 8故应该送入 ex 段的 pc4 值。
3.2.4 重定向流水线跑马故障
重定向流水线跑马灯效果不正确。
故障现象对重定向流水线进行 benchmark 程序测试程序的跑马效果从一开始就完全不对紧接着程序执行完全混乱如图 4.22 所示。 图 4.24 重定向跑马灯故障
原因分析程序运行出现了这种完全不正确的情况很难定位错误只能单步执行。将 benchmark 测试程序在 Mars 中打开logisim 也同时打开两者交替单步执行每执行完一步观察 logisim 中的寄存器和数据存储器的值是否与 Mars 中相同。在执行了数十条指令后寄存器和存储器的值都正确但是 syscall 应该在数码管显示的值没有显示出来所以是显示模块出了问题。
解决方案显示模块是从原来的气泡流水线继承的不应该有问题所以显示错误是因为输入的数据有错误观察发现输入显示模块的寄存器的第二个输出是重定向以前的数据也就是说重定向的数据成功送入了 alu但是没有成功送到显示模块导致程序正确执行却得不到正确的显示效果将重定向以后的数据送到显示模块即可。
3.2.5 分支预测替换故障
动态分支预测旧表项替换逻辑错误。
故障现象对分支预测流水线进行 benchmark 测试跑马效果正确但是总周期数与重定向流水线的 2298 相比仅仅减少了不到 100如图 4.23 所示。 图 4.25 分支预测故障示意图
原因分析该分支预测流水线的功能完全正确但是性能不好预测成功数太少总周期数应该在 2000 以下。Bht 中有 8 个表项这不是个很小的数目理应能命中多次然而结果不如人意一定是替换策略存在问题。
解决方案先让测试程序执行一段时间让 bht 表填满然后再单步执行遇到分支指令时进入 bht 中观察发现没有命中则该分支的地址应该替换表中 lru 值最大的表项结果发现替换的永远都是第 0 或者第 1 项而不是 lru 最大的项最大数的选择存在问题。
如图 4.24 所示在最大数选择电路中发现所有的多路选择器的输入端都接的是 0、1这导致选出的最大数的编号永远为 0 或者 1。因为在画电路时很多重复的模块都是直接复制的复制以后忘记修改常量的值将 0、1、0、1、0、1、0、1 修改为 0-7 以后电路功能就正常了。 图 4.26 最大数选择逻辑
3.3 实验进度
表 4.1 课程设计进度表 时间 进度 第一天 进行了模块分工确定了各模块间的接口完成了操作控制器、指令解析器和总控模块。 第二天 全天都在仿真、综合调试现已能够上班运行指令计数部分功能正常能够正确执行部分指令但是跳转指令存在问题还在调试中 第三天 继续调试单周期 CPU仿真与上板验证相结合排除各模块故障。一开始无法正常跳转解决这一问题后程序总周期不正确大家一同调试最终完成了单周期 CPU 上板测试最高频率 50MHz 第四天 对单周期 CPU 进行模块拆分一开始由于结构不合理而进行了多次重复的封装。最终顺利完成了理想流水线没有遇到太大的麻烦。 第五天 完成气泡流水线运行结果出现了许多问题调试 过程发现了单周期 CPU 中的诸多隐藏问题修改以后的电路结构更为合理。 第六天 周末完成了气泡和重定向流水线今天在将重定向流水线转换成 Verilog 语言准备做流水线上板。 第七天 修改重定向 Verilog 代码中的部分 bug成功实现上板 第八天 基本完成单级中断还有部分问题。 第九天 单级中断提交检查还完成了多级嵌套中断。 第十天 完成 BHT 和分支预测的数据通路正在进行功能调试。
4 设计总结与心得
4.1 课设总结
本次课程设计主要作了如下几点工作
1 完成了 logisim 到 Verilog 的转换在 FPGA 上实现了单周期 CPU在单周期 CPU 上加入中断逻辑实现了多级嵌套中断对单周期 CPU 进行了合理的划分得到了理想流水线对理想流水线加入冲突处理逻辑实现了气泡流水线对气泡流水线进行优化实现了重定向流水线对重定向流水线加入 bht实现了动态分支预测。
2 FPGA 上的单周期 CPU 与 logisim 上的单周期 CPU 功能相同最高运行频率达到了 50MHz气泡流水线实现了流水执行但性能低下重定向流水线性能相比气泡流水线得到了大幅度提升动态分支预测流水线改进了重定向流水线增加了分支缓冲表实现了性能的进一步提升。
3 修正了课程实验中的单周期 CPU 中的部分 bug实现了对 ccmb 指令的支持通过实践弄懂了很多问题对 CPU 性能提升策略有了一定的了解发现并改正了原来常犯的许多低级错误。
4.2 课设心得
虽然没有实现完全通关但是拿到了 105 分完成度稍微高于预期对自己的工作比较满意。课设两周期间大脑一直处于高负荷运转状态睡醒以后立马就能想起还有电路没有画好周末也没有休息多少。虽然做得不算快但是还比较顺利每个任务都会遇到一些小问题但是单步调试基本都能解决。将单周期 CPU 改造成流水线以后发现无法运行 ccmb 测试程序这是因为课程实验中实现的单周期 CPU 没有 ccmb 标准测试程序只用自己写的程序稍微验证了一下没有涵盖所有的可能性所以还存在问题。类似于这样的问题还有很多每次都是做到高阶的任务时发现低阶版本中存在问题这主要还是因为对知识的掌握不熟练导致数据通路和控制信号的设计有不周全之处。
团队建设不太成功大家合作的单周期 CPU 上板在平均水平以上但是各自分工以后某些队员的速度就明显变慢了有人在气泡流水线上花费了好几天时间遇到问题没有及时与其他人讨论总是自己蛮干。虽然小组内所有人都至少拿到了 70 分但是团队建设仍然不算成功没有形成合作学习的氛围。
应该允许自由组队这样的结果是关系好的人都分在同一组大家一定会心齐弊端就是学习差的人可能找不到队友不过他们是可以到其他组问学习好的同学的。要做得开心就要和自己中意的队友一起无所谓各自的水平不会的问题大家一起讨论或者一起去问其他人。七班的完成度最高我不清楚他们具体的分组方法老师也可以询问一下他们参照他们的模式进行分组。不过每个班的风气不同可能没有一个通用的方法。
最先通关的同学在课设结束前几天就完成了所有的任务紧接着也有很多人通关这说明课设的难度不够大最优秀的学生拿到 110 分是因为他没有其他任务可以做了只能拿 110 分而其他人的 110 分是努力了很久才刚好拿到的这两个 110 是有区别的。也不是说非要把差距拉开但还是要让很早做完的同学有事可做应该设置一个终极关卡难度控制到只有极个别人能够实现。
课设完成了以后还有意犹未尽的感觉虽然不想再来一遍了但是还是一直在回味的确很难忘感谢老师为课程付出的心血。任务书中还有少许错别字希望能够更正。
参考文献
[1] DAVID A.PATTERSON(美).计算机组成与设计硬件/软件接口(原书第 4 版).北京机械工业出版社.
[2] David Money Harris(美).数字设计和计算机体系结构第二版. 机械工业出版社
[3] 秦磊华吴非莫正坤.计算机组成原理. 北京清华大学出版社2011 年.
[4] 袁春风编著. 计算机组成与系统结构. 北京清华大学出版社2011 年.
[5] 张晨曦王志英. 计算机系统结构. 高等教育出版社2008 年.