从零开始设计RISC-V处理器——单周期处理器的仿真

系列文章目录

(一)从零开始设计RISC-V处理器——指令系统
(二)从零开始设计RISC-V处理器——单周期处理器的设计
(三)从零开始设计RISC-V处理器——单周期处理器的仿真
(四)从零开始设计RISC-V处理器——ALU的优化
(五)从零开始设计RISC-V处理器——五级流水线之数据通路的设计
(六)从零开始设计RISC-V处理器——五级流水线之控制器的设计
(七)从零开始设计RISC-V处理器——五级流水线之数据冒险
(八)从零开始设计RISC-V处理器——五级流水线之控制冒险
(九)从零开始设计RISC-V处理器——五级流水线之分支计算前移
(十)从零开始设计RISC-V处理器——五级流水线之静态预测


文章目录

  • 系列文章目录
  • 前言
  • 一、U-type测试
  • 二、跳转指令测试
  • 三、访存指令测试
  • 四、算数运算指令测试
  • 五、逻辑运算指令测试
  • 六、移位运算指令测试
  • 七、小于置一指令测试
  • 总结


前言

上一篇文章介绍了单周期CPU的实现,本篇文章进行功能仿真
(目前单周期处理器代码已经更新完成,点击链接直达:基于RISC-V指令集的单周期处理器的设计)


一、U-type测试

包含lui,auipc两条指令。
测试代码如下:

lui x1,0xfffff
addi x2,x0,0xff
slli x3,x2,4
addi x3,x3,0xf
add x4,x3,x1
auipc x5,0xfff

汇编器执行结果如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第1张图片
CPU的仿真波形如下:
在这里插入图片描述

二、跳转指令测试

包含jal,jalr,beq,bne,blt,bge,bltu,bgeu共8条指令。
测试代码如下:

addi x1,x0,1
addi x2,x0,2
jal x31,label1
addi x3,x0,3
label1:
addi x4,x0,4
add x5,x2,x2
beq x4,x5,label2
addi x6,x0,6
label2:
bne x4,x5,label3
addi x7,x0,7
label3:
bne x7,x6,label4
addi x8,x0,8
label4:
addi x9,x0,0x30
jalr x10,x9,12
addi x11,x0,11
addi x12,x0,-12
addi x13,x0,-13
blt x13,x12,label5
addi x14,x0,-14
label5:
bltu x13,x12,label6
addi x15,x0,-15
label6:
bltu x12,x13,label7
addi x16,x0,-16
label7:
bge x12,x13,label8
addi x17,x0,-17
label8:
bge x1,x2,label9
addi x18,x0,-18
label9:
bgeu x12,x13,label10
addi x19,x0,-19
label10:
bgeu x13,x12,label11
addi x20,x0,-20
label11:
addi x21,x0,-20
addi x22,x0,-20
bge x21,x22,label12
addi x23,x0,-23
label12:
addi x24,x0,-24

以上代码在编写的过程中,在跳转指令与跳转目标地址的指令之间都至少插入了一条指令,目的是为了体现跳转与否。

汇编器执行结果如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第2张图片
从零开始设计RISC-V处理器——单周期处理器的仿真_第3张图片
从零开始设计RISC-V处理器——单周期处理器的仿真_第4张图片

CPU的仿真波形如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第5张图片
可以看到,在这里,给X7赋值之后后面的指令都没有正常运行。
这是 因为下一条指令是bne x7,x6,label4,由于X6是未知态,所以这条指令无法正确判断。所以我们暂时在寄存器堆模块给32个寄存器赋一个初始值0。
代码修改如下:

`include "define.v"
//`define INITIAL
module registers(
	clk,
	rst_n,
	W_en,
	Rs1,
	Rs2,
	Rd,
	Wr_data,
	Rd_data1,
	Rd_data2
    );
	input clk;
	input rst_n;
	input W_en;
	input [4:0]Rs1;
	input [4:0]Rs2;
	input [4:0]Rd;
	input [31:0]Wr_data;
	
	output [31:0]Rd_data1;
	output [31:0]Rd_data2;
	
	reg [31:0] regs [31:0];
	
	
///write
`ifdef INITIAL
	always@(posedge clk )
		begin
			if(W_en & (Rd!=0))
			regs[Rd]<=Wr_data;	
		end
`else		
	always@(posedge clk )
		begin
			if(!rst_n)
				begin
					regs[0]<=`zero_word;
					regs[1]<=`zero_word;
					regs[2]<=`zero_word;
					regs[3]<=`zero_word;
					regs[4]<=`zero_word;
					regs[5]<=`zero_word;
					regs[6]<=`zero_word;
					regs[7]<=`zero_word;
					regs[8]<=`zero_word;
					regs[9]<=`zero_word;
					regs[10]<=`zero_word;
					regs[11]<=`zero_word;
					regs[12]<=`zero_word;
					regs[13]<=`zero_word;
					regs[14]<=`zero_word;
					regs[15]<=`zero_word;
					regs[16]<=`zero_word;
					regs[17]<=`zero_word;
					regs[18]<=`zero_word;
					regs[19]<=`zero_word;
					regs[20]<=`zero_word;
					regs[21]<=`zero_word;
					regs[22]<=`zero_word;
					regs[23]<=`zero_word;
					regs[24]<=`zero_word;
					regs[25]<=`zero_word;
					regs[26]<=`zero_word;
					regs[27]<=`zero_word;
					regs[28]<=`zero_word;
					regs[29]<=`zero_word;
					regs[30]<=`zero_word;
					regs[31]<=`zero_word;
				end
			else if(W_en & (Rd!=0))
					regs[Rd]<=Wr_data;	
		end
`endif	
//read

	assign Rd_data1=(Rs1==5'd0)?`zero_word: regs[Rs1];
	assign Rd_data2=(Rs2==5'd0)?`zero_word: regs[Rs2];
	

endmodule

注意:此处由于仿真时寄存器的值是未知态,所以需要对寄存器赋初始值。在实际的设计中,这里是不需要进行赋初值的,因为CPU上电之后都会执行一段初始化代码。在FPGA开发板中,也是不需要赋初值的,因为FPGA开发板内部的寄存器上电会自动置零。

更改后的仿真波形如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第6张图片
从零开始设计RISC-V处理器——单周期处理器的仿真_第7张图片

三、访存指令测试

包含lb,lh,lw,lbu,lhu,sb,sh,sw共8条指令。
测试代码如下:

addi x1,x0,0x70
slli x2,x1,8
addi x1,x0,0x71
add x2,x2,x1
slli x2,x2,8
addi x1,x0,0xf2
add x2,x2,x1
slli x2,x2,8
addi x1,x0,0xf3
add x2,x2,x1
sw x2,0,x0
sh x2,4,x0
sb x2,7,x0
lb x3,0,x0
lb x4,1,x0
lb x5,2,x0
lb x6,3,x0
lbu x7,0,x0
lbu x8,1,x0
lbu x9,2,x0
lbu x10,3,x0
lh x11,0,x0
lh x12,2,x0
lh x13,4,x0
lhu x14,0,x0
lhu x15,2,x0
lhu x16,4,x0
lw x17,0,x0

汇编器执行结果如下:
寄存器堆:
从零开始设计RISC-V处理器——单周期处理器的仿真_第8张图片
从零开始设计RISC-V处理器——单周期处理器的仿真_第9张图片

数据存储器:
从零开始设计RISC-V处理器——单周期处理器的仿真_第10张图片

CPU的仿真波形如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第11张图片
从零开始设计RISC-V处理器——单周期处理器的仿真_第12张图片
从零开始设计RISC-V处理器——单周期处理器的仿真_第13张图片

四、算数运算指令测试

包含add,sub,addi共3条指令。
测试代码如下:

addi x1,x0,1
add x2,x1,x1
add x3,x2,x2
sub x3,x3,x1

addi x4,x0,-4
add x5,x4,x4
sub x6,x5,x3
sub x7,x6,x4
add x8,x7,x3

汇编器执行结果如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第14张图片

CPU的仿真波形如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第15张图片

五、逻辑运算指令测试

包含and,or,xor,andi,ori,xori六条指令。
测试代码如下:

addi x1,x0,0b00110011
addi x2,x0,0b11111100
and x3,x1,x2
or x4,x1,x2
xor x5,x1,x2
andi x6,x1,0b11111100
ori x7,x1,0b11111100
xori x8,x1,0b11111100

汇编器执行结果如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第16张图片
CPU的仿真波形如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第17张图片

六、移位运算指令测试

包含sll,srl,sra,slli,srli,srai六条指令。
测试代码如下:

addi x1,x0,0xff
addi x2,x0,4
sll x3,x1,x2
srl x4,x1,x2
sra x5,x1,x2

addi x6,x0,-0xff
sll x7,x6,x2
srl x8,x6,x2
sra x9,x6,x2

slli x11,x1,4
srli x12,x1,4
srai x13,x1,4

slli x11,x6,4
srli x12,x6,4
srai x13,x6,4

汇编器执行结果如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第18张图片
在这里插入图片描述

CPU的仿真波形如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第19张图片

七、小于置一指令测试

包含slt,stlu,slti,sltiu四条指令。
测试代码如下:

addi x1,x0,-1
addi x2,x0,-2
addi x3,x0,3
addi x4,x0,4
slt x5,x1,x2
slt x6,x2,x1
slt x7,x3,x4
slt x8,x4,x3
sltu x9,x1,x3
sltu x10,x3,x1
sltu x11,x1,x2
slti x12,x3,-3
slti x13,x3,4
slti x14,x2,-1
slti x15,x2,-4
sltiu x16,x3,-3
sltiu x17,x3,4
sltiu x18,x2,-1
sltiu x19,x2,-4

汇编器执行结果如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第20张图片
从零开始设计RISC-V处理器——单周期处理器的仿真_第21张图片

CPU的仿真波形如下:
从零开始设计RISC-V处理器——单周期处理器的仿真_第22张图片

总结

以上就是今天的内容,对37条指令进行逐条仿真,在设计仿真的指令时要注意测试的完备性,比如正数的加减法,负数的加减法,正数与负数的加减法,溢出检测,进位检测等。 下一篇文章开始对处理器进一步优化。

你可能感兴趣的:(RISC-V学习笔记,risc-v,fpga开发,cpu,硬件工程)