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

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

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

5.5.1 修改译码阶段的ID模块

修改宏定义defines.v

defines.v +=

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

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

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

`define EXE_SYNC  6‘b001111
`define EXE_PREF  6‘b110011

`define EXE_SPECIAL_INST 6‘b000000

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

修改后的代码如下:

`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 <= 1‘b0;
            reg2_read_o <= 1‘b0;
            reg1_addr_o <= `NOPRegAddr;
            reg2_addr_o <= `NOPRegAddr;
            imm <= 32‘h0;
        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 <= 1‘b0;
            reg2_read_o <= 1‘b0;
            reg1_addr_o <= inst_i[25:21];
            reg2_addr_o <= inst_i[20:16];
            imm <= `ZeroWord;
            case (op)
                `EXE_SPECIAL_INST: begin
                    case (op2)
                        5‘b00000: begin
                            case (op3)
                                `EXE_OR:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_OR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1‘b1;
                                    reg2_read_o <= 1‘b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_AND:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_AND_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1‘b1;
                                    reg2_read_o <= 1‘b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_XOR:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_XOR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1‘b1;
                                    reg2_read_o <= 1‘b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_NOR:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_NOR_OP;
                                    alusel_o <= `EXE_RES_LOGIC;
                                    reg1_read_o <= 1‘b1;
                                    reg2_read_o <= 1‘b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_SLLV:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_SLL_OP;
                                    alusel_o <= `EXE_RES_SHIFT;
                                    reg1_read_o <= 1‘b1;
                                    reg2_read_o <= 1‘b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_SRLV: begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_SRL_OP;
                                    alusel_o <= `EXE_RES_SHIFT;
                                    reg1_read_o <= 1‘b1;
                                    reg2_read_o <= 1‘b1;
                                    instvalid <= `InstValid;
                                end
                                `EXE_SRAV:begin
                                    wreg_o <= `WriteEnable;
                                    aluop_o <= `EXE_SRA_OP;
                                    alusel_o <= `EXE_RES_SHIFT;
                                    reg1_read_o <= 1‘b1;
                                    reg2_read_o <= 1‘b1;
                                    instvalid <= `InstValid;
                                  end
                                `EXE_SYNC: begin
                                    wreg_o <= `WriteDisable;
                                    aluop_o <= `EXE_NOP_OP;
                                    alusel_o <= `EXE_RES_NOP;
                                    reg1_read_o <= 1‘b0;
                                    reg2_read_o <= 1‘b1;
                                    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 <= 1‘b1;
                    reg2_read_o <= 1‘b0;
                    imm <= {16‘h0, 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 <= 1‘b1;
                    reg2_read_o <= 1‘b0;
                    imm <= {16‘h0, 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 <= 1‘b1;
                    reg2_read_o <= 1‘b0;
                    imm <= {16‘h0, 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 <= 1‘b1;
                    reg2_read_o <= 1‘b0;
                    imm <= {inst_i[15:0], 16‘h0};
                    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 <= 1‘b0;
                    reg2_read_o <= 1‘b0;
                    instvalid <= `InstValid;
                end
                default:begin end
            endcase          //case op

            if (inst_i[31:21] == 11‘b00000000000) begin
                if (op3 == `EXE_SLL) begin
                    wreg_o <= `WriteEnable;
                    aluop_o <= `EXE_SLL_OP;
                    alusel_o <= `EXE_RES_SHIFT;
                    reg1_read_o <= 1‘b0;
                    reg2_read_o <= 1‘b1;
                    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 <= 1‘b0;
                    reg2_read_o <= 1‘b1;
                    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 <= 1‘b0;
                    reg2_read_o <= 1‘b1;
                    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]}} << (6‘d32-{1‘b0, 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

原文地址:https://www.cnblogs.com/ycc1997/p/12210149.html

时间: 2024-10-21 19:27:06

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

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

5.4 逻辑.位移操作与空指令说明 5.4.1 and.or.xor.nor 指令格式 指令用法 5.4.2 andi.xori指令 指令格式 指令用法 5.4.3 lui 指令格式 指令用法 5.4.4 sll.slv.sra.srav.srl.srlv 指令格式 指令用法 指令命名方式 5.4.5 nop.ssnop.sync.pref 原文地址:https://www.cnblogs.com/ycc1997/p/12207452.html

自己动手写CPU之第五阶段(4)——逻辑、移位与空指令的实现

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第18篇,我尽量每周四篇 5.5 修改OpenMIPS以实现逻辑.移位操作与空指令 为了实现逻辑.移位操作与空指令(其中nop.ssnop不用特意实现,可以认为是特殊的逻辑左移指令sll),只需要修改OpenMIPS的如下两个模块. 修改译码阶段的ID模块,用以实现对上述指令的译码. 修改执行阶段的EX模块,使其按照译码结果进行运算. 5.5.1 修改译码阶段的ID模块 首先给出如下宏定义,都在文件defines.v中定义,读者可以

自己动手写CPU之第四阶段(2)——验证第一条指令ori的实现效果

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第12篇,我尽量每周四篇 书名又之前的<自己动手写处理器>改为<自己动手写CPU> 4.3 验证OpenMIPS实现效果 4.3.1指令存储器ROM的实现 本节将验证我们的OpenMIPS是否实现正确,包含:流水线是否正确.ori指令是否实现正确.在验证之前,需要首先实现指令存储器,以便OpenMIPS从中读取指令. 指令存储器模块是只读的,其接口如图4-7所示,还是采用左边是输入接口,右边是输出接口的方式绘

自己动手写CPU之第五阶段(5)——测试逻辑、移位与空指令的实现

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第19篇,我尽量每周四篇 5.6 测试程序1--测试逻辑操作实现效果 编写如下测试程序用于检验逻辑操作指令是否实现正确,文件名命名为inst_rom.S,在本附带光盘Code\Chapter5_2\AsmTest\LogicInstTest目录下有测试程序源文件. .org 0x0 .global _start .set noat _start: lui $1,0x0101 # $1 = 0x01010000 ori $1,$1,0

自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第17篇,我尽量每周四篇 5.4 逻辑.移位操作与空指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条:and.andi.or.ori.xor.xori.nor.lui,其中ori指令已经实现了,本章要实现其余7条指令. MIPS32指令集架构中定义的移位操作指令有6条:sll.sllv.sra.srav.srl.srlv. MIPS32指令集架构中定义的空指令有2条:nop.ssnop.其中ssnop是一种特殊类型的空操作

自己动手写CPU之第九阶段(5)——实现加载存储指令2(修改执行阶段)

将陆续上传新书<自己动手写CPU>,今天是第42篇,我尽量每周四篇,但是最近已经很久没有实现这个目标了,一直都有事,不好意思哈. 开展晒书评送书活动,在亚马逊.京东.当当三大图书网站上,发表<自己动手写CPU>书评的前十名读者,均可获赠<步步惊芯--软核处理器内部设计分析>一书,大家踊跃参与吧!活动时间:2014-9-11至2014-10-30 9.3.2 修改执行阶段 1.修改EX模块 在执行阶段的EX模块会计算加载存储的目的地址,参考图9-19可知,EX模块会增加部

自己动手写CPU之第七阶段(4)——验证简单算术操作指令实现效果

将陆续上传本人写的新书<自己动手写CPU>,今天是第27篇,我尽量每周四篇 China-pub的预售地址如下(有目录.内容简介.前言): http://product.china-pub.com/3804025 亚马逊的预售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 7.4 测试简单算术操作指令实现效果 本节通过实验来检验我们修改后的代码是否实现了简单算术操作指令,测试程序如下

自己动手写CPU之第七阶段(8)——验证乘累加指令的实现效果

将陆续上传本人写的新书<自己动手写CPU>,今天是第31篇,我尽量每周四篇 亚马逊的销售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 China-pub的销售地址如下: http://product.china-pub.com/3804025 北发的销售地址如下: http://book.beifabook.com/Product/BookDetail.aspx?Plucode=

自己动手写CPU_5_5.2 OpenMIPS对数据相关问题的解决措施

5.2 OpenMIPS对数据相关问题的解决措施 OpenMIPS采用数据前推的方式来解决流水线数据相关问题.如图所示(虚线),将执行阶段的结果.访存阶段的结果推到译码阶段,参与译码阶段选择运算源操作数的过程. 下图给出了实现数据前推对OpenMIPS系统结构的修改,具体为以下两方面: 1. 处于EX阶段的指令运算结果送到ID阶段. 2. 将MEM阶段的指令送到ID阶段. 为此需要修改ID模块的接口: 译码阶段的ID模块会根据送入的信息进行判断,解决数据相关,给出最后要参与运算的操作数.ID模块