目录
引言
本篇学习书本的第四章,实现 ori 指令。
致谢
感谢书籍《自己动手写CPU》及其作者雷思磊。一并感谢开源精神。
平台
开发环境:Vivado IDE 2018.3
FPGA芯片型号:xc7a35tfgg484-2
ori 指令
指令格式:
指令用法:
ori rt, rs,immediate
其作用是将指令中的16位立即数进行无符号数扩展至 32 位,然后与索引号为 rt 的通用寄存器的值进行逻辑或运算,运算的结果保存到索引号为 rs 的寄存器内。
符号扩展示例:
此处书本有误:
书本中给出的指令用法为:
但是随后举的例子却是:
所以正确的指令使用格式为:(上面写过了,再强调一遍)
ori rt, rs,immediate
流水线结构建立
模型
简单的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 /
1
ps
-
-
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 /
1
ps
-
-
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个时钟周期。
时序细节
转载:https://blog.csdn.net/qq_43045275/article/details/128209440