我是靠谱客的博主 天真绿草,这篇文章主要介绍基于modelsim软件进行仿真简易CPU指令的实现基于modelsim软件进行仿真简易CPU指令的实现一、 任务、要求、目的二、 指令实现原理三、 指令实现详情及仿真四、 小结五、 参考文献,现在分享给大家,希望可以做个参考。

文章目录

  • 基于modelsim软件进行仿真简易CPU指令的实现
  • 一、 任务、要求、目的
  • 二、 指令实现原理
    • 2.1 Verilog HDL基础
    • 2.2 MIPS架构简介
      • 2.2.1 指令基础
      • 2.2.2 指令格式
    • 2.3 设计思想
      • 2.3.1 流水线
      • 2.3.2 模块化
  • 三、 指令实现详情及仿真
    • 3.1 逻辑操作类指令:ORI、ANDI、AND、XORI、XOR、NOR、OR
    • 3.2 移位操作类指令:SLL、SLLV、SRL、SRLV、SRA、SRAV
    • 3.3 移动操作类指令:MOVZ、MOVN
    • 3.4 算数运算类指令:ADD、ADDI、ADDIU、ADDU、SUBU、SUB、SUBI
    • 3.5 转移操作类指令:J、JAL、JR、BEQ
    • 3.6 访存操作类指令:SW、LW
    • 3.7 各类指令综合测试:
  • 四、 小结
  • 五、 参考文献

基于modelsim软件进行仿真简易CPU指令的实现

一、 任务、要求、目的

设计CPU系统的总体结构、指令系统和时序信号,实现至少10条并且至少涵盖4种不同类型的指令。利用Modelsim软件进行仿真。

二、 指令实现原理

2.1 Verilog HDL基础

Verilog HDL是在C语言的基础上发展而来的,就语法结构而言,Verilog HDL继承了C语言的很多语法结构,两者有许多相似之处。
  Verilog程序的基本设计单元是“模块”(Module),模块结构如图所示,Verilog的模块完全定义在module与endmodule关键字之间,每个模块包括四个主要部分:模块声明、端口定义、数据类型说明和逻辑功能描述。
在这里插入图片描述

图1.1 Verilog模块组成图
 Verilog中的常量(Constant)有三种:整数、实数、字符串。在OpenMIPS的实现过程中只使用到了整数常量,所以,此处也仅介绍整数常量。其格式如图所示

在这里插入图片描述

图1.2 Verilog常量结构图
  Verilog中变量声明的格式图所示。只有数据类型、变量名是必要的,其他部分都可以省略。如果省略符号和位宽,那么根据数据类型设置为默认值。如果省略元素数,那么默认声明元素数为1。

在这里插入图片描述

图1.3 Verilog变量结构图
  数据类型可以是net型、variable型。net型相当于硬件电路中各种物理连接,其特点是输出的值紧跟输入值的变化而变化。net型相当于硬件电路中各种物理连接,其特点是输出的值紧跟输入值的变化而变化。variable型变量是可以保存上次写入数据的数据类型,一般对应硬件上的一个触发器或锁存器等存储元件,但并不是绝对的,在综合器综合的时候,会根据其被赋值的情况来具体确定是映射成连线还是映射为存储元件。

2.2 MIPS架构简介

2.2.1 指令基础

指令的主要任务就是对操作数进行运算,操作数有不同的类型和长度,MIPS32提供的基本数据类型有位(b)、字节(Byte)、半字(Half Word)、字(Word)、双字(Double Word)等。
  MIPS32的指令中除加载/存储指令外,都是使用寄存器或立即数作为操作数的。MIPS32中的寄存器分为两类:通用寄存器(GPR:General Purpose Register)、特殊寄存器。
在这里插入图片描述

表2.1 MIPS32通用存储器列表
  MIPS32架构中定义的特殊寄存器有三个:PC(Program Counter程序计数器)、HI(乘除结果高位寄存器)、LO(乘除结果低位寄存器)。进行乘法运算时,HI和LO保存乘法运算的结果,其中HI存储高32位,LO存储低32位;进行除法运算时,HI和LO保存除法运算的结果,其中HI存储余数,LO存储商。

2.2.2 指令格式

MIPS32架构中的所有指令都是32位,也就是32个0、1编码连在一起表示一条指令,有三种指令格式。如图所示。其中op是指令码、func是功能码。
在这里插入图片描述

图2.1 MIPS32指令格式

MIPS32架构中定义的指令可以分为以下几类:

复制代码
1
2
3
4
5
6
7
1、逻辑操作指令: and、andi、or、ori、xor、xori、nor、lui 2、移位操作指令:sll、sllv、sra、srav、srl、srlv 3、移动操作指令:movn、movz、mfhi、mthi、mflo、mtlo 4、算术操作指令:add、addi、addiu、addu、sub、subu、clo、clz、slt、slti、sltiu、sltu、mul、mult、multu、madd、maddu、msub、msubu、div、divu 5、转移指令:jr 、jalr 、j 、jal、b、bal、beq、bgez、bgezal、bgtz、blez、bltz、bltzal、bne 6、加载存储指令:lb、lbu、lh、lhu、ll、lw、lwl、lwr、sb、sc、sh、sw、swl、swr

还有协处理器访问指令、异常相关指令等。但是我们只要实现其中的一小部分就可以了。

2.3 设计思想

2.3.1 流水线

将指令执行过程划分为5个模块,即取指阶段、译码阶段、执行阶段、访存阶段、回写阶段。并将其对应的文件描述如下:
在这里插入图片描述

图2.2 流水线对应各个阶段的模块、对应的文件

具体说明如下。
(1)取指阶段
PC模块:给出指令地址,其中实现指令指针寄存器PC,该寄存器的值就是指令地址。对应pc_reg.v文件
IF/ID模块:实现取指与译码阶段之间的寄存器,将取指阶段的结果(取得的指令、指令地址等信息)在下一个时钟传递到译码阶段。对应if_id.v文件

(2)译码阶段
ID模块:对指令进行译码,译码结果包括运算类型、运算所需的源操作数、要写入的目的寄存器地址等。对应id.v文件。
Regfile模块:实现了32个32位通用整数寄存器,可以同时进行两个寄存器的读操作和一个寄存器的写操作。对应regfile.v文件。
ID/EX模块:实现译码与执行阶段之间的寄存器,将译码阶段的结果在下一个时钟周期传递到执行阶段。对应id_ex.v文件。

(3)执行阶段
EX模块:依据译码阶段的结果,进行指定的运算,给出运算结果。对应ex.v文件。
DIV模块:进行除法运算的模块。对应div.v文件。
EX/MEM模块:实现执行与访存阶段之间的寄存器,将执行阶段的结果在下一个时钟周期传递到访存阶段。对应ex_mem.v文件。

(4)访存阶段
MEM模块:如果是加载、存储指令,那么会对数据存储器进行访问。此外,还会在该模块进行异常判断。对应mem.v文件。
MEM/WB模块:实现访存与回写阶段之间的寄存器,将访存阶段的结果在下一个时钟周期传递到回写阶段。对应mem_wb.v文件。

(5)回写阶段
CP0模块:对应MIPS架构中的协处理器CP0。
LLbit模块:实现寄存器LLbit,在链接加载指令ll、条件存储指令sc的处理过程中会使用到该寄存器。
HILO模块:实现寄存器HI、LO,在乘法、除法指令的处理过程中会使用到这两个寄存器。

2.3.2 模块化

复制代码
1
2
另外,模块化的接口以及连接关系如下所示:

在这里插入图片描述

图2.3 五级流水线结构及模块对应关系图

三、 指令实现详情及仿真

鉴于程序实现代码太多,就不贴出来了。

3.1 逻辑操作类指令:ORI、ANDI、AND、XORI、XOR、NOR、OR

在这里插入图片描述

图3.1
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200408213839504.png#pic_center)
图3.2

在这里插入图片描述

图3.3

在这里插入图片描述

图3.4

测试程序:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.org 0x0 .global _start .set noat _start: lui $1,0x0101 ori $1,$1,0x0101 ori $2,$1,0x1100    # $2 = $1 | 0x1100 = 0x01011101 or $1,$1,$2    # $1 = $1 | $2 = 0x01011101 andi $3,$1,0x00fe   # $3 = $1 & 0x00fe = 0x00000000  #($1 = 0x0101 1101 andi 0x00fe0000>$3) and $1,$3,$1   # $1 = $3 & $1 = 0x00000000 xori $4,$1,0xff00   # $4 = $1 ^ 0xff00 = 0x0000ff00 xor $1,$4,$1   # $1 = $4 ^ $1 = 0x0000ff00 nor $1,$4,$1    # $1 = $4 ~^ $1 = 0xffff00ff nor is "not or"

在这里插入图片描述

图3.5

3.2 移位操作类指令:SLL、SLLV、SRL、SRLV、SRA、SRAV

在这里插入图片描述

图3.6

测试程序:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.org 0x0 .set noat .global _start _start: lui $2,0x0404 ori $2,$2,0x0404 ori $7,$0,0x7 ori $5,$0,0x5 ori $8,$0,0x8 sync sll $2,$2,8 # $2 = 0x40404040 sll 8 = 0x04040400 //算术左移 sllv $2,$2,$7 # $2 = 0x04040400 sll 7 = 0x02020000 //逻辑左移,移位位数是通过寄存器的值 srl $2,$2,8 # $2 = 0x02020000 srl 8 = 0x00020200 //逻辑右移 srlv $2,$2,$5 # $2 = 0x00020200 srl 5 = 0x00001010 //逻辑右移,移位位数是通过寄存器的值 nop sll $2,$2,19 # $2 = 0x00001010 sll 19 = 0x80800000 ssnop sra $2,$2,16 # $2 = 0x80800000 sra 16 = 0xffff8080 //算术右移 srav $2,$2,$8 # $2 = 0xffff8080 sra 8 = 0xffffff80  //算术右移,移位位数是通过寄存器的值

对应波形如下:
在这里插入图片描述

图3.7

3.3 移动操作类指令:MOVZ、MOVN

在这里插入图片描述

图3.8

测试程序:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.org 0x0 .set noat .global _start _start: #//给寄存器$1、$2、$3、/4赋初值 lui $1,0x0000  # $1 = 0x00000000 lui $2,0xffff   # $2 = 0xffff0000 lui $3,0x0505  # $3 = 0x05050000 lui $4,0x0000  # $4 = 0x00000000 #//movz指令,寄存器$1为0,所以$2的值赋给$4 movz $4,$2,$1  # $4 = 0xffff0000 #//movn指令,寄存器$1为0,所以$2不值赋,$4不变 movn $4,$3,$1  # $4 = 0xffff0000 #//movn指令,寄存器$1不为0,所以$2的值赋给$4 movn $4,$3,$2  # $4 = 0x05050000 #//movz指令,寄存器$3不为0,所以不值赋,$4保持不变 movz $4,$2,$3  # $4 = 0x05050000

对应波形如下:
在这里插入图片描述

图3.9

3.4 算数运算类指令:ADD、ADDI、ADDIU、ADDU、SUBU、SUB、SUBI

在这里插入图片描述

图3.10
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200408214250813.png#pic_center?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM0NzY3Nzg0,size_16,color_FFFFFF,t_70)
图3.11

测试程序:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.org 0x0 .set noat .global _start _start: ######### addaddiaddiuaddusubsubu ########## ori $1,$0,0x8000   # $1 = 0x8000 sll $1,$1,16    # $1 = 0x80000000 ori $1,$1,0x0010   # $1 = 0x80000010//$1赋值 ori $2,$0,0x8000   # $2 = 0x8000 sll $2,$2,16    # $2 = 0x80000000 ori $2,$2,0x0001   # $2 = 0x80000001//$2赋值 ori $3,$0,0x0000   # $3 = 0x00000000 addu $3,$2,$1    # $3 = 0x00000011//$1加$2,无符号加 ori $3,$0,0x0000   # $3 = 0x00000000     #//$1加$2,有符号加,溢出 add $3,$2,$1     # overflow,$3 keep 0x00000000 sub $3,$1,$3    # $3 = 0x80000010 //$1减去$3,有符号减 subu $3,$3,$2     # $3 = 0xF //$3减去$2,(0x80000010 -0x80000001 )无符号减 addi $3,$3,2    # $3 = 0x11 //(0xF +0x2)$3加2,有符号加 ori $3,$0,0x0000    # $3 = 0x00000000 addiu $3,$3,0x8000   # $3 = 0xffff8000 // $3 (0x0)加0xffff8000,无符号加

对应波形如下:
在这里插入图片描述

图3.12

3.5 转移操作类指令:J、JAL、JR、BEQ

在这里插入图片描述

图3.13

在这里插入图片描述

图3.14

测试程序:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
.org 0x0 .set noat .set noreorder .set nomacro .global _start _start: ori $1,$0,0x0001    # $1 = 0x1 j 0x20     ##//直接跳转 ori $1,$0,0x0002    # $1 = 0x2,这是延迟槽指令 //乱序执行 ori $1,$0,0x1111 ori $1,$0,0x1100 .org 0x20 ori $1,$0,0x0003     # $1 = 0x3 jal 0x40# 转移到0x40处,同时设置$310x2c #//jal指令的延迟槽指令是除法指令,$1需要多个时钟周期保持为0x3 div $zero,$31,$1      # $31 = 0x2c, $1 = 0x3         # HI = 0x2, LO = 0xe //除法计算结果,延迟槽指令 ori $1,$0,0x0005    # r1 = 0x5 ori $1,$0,0x0006    # r1 = 0x6 j 0x60        #//跳到0x60 nop .org 0x40 jalr $2,$31     # $310x2c,转移到0x2c,同时设置$20x48 or $1,$2,$0     # $1 = 0x48,延迟槽指令 #//乱序执行,除法之后$1保留站数据到位,该指令就执行了 ori $1,$0,0x0009    # $1 = 0x9 ori $1,$0,0x000a    # $1 = 0xa j 0x80 nop .org 0x60 ori $1,$0,0x0007     # $1 = 0x7 jr $2       #此时$20x48,所以转移到0x48处 ori $1,$0,0x0008    # $1 = 0x8,延迟槽指令 ori $1,$0,0x1111 ori $1,$0,0x1100 .org 0x80 nop _loop: j _loop nop ori $1,$0,0x0005    # r1 = 0x5 ori $1,$0,0x0006     # r1 = 0x6 j 0x60        #//跳到0x60 nop .org 0x40 jalr $2,$31 or $1,$2,$0     # $1 = 0x48//乱序执行,除法之后$1保留站数据到位,该指令就执行了 ori $1,$0,0x0009    # $1 = 0x9 ori $1,$0,0x000a    # $1 = 0xa j 0x80 nop .org 0x60 ori $1,$0,0x0007   # $1 = 0x7 jr $2 ori $1,$0,0x0008   # $1 = 0x8 ori $1,$0,0x1111 ori $1,$0,0x1100 .org 0x80 nop _loop: j _loop nop

对应波形如下:
在这里插入图片描述

图3.15

在这里插入图片描述

图3.16

3.6 访存操作类指令:SW、LW

在这里插入图片描述

图3.17

在这里插入图片描述

图3.18

测试程序:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.org 0x0 .set noat .set noreorder .set nomacro .global _start _start: ori $1,$0,0x1234    # $1 = 0x00001234 sw $1,0x0($0)     # [0x0] = 0x00001234      #向数据存储器的地址0x0处存储0x00001234 ori $2,$0,0x1234    # $2 = 0x00001234 ori $1,$0,0x0    # $1 = 0x0 lw $1,0x0($0)    # 从数据存储器的地址0x0将数据处加到寄存器$1,       # $1 = 0x00001234 beq $1,$2,Label    #比较寄存器$1与$2,若相等,则则转移到Label处 nop ori $1,$0,0x4567 nop Label: ori $1,$0,0x89ab      # $1 = 0x000089ab nop _loop: j _loop nop

对应波形如下:
在这里插入图片描述

图3.19

34011234 ac010000 34021234 34010000 8c010000 10220003 00000000 34014567 00000000 340189ab 00000000 0800000b 00000000

3.7 各类指令综合测试:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//addi $1, $0, 2 $1=0000 0002 001000 00000 00001 0000000000000010 //addi $2, $1, 4 $2=0000 0006 001000 00001 00010 0000000000000100 //add $3, $1, $2 $3=0000 0008 000000 00001 00010 00011 00000 100000 //sub $4, $3, $2 $4=0000 0002 000000 00011 00010 00100 00000 100010 //ori $5, $2, 1 $5=0000 0007 001101 00010 00101 0000000000000001 //or $6, $2, $1 $6=0000 0006 000000 00010 00001 00110 00000 100101 //and $7, $5, $6 $7=0000 0006 000000 00101 00110 00111 00000 100100 //sw $7, 0($7) mem[$7]=00000006 101011 00111 00111 0000000000000000 //lw $8, 0($2) $8=0000 0006 100011 00010 01000 0000000000000000 //beq $6, $7, -3 PC-=8; 20010002   //addi $1, $0, 2 $1=0000 0002 20220004   //addi $2, $1, 4 $2=0000 0006 00221820   //add $3, $1, $2 $3=0000 0008 00622022   //sub $4, $3, $2 $4=0000 0002 34450001   //ori $5, $2, 1 $5=0000 0007 00413025   //or $6, $2, $1 $6=0000 0006 00a63824   //and $7, $5, $6 $7=0000 0006 ace70000   //sw $7, 0($7) $7=00000006 8c480000   //lw $8, 0($2) $8=0000 0006 10c7fffd   //beq $6, $7, -3 PC-=8;

各个寄存器的值:

对应波形如下:
在这里插入图片描述

图3.20
PC值减8:0x28到0x1c ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200408214627942.png#pic_center)
图3.21

四、 小结

本次计算机设计与综合实践课程设计令我获益匪浅。经过这次CPU的设计,是我对于计算机指令的执行有了更深的了解,同时体会到计算机各个功能结构协同运行实现相关指令的美妙。
  学习Verilog语言时候我才意识到语言的学习都是想通的,有了C语言的基础后,也就等于掌握了一类高级语言的语法。

五、 参考文献

[1] 雷思磊《自己动手写CPU》及其博客
https://blog.csdn.net/leishangwen/article/category/5723475/1
[2] MIPS单周期CPU设计(Verilog):
https://blog.csdn.net/quinze_lee/article/details/51174019
[3] 张晨曦 王志英《计算机体系结构》
[4] 唐朔飞《计算机组成原理》

最后

以上就是天真绿草最近收集整理的关于基于modelsim软件进行仿真简易CPU指令的实现基于modelsim软件进行仿真简易CPU指令的实现一、 任务、要求、目的二、 指令实现原理三、 指令实现详情及仿真四、 小结五、 参考文献的全部内容,更多相关基于modelsim软件进行仿真简易CPU指令的实现基于modelsim软件进行仿真简易CPU指令的实现一、内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(76)

评论列表共有 0 条评论

立即
投稿
返回
顶部