目录
引言
致谢
平台
ori 指令
流水线结构建立
模型
简单的MIPS五级流水线结构
设计
宏定义
程序计数器
译码
通用寄存器
指令执行
内存访问
指令ROM
顶层文件
处理器顶层
SOPC顶层
功能仿真
TestBench
仿真结果
执行时间
时序细节
本篇学习书本的第四章,实现 ori 指令。
感谢书籍《自己动手写CPU》及其作者雷思磊。一并感谢开源精神。
开发环境:Vivado IDE 2018.3
FPGA芯片型号:xc7a35tfgg484-2
指令格式:
指令用法:
ori rs, rt,immediate
其作用是将指令中的16位立即数进行无符号数扩展至 32 位,然后与索引号为 rs 的通用寄存器的值进行逻辑或运算,运算的结果保存到索引号为 rt 的寄存器内。
符号扩展示例:
声明:
设计思路基本借鉴书本,但是具体的模块代码编写,与作者有较大不同。
此文件主要定义了一些与设计相关的宏,当设计的参数需要更改时,在此文件修改即可,不需要改动内部设计文件。方便代码维护,也增强了代码的可读性。
// |------------------------------ ================================== ------------------------------
// |============================== 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 / 1psmodule 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)
beginif(~I_CPU_RSTN)beginO_ISTC_ROM_CE <= `DEF_CHIP_DIS;endelsebeginO_ISTC_ROM_CE <= `DEF_CHIP_EN;end
end// PC
always @ (posedge I_CPU_CLK)
beginif(O_ISTC_ROM_CE == `DEF_CHIP_DIS)beginO_PC <= 32'd0;endelsebeginO_PC <= O_PC + 32'd4;end
endendmodule
此模块主要接收来自指令存储器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 / 1psmodule 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)
beginif(~I_CPU_RSTN)beginO_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;endelsebegincase(W_ISTC_TYPE)`DEF_ISTC_ORI:// ori指令beginO_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};enddefault:beginO_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;endendcaseend
end// | 数据输出
always @ (posedge I_CPU_CLK)
beginif(~I_CPU_RSTN)beginO_SRC_OPR_DATA_A <= `DEF_ZERO_WORD;endelse if(O_GPR_RD_EN_A)beginO_SRC_OPR_DATA_A <= I_GPR_RD_DATA_A;endelse if(~O_GPR_RD_EN_A)beginO_SRC_OPR_DATA_A <= R_IMM_DATA_32BIT;endelsebeginO_SRC_OPR_DATA_A <= `DEF_ZERO_WORD;end
endalways @ (posedge I_CPU_CLK)
beginif(~I_CPU_RSTN)beginO_SRC_OPR_DATA_B <= `DEF_ZERO_WORD;endelse if(O_GPR_RD_EN_B)beginO_SRC_OPR_DATA_B <= I_GPR_RD_DATA_B;endelse if(~O_GPR_RD_EN_B)beginO_SRC_OPR_DATA_B <= R_IMM_DATA_32BIT;endelsebeginO_SRC_OPR_DATA_B <= `DEF_ZERO_WORD;end
endendmodule
此模块主要负责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 / 1psmodule 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)
beginif(I_CPU_RSTN)beginif(I_GPR_WR_EN && I_GPR_WR_ADDR != `DEF_GPR_ADDR_WIDTH'd0)beginR_GPR[I_GPR_WR_ADDR] <= I_GPR_WR_DATA;endend
end// |-------------------------------------- PORT A 读操作 --------------------------------------
// |------------------------------------------------------------------------------------------------
always @ (*)
beginif(~I_CPU_RSTN)beginO_GPR_RD_DATA_A = `DEF_ZERO_WORD;endelse if(I_GPR_WR_EN && I_GPR_RD_EN_A && (I_GPR_RD_ADDR_A == I_GPR_WR_ADDR))beginO_GPR_RD_DATA_A = I_GPR_WR_DATA;endelse if(I_GPR_RD_EN_A)beginO_GPR_RD_DATA_A = R_GPR[I_GPR_RD_ADDR_A];endelsebeginO_GPR_RD_DATA_A = `DEF_ZERO_WORD;end
end// |-------------------------------------- PORT B 读操作 --------------------------------------
// |------------------------------------------------------------------------------------------------
always @ (*)
beginif(~I_CPU_RSTN)beginO_GPR_RD_DATA_B = `DEF_ZERO_WORD;endelse if(I_GPR_WR_EN && I_GPR_RD_EN_B && (I_GPR_RD_ADDR_B == I_GPR_WR_ADDR))beginO_GPR_RD_DATA_B = I_GPR_WR_DATA;endelse if(I_GPR_RD_EN_B)beginO_GPR_RD_DATA_B = R_GPR[I_GPR_RD_ADDR_B];endelsebeginO_GPR_RD_DATA_B = `DEF_ZERO_WORD;end
endendmodule
初始化文件:
说明:此处文中的示例代码存在如下问题:
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 / 1psmodule 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)
beginif(~I_CPU_RSTN)beginR_I_ALU_OP_TYPE <= 0;endelsebeginR_I_ALU_OP_TYPE <= I_ALU_OP_TYPE;end
end
// | 计算单元
always @ (posedge I_CPU_CLK)
beginif(~I_CPU_RSTN)beginO_DST_GPR_WR_DATA <= `DEF_ZERO_WORD;endelsebegincase(R_I_ALU_OP_TYPE)`DEF_ALU_OR_OPR:beginO_DST_GPR_WR_DATA <= I_SRC_OPR_DATA_A | I_SRC_OPR_DATA_B;enddefault:beginO_DST_GPR_WR_DATA <= `DEF_ZERO_WORD;endendcaseend
end// | 写操作打拍
always @ (posedge I_CPU_CLK)
beginif(~I_CPU_RSTN)beginO_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;endelsebeginR_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 / 1psmodule 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)
beginif(~I_CPU_RSTN)beginO_DST_GPR_WR_EN <= 1'b0; O_DST_GPR_WR_ADDR <= 5'd0;O_DST_GPR_WR_DATA <= 32'd0; endelsebeginO_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
endendmodule
此模块存放程序指令。
// |------------------------------ ================================== ------------------------------
// |============================== 程序计数寄存器模块 ==============================
// |------------------------------ ================================== ------------------------------
// |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 / 1psmodule 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)
beginif(~I_CPU_RSTN)beginO_ISTC <= `DEF_ZERO_WORD;endelsebeginif(I_RD_EN)beginO_ISTC <= R_ROM_DATA[I_RD_ADDR[`DEF_ISTC_ADDR_WIDTH_ACTUAL+1:2]];endelsebeginO_ISTC <= `DEF_ZERO_WORD;endend
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 / 1psmodule 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
// |------------------------------ ================================== ------------------------------
// |============================== 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 / 1psmodule 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
// |------------------------------ ================================== ------------------------------
// |============================== 顶层模块仿真平台 ==============================
// |------------------------------ ================================== ------------------------------
// |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 20module 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
beginI_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个时钟周期。