✅作者简介:CSDN内容合伙人、信息安全专业在校大学生
系列专栏 :本科生课设-计算机组成原理实验
新人博主 :欢迎点赞收藏关注,会回访!
舞台再大,你不上台,永远是个观众。平台再好,你不参与,永远是局外人。能力再大,你不行动,只能看别人成功!没有人会关心你付出过多少努力,撑得累不累,摔得痛不痛,他们只会看你最后站在什么位置,然后羡慕或鄙夷。
手懒,word直接转的markdown,所以格式很乱
熟悉并掌握 Verilog HDL 与 的使用。
请使用 Verilog 完成4选1 多路选择器(MUX) 、4 位全加器、8 位比较器、74138 译码器等模块设计,然后编写测试文件进行仿真验证。
**1)多路选择器(MUX41)**是一种在多路数据传送过程中,能够根据需要将其中任意一路选出来的电路,其原理图和真值表如图 1.1所示。
图 .1 4 选 1 多路选择器及其真值表
2)4位全加器,顾名思义,两个四位数相加,需要考虑输入的进位和输出的进位,其原理图如图1.2所示:
图1.2 4位加法器原理图
3)**8位比较器,**通过比较两个8位数的大小,最后相应的位置输出1,达到比较的目录。其原理图如图1.3所示:
图1.3 n位比较器原理图
4)**74138译码器,**其原理图如图1.4所示:
图1.4 74138译码器原理图
1)MUX41的实现
MUX 模块的功能描述如**错误!书签自引用无效。**所示。实现代码如图1.2
**设计思路:**首先创建一个模板,设计四个4位的输入,一个2位的选择器(2=4),一个4位的输出。然后设计一个switch选择器,通过选择器的不同输入,对应不同的输出。
表.1 MUX41模块功能描述
图1.5 MUX41的实现代码
2)四位全加器的实现
**设计思路:**通过将两个四位二进制数相交,然后再加上输入的进位。考虑到可能溢出(进位),所以保存时用五位数字来保存,最高位代表是否进位。代码如下图1.6所示:
图1.6 四位全加器代码实现
3)8位比较的实现
**设计思路:**输入为两个8位数,输出为3个参数,分别是(赋值为1时代表该位有效),所以通过判断俩个数的大小,然后对三个输出参量分别赋值即可。此处可以优化为n位比较器。代码如下图1.7:
图1.7 n位比较器的代码实现
4)74138译码器的实现
**设计思路:**74138译码器有三个输入,8个输出。(2=8),通过一个case查询输入的3位二进制序列,得到输出的对应序列。实现的代码如下图1.8:
图1.8 74138的代码实现
1)MUX41的测试代码
**实现思路:**首先定义5个寄存器,4个4位的用来输入,一个2位的用来选择。首先初始化每个寄存器的值,分别为1,2,4,8。然后通过对select赋值,可以得到不同的输出,为了一次实验可以看到全部结果,可以用命令,实现延时10个单位时间的作用,通过他对select赋值,即可实现一次实验测出不同select下的输出值。代码如下图1.9:
图1.9 四选选择器测试代码
2)4位全加器的测试代码
**实现思路:**首先定义两个4位的二进制输入和1个进位输入,然后调用写好的全加器,最终得到五位数字,最高位代表是否有进位。代码如下图1.10:
图1.10 四位全加器的测试代码
3)8位比较器的测试代码
**实现思路:**通过传入不同的8位二进制代码,来得到相应的输出。如下图所示:
图1.11 8位比较器的测试代码
4)74138译码器的测试代码
**实现思路:**通过输入不同的3位二进制数据,得到不同的输入,通过三八译码器得到不同的输出,测试代码如下图所示:
图1.12 74138译码器的测试代码
故障现象: 软件报错,提示下列信息
**原因分析:**创建项目是所选用的开发板不对应
**解决方案:**创建项目时选用正确的开放板,有许可签证的开发板。
**故障现象:**模拟仿真时没有出现相应的数字。而是X和Z
**原因分析:**查找了相关资料,应该是函数之间的接口或者传参时发生了问题,导致参数没有被传过去。
**解决方案:**检查函数的接口和传参即可。
表1.2 MUX41选择器仿真数据
图1.13 模拟仿真结果
2) 4位全加器:
输入a | 输入b | 输入进位 | 输出(含进位) |
---|---|---|---|
1100 | 0111 | 0 | 10011 |
1001 | 0110 | 0 | 01111 |
0010 | 0101 | 1 | 01000 |
1001 | 1010 | 1 | 10100 |
表1.3 4位全加器的测试数据
图1.14 模拟仿真结果
3)8位比较器
输入a | 输入b | 输出Great | 输出Equal | 输出Small |
---|---|---|---|---|
11110000 | 10000000 | 1 | 0 | 0 |
11110000 | 11110000 | 0 | 1 | 0 |
10000000 | 11110000 | 0 | 0 | 1 |
理解和掌握 CPU 中的算术逻辑运算部件(ALU)和寄存器堆(Register File)的工作 原理,并使用 Verilog 和 ModelSim 进行设计和仿真。
1)使用 Verilog 完成 ALU 的设计,并编写测试仿真文件验证其正确性。要求: ALU 支持 16 位的加、减、与、或以及移位运算。
2)使用 Verilog 完成通用寄存器堆的设计,并编写测试仿真文件验证其正确性。
要求 寄存器堆包含 8 个 16 位的寄存器。
寄存器堆有两个读端口和一个写端口。
1)16位ALU的逻辑运算及移位运算的实现
**设计思路:**首先创建一个模板,该模块输入有两个被运算的数和一个操作数类型,输出为两个操作数经过操作后的记过。两个输入和一个输出为16为二进制数,输入的操作数类型为4位二进制数(因为有2=16种运算)。然后用一个case选择器,根据不同的操作数输入,返回不同的结果,实现代码如下:
图2.1 16位的ALU逻辑运算及移位运算的代码实现
2)使用 Verilog 完成通用寄存器堆的设计,并编写测试仿真文件验证其正确性。
**设计思路:**首先创建一个模板,该模板有一个时钟信号,一个写信号,两个读位置,一个写位置,两个读数据,一个写数据的位置。因为有8个寄存器, 所以用3位二进制表示他们的位置,用命令创建8个16位的寄存器,实现代码如下:
图2.2 通用寄存器堆的设计代码实现
1)16位ALU的逻辑运算及移位运算的实现的测试代码
**实现思路: **选取起点a=1,b=1,op=0进行循环,每次循环后a++,b++,op++,通过遍历16种可能的op即可得到相应的输出值。测试代码如下图2.3:
图2.3 16位ALU的逻辑运算及移位运算的实现的测试代码
2)8个16位的通用寄存器堆的设计的测试代码
**实现思路:**初始化写信号为0,俩个读的位置分别为1和2,写的位置为0,要写入的数据为10,然后循环,每次循环结束,读的位置+1,写的位置+1,要写入的数据+1,即可遍历所有的可能,测试代码如下图2.4:
图2.4 8个16位的通用寄存器堆的设计的测试代码
故障现象: 软件报错,提示下列信息
**原因分析:**创建项目是所选用的开发板不对应
**解决方案:**创建项目时选用正确的开放板,有许可签证的开发板。
**故障现象:**模拟仿真时没有出现相应的数字。而是X和Z
**原因分析:**查找了相关资料,应该是函数之间的接口或者传参时发生了问题,导致参数没有被传过去。
**解决方案:**检查函数的接口和传参即可。
表2.1 16位ALU的逻辑运算及移位运算测试数据
图2.5 16位ALU的逻辑运算及移位运算模拟仿真1
图2.6 16位ALU的逻辑运算及移位运算模拟仿真2
图2.7 16位ALU的逻辑运算及移位运算的电路图
clk | We | ReadA | ReadB | RW | busW | busA | busB |
---|---|---|---|---|---|---|---|
0000 | 0001 | 0005 | 0006 | 0001 | 000b | 0005 | 0006 |
0001 | 0000 | 0006 | 0007 | 0002 | 000c | 0006 | 0007 |
0000 | 0000 | 0007 | 0000 | 0002 | 000c | 0007 | 0000 |
0001 | 0001 | 0000 | 0001 | 0002 | 000c | 0000 | 0001 |
0000 | 0000 | 0001 | 0002 | 0003 | 000d | 0001 | 000c |
0001 | 0001 | 0002 | 0003 | 0003 | 000d | 000c | 000d |
0000 | 0000 | 0003 | 0004 | 0004 | 000e | 000d | 0004 |
0001 | 0000 | 0004 | 0005 | 0004 | 000e | 0004 | 0005 |
表2.2 两个读,一个写的通用寄存器堆的测试数据(16进制)
图2.8 两个读,一个写的通用寄存器堆的模拟仿真
图2.9 两个读,一个写的通用寄存器堆的电路图
理解和掌握 CPU 中程序计数器 PC 和半导体存储器 RAM 的工作原理,并使用 Verilog 和 ModelSim 进行设计和仿真。
1) 使用 Verilog 完成程序计数器 PC 的设计,要求: PC 为 8 位计数器
2) 使用 Verilog 完成数据存储器的设计,并编写测试仿真文件验证其正确性。要求存储字长 16 位,存储容量 1K 字节;一根读写控制信号线控制读写,低电平有效。
1)使用 Verilog 完成程序计数器 PC 的设计,要求: PC 为 8 位计数器
**设计思路:**定义两个输入信号时钟和复位信号,一个输出PC。当时钟信号来临时,需要进行操作,普通时钟信号,则PC+1,若是复位信号,则PC=0;设计代码如下图
图3.1 程序计数器PC的代码实现
2)使用 Verilog 完成数据存储器的设计,并编写测试仿真文件验证其正确性。要求存储字长 16 位,存储容量 1K 字节;一根读写控制信号线控制读写,低电平有效。
**设计思路:**定义四个输入,一个时钟信号,一个读写信号,一个写的地址,一个写的数据,定义一个输出端口,用于输出数据。存储字长16位,存储容量1K字节,一根读写控制信号线控制读写,低电平有效。实现代码如下图3.2:
图3.2 存储器RAM的代码实现
1)使用 Verilog 完成程序计数器 PC 的设计,要求: PC 为 8 位计数器
**测试思路:**随机选取不同的时钟信号和复位信号,观察相应的PC输出,测试代码如下图3.:
图3.3程序计数器PC测试代码的实现
2)测试存储器RAM的代码实现
**测试思路:**通过编写一个随机的时钟信号和随机的内容,对存储器进行读写操作,测试代码如下图3.4:
故障现象: 软件报错,提示下列信息
**原因分析:**创建项目是所选用的开发板不对应
**解决方案:**创建项目时选用正确的开放板,有许可签证的开发板。
**故障现象:**模拟仿真时没有出现相应的数字。而是X和Z
**原因分析:**查找了相关资料,应该是函数之间的接口或者传参时发生了问题,导致参数没有被传过去。
**解决方案:**检查函数的接口和传参即可。
表3.1 程序计数器PC测试数据
图3.5 程序计数器PC模拟仿真
图3.5 程序计数器PC电路图
图3.6 程序计数器PC模拟仿真
图3.7 程序计数器PC电路图
通过设计并实现支持一条指令的 CPU,理解和掌握 CPU 设计的基本原理和过程。
设计和实现一个支持加法指令的单周期 CPU。要求该加法指令(表示为 add r1,r2, r3)格式约定如下:
采用寄存器寻址,r1,r2,r3 为寄存器编号,r1 和 r2 存放两个源操作数,r3 为目标寄存器,其功能为[r1] + [r2] -> r3;
指令字长 16 位,操作码和地址码字段分配如下所示:
图4.1 指令分配字段图
单周期 CPU 是指所有指令均在一个时钟周期内完成的 CPU。CPU 由数据通路及其控 制部件两部分构成,因而要完成一个支持若干条指令 CPU 的设计,需要依次完成以下两件 事: 1)根据指令功能和格式设计 CPU 的数据通路; 2)根据指令功能和数据通路设计控制部件。
1)根据功能和格式完成 CPU 的数据通路设计
本实验需要设计的 CPU 只需要支持一条加法指令,而该指令的功能是在一个时钟周期 内从寄存器组中 r1 和 r2 中取出两个操作数,然后送到 ALU 进行加法运算,最后把计算结 果保存到 r1 寄存器中。下图给出了改加法指令的数据通路图。此外,还需要确定各个部件的位数,为了简单起见,我们假设目标 CPU 的机器字长、 存储字长和指令字长相等均为 16 位,存储单元个数假设为 256,按字寻址,并取 PC 位数为 8。
图4.2 加法指令add r1,r2,r3 数据通路
2)根据指令功能、数据通路完成控制单元的设计
控制单元的功能是为当前要执行的指令产生微操作命令从而完成该指令的执行。为了能 够完成加法指令的执行,结合图 4…2,控制单元需要在取出指令后根据指令操作码(本例中是加法指令),控制 ALU做加法(通过给 信号线相应赋值),并把结果写回寄存器组中(通过给 赋值为 true)。图 4.3 给出了整合控制单元后目标 CPU 的原理图,系统时钟信号也已标注。
图4.3 单指令CPU原理图
表4.1 PC模块功能描述
**实现思路:**定义俩个输入信号和一个8位的输出信号,每次时钟上沿时,PC自动加1,若重置信号到来则PC=0;实现代码如下图4.4:
图4.4 PC模块代码实现
表4.2 PC指令存储器模块功能描述
**实现思路:**定义一个8位的输入和一个16位的输出,按照1K编址,然后随机存储待执行的指令。实现代码如下图4.5:
图4.5 PC指令存储器模块功能实现
表4.3 寄存器堆模块功能描述
**实现思路:**定义一个时钟信号输入,一个读写控制线,两个读寄存器编号,一个写寄存器编号,一个写入数据。首先进行随机初始化,然后对于读寄存器编号,读出相应的值,写入段的数据在下降沿写到写寄存器编号对应的寄存器里。实现代码如下图4.6:
图4.6 寄存器堆功能实现代码
表 4.4 ALU 模块功能描述
**实现思路:**定义两个操作数in1和in2,一个操作选择信号alu_op,编写一个switch循环,通过不同的选择信号,返回不同的运算结果值。代码如下图4.7:
图4.7 ALU模块实现代码
表 4.5 控制单元模块功能描述
**实现思路:**设置一个输入的操作码,输出寄存器堆的读写控制线和操作信号选择先,根据当前指令的功能,对wr_en和alu_op赋值。代码如下图4.8:
图4.8 CU模块实现代码
通过根据图 4.3 将以上定义的模块进行连接、封装就得到了目标 CPU,该 CPU 的输入为 系统时钟信号 clk 和重置信号 reset。
为了仿真验证所实现的 CPU,需要定义测试文件并在测试文件中对指令存储器和寄存器堆中的相应寄存器的值进行初始化,并通过仿真波形图查看是否指令得到了正确执行。
通过根据图 4.3 将以上定义的模块进行连接、封装。测试代码时,输入时钟和复位信号,初始化各个模块,
图4.9 测试代码
故障现象: 软件报错,提示下列信息
**原因分析:**创建项目是所选用的开发板不对应
**解决方案:**创建项目时选用正确的开放板,有许可签证的开发板。
**故障现象:**模拟仿真时没有出现相应的数字。而是X和Z
**原因分析:**查找了相关资料,应该是函数之间的接口或者传参时发生了问题,导致参数没有被传过去。
**解决方案:**检查函数的接口和传参即可。
clk | Rst | Op | Addr | Z | Ins | R1 | R2 | St_r1 | St_addr |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 0 | 7b | 0020 | 0763 | 000d | 0013 | zzzz | zzzz |
1 | 0 | 0 | 7c | 0013 | 09ac | 0006 | 000d | zzzz | zzzz |
0 | 0 | 0 | 7d | 000d | 0bf5 | 0007 | 0006 | zzzz | zzzz |
0 | 0 | 6 | 7e | 0086 | 0088 | 0033 | 0053 | zzzz | zzzz |
表4.6 单周期CPU测试数据(OP=0)
clk | Rst | Op | Addr | Z | Ins | R1 | R2 | St_r1 | St_addr |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 1 | 65 | 0001 | 0bf5 | 0007 | 0006 | zzzz | zzzz |
0 | 0 | 1 | 67 | fff3 | 02d1 | fffc | 0009 | zzzz | zzzz |
1 | 0 | 1 | 68 | 0009 | 051a | 0005 | Fffc | zzzz | zzzz |
0 | 0 | 1 | 69 | ffffc | 0763 | 0001 | 0005 | zzzz | zzzz |
表4.7 单周期CPU测试数据(OP=1)
clk | Rst | Op | Addr | Z | Ins | R1 | R2 | St_r1 | St_addr |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 2 | 1b | 0001 | 0763 | 0001 | 0001 | zzzz | zzzz |
1 | 0 | 2 | 1c | 0001 | 09ac | 0006 | 0001 | zzzz | zzzz |
0 | 0 | 2 | 53 | 0001 | 0bf5 | 0007 | 0006 | zzzz | zzzz |
0 | 0 | 2 | 52 | 0001 | 09ac | 0006 | 0001 | zzzz | zzzz |
表4.8单周期CPU测试数据(OP=2)
clk | Rst | Op | Addr | Z | Ins | R1 | R2 | St_r1 | St_addr |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 3 | 94 | 0001 | 09ac | 0006 | 0001 | zzzz | zzzz |
1 | 0 | 3 | 95 | 0001 | 0bf5 | 0007 | 0006 | zzzz | zzzz |
0 | 0 | 3 | 97 | 0001 | 02d1 | 0001 | 0001 | zzzz | zzzz |
0 | 0 | 3 | 87 | 0001 | 0763 | 0001 | 0001 | zzzz | zzzz |
表4.9 单周期CPU测试数据(OP=3)
clk | Rst | Op | Addr | Z | Ins | R1 | R2 | St_r1 | St_addr |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 4 | 85 | 01c0 | 02d1 | 01c0 | 0000 | zzzz | zzzz |
1 | 0 | 4 | 86 | 0000 | 051a | 0000 | 01c0 | zzzz | zzzz |
0 | 0 | 4 | 87 | 01c0 | 0763 | 01c0 | 0000 | zzzz | zzzz |
0 | 0 | 4 | D6 | 0000 | 09ac | 0006 | 01c0 | zzzz | zzzz |
表4.10 单周期CPU测试数据(OP=4)
clk | Rst | Op | Addr | Z | Ins | R1 | R2 | St_r1 | St_addr |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 5 | 65 | 0006 | 0bf5 | 0007 | 0006 | zzzz | zzzz |
1 | 0 | 5 | 85 | 0000 | 02d1 | 0000 | 0006 | zzzz | zzzz |
0 | 0 | 5 | 86 | 0006 | 051a | 0006 | 0000 | zzzz | zzzz |
0 | 0 | 5 | 87 | 0000 | 0763 | 0000 | 0006 | zzzz | zzzz |
表4.9 单周期CPU测试数据(OP=5)
clk | Rst | Op | Addr | Z | Ins | R1 | R2 | St_r1 | St_addr |
---|---|---|---|---|---|---|---|---|---|
1 | 0 | 6 | 3d | zzzz | 02d1 | zzzz | zzzz | zzzz | zzzz |
0 | 0 | 6 | 3a | zzzz | 051a | zzzz | zzzz | zzzz | zzzz |
1 | 0 | 6 | 40 | zzzz | 09ac | 0006 | zzzz | zzzz | zzzz |
0 | 0 | 6 | 07 | zzzz | 02d1 | zzzz | zzzz | zzzz | zzzz |
表4.6 单周期CPU测试数据(OP=6)
图4.10 单周期CPU模拟仿真图(OP=0)
图4.11 单周期CPU模拟仿真图(OP=1)
图4.12 单周期CPU模拟仿真图(OP=2)
图4.13 单周期CPU模拟仿真图(OP=3)
图4.14 单周期CPU模拟仿真图(OP=4)
图4.15 单周期CPU模拟仿真图(OP=5)
图4.10 单周期CPU模拟仿真图(OP=6)
图4.11 单周期CPU电路图
本次实验主要完成了如下几点工作:
通过本次实验,我熟悉了verilog语言的语法,可以熟练的使用vivado。同时也培养了我的动手能力,“实验就是为了让你动手做,去探索一些你未知的或是你尚不是深刻理解的东西。每个步骤我都亲自去做,不放弃每次锻炼的机会。经过这两周,让我的动手能力有了明显的提高。计算机组成原理的课程历时大半个学期,做实验时通过自己编写、运行程序,不仅可以巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。以前对于编程工具的使用还处于一知半解的状态上,但是经过一段上机的实践,对于怎么去排错、查错,怎么去看每一步的运行结果,怎么去了解每个寄存器的内容以确保程序的正确性上都有了很大程度的提高。前四个简单程序设计,加深了我们对初学堆verilog指令的熟悉和理解。通过学习和使用,向上为理解各种软件系统打好基础,打下技术理论基础;向下为掌握硬件系统的原理,打下实践应用基础。不仅巩固了书本所学的知识,还具有一定的灵活性,发挥了我们的创造才能。
通过这次课程设计使我懂得了理论与实际相结合是很重要的,只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,才能真正提高自己的实际动手能力和独立思考的能力。在设计的过程中遇到问题,可以说得是困难重重,这毕竟第一次做的,难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。这次课程设计终于顺利完成了,在设计中遇到了很多编程问题,最后在自己的思考以及和同学的讨论中,终于迎刃而解。
hfut学弟后台私信我,可以领代码