1. ori指令说明
I类型指令,“立即数位或”运算,指令码为6'b001101
。
汇编格式:ori rs, rt, immediate(注意rs, rt的次序)。
功能表述:寄存器 rs 中的值与 0 扩展至 32 位的立即数 imm 按位逻辑或,结果写入寄存器 rt 中。
rs(source regsiter)指定第一个源操作数所在的寄存器编号。
rt(target regsiter)指定第二个源操作数所在的寄存器编号。
rd(destination regsiter)指定目的操作数所在的寄存器编号。
2. 流水线结构的建立
宏定义
//全局的宏定义
`define RstEnable 1'b1 // 复位信号有效
`define RstDisable 1'b0 // 复位信号无效
`define ZeroWord 32'h00000000 // 32位的数值零
`define WriteEnable 1'b1 // 使能写
`define WriteDisable 1'b0 // 禁止写
`define ReadEnable 1'b1 // 使能读
`define ReadDisable 1'b0 // 使能读
`define AluOpBus 7:0 // 译码阶段aluop_o的宽度
`define AluSelBus 2:0 // 译码阶段alusel_o的宽度
`define InstValid 1'b0 // 指令有效
`define InstInvalid 1'b1 // 指令无效
`define True_v 1'b1 // 逻辑真
`define False_v 1'b0 // 逻辑假
`define ChipEnable 1'b1 // 芯片使能
`define ChipDisable 1'b0 // 芯片禁止
//与具体指令有关的宏定义
`define EXE_ORI 6'b001101 // 指令ori的指令码
`define EXE_NOP 6'b000000
//AluOp
`define EXE_OR_OP 8'b00100101
`define EXE_ORI_OP 8'b01011010
`define EXE_NOP_OP 8'b00000000
//AluSel
`define EXE_RES_LOGIC 3'b001
`define EXE_RES_NOP 3'b000
//与指令存储器ROM有关的宏定义
`define InstAddrBus 31:0 // ROM的地址总线宽度
`define InstBus 31:0 // ROM的数据总线宽度
`define InstMemNum 131071 // ROM的实际大小128KB
`define InstMemNumLog2 17 // ROM实际使用的地址线宽度
//与通用存储器Regfile有关的宏定义
`define RegAddrBus 4:0 // Regfile 模块的地址线宽度
`define RegBus 31:0 // Regfile 模块的数据线宽度
`define RegWidth 32 // 通用寄存器的宽度
`define DoubleRegWidth 64 // 两倍的通用寄存器的宽度
`define DoubleRegBus 63:0 // 两倍的通用寄存器的数据线宽度
`define RegNum 32 // 通用寄存器的数量
`define RegNumLog2 5 // 寻址通用寄存器使用的地址位数
`define NOPRegAddr 5'b00000
取指阶段
PC模块
`include "defines.v"
`timescale 1ns/1ps
module pc_reg(
input wire clk, // 复位信号
input wire rst, // 时钟信号
output reg[`InstAddrBus] pc, // 要读取的指令地址
output reg ce // 指令寄存器使能信号
);
always @(posedge clk) begin
if (rst == `RstEnable) begin
ce <= `ChipDisable; // 复位的时候指令寄存器禁用
end else begin
ce <= `ChipEnable; // 复位结束后,指令寄存器使能
end
end
always @(posedge clk) begin
if (ce == `ChipDisable) begin
pc <= 32'h0000_0000; // 指令寄存器禁用的时候,pc为0
end else begin
pc <= pc + 4'h4; // 一条指令32位
end
end
endmodule
IF/ID模块
`include "defines.v"
`timescale 1ns/1ps
module if_id(
input wire clk, // 复位信号
input wire rst, // 时钟信号
// 来自取指阶段的信号,其中宏定义InstBus表示指令宽度,为32
input wire[`InstAddrBus] if_pc, // 取指阶段取得的指令对应的地址
input wire[`InstBus] if_inst, // 取指阶段取得的指令
// 对应译码阶段的信号
output reg[`InstAddrBus] id_pc, // 译码阶段的指令的地址
output reg[`InstBus] id_inst // 译码阶段的指令
);
always @(posedge clk) begin
if (rst == `RstEnable) begin
id_pc <= `ZeroWord; // 复位的时候pc为0
id_inst <= `ZeroWord; // 复位的时候指令也为0,实际就是空指令
end else begin
id_pc <= if_pc; // 其余时刻向下传递取指阶段的值
id_inst <= if_inst;
end
end
endmodule
译码阶段
Regfile模块
`include "defines.v"
`timescale 1ns/1ps
module regfile(
input wire clk,
input wire rst,
// 写端口
input wire we, // 写端口的使能信号
input wire[`RegAddrBus] waddr, // 要写入的寄存器地址
input wire[`RegBus] wdata, // 要写入的值
// 读端口 1
input wire re1, // 第一个读寄存器端口读使能信号
input wire[`RegAddrBus] raddr1, // 第一个读寄存器端口要读取的寄存器的地址
output reg[`RegBus] rdata1, // 第一个读寄存器端口输出的寄存器数据
// 读端口 2
input wire re2, // 第二个读寄存器端口读使能信号
input wire[`RegAddrBus] raddr2, // 第二个读寄存器端口要读取的寄存器的地址
output reg[`RegBus] rdata2 // 第二个读寄存器端口输出的寄存器数据
);
/****************** 第一段:定义32个32位寄存器 *******************/
reg[`RegBus] regs[0:`RegNum-1]; // 前面[31:0]表示位宽,regs是此存储的名字,[0:31]表示0到31共32个
/****************** 第二段:写操作 *******************/
always @(posedge clk) begin
if (rst == `RstDisable) begin // 复位信号无效
if ((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) begin // 写使能&&写目的寄存器不为$0
regs[waddr] <= wdata;
end
end
end
/****************** 第三段:读端口 1操作 *******************/
always @(*) begin
if (rst == `RstEnable) begin // 复位信号有效
rdata1 <= `ZeroWord; // 输出 0
end else if (raddr1 == `RegNumLog2'h0) begin // 读目的寄存器为$0
rdata1 <= `ZeroWord; // 输出 0
end else if((raddr1 == waddr) && (we == `WriteEnable) && (re1 == `ReadEnable)) begin // 读写目的寄存器一致&&写使能&&读使能
rdata1 <= wdata; // 输出要写入的值
end else if (re1 == `ReadEnable) begin //读端口有效
rdata1 <= regs[raddr1]; // 输出读目的寄存器的值
end else begin // 读端口不能使用
rdata1 <= `ZeroWord;
end
end
/****************** 第四段:读端口 2操作 *******************/
always @(*) begin
if (rst == `RstEnable) begin
rdata2 <= `ZeroWord;
end else if (raddr2 == `RegNumLog2'h0) begin
rdata2 <= `ZeroWord;
end else if((raddr2 == waddr) && (we == `WriteEnable) && (re2 == `ReadEnable)) begin
rdata2 <= wdata;
end else if (re2 == `ReadEnable) begin
rdata2 <= regs[raddr2];
end else begin
rdata2 <= `ZeroWord;
end
end
endmodule
reg[`RegBus] regs[0:`RegNum-1]
定义了32个32位寄存器。RegBus 表示位宽,regs 为此存储器的名字,[0:`RegNUm - 1]表示深度(个数)
ID模块
`include "defines.v"
`timescale 1ns/1ps
module id(
input wire rst, // 复位信号
input wire[`InstAddrBus] pc_i, // 译码阶段的指令对应的地址
input wire[`InstBus] inst_i, // 译码阶段的指令
// 读取的Regfile的值
input wire[`RegBus] reg1_data_i, // 从Regfile输入的第一个读寄存器端口的输入
input wire[`RegBus] reg2_data_i, // 从Regfile输入的第二个读寄存器端口的输入
// 输出到Regfile的信息
output reg reg1_read_o, // Regfile模块的第一个读寄存器模块的读使能信号
output reg reg2_read_o, // Regfile模块的第二个读寄存器模块的读使能信号
output reg[`RegAddrBus] reg1_addr_o, // Regfile模块的第一个读寄存器模块的读地址信号
output reg[`RegAddrBus] reg2_addr_o, // Regfile模块的第二个读寄存器模块的读地址信号
// 送到执行阶段的信息
output reg[`AluOpBus] aluop_o, // 译码阶段的指令要进行的运算的子类型
output reg[`AluSelBus] alusel_o, // 译码阶段的指令要进行的运算的类型
output reg[`RegBus] reg1_o, // 译码阶段的指令要进行的运算的源操作数1
output reg[`RegBus] reg2_o, // 译码阶段的指令要进行的运算的源操作数2
output reg[`RegAddrBus] wd_o, // 译码阶段的指令要写入的目的寄存器地址
output reg wreg_o // 译码阶段的指令要是否有要写入的目的寄存器
);
// 取得指令的指令码,功能码
// 对于ori指令只需判断26~31bit的值,即可判断是否是ori指令
wire[5:0] op = inst_i[31:26]; // 取指令码,判断
wire[4:0] op2 = inst_i[10:6]; //目前没用
wire[5:0] op3 = inst_i[5:0]; //目前没用
wire[4:0] op4 = inst_i[20:16]; //目前没用
// 保存指令执行需要的立即数
reg[`RegBus] imm;
// 指示指令是否有效
reg instvalid;
/*************** 第一段:对指令进行译码 ***************/
always @(*) begin
if (rst == `RstEnable) begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= `NOPRegAddr;
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
reg1_read_o <= `ReadDisable;
reg2_read_o <= `ReadDisable;
reg1_addr_o <= `NOPRegAddr;
reg2_addr_o <= `NOPRegAddr;
imm <= `ZeroWord;
end else begin
aluop_o <= `EXE_NOP_OP;
alusel_o <= `EXE_RES_NOP;
wd_o <= inst_i[15:11]; // R类指令,rd,目的寄存器编号;目前没用
wreg_o <= `WriteDisable;
instvalid <= `InstInvalid; // 先给指令无效,后续case中会依据指令赋值
reg1_read_o <= `ReadDisable;
reg2_read_o <= `ReadDisable;
reg1_addr_o <= inst_i[25:21]; // rs
reg2_addr_o <= inst_i[20:16]; // rt
imm <= `ZeroWord;
case (op)
`EXE_ORI: begin
wreg_o <= `WriteEnable; // ori指令需要将结果写入目的寄存器
aluop_o <= `EXE_OR_OP; // 运算的子类型是或运算
alusel_o <= `EXE_RES_LOGIC; // 运算类型是逻辑运算
reg1_read_o <= `ReadEnable; // 需要通过Regfile的读端口1读取寄存器
reg2_read_o <= `ReadDisable; // 不需要通过Regfile的读端口2读取寄存器
imm <= {16'h0, inst_i[15:0]}; // 立即数无符号拓展到32位
wd_o <= inst_i[20:16]; // 指令执行结果要写入的目的寄存器rt
instvalid <= `InstValid; // ori是有效指令
end
default: begin
end
endcase // case op
end // if
end // always
/*************** 第二段:确定进行运算的源操作数1 ***************/
always @(*) begin
if (rst == `RstEnable) begin
reg1_o <= `ZeroWord;
end else if (reg1_read_o == `ReadEnable) begin
reg1_o <= reg1_data_i; // Regfile读端口1的输出值
end else if (reg1_read_o == `ReadDisable) begin
reg1_o <= imm; // 读立即数
end else begin
reg1_o <= `ZeroWord;
end
end
/*************** 第三阶段:确定进行运算的源操作数2 ***************/
always @(*) begin
if (rst == `RstEnable) begin
reg2_o <= `ZeroWord;
end else if (reg2_read_o == `ReadEnable) begin
reg2_o <= reg2_data_i; // Regfile读端口2的输出值
end else if (reg2_read_o == `ReadDisable) begin
reg2_o <= imm; // 读立即数
end else begin
reg2_o <= `ZeroWord;
end
end
endmodule
ID/EX模块
`include "defines.v"
`timescale 1ns/1ps
module id_ex(
input wire clk,
input wire rst,
// 从译码阶段传递过来的信息
input wire[`AluOpBus] id_aluop,
input wire[`AluSelBus] id_alusel,
input wire[`RegBus] id_reg1,
input wire[`RegBus] id_reg2,
input wire[`RegAddrBus] id_wd,
input wire id_wreg,
// 传递到执行阶段的信息
output reg[`AluOpBus] ex_aluop,
output reg[`AluSelBus] ex_alusel,
output reg[`RegBus] ex_reg1,
output reg[`RegBus] ex_reg2,
output reg[`RegAddrBus] ex_wd,
output reg ex_wreg
);
always @(posedge clk) begin
if (rst == `RstEnable) begin
ex_aluop <= `EXE_NOP_OP;
ex_alusel <= `EXE_RES_NOP;
ex_reg1 <= `ZeroWord;
ex_reg2 <= `ZeroWord;
ex_wd <= `NOPRegAddr;
ex_wreg <= `WriteDisable;
end else begin
ex_aluop <= id_aluop;
ex_alusel <= id_alusel;
ex_reg1 <= id_reg1;
ex_reg2 <= id_reg2;
ex_wd <= id_wd;
ex_wreg <= id_wreg;
end
end
endmodule
执行阶段
EX模块
`include "defines.v"
`timescale 1ns/1ps
module ex(
input wire rst,
// 译码阶段送到执行阶段的信息
input wire[`AluOpBus] aluop_i,
input wire[`AluSelBus] alusel_i,
input wire[`RegBus] reg1_i,
input wire[`RegBus] reg2_i,
input wire[`RegAddrBus] wd_i,
input wire wreg_i,
// 执行结果
output reg[`RegBus] wdata_o,
output reg[`RegAddrBus] wd_o,
output reg wreg_o
);
// 保存逻辑运算的结果
reg[`RegBus] logicout;
/********** 第一段:依据aluop_i指示的运算子类型进行运算,此处只有逻辑“或”运算 **********/
always @(*) begin
if (rst == `RstEnable) begin
logicout <= `ZeroWord;
end else begin
case (aluop_i)
`EXE_OR_OP: begin
logicout <= reg1_i | reg2_i; // 此时reg2_i中的是imm
end
default: begin
logicout <= `ZeroWord;
end
endcase
end // if
end // always
/***** 第二段:依据alusel_i指示的运算的类型,选择一个运算结果作为最终结果,此处只有逻辑运算结果 *****/
always @(*) begin
wd_o <= wd_i;
wreg_o <= wreg_i;
case (alusel_i)
`EXE_RES_LOGIC: begin
wdata_o <= logicout;
end
default: begin
wdata_o <= `ZeroWord;
end
endcase
end
endmodule
EX/MEM模块
`include "defines.v"
`timescale 1ns/1ps
module ex_mem (
input wire clk,
input wire rst,
// 来自执行阶段的信息
input wire[`RegBus] ex_wdata,
input wire[`RegAddrBus] ex_wd,
input wire ex_wreg,
// 传递到访存阶段的信息
output reg[`RegBus] mem_wdata,
output reg[`RegAddrBus] mem_wd,
output reg mem_wreg
);
always @(posedge clk) begin
if (rst == `RstEnable) begin
mem_wdata <= `ZeroWord;
mem_wd <= `NOPRegAddr;
mem_wreg <= `WriteDisable;
end else begin
mem_wdata <= ex_wdata;
mem_wd <= ex_wd;
mem_wreg <= ex_wreg;
end
end
endmodule
访存阶段
MEM模块
`include "defines.v"
`timescale 1ns/1ps
module mem_wb(
input wire rst,
input wire clk,
// 访存阶段的结果
input wire[`RegBus] mem_wdata,
input wire[`RegAddrBus] mem_wd,
input wire mem_wreg,
// 传递到写回阶段的信息
output reg[`RegBus] wb_wdata,
output reg[`RegAddrBus] wb_wd,
output reg wb_wreg
);
always @(*) begin
if (rst == `RstEnable) begin
wb_wdata <= `ZeroWord;
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
end else begin
wb_wdata <= mem_wdata;
wb_wd <= mem_wd;
wb_wreg <= mem_wreg;
end
end
endmodule
MEM/WB模块
`include "defines.v"
`timescale 1ns/1ps
module mem_wb(
input wire rst,
input wire clk,
// 访存阶段的结果
input wire[`RegBus] mem_wdata,
input wire[`RegAddrBus] mem_wd,
input wire mem_wreg,
// 传递到写回阶段的信息
output reg[`RegBus] wb_wdata,
output reg[`RegAddrBus] wb_wd,
output reg wb_wreg
);
always @(*) begin
if (rst == `RstEnable) begin
wb_wdata <= `ZeroWord;
wb_wd <= `NOPRegAddr;
wb_wreg <= `WriteDisable;
end else begin
wb_wdata <= mem_wdata;
wb_wd <= mem_wd;
wb_wreg <= mem_wreg;
end
end
endmodule
写回阶段
利用MEM/WB模块和Regfile模块实现
顶层模块OpenMIPS实现
`include "defines.v"
`timescale 1ns/1ps
module openmips (
input wire clk,
input wire rst,
input wire[`RegBus] rom_data_i, // 从指令存储器取得的指令
output wire[`RegBus] rom_addr_o, // 输出到指令寄存器的地址
output wire rom_ce_o // 指令寄存器使能信号
);
// 连接IF/ID模块与译码阶段ID模块的变量
wire[`InstAddrBus] pc;
wire[`InstAddrBus] id_pc_i;
wire[`InstBus] id_inst_i;
// 连接译码阶段ID模块输出与ID/EX模块输入的变量
wire[`AluOpBus] id_aluop_o;
wire[`AluSelBus] id_alusel_o;
wire[`RegBus] id_reg1_o;
wire[`RegBus] id_reg2_o;
wire[`RegAddrBus] id_wd_o;
wire id_wreg_o;
// 连接ID/EX模块的输出与执行阶段EX模块输入的变量
wire[`AluOpBus] ex_aluop_i;
wire[`AluSelBus] ex_alusel_i;
wire[`RegBus] ex_reg1_i;
wire[`RegBus] ex_reg2_i;
wire[`RegAddrBus] ex_wd_i;
wire ex_wreg_i;
// 连接执行阶段EX模块的输出与EX/MEM模块输入的变量
wire[`RegBus] ex_wdata_o;
wire[`RegAddrBus] ex_wd_o;
wire ex_wreg_o;
// 连接EX/MEM模块的输出与访存阶段MEM模块的输入的变量
wire[`RegBus] mem_wdata_i;
wire[`RegAddrBus] mem_wd_i;
wire mem_wreg_i;
// 连接访存阶段MEM模块输出与MEM/WB模块输入的变量
wire[`RegBus] mem_wdata_o;
wire[`RegAddrBus] mem_wd_o;
wire mem_wreg_o;
// 连接MEM/WB模块输出与写回阶段的输入的变量
wire[`RegBus] wb_wdata_i;
wire[`RegAddrBus] wb_wd_i;
wire wb_wreg_i;
// 连接译码阶段ID模块与通用寄存器Regfile模块的变量
wire reg1_read;
wire reg2_read;
wire[`RegBus] reg1_data;
wire[`RegBus] reg2_data;
wire[`RegAddrBus] reg1_addr;
wire[`RegAddrBus] reg2_addr;
// pc_reg实例化
pc_reg pc_reg0(
.clk(clk),
.rst(rst),
.pc(pc),
.ce(rom_ce_o)
);
// 指令寄存器的输入地址就是pc的值
assign rom_addr_o = pc;
//IF/ID模块的实例化
if_id if_id0(
.clk(clk),
.rst(rst),
.if_pc(pc),
.if_inst(rom_data_i),
.id_pc(id_pc_i),
.id_inst(id_inst_i)
);
// 译码阶段ID模块实例化
id id0(
.rst(rst),
.pc_i(id_pc_i),
.inst_i(id_inst_i),
// 读取的Regfile的值
.reg1_data_i(reg1_data),
.reg2_data_i(reg2_data),
// 输出到Regfile的信息
.reg1_read_o(reg1_read),
.reg2_read_o(reg2_read),
.reg1_addr_o(reg1_addr),
.reg2_addr_o(reg2_addr),
// 送到执行阶段的信息
.aluop_o(id_aluop_o),
.alusel_o(id_alusel_o),
.reg1_o(id_reg1_o),
.reg2_o(id_reg2_o),
.wd_o(id_wd_o),
.wreg_o(id_wreg_o)
);
// Regfile模块的实例化
regfile regfile0(
.clk(clk),
.rst(rst),
// 写端口
.we(wb_wreg_i),
.waddr(wb_wd_i),
.wdata(wb_wdata_i),
// 读端口 1
.re1(reg1_read),
.raddr1(reg1_addr),
.rdata1(reg1_data),
// 读端口 2
.re2(reg2_read),
.raddr2(reg2_addr),
.rdata2(reg2_data)
);
// ID/EX模块实例化
id_ex id_ex0(
.clk(clk),
.rst(rst),
// 从译码阶段ID模块传递过来的信息
.id_aluop(id_aluop_o),
.id_alusel(id_alusel_o),
.id_reg1(id_reg1_o),
.id_reg2(id_reg2_o),
.id_wd(id_wd_o),
.id_wreg(id_wreg_o),
// 传递到执行阶段的信息
.ex_aluop(ex_aluop_i),
.ex_alusel(ex_alusel_i),
.ex_reg1(ex_reg1_i),
.ex_reg2(ex_reg2_i),
.ex_wd(ex_wd_i),
.ex_wreg(ex_wreg_i)
);
// EX模块实例化
ex ex0(
.rst(rst),
// 从ID/EX模块传递来的信息
.aluop_i(ex_aluop_i),
.alusel_i(ex_alusel_i),
.reg1_i(ex_reg1_i),
.reg2_i(ex_reg2_i),
.wd_i(ex_wd_i),
.wreg_i(ex_wreg_i),
// 执行结果输出到EX/MEM模块
.wdata_o(ex_wdata_o),
.wd_o(ex_wd_o),
.wreg_o(ex_wreg_o)
);
// EX/MEM模块实例化
ex_mem ex_mem0(
.clk(clk),
.rst(rst),
// 来自EX模块的信息
.ex_wdata(ex_wdata_o),
.ex_wd(ex_wd_o),
.ex_wreg(ex_wreg_o),
// 传递到访存阶段MEM模块的信息
.mem_wdata(mem_wdata_i),
.mem_wd(mem_wd_i),
.mem_wreg(mem_wreg_i)
);
// MEM模块实例化
mem mem0(
.rst(rst),
// 来自EX/MEM模块的信息
.wdata_i(mem_wdata_i),
.wd_i(mem_wd_i),
.wreg_i(mem_wreg_i),
// 传递到MEM/WB模块的信息
.wdata_o(mem_wdata_o),
.wd_o(mem_wd_o),
.wreg_o(mem_wreg_o)
);
// MEM/WB模块实例化
mem_wb mem_wb0(
.rst(rst),
.clk(clk),
// 访存阶段MEM模块的结果
.mem_wdata(mem_wdata_o),
.mem_wd(mem_wd_o),
.mem_wreg(mem_wreg_o),
// 传递到写回阶段的信息
.wb_wdata(wb_wdata_i),
.wb_wd(wb_wd_i),
.wb_wreg(wb_wreg_i)
);
endmodule
3. 验证OpenMIPS实现效果
指令存储器ROM实现
`include "defines.v"
`timescale 1ns/1ps
module inst_rom(
input wire ce, // 使能信号
input wire[`InstAddrBus] addr, // 要读取的地址
output reg[`InstBus] inst // 读出的指令
);
// 定义一个数组,大小是InstMemNum,元素宽度是InstBus
reg[`InstBus] inst_mem[0:`InstMemNum-1];
// 使用文件inst_rom.data初始化指令寄存器
initial $readmemh ( "inst_rom.mem",inst_mem );
// 当复位信号无效时,依据输入的地址,给出指令寄存器ROM中对应的元素
always @(*) begin
if (ce == `ChipDisable) begin
inst <= `ZeroWord;
end else begin
inst <= inst_mem[addr[`InstMemNumLog2+1:2]]; // 指令寄存器的每个地址是一个32bit的字,addr要除4
end
end
endmodule
OpenMIPS按字节寻址,此处定义的指令存取器的每个地址是一个32bit的1字,所以要将OpenMIPS给出的指令地址除以4再使用。
最小SOPC的实现
`include "defines.v"
`timescale 1ns/1ps
module openmips_min_sopc(
input wire clk,
input wire rst
);
// 连接指令存储器
wire[`InstAddrBus] inst_addr;
wire[`InstBus] inst;
wire rom_ce;
// 实例化处理器OpenMIPS
openmips openmips0(
.clk(clk),
.rst(rst),
.rom_data_i(inst),
.rom_addr_o(inst_addr),
.rom_ce_o(rom_ce)
);
// 实例化指令存储器ROM
inst_rom inst_rom0(
.ce(rom_ce),
.addr(inst_addr),
.inst(inst)
);
endmodule
测试程序
34011100
34020020
3403ff00
3404ffff
34210020
34214400
34210044
Test Bench文件
`timescale 1ns / 1ps // 时间单位1ns,精度1ps
`include "../rtl/defines.v"
module openmips_min_sopc_tb ();
reg CLOCK_50;
reg rst;
//实例化最小SOPC
openmips_min_sopc openmips_min_sopc0(
.clk(CLOCK_50),
.rst(rst)
);
// 每隔10ns,CLOCK_50信号翻转一次,所以一个周期是20ns,对应50MHz
initial begin
CLOCK_50 = 1'b0;
forever begin
#10 CLOCK_50 = ~CLOCK_50;
end
end
// 最初时刻,复位信号有效,在第195ns,复位信号无效,最小SOPC开始运行
// 运行1000ns后,暂停仿真
initial begin
rst = `RstEnable;
#195 rst = `RstDisable;
#1000 $stop;
end
endmodule