tiny riscv -soc文件-及仿真验证

286 阅读3分钟

image.png

通过risc-v访问rom。

	input  wire 		  clk   		,
	input  wire 		  rst     		
);

	// open_risc_v to rom 
	wire[31:0] open_risc_v_inst_addr_o;
	
	//rom to open_risc_v
	wire[31:0] rom_inst_o;
	
	open_risc_v open_risc_v_inst(
	.clk  			    (clk  					), 
	.rst 				(rst					),
	.inst_i				(rom_inst_o				),
	.inst_addr_o		(open_risc_v_inst_addr_o)
    );


	rom rom_inst(
	.inst_addr_i	(open_risc_v_inst_addr_o),
	.inst_o         (rom_inst_o				)
);


endmodule

进行测试

image.png

image.png

1 第一条指令

MOV x27,12'd26 : 将寄存器x7填充,立即数38

ADDI x27,x0,imm

000000100110_00000_000_11011_0010011

rs1为0,0010011为操作码I型指令操作码

2 第二条指令

MOV x28,12'd54 :将x28寄存器填充立即数54

ADDI x28,x0,immm

000000110110_00000_000_11011_0010011

3 第三条指令 0110011 为R型指令操作码

ADD X29,X28,x27

0000000_11100_11011_000_rd_0110011

testbench

指令通过txt文件写入。

inst_data_ADD.txt:

00000010011000000000110110010011 00000111100000000000111000010011 00000001110011011000111010110011

应该去打印x27 x28 x29寄存器的值,去查看。

通过while循环。while(1),


	reg clk;
	reg rst;
	
        // 延时后生成时钟
	always #10 clk = ~clk;
	
	initial begin
		clk <= 1'b1;
		rst <= 1'b0;
		#30;  // 延时后取消复位
		rst <= 1'b1;	
	end
	
        
        
        
	//rom 初始值  仿真开始就加入
	initial begin
//系统函数写入。 文件名和写入地址。 写入地址通过例化名. 的形式获取将数据吸入rom_mem中		$readmemb("inst_data_ADD.txt",tb.open_risc_v_soc_inst.rom_inst.rom_mem);
	end

//打印寄存器输出。 第一个为格式,第二个为寄存器变量名regs[27],regs[28],regs[29]
	initial begin
		while(1)begin
			@(posedge clk) 
			$display("x27 register value is %d",tb.open_risc_v_soc_inst.open_risc_v_inst.regs_inst.regs[27]);
			$display("x28 register value is %d",tb.open_risc_v_soc_inst.open_risc_v_inst.regs_inst.regs[28]);
			$display("x29 register value is %d",tb.open_risc_v_soc_inst.open_risc_v_inst.regs_inst.regs[29]);
                        //分隔线
			$display("---------------------------");
			$display("---------------------------");
		end
	end
	
        
        // 例化处理器 
	open_risc_v_soc open_risc_v_soc_inst(
		.clk   		(clk),
		.rst 		(rst)
	);


	
endmodule

verilog中的displaydisplay 和write

$display(p1,p2, …,pn);

$write(p1,p2, …,pn);

这两个函数和系统任务的作用都是用来输出信息,即将参数p2到pn按参数p1给定的格式输出。参数p1通常称为:“格式控制”,参数p2至pn通常称为“输出列表”。

display自动地在输出后进行换行,display自动地在输出后进行换行,write则不是这样。如果想在一行里输出多个信息,可以使用write。如:write。如:display(“%d”,10) 和 $display(“%d\n”,10) 效果相同

verilog系统函数 readmembreadmemb和readmemh

作用:把文本文件中的数据赋值到存储器中。

$readmemb(“File”,MemoryName[, StartAddr[, FinishAddr]]);

$readmemh(“File”,MemoryName[, StartAddr[, FinishAddr]]);

起始地址可以省略。

readmemb(File,MemoryName); readmemb(“File”,MemoryName);\ readmemh(“File”,MemoryName);

readmemb要求文本中的每个数字是二进制值,而readmemb要求文本中的每个数字是二进制值,而readmemh要求文本中的每个数字是十六进制值。

modelsim仿真

change directory - new library - new project - 导入工程

compel all

宏定义文件,需要包含文件的绝对路径。且/ 分隔符。

image.png

image.png

双击tb文件,只仿真测试文件即可。

image.png

vsim命令行进行仿真

run # 执行仿真(默认执行100ns,-all 执行到结束)

txt文件的读取也要加上路径。

image.png

image.png

流水线输出,第一条指令完成后,下一个周期第二条指令,也完成了

,再一下个周期完成第三条指令

image.png

第一个时钟上升沿开始,第一个周期为不定态,因为未复位,第二个周期开始复位。

第三个周期开始为cpu的第一个周期取指, 依次译码,执行。

即在第五个周期到来时,完成第一条指令。 第一条指令有效耗时,三个周期,第六个周期完成第二条指令,第七个周期完成执行第三条指令

与下图仿真结果完全一致。

image.png

image.png