第一条ori指令的实现

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

仿真波形

在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值