自己动手写CPU_5_5.5 修改OpenMIPS以实现逻辑位移操作和空指令

Posted ycc1997

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自己动手写CPU_5_5.5 修改OpenMIPS以实现逻辑位移操作和空指令相关的知识,希望对你有一定的参考价值。

5.5 修改OpenMIPS以实现逻辑、位移操作和空指令

为了实现逻辑、位移操作与空指令,需要修改ID和EX模块。

5.5.1 修改译码阶段的ID模块

修改宏定义defines.v

defines.v +=

/**
    EXE_* 功能码 或 指令码
**/

`define EXE_AND  6b100100    
`define EXE_OR   6b100101
`define EXE_XOR 6b100110
`define EXE_NOR 6b100111
`define EXE_ANDI 6b001100
`define EXE_ORI  6b001101
`define EXE_XORI 6b001110
`define EXE_LUI 6b001111

`define EXE_SLL  6b000000
`define EXE_SLLV  6b000100
`define EXE_SRL  6b000010
`define EXE_SRLV  6b000110
`define EXE_SRA  6b000011
`define EXE_SRAV  6b000111

`define EXE_SYNC  6b001111
`define EXE_PREF  6b110011

`define EXE_SPECIAL_INST 6b000000

以下是对指令编码和指令的映射算法:

技术图片

 

修改后的代码如下:

`include "defines.h"

module id
(
    input wire rst,
    input wire[`InstAddrBus] pc_i,
    input wire[`InstBus] inst_i,
    
    //处于执行阶段的指令要写入的目的寄存器信息
    input wire ex_wreg_i,
    input wire[`RegBus] ex_wdata_i,
    input wire[`RegAddrBus] ex_wd_i,
    
    //处于访存阶段的指令要写入的目的寄存器信息
    input wire mem_wreg_i,
    input wire[`RegBus] mem_wdata_i,
    input wire[`RegAddrBus] mem_wd_i,
    
    //从regfile读取的数据
    input wire[`RegBus] reg1_data_i,
    input wire[`RegBus] reg2_data_i,
    
    //送到regfile的信息
    output reg                    reg1_read_o,
    output reg                    reg2_read_o,     
    output reg[`RegAddrBus]       reg1_addr_o,
    output reg[`RegAddrBus]       reg2_addr_o,
    
    //送到执行阶段的信息
    output reg[`AluOpBus]         aluop_o,
    output reg[`AluSelBus]        alusel_o,
    output reg[`RegBus]           reg1_o,
    output reg[`RegBus]           reg2_o,
    output reg[`RegAddrBus]       wd_o,
    output reg                    wreg_o
);
    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 <= 1b0;
            reg2_read_o <= 1b0;
            reg1_addr_o <= `NOPRegAddr;
            reg2_addr_o <= `NOPRegAddr;
            imm <= 32h0;
        end else begin
            aluop_o <= `EXE_NOP_OP;
            alusel_o <= `EXE_RES_NOP;
            wd_o <= inst_i[15:11];
            wreg_o <= `WriteDisable;
            instvalid <= `InstInvalid;       
            reg1_read_o <= 1b0;
            reg2_read_o <= 1b0;
            reg1_addr_o <= inst_i[25:21];
            reg2_addr_o <= inst_i[20:16];        
            imm <= `ZeroWord;
            case (op)
                `EXE_SPECIAL_INST: begin
                    case (op2)
                        5b00000: begin
                            case (op3)
                                `EXE_OR:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_OR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1b1;
                                    reg2_read_o <= 1b1;
                                    instvalid <= `InstValid;    
                                end  
                                `EXE_AND:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_AND_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1b1;
                                    reg2_read_o <= 1b1;    
                                    instvalid <= `InstValid;    
                                end
                                `EXE_XOR:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_XOR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1b1;
                                    reg2_read_o <= 1b1;    
                                    instvalid <= `InstValid;    
                                end                  
                                `EXE_NOR:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_NOR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1b1;
                                    reg2_read_o <= 1b1;    
                                    instvalid <= `InstValid;    
                                end
                                `EXE_SLLV:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_SLL_OP;
                                    alusel_o <= `EXE_RES_SHIFT;
                                    reg1_read_o <= 1b1;
                                    reg2_read_o <= 1b1;
                                    instvalid <= `InstValid;    
                                end 
                                `EXE_SRLV: begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_SRL_OP;
                                    alusel_o <= `EXE_RES_SHIFT;
                                    reg1_read_o <= 1b1;
                                    reg2_read_o <= 1b1;
                                    instvalid <= `InstValid;    
                                end            
                                `EXE_SRAV:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_SRA_OP;
                                    alusel_o <= `EXE_RES_SHIFT;
                                    reg1_read_o <= 1b1;
                                    reg2_read_o <= 1b1;
                                    instvalid <= `InstValid;            
                                  end
                                `EXE_SYNC: begin
                                    wreg_o <= `WriteDisable;
                                    aluop_o <= `EXE_NOP_OP;
                                    alusel_o <= `EXE_RES_NOP;
                                    reg1_read_o <= 1b0;
                                    reg2_read_o <= 1b1;
                                    instvalid <= `InstValid;    
                                end                                                                      
                                default:begin end
                            endcase
                        end
                        default: begin end
                    endcase    
                end                                      
                `EXE_ORI:begin                        //ORI指令
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_OR_OP;
                    alusel_o <= `EXE_RES_LOGIC;
                    reg1_read_o <= 1b1;
                    reg2_read_o <= 1b0;          
                    imm <= {16h0, inst_i[15:0]};
                    wd_o <= inst_i[20:16];
                    instvalid <= `InstValid;    
                end
                `EXE_ANDI:begin
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_AND_OP;
                    alusel_o <= `EXE_RES_LOGIC;
                    reg1_read_o <= 1b1;
                    reg2_read_o <= 1b0;          
                    imm <= {16h0, inst_i[15:0]};
                    wd_o <= inst_i[20:16];              
                    instvalid <= `InstValid;    
                end         
                `EXE_XORI:begin
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_XOR_OP;
                    alusel_o <= `EXE_RES_LOGIC;
                    reg1_read_o <= 1b1;
                    reg2_read_o <= 1b0;          
                    imm <= {16h0, inst_i[15:0]};
                    wd_o <= inst_i[20:16];              
                    instvalid <= `InstValid;    
                end             
                `EXE_LUI:begin
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_OR_OP;
                    alusel_o <= `EXE_RES_LOGIC;
                    reg1_read_o <= 1b1;
                    reg2_read_o <= 1b0;          
                    imm <= {inst_i[15:0], 16h0};
                    wd_o <= inst_i[20:16];              
                    instvalid <= `InstValid;    
                end        
                `EXE_PREF:begin
                    wreg_o <= `WriteDisable;
                    aluop_o <= `EXE_NOP_OP;
                    alusel_o <= `EXE_RES_NOP;
                    reg1_read_o <= 1b0;
                    reg2_read_o <= 1b0;                
                    instvalid <= `InstValid;    
                end
                default:begin end
            endcase          //case op
            
            if (inst_i[31:21] == 11b00000000000) begin
                if (op3 == `EXE_SLL) begin
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_SLL_OP;
                    alusel_o <= `EXE_RES_SHIFT;
                    reg1_read_o <= 1b0;
                    reg2_read_o <= 1b1;          
                    imm[4:0] <= inst_i[10:6];
                    wd_o <= inst_i[15:11];
                    instvalid <= `InstValid;    
                end else if ( op3 == `EXE_SRL ) begin
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_SRL_OP;
                    alusel_o <= `EXE_RES_SHIFT;
                    reg1_read_o <= 1b0;
                    reg2_read_o <= 1b1;          
                    imm[4:0] <= inst_i[10:6];
                    wd_o <= inst_i[15:11];
                    instvalid <= `InstValid;    
                end else if ( op3 == `EXE_SRA ) begin
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_SRA_OP;
                    alusel_o <= `EXE_RES_SHIFT;
                    reg1_read_o <= 1b0;
                    reg2_read_o <= 1b1;          
                    imm[4:0] <= inst_i[10:6];
                    wd_o <= inst_i[15:11];
                    instvalid <= `InstValid;    
                end
            end
        end       //if
    end         //always
endmodule

 

AND指令的译码过程:

 技术图片

 

 

 ANDI指令的译码过程:

技术图片

 

 SLLV指令的译码过程

技术图片

 

LUI指令的译码过程

技术图片

 

SLL指令的译码过程

技术图片

 

 5.5.2 修改执行阶段的EX模块

`include "defines.v"

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[`RegAddrBus] wd_o,
    output reg wreg_o,
    output reg[`RegBus] wdata_o
    
);

    reg[`RegBus] logicout;            //保存逻辑运算结果
    reg[`RegBus] shiftres;            //保存位移运算结果

    //进行逻辑运算
    always @ (*) begin
        if(rst == `RstEnable) begin
            logicout <= `ZeroWord;
        end else begin
            case (aluop_i)
                `EXE_OR_OP:    begin logicout <= reg1_i | reg2_i;    end
                `EXE_AND_OP:begin logicout <= reg1_i & reg2_i;    end
                `EXE_NOR_OP:begin logicout <= ~(reg1_i |reg2_i);end
                `EXE_XOR_OP:begin logicout <= reg1_i ^ reg2_i;    end
                default:    begin logicout <= `ZeroWord;        end
            endcase
        end    //if
    end      //always

    //进行位移运算
    always @ (*) begin
        if(rst == `RstEnable) begin
            shiftres <= `ZeroWord;
        end else begin
            case (aluop_i)
                `EXE_SLL_OP:begin shiftres <= reg2_i << reg1_i[4:0]; end
                `EXE_SRL_OP:begin shiftres <= reg2_i >> reg1_i[4:0]; end
                `EXE_SRA_OP:begin shiftres <= ({32{reg2_i[31]}} << (6d32-{1b0, reg1_i[4:0]})) | reg2_i >> reg1_i[4:0]; end
                default:begin shiftres <= `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
            `EXE_RES_SHIFT:begin wdata_o <= shiftres; end
            default:begin wdata_o <= `ZeroWord; end
        endcase
    end    

endmodule

以上是关于自己动手写CPU_5_5.5 修改OpenMIPS以实现逻辑位移操作和空指令的主要内容,如果未能解决你的问题,请参考以下文章

自己动手写CPU——第一篇

自己动手写CPU_5_5.4 逻辑位移操作与空指令的说明

自己动手写CPU之第四阶段——MIPS编译环境的建立

自己动手写一个操作系统——总目录

自己动手写一个操作系统——总目录

自己动手写一个操作系统——MBR_调试_elf_bin