《自己动手写CPU》学习记录(3)——第4章/Part 1

news2024/11/19 3:48:15




目录

引言

致谢

平台

ori 指令

流水线结构建立

模型

简单的MIPS五级流水线结构

设计

宏定义

程序计数器

译码

通用寄存器

指令执行

内存访问

指令ROM

顶层文件

处理器顶层

SOPC顶层 

功能仿真

TestBench

仿真结果

执行时间

时序细节


 


引言

本篇学习书本的第四章,实现 ori 指令。

致谢

感谢书籍《自己动手写CPU》及其作者雷思磊。一并感谢开源精神。

平台

开发环境:Vivado IDE 2018.3

FPGA芯片型号:xc7a35tfgg484-2



ori 指令

指令格式:

指令用法:

ori rs, rt,immediate

其作用是将指令中的16位立即数进行无符号数扩展至 32 位,然后与索引号为 rs 的通用寄存器的值进行逻辑或运算,运算的结果保存到索引号为 rt 的寄存器内。

符号扩展示例:

流水线结构建立

模型

简单的MIPS五级流水线结构

设计

声明:

设计思路基本借鉴书本,但是具体的模块代码编写,与作者有较大不同

宏定义

此文件主要定义了一些与设计相关的宏,当设计的参数需要更改时,在此文件修改即可,不需要改动内部设计文件。方便代码维护,也增强了代码的可读性。

// |------------------------------ ================================== ------------------------------
// |============================== MIPS32 CPU SYSTEM ALL MACRO DEFINE ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-06
// |Finish Date : 2022-
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |


// |--------------------------------------  系统级全局宏定义  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 0字
`define 							DEF_ZERO_WORD						32'd0				// 0字

// | 关于译码
`define 							DEF_ALU_OPR_BUS						7:0					// 译码输出 O_ALU_OPR 总线
`define 							DEF_ALU_SEL_BUS 					2:0					// 译码输出 O_ALU_SEL 总线

// | 逻辑 0 1
`define 							DEF_LOG_TRUE						1'b1				// 逻辑 真
`define 							DEF_LOG_FALSE						1'b0				// 逻辑 假

// | 芯片使能
`define 							DEF_CHIP_EN							1'b1				// 芯片使能
`define 							DEF_CHIP_DIS						1'b0				// 芯片不使能



// |--------------------------------------  指令相关的宏定义  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 指令码
`define 							DEF_ISTC_ORI						6'b001101 			// ori
`define 							DEF_ISTC_NOP						6'd0				// nop

// | ALU操作码
`define 							DEF_ALU_OR_OPR						8'b00100101			// ALU 或 操作码
`define 							DEF_ALU_NOP_OPR						8'd0				// ALU 空 操作码

// | ALU 选择
`define 							DEF_ALU_SEL_LOGIC					3'b001
`define 							DEF_ALU_SEL_NOP						3'b000				

// | 操作数
`define 							DEF_SRC_OPR_DATA_BUS				31:0
`define 							DEF_IMM_DATA_BUS					15:0


// |--------------------------------------  指令存储器宏定义  --------------------------------------
// |------------------------------------------------------------------------------------------------
`define 							DEF_ISTC_ADDR_BUS					31:0				// 地址线总线
`define 							DEF_ISTC_DATA_BUS 					31:0				// 数据线总线
`define 							DEF_ISTC_CACH_DEPTH					2**17-1				// 缓存深度/地址最大值
`define 							DEF_ISTC_ADDR_WIDTH_ACTUAL			17					// 实际使用的缓存地址线宽度



// |--------------------------------------  通用寄存器宏定义  --------------------------------------
// |------------------------------------------------------------------------------------------------
`define 							DEF_GPR_ADDR_WIDTH					5					// 通用寄存器地址位宽(32个)
`define 							DEF_GPR_DATA_WIDTH					32					// 通用寄存器数据位宽
`define 							DEF_GPR_NUM							32					// 通用寄存器数目
`define 							DEF_GPR_ADDR_NOP					5'd0				// 空操作 GPR 地址

程序计数器

该模块在时钟节拍下,给出程序指令寄存器要读取的地址,以及读使能信号。输出接口对接指令存储器ROM模块。

// |------------------------------ ================================== ------------------------------
// |============================== 		   程序计数寄存器模块		  ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-06
// |Finish Date : 2022-12-06
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |

`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps

module PC_REG_MDL(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
input														  I_CPU_CLK,
input 														  I_CPU_RSTN,

output 		reg 	[`DEF_ISTC_ADDR_BUS]					  O_PC,
output		reg 											  O_ISTC_ROM_CE
    );

// |--------------------------------------  模块内部逻辑设计  --------------------------------------
// |------------------------------------------------------------------------------------------------
// CE
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_ISTC_ROM_CE <= `DEF_CHIP_DIS;
	end
	else
	begin
		O_ISTC_ROM_CE <= `DEF_CHIP_EN;
	end
end

// PC
always @ (posedge I_CPU_CLK)
begin
	if(O_ISTC_ROM_CE == `DEF_CHIP_DIS)
	begin
		O_PC <= 32'd0;
	end
	else
	begin
		O_PC <= O_PC + 32'd4;
	end
end

endmodule

译码

此模块主要接收来自指令存储器ROM模块输出的指令,并且按照指令编码规则进行指令译码,为后续的指令执行模块提供必要的计算信息。

// |------------------------------ ================================== ------------------------------
// |============================== 		     指令-译码模块  	      ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-07
// |Finish Date : 2022-12-07
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |


`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps


module ID_MDL(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 时钟、复位
input 															I_CPU_CLK,
input 															I_CPU_RSTN,
// | 指令
input 		[`DEF_ISTC_DATA_BUS]								I_ISTC,
// | GPR读写控制
output 	reg														O_GPR_RD_EN_A,
output	reg	[`DEF_GPR_ADDR_WIDTH-1:0]							O_GPR_RD_ADDR_A,
input 		[`DEF_GPR_DATA_WIDTH-1:0]							I_GPR_RD_DATA_A,
output reg														O_GPR_RD_EN_B,
output reg	[`DEF_GPR_ADDR_WIDTH-1:0]							O_GPR_RD_ADDR_B,
input 		[`DEF_GPR_DATA_WIDTH-1:0]							I_GPR_RD_DATA_B,
// | 译码输出相关 对接 ALU 运算单元
// output  reg [`DEF_ALU_SEL_BUS]									O_ALU_SEL,
output	reg [`DEF_ALU_OPR_BUS]									O_ALU_OP_TYPE,
output  reg	[`DEF_SRC_OPR_DATA_BUS]								O_SRC_OPR_DATA_A,
output  reg	[`DEF_SRC_OPR_DATA_BUS]								O_SRC_OPR_DATA_B,
output  reg 													O_DST_GPR_WR_EN,
output  reg [`DEF_GPR_ADDR_WIDTH-1:0]							O_DST_GPR_WR_ADDR

    );
// |--------------------------------------  模块内部信号声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 指令分解相关
wire		[5:0]												W_ISTC_TYPE;
wire		[`DEF_GPR_ADDR_WIDTH-1:0]							W_SRC_GPR_ADDR;
wire 		[`DEF_GPR_ADDR_WIDTH-1:0]							W_DST_GPR_ADDR;
wire		[`DEF_IMM_DATA_BUS]									W_ISTC_IMM_DATA;

// | 32位立即数
reg			[31:0]												R_IMM_DATA_32BIT;

// | 指令有效信号
reg																R_ISTC_VAL;

// |--------------------------------------  模块内部逻辑设计  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 指令分解相关
assign 		W_ISTC_TYPE			=		I_ISTC[31:26];
assign 		W_SRC_GPR_ADDR  	=       I_ISTC[25:21];
assign		W_DST_GPR_ADDR  	=       I_ISTC[20:16];
assign 		W_ISTC_IMM_DATA		=		I_ISTC[15:0] ;

// | 指令译码
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_GPR_RD_EN_A	  <= 1'b0;
		O_GPR_RD_ADDR_A   <= `DEF_GPR_ADDR_NOP;
		O_GPR_RD_EN_B	  <= 1'b0;
		O_GPR_RD_ADDR_B	  <= `DEF_GPR_ADDR_NOP;

		O_ALU_OP_TYPE     <= `DEF_ALU_NOP_OPR;
		// O_ALU_SEL         <= `DEF_ALU_SEL_NOP;
		O_DST_GPR_WR_EN   <= 1'b0;
		O_DST_GPR_WR_ADDR <= `DEF_GPR_ADDR_NOP;
		
		R_ISTC_VAL		  <= 1'b0;
		R_IMM_DATA_32BIT  <= 32'd0;
	end
	else
	begin
		case(W_ISTC_TYPE)
			`DEF_ISTC_ORI:// ori指令
			begin
				O_GPR_RD_EN_A	  <= 1'b1;
				O_GPR_RD_ADDR_A   <= W_SRC_GPR_ADDR;
				O_GPR_RD_EN_B	  <= 1'b0;
				O_GPR_RD_ADDR_B	  <= `DEF_GPR_ADDR_NOP;

				O_ALU_OP_TYPE     <= `DEF_ALU_OR_OPR;
				// O_ALU_SEL         <= `DEF_ALU_SEL_LOGIC;
				O_DST_GPR_WR_EN   <= 1'b1;
				O_DST_GPR_WR_ADDR <= W_DST_GPR_ADDR;

				R_ISTC_VAL		  <= 1'b1;
				R_IMM_DATA_32BIT  <= {16'd0,W_ISTC_IMM_DATA};
			end
			default:
			begin
				O_GPR_RD_EN_A	  <= 1'b0;
				O_GPR_RD_ADDR_A   <= `DEF_GPR_ADDR_NOP;
				O_GPR_RD_EN_B	  <= 1'b0;
				O_GPR_RD_ADDR_B	  <= `DEF_GPR_ADDR_NOP;

				O_ALU_OP_TYPE     <= `DEF_ALU_NOP_OPR;
				// O_ALU_SEL         <= `DEF_ALU_SEL_NOP;
				O_DST_GPR_WR_EN   <= 1'b0;
				O_DST_GPR_WR_ADDR <= `DEF_GPR_ADDR_NOP;
		
				R_ISTC_VAL		  <= 1'b0;
				R_IMM_DATA_32BIT  <= 32'd0;
			end
		endcase
	end
end

// | 数据输出
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_SRC_OPR_DATA_A <= `DEF_ZERO_WORD;
	end
	else if(O_GPR_RD_EN_A)
	begin
		O_SRC_OPR_DATA_A <= I_GPR_RD_DATA_A;
	end
	else if(~O_GPR_RD_EN_A)
	begin
		O_SRC_OPR_DATA_A <= R_IMM_DATA_32BIT;
	end
	else
	begin
		O_SRC_OPR_DATA_A <= `DEF_ZERO_WORD;
	end
end


always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_SRC_OPR_DATA_B <= `DEF_ZERO_WORD;
	end
	else if(O_GPR_RD_EN_B)
	begin
		O_SRC_OPR_DATA_B <= I_GPR_RD_DATA_B;
	end
	else if(~O_GPR_RD_EN_B)
	begin
		O_SRC_OPR_DATA_B <= R_IMM_DATA_32BIT;
	end
	else
	begin
		O_SRC_OPR_DATA_B <= `DEF_ZERO_WORD;
	end
end


endmodule

通用寄存器

此模块主要负责32位通用寄存器的初始化、读写等操作。可当作RAM理解。

// |------------------------------ ================================== ------------------------------
// |============================== 		   取指-译码接口模块	      ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-06
// |Finish Date : 2022-12-06
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |

`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps

module GPR_WR_RD_MDL(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 时钟、复位
input 															I_CPU_CLK,
input 															I_CPU_RSTN,
// | 写
input 															I_GPR_WR_EN,
input 		[`DEF_GPR_ADDR_WIDTH-1:0]							I_GPR_WR_ADDR,
input 		[`DEF_GPR_DATA_WIDTH-1:0]							I_GPR_WR_DATA,
// |读
input 															I_GPR_RD_EN_A,
input 		[`DEF_GPR_ADDR_WIDTH-1:0]							I_GPR_RD_ADDR_A,
output	reg	[`DEF_GPR_DATA_WIDTH-1:0]							O_GPR_RD_DATA_A,
input 															I_GPR_RD_EN_B,
input 		[`DEF_GPR_ADDR_WIDTH-1:0]							I_GPR_RD_ADDR_B,
output	reg	[`DEF_GPR_DATA_WIDTH-1:0]							O_GPR_RD_DATA_B

    );
// |--------------------------------------  GPR-寄存器组定义  --------------------------------------
// |------------------------------------------------------------------------------------------------
reg 		[`DEF_GPR_DATA_WIDTH-1:0]							R_GPR [`DEF_GPR_NUM-1:0];

// |--------------------------------------  GPR-寄存器初始化  --------------------------------------
// |------------------------------------------------------------------------------------------------
initial $readmemh("D:/VIVADO_WORK_SPACE/CPU_MIPS32/DATA_FILE/GPR_INIT.txt",R_GPR);

// |--------------------------------------  GPR-寄存器写操作  --------------------------------------
// |------------------------------------------------------------------------------------------------
always @ (posedge I_CPU_CLK)
begin
	if(I_CPU_RSTN)
	begin
		if(I_GPR_WR_EN && I_GPR_WR_ADDR != `DEF_GPR_ADDR_WIDTH'd0)
		begin
			R_GPR[I_GPR_WR_ADDR] <= I_GPR_WR_DATA;
		end
	end
end

// |--------------------------------------    PORT A 读操作   --------------------------------------
// |------------------------------------------------------------------------------------------------
always @ (*)
begin
	if(~I_CPU_RSTN)
	begin
		O_GPR_RD_DATA_A = `DEF_ZERO_WORD;
	end
	else if(I_GPR_WR_EN && I_GPR_RD_EN_A && (I_GPR_RD_ADDR_A == I_GPR_WR_ADDR))
	begin
		O_GPR_RD_DATA_A = I_GPR_WR_DATA;
	end
	else if(I_GPR_RD_EN_A)
	begin
		O_GPR_RD_DATA_A = R_GPR[I_GPR_RD_ADDR_A];
	end
	else
	begin
		O_GPR_RD_DATA_A = `DEF_ZERO_WORD;
	end
end


// |--------------------------------------    PORT B 读操作   --------------------------------------
// |------------------------------------------------------------------------------------------------
always @ (*)
begin
	if(~I_CPU_RSTN)
	begin
		O_GPR_RD_DATA_B = `DEF_ZERO_WORD;
	end
	else if(I_GPR_WR_EN && I_GPR_RD_EN_B && (I_GPR_RD_ADDR_B == I_GPR_WR_ADDR))
	begin
		O_GPR_RD_DATA_B = I_GPR_WR_DATA;
	end
	else if(I_GPR_RD_EN_B)
	begin
		O_GPR_RD_DATA_B = R_GPR[I_GPR_RD_ADDR_B];
	end
	else
	begin
		O_GPR_RD_DATA_B = `DEF_ZERO_WORD;
	end
end


endmodule

初始化文件:

 

说明:此处文中的示例代码存在如下问题:

1、模块输出一般不选择组合逻辑输出;

2、always快描述组合逻辑时,要用阻塞赋值 “=”

指令执行

此模块是CPU的核心运算模块,将译码阶段传递的运算指令执行,并且完成数据的写请求。

// |------------------------------ ================================== ------------------------------
// |============================== 		     指令-执行模块  	      ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-07
// |Finish Date : 2022-12-07
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |


`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps

module EXE_MDL(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 时钟、复位
input 															I_CPU_CLK,
input 															I_CPU_RSTN,
// | 操作指令
// input		[`DEF_ALU_SEL_BUS]									I_ALU_SEL,		
input 		[`DEF_ALU_OPR_BUS]									I_ALU_OP_TYPE,	
// | 源操作数
input 		[`DEF_SRC_OPR_DATA_BUS]								I_SRC_OPR_DATA_A,
input 		[`DEF_SRC_OPR_DATA_BUS]								I_SRC_OPR_DATA_B,
// | 目的寄存器写
input 															I_DST_GPR_WR_EN,
input 		[`DEF_GPR_ADDR_WIDTH-1:0]							I_DST_GPR_WR_ADDR,
// | 输出 
output 	reg														O_DST_GPR_WR_EN,   //输入打一拍
output 	reg	[`DEF_GPR_ADDR_WIDTH-1:0]							O_DST_GPR_WR_ADDR, //输入打一拍
output  reg [`DEF_GPR_DATA_WIDTH-1:0]							O_DST_GPR_WR_DATA

    );
// |--------------------------------------  模块内部信号声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | I_ALU_OP_TYPE 打拍
reg 		[`DEF_ALU_OPR_BUS]									R_I_ALU_OP_TYPE;
reg         													R_I_DST_GPR_WR_EN;
reg         [`DEF_GPR_ADDR_WIDTH-1:0]							R_I_DST_GPR_WR_ADDR;

// |--------------------------------------  模块内部逻辑设计  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | I_ALU_OP_TYPE 打拍对齐时序
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		R_I_ALU_OP_TYPE <= 0;
	end
	else
	begin
		R_I_ALU_OP_TYPE <= I_ALU_OP_TYPE;
	end
end
// | 计算单元
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_DST_GPR_WR_DATA <= `DEF_ZERO_WORD;
	end
	else
	begin
		case(R_I_ALU_OP_TYPE)
			`DEF_ALU_OR_OPR:
			begin
				O_DST_GPR_WR_DATA <= I_SRC_OPR_DATA_A | I_SRC_OPR_DATA_B;
			end
			default:
			begin
				O_DST_GPR_WR_DATA <= `DEF_ZERO_WORD;
			end
		endcase
	end
end

// | 写操作打拍
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_DST_GPR_WR_EN <= 1'b0;
		O_DST_GPR_WR_ADDR <= 5'd0;
		R_I_DST_GPR_WR_EN <= 1'b0;
		R_I_DST_GPR_WR_ADDR <= 5'd0;
	end
	else
	begin
		R_I_DST_GPR_WR_EN <= I_DST_GPR_WR_EN;
		R_I_DST_GPR_WR_ADDR <= I_DST_GPR_WR_ADDR;
		O_DST_GPR_WR_EN <= R_I_DST_GPR_WR_EN;
		O_DST_GPR_WR_ADDR <= R_I_DST_GPR_WR_ADDR;
	end
end
endmodule

内存访问

此模块主要是一些内存访问的操作,由于 ori 指令暂时不需要访存,所以该模块目前只有写使能传递功能。

// |------------------------------ ================================== ------------------------------
// |============================== 		     -执行模块  	      ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-07
// |Finish Date : 2022-12-07
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |


`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps



module MEM_ACS_MDL(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 时钟、复位
input 															I_CPU_CLK,
input 															I_CPU_RSTN,
// | 前接指令执行模块输出
input 															I_DST_GPR_WR_EN,  
input 		[`DEF_GPR_ADDR_WIDTH-1:0]							I_DST_GPR_WR_ADDR,
input 		[`DEF_GPR_DATA_WIDTH-1:0]							I_DST_GPR_WR_DATA,

// | 后接写回模块
output reg  													O_DST_GPR_WR_EN,  
output reg  [`DEF_GPR_ADDR_WIDTH-1:0]							O_DST_GPR_WR_ADDR,
output reg  [`DEF_GPR_DATA_WIDTH-1:0]							O_DST_GPR_WR_DATA

    );
// |--------------------------------------  模块内部逻辑设计  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 目的寄存器写操作传递/打拍
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_DST_GPR_WR_EN   <= 1'b0;  
		O_DST_GPR_WR_ADDR <= 5'd0;
		O_DST_GPR_WR_DATA <= 32'd0;		
	end
	else
	begin
		O_DST_GPR_WR_EN   <= I_DST_GPR_WR_EN  ;  
		O_DST_GPR_WR_ADDR <= I_DST_GPR_WR_ADDR;
		O_DST_GPR_WR_DATA <= I_DST_GPR_WR_DATA;		
	end
end


endmodule

指令ROM

此模块存放程序指令。

// |------------------------------ ================================== ------------------------------
// |============================== 		   程序计数寄存器模块		  ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-08
// |Finish Date : 2022-12-08
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |

`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps



module ROM_ISTC_MDL(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
input														  I_CPU_CLK,
input 														  I_CPU_RSTN,

input														  I_RD_EN,
input 			[`DEF_ISTC_ADDR_BUS]						  I_RD_ADDR,

output	reg		[`DEF_ISTC_DATA_BUS]						  O_ISTC
    );

// |--------------------------------------  模块内部信号声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | ROM空间开辟
reg				[`DEF_ISTC_DATA_BUS]						  R_ROM_DATA [`DEF_ISTC_CACH_DEPTH:0];
// |--------------------------------------  模块内部逻辑设计  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | ROM初始化
initial $readmemh("D:/VIVADO_WORK_SPACE/CPU_MIPS32/DATA_FILE/ISTC_ROM.txt",R_ROM_DATA);
// | 数据读取
always @ (posedge I_CPU_CLK)
begin
	if(~I_CPU_RSTN)
	begin
		O_ISTC <= `DEF_ZERO_WORD;
	end
	else
	begin
		if(I_RD_EN)
		begin
			O_ISTC <= R_ROM_DATA[I_RD_ADDR[`DEF_ISTC_ADDR_WIDTH_ACTUAL+1:2]];
		end
		else
		begin
			O_ISTC <= `DEF_ZERO_WORD;
		end
	end
end
endmodule

程序代码示例:(此处借鉴书本的方法,仅为了完成仿真)

顶层文件

处理器顶层

// |------------------------------ ================================== ------------------------------
// |============================== 		     指令-执行模块  	      ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-07
// |Finish Date : 2022-12-07
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |


`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps

module TOP_MIPS32(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 时钟、复位
input 															I_CPU_CLK,
input 															I_CPU_RSTN,
// | 指令取
input			[`DEF_ISTC_DATA_BUS]							I_ISTC_FROM_ROM,
output			[`DEF_ISTC_ADDR_BUS]							O_ISTC_ADDR_2_ROM,
// | 指令存储器使能
output															O_ISTC_ROM_CE
    );

// |--------------------------------------  模块内部信号声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | PC_REG_MDL 输出
wire			[`DEF_ISTC_ADDR_BUS]							W_PC;
// | IF_ID_MDL 输出
wire 			[`DEF_ISTC_ADDR_BUS] 							W_ID_ADDR;
wire 			[`DEF_ISTC_DATA_BUS] 							W_ID_DATA;
// ID_MDL 端口信号(GPR相关)
wire															W_GPR_RD_EN_A;
wire			[`DEF_GPR_ADDR_WIDTH-1:0]						W_GPR_RD_ADDR_A;
wire			[`DEF_GPR_DATA_WIDTH-1:0]						W_GPR_RD_DATA_A;
wire															W_GPR_RD_EN_B;
wire			[`DEF_GPR_ADDR_WIDTH-1:0]						W_GPR_RD_ADDR_B;
wire 			[`DEF_GPR_DATA_WIDTH-1:0]						W_GPR_RD_DATA_B;
// ID_MDL 端口信号(EXE 相关)
wire			[`DEF_ALU_OPR_BUS]								W_ALU_OP_TYPE;
wire			[`DEF_SRC_OPR_DATA_BUS]							W_SRC_OPR_DATA_A;
wire			[`DEF_SRC_OPR_DATA_BUS]							W_SRC_OPR_DATA_B;
// GPR_WR_RD_MDL 写操作端口(EXE 相关)
wire															W_DST_GPR_WR_EN_EXE_MDL_IN;
wire			[`DEF_GPR_ADDR_WIDTH-1:0]						W_DST_GPR_WR_ADDR_EXE_MDL_IN;
// GPR_WR_RD_MDL 写操作端口(MEM 相关)
wire															W_DST_GPR_WR_EN_MEM_MDL_IN;
wire			[`DEF_GPR_ADDR_WIDTH-1:0]						W_DST_GPR_WR_ADDR_MEM_MDL_IN;
wire			[`DEF_GPR_DATA_WIDTH-1:0]						W_DST_GPR_WR_DATA_MEM_MDL_IN;
// GPR_WR_RD_MDL 写操作端口(GPR 相关)
wire															W_DST_GPR_WR_EN_GPR_MDL_IN;
wire			[`DEF_GPR_ADDR_WIDTH-1:0]						W_DST_GPR_WR_ADDR_GPR_MDL_IN;
wire			[`DEF_GPR_DATA_WIDTH-1:0]						W_DST_GPR_WR_DATA_GPR_MDL_IN;

// |--------------------------------------  模块内部逻辑设计  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 输出
assign 			O_ISTC_ADDR_2_ROM		=		W_PC;

// |--------------------------------------      子模块例化    --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 程序计数器模块
	PC_REG_MDL INST_PC_REG_MDL
		(
			.I_CPU_CLK     (I_CPU_CLK),
			.I_CPU_RSTN    (I_CPU_RSTN),
			.O_PC          (W_PC),
			.O_ISTC_ROM_CE (O_ISTC_ROM_CE)
		);
// | 译码模块例化
	ID_MDL INST_ID_MDL
		(
			.I_CPU_CLK         (I_CPU_CLK),
			.I_CPU_RSTN        (I_CPU_RSTN),
			.I_ISTC            (I_ISTC_FROM_ROM),

			.O_GPR_RD_EN_A     (W_GPR_RD_EN_A),
			.O_GPR_RD_ADDR_A   (W_GPR_RD_ADDR_A),
			.I_GPR_RD_DATA_A   (W_GPR_RD_DATA_A),
			.O_GPR_RD_EN_B     (W_GPR_RD_EN_B),
			.O_GPR_RD_ADDR_B   (W_GPR_RD_ADDR_B),
			.I_GPR_RD_DATA_B   (W_GPR_RD_DATA_B),

			.O_ALU_OP_TYPE     (W_ALU_OP_TYPE),
			.O_SRC_OPR_DATA_A  (W_SRC_OPR_DATA_A),
			.O_SRC_OPR_DATA_B  (W_SRC_OPR_DATA_B),

			.O_DST_GPR_WR_EN   (W_DST_GPR_WR_EN_EXE_MDL_IN),
			.O_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_EXE_MDL_IN)
		);
// | 通用寄存器模块例化
	GPR_WR_RD_MDL INST_GPR_WR_RD_MDL
		(
			.I_CPU_CLK       (I_CPU_CLK),
			.I_CPU_RSTN      (I_CPU_RSTN),

			.I_GPR_WR_EN     (W_DST_GPR_WR_EN_GPR_MDL_IN),
			.I_GPR_WR_ADDR   (W_DST_GPR_WR_ADDR_GPR_MDL_IN),
			.I_GPR_WR_DATA   (W_DST_GPR_WR_DATA_GPR_MDL_IN),

			.I_GPR_RD_EN_A   (W_GPR_RD_EN_A),
			.I_GPR_RD_ADDR_A (W_GPR_RD_ADDR_A),
			.O_GPR_RD_DATA_A (W_GPR_RD_DATA_A),
			.I_GPR_RD_EN_B   (W_GPR_RD_EN_B),
			.I_GPR_RD_ADDR_B (W_GPR_RD_ADDR_B),
			.O_GPR_RD_DATA_B (W_GPR_RD_DATA_B)
		);
// | 执行模块例化
	EXE_MDL INST_EXE_MDL
		(
			.I_CPU_CLK         (I_CPU_CLK),
			.I_CPU_RSTN        (I_CPU_RSTN),

			.I_ALU_OP_TYPE     (W_ALU_OP_TYPE),
			.I_SRC_OPR_DATA_A  (W_SRC_OPR_DATA_A),
			.I_SRC_OPR_DATA_B  (W_SRC_OPR_DATA_B),

			.I_DST_GPR_WR_EN   (W_DST_GPR_WR_EN_EXE_MDL_IN),
			.I_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_EXE_MDL_IN),

			.O_DST_GPR_WR_EN   (W_DST_GPR_WR_EN_MEM_MDL_IN),
			.O_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_MEM_MDL_IN),
			.O_DST_GPR_WR_DATA (W_DST_GPR_WR_DATA_MEM_MDL_IN)
		);
// | 存储器存取模块例化
	MEM_ACS_MDL INST_MEM_ACS_MDL
		(
			.I_CPU_CLK         (I_CPU_CLK),
			.I_CPU_RSTN        (I_CPU_RSTN),

			.I_DST_GPR_WR_EN   (W_DST_GPR_WR_EN_MEM_MDL_IN),
			.I_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_MEM_MDL_IN),
			.I_DST_GPR_WR_DATA (W_DST_GPR_WR_DATA_MEM_MDL_IN),

			.O_DST_GPR_WR_EN   (W_DST_GPR_WR_EN_GPR_MDL_IN),
			.O_DST_GPR_WR_ADDR (W_DST_GPR_WR_ADDR_GPR_MDL_IN),
			.O_DST_GPR_WR_DATA (W_DST_GPR_WR_DATA_GPR_MDL_IN)
		);

endmodule

SOPC顶层 

// |------------------------------ ================================== ------------------------------
// |============================== 		     MIPS32 SOPC 系统  	      ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-07
// |Finish Date : 2022-12-07
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |


`include "MIPS_SYS_DEFINES.v"
`timescale 1ns / 1ps

module TOP_MIPS32_SOPC(

// |--------------------------------------  输入输出端口声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 时钟、复位
input 															I_CPU_CLK,
input 															I_CPU_RSTN

    );
// |--------------------------------------  模块内部信号声明  --------------------------------------
// |------------------------------------------------------------------------------------------------
// | TOP_MIPS32 模块端口
// | 指令取
wire			[`DEF_ISTC_DATA_BUS]							W_ISTC_FROM_ROM;
wire			[`DEF_ISTC_ADDR_BUS]							W_ISTC_ADDR_2_ROM;
// | 指令存储器使能
wire															W_ISTC_ROM_CE;

// |--------------------------------------      子模块例化    --------------------------------------
// |------------------------------------------------------------------------------------------------
// | 处理器模块
	TOP_MIPS32 INST_TOP_MIPS32
		(
			.I_CPU_CLK         (I_CPU_CLK),
			.I_CPU_RSTN        (I_CPU_RSTN),
			.I_ISTC_FROM_ROM   (W_ISTC_FROM_ROM),
			.O_ISTC_ADDR_2_ROM (W_ISTC_ADDR_2_ROM),
			.O_ISTC_ROM_CE     (W_ISTC_ROM_CE)
		);
// | 指令存储模块
	ROM_ISTC_MDL INST_ROM_ISTC_MDL
		(
			.I_CPU_CLK  (I_CPU_CLK),
			.I_CPU_RSTN (I_CPU_RSTN),
			.I_RD_EN    (W_ISTC_ROM_CE),
			.I_RD_ADDR  (W_ISTC_ADDR_2_ROM),
			.O_ISTC     (W_ISTC_FROM_ROM)
		);

endmodule

功能仿真

TestBench

// |------------------------------ ================================== ------------------------------
// |============================== 		    顶层模块仿真平台  	      ==============================
// |------------------------------ ================================== ------------------------------
// |Create Date : 2022-12-08
// |Finish Date : 2022-12-08
// |Edited by   : Xu Y. B. (CSDN USER NAME :在路上,正出发)
// |Reference   : 《自己动手写CPU》——第4章
// |
// |
// |------------------------------------------------------------------------------------------------
// |Change History:
// |



`timescale 1ns / 1ps
`define 	CLK_PERIOD 		20


module TB_TOP_MIPS32();
reg 						I_CPU_CLK;
reg 						I_CPU_RSTN;
// 产生时钟
initial 	I_CPU_CLK	=	0;
always #(`CLK_PERIOD/2) I_CPU_CLK = ~I_CPU_CLK;
// 产生复位
initial
begin
	I_CPU_RSTN <= 0;
	#(`CLK_PERIOD*3);
	@(posedge I_CPU_CLK);
	I_CPU_RSTN <= 1;
	#(`CLK_PERIOD*10);
	$finish;
end
// 顶层例化
	TOP_MIPS32_SOPC INST_TOP_MIPS32_SOPC 
	(.I_CPU_CLK(I_CPU_CLK), 
	 .I_CPU_RSTN(I_CPU_RSTN)
	);

endmodule

仿真结果

执行时间

从取到第一条指令,到第一条指令完成并写入寄存器,共耗费100纳秒=5个时钟周期。

时序细节



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/72404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java大型企业进销存系统源码带文字搭建教程

技术架构 技术框架&#xff1a;SpringBoot Spring Data Jpa SpringMvc Shiro安全认证 完整权限系统 easyui 运行环境&#xff1a;jdk8 IntelliJ IDEA maven 宝塔面板 本地搭建教程&#xff1a; 1.下载源码&#xff0c;小皮面板创建一个数据库&#xff0c;导入db_jxc2.…

nodejs模板引擎的使用

前后端不分离的情况(数据都来源于后端,前后端不可以分离使用) npm i express art-template express-art-template --S 先下载模板引擎,模板渲染,还有experss服务器的包 js代码 //导入express服务器第三方的包 const express require("express") //导入模板引擎 con…

Spring Cloud(十六):微服务分布式唯一ID

分布式唯一ID 特点方案 雪花算法 特点开源实现优缺点 替代方案 UUIDMongdbSeata数据库生成Redis 基于美团的 Leaf分布式 ID 微服务 Leaf-segment 数据库方案 双 buffer 优化 — TP999 数据波动大 Leaf 高可用容灾 — DB 可用性Leaf-snowflake 雪花方案 弱依赖 ZooKeeper 解决时…

加减大师-第10届蓝桥杯Scratch选拔赛真题精选

[导读]&#xff1a;超平老师计划推出Scratch蓝桥杯真题解析100讲&#xff0c;这是超平老师解读Scratch蓝桥真题系列的第98讲。 蓝桥杯选拔赛每一届都要举行4~5次&#xff0c;和省赛、国赛相比&#xff0c;题目要简单不少&#xff0c;再加上篇幅有限&#xff0c;因此我精挑细选…

Vue学习笔记--第一章(尚硅谷学习视频总结)

目录 一、第一章 Vue核心 1.1. Vue简介 1.1.1. 官网 1.1.2. 介绍与描述 1.1.3. Vue 的特点 1.1.4. 与其它 JS 框架的关联 1.1.5. Vue 周边库 1.2.初识Vue 1.3. 模板语法 1.4. 数据绑定 1.5 el与data的两种写法 1.6 MVVM模型 1.7 Vue中的数据代理 1.8.事件处理 1.…

从零学习 InfiniBand-network架构(九) —— IB协议中子网本地地址

从零学习 InfiniBand-network架构&#xff08;九&#xff09; —— IB协议中子网本地地址 &#x1f508;声明&#xff1a; &#x1f603;博主主页&#xff1a;王_嘻嘻的CSDN主页 &#x1f511;未经作者允许&#xff0c;禁止转载 &#x1f6a9;本专题部分内容源于《InfiniBand-n…

鸿蒙3.0应用开发若干问题及上架总结

1.如何去掉默认标题栏&#xff0c;实现全屏显示&#xff1f; 在config.json中的ability配置信息中添加属性&#xff1a; "abilities": [ {..."metaData": {"customizeData": [{"name": "hwc-theme","value": &q…

Buildroot系列开发(五)bootloader简述

参考&#xff1a;百问网 文章目录1.什么是Boot-loader?2.有哪些bootloader?哪些支持linux&#xff1f;3.Bootloader支持的Flash设备4.Bootloader支持的文件系统类型4.Bootloader支持的CPU架构5.Bootloader总结1.什么是Boot-loader? 2.有哪些bootloader?哪些支持linux&#…

广州蓝景分享——前端学习5 种在 JavaScript 中获取字符串第一个字符的方法

在本文中&#xff0c;我们将研究多种方法来轻松获取 JavaScript 中字符串的第一个字符。 1.charAt() 方法 要获取字符串的第一个字符&#xff0c;我们可以在字符串上调用 charAt() &#xff0c;将 0 作为参数传递。例如&#xff0c;str.charAt(0) 返回 str 的第一个字符。 c…

AT1106S(PHS/EN输入接口通道0.8A低压H桥直流刷式电机驱动IC)

描述 泛海微AT1106S为摄像机、消费类产品、玩具和其它低电压或者电池供电的运动控制类应用提供了一个集成的电机驱动器解决方案。泛海微AT1106S能够驱动一个直流电机或其他诸 如螺线管的器件。输出驱动模块由N MOS功率管构成的H桥组成&#xff0c;以驱动电机绕组。泛海微AT110…

车企接连押注「重感知」 ,高精地图真会被弃用?

实现高阶智能驾驶&#xff0c;“重感知”是否为大势所趋&#xff1f; 答案正日益明晰。 2022年&#xff0c;以特斯拉为代表的“重感知”阵营&#xff0c;押注者正日趋增多。以在2022年尝试落地城市NOA的三家厂商为例&#xff1a;毫末智行一早便属“重感知”阵营&#xff1b;小…

【20221208】【每日一题】目标和

给你一个整数数组 nums 和一个整数 target 。 向数组中的每个整数前添加 或 - &#xff0c;然后串联起所有整数&#xff0c;可以构造一个 表达式 &#xff1a; 例如&#xff0c;nums [2, 1] &#xff0c;可以在 2 之前添加 &#xff0c;在 1 之前添加 - &#xff0c;然后串…

5G无线技术基础自学系列 | SA移动性管理流程

素材来源&#xff1a;《5G无线网络规划与优化》 一边学习一边整理内容&#xff0c;并与大家分享&#xff0c;侵权即删&#xff0c;谢谢支持&#xff01; 附上汇总贴&#xff1a;5G无线技术基础自学系列 | 汇总_COCOgsta的博客-CSDN博客 SA移动性管理流程包括站内切换、Xn切换…

Java基础之序列化和反序列化

序列化的实现 java.io中的对象流提供了序列化和反序列化对象的方法 对象输出流 ObjectOutputStream 构造方法&#xff1a; ObjectOutputStream(OutputStream out) 保存对象的方法&#xff1a; void writeObject(Object obj) 对象输入流 ObjectInputStream 构造方法&…

使用 MySQL、Thymeleaf 和 Spring Boot Framework 上传、存储和查看图像

在本文中&#xff0c;我们将使用 Spring Boot 框架从头开始构建映像库应用程序&#xff0c;用户可以在其中列出其映像。 以下是我们将在应用程序中实现的功能。 用户可以列出他们的图像以及详细信息&#xff0c;例如&#xff0c; 名字描述图像价格。&#xff08;如果他们想卖…

Win11 启用旧右键菜单 _ Windows11 右键改回老版

Win11 系统在使用上和之前的系统差不多&#xff0c;但是在设计上&#xff0c;有了很大的改变&#xff0c;系统界面&#xff0c;设置等功能都使用了全新的风格&#xff0c;包括右键菜单&#xff0c;这让很多用户使用起来都很不习惯&#xff0c;因此想改回旧版的右键菜单来使用。…

汽车控制器概述

目录 一、整车控制器&#xff08;VCU&#xff09; 功能 工作模式 二、发动机控制器/电子控制单元&#xff08;ECU&#xff09; ECU基本组成 ECU的作用 ECU的工作原理 常见的ECU的类型 三、电机控制器&#xff08;MCU&#xff09; 四、 电池管理系统&#xff08;BMS&a…

cubeIDE开发, stm32的USB从设备串口驱动设计

一、USB_OTG简介 USB_OTG&#xff08;OTG&#xff0c;ON THE GO&#xff09;是一款双角色设备(DRD) 控制器&#xff0c;同时支持从机&#xff08;USB DEVICE&#xff09;功能和主机&#xff08;USB HOST&#xff09;功能。在主机模式下&#xff0c;OTG 支持全速&#xff08;OTG…

2022圣诞在即,出海品牌如何做好网红营销?

随着2022圣诞节逐渐临近&#xff0c;节日气氛也开始浓郁起来&#xff0c;尤其在社交媒体上&#xff0c;圣诞主题的内容越来越多&#xff0c;随之而来的则是各种营销与折扣。受经济形势影响&#xff0c;性价比在当下显得尤为重要&#xff0c;有60%的消费者表示&#xff0c;今年圣…

【能效分析】安科瑞变电所运维云平台解决方案应用分析

概述 安科瑞 李亚俊 壹捌柒贰壹零玖捌柒伍柒 AcrelCloud-1000变电所运维云平台基于互联网&#xff0b;大数据、移动通讯等技术开发的云端管理平台&#xff0c;满足用户或运维公司监测众多变电所回路运行状态和参数、室内环境温湿度、电缆及母线运行温度、现场设备或环境视频场…