自己动手写CPU(2)第一条ori指令

本博客内容基于《自己动手写CPU》这本书

上一篇文章介绍了一下流水线思想、设计流程等,下面我们可以实操一下实现第一条ori指令。

其实实现一条ori指令不难,我目前对这一条指令的理解简单来说就是,先看图对应每一个接口连线。

ori指令说明

ori是进行逻辑“或”运算的指令,指令格式如下图所示

3.png

指令用法为:ori rs,rt,immediate,将指令中的16位立即数immediate进行无符号拓展至32位,然后与地址为rs的通用寄存器进行逻辑“或”运算,将运算结果保存至地址为rt的通用寄存器中。

原始OpenMIPS五级流水线结构

首先看图,在上一篇文章介绍了五级流水线,这里就不在赘述了。下图是实现一条ori指令的五级流水线结构,在后续的学习中我们会在每个阶段增加一点,到最后形成一个OpenMIPS32五级流水线。

1.png

下图是原始OpenMIPS五级流水线系统结构图

然后就是将你现在看到的线通过各个模块连接起来。(我把宏定义放在最后了)

取指阶段

用于给出指令地址,其 I/O 端口如下

 PC模块代码:

`include "defines.v"

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'h00000000;   //指令存储器禁用时,PC为0
        end
        else begin
          pc <= pc + 4'h4;      //指令存储器使能时,PC的值每时钟周期加4
        end 
    end

endmodule

取指/译码模块

用于暂时保存取指得到的指令,以及地址,在下一个时钟周期送给译码阶段,其 I/O 端口如下 

if_id 模块代码:

`include "defines.v"

module if_id(
    input wire              rst,
    input wire              clk,

    //来自取值阶段的信号,InstBus表示指令宽度为32
    input wire [`InstBus]   if_inst,

    //对应的译码阶段的信号
    output reg [`InstBus]   id_inst
);

    always @(posedge clk) begin
        if(rst == `RstEnable) begin
          id_inst <= `ZeroWord;
        end
        else begin
          id_inst <= if_inst;
        end
    end

endmodule

译码模块

将得到的指令1.给出运算类型 2.给出参与运算的操作数

Regfile模块

实现了32个32位通用整数寄存器,可以同时进行两个寄存器的读操作和一个寄存器的写操作,其 I/O 端口如下 

   

模块代码:

`include "defines.v"

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];

//写操作
always @(posedge clk) begin
    if(rst == `RstDisable) begin
      if((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) begin   //寄存器0不可写
        regs[waddr] <= wdata;
      end
    end
end
//MIPS32架构规定$0的值只能为0

//读操作1,组合逻辑
always @(*) begin
    if(rst == `RstEnable) begin
      rdata1 <= `ZeroWord;
    end
    else if(raddr1 == `RegNumLog2'h0) begin
      rdata1 <= `ZeroWord;
    end
    else if((re1 == `ReadEnable) && (we == `WriteEnable) && (waddr == raddr1)) 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((re2 == `ReadEnable) && (we == `WriteEnable) && (waddr == raddr2)) begin
      rdata2 <= wdata;
    end
    else if(re2 == `ReadEnable) begin
      rdata2 <= regs[raddr2];
    end
    else begin
      rdata2 <= `ZeroWord;
    end
end
 
endmodule

ID模块

对指令进行译码,得到最终的运算类型、子类型、源操作数1 2、要写入的目的寄存器等,其 I/O 端口如下 

     

 模块代码:

`include "defines.v"

module id(
    input wire                rst,
    input wire [`InstBus]     inst_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[`AluSelBus]    alusel_o,
    output reg[`AluOpBus]     aluop_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 = `InstInvalid;
          reg1_read_o = `ReadDisable;
          reg2_read_o = `ReadDisable;
          reg1_addr_o = `NOPRegAddr;
          reg2_addr_o = `NOPRegAddr;
          imm = `ZeroWord;
        end
        else begin
          case(op)
            `EXE_ORI:begin
              aluop_o = `EXE_OR_OP;
              alusel_o = `EXE_RES_LOGIC;
              wd_o = inst_i[20:16];
              wreg_o = `WriteEnable;
              instvalid = `InstValid;
              reg1_read_o = `ReadEnable;
              reg2_read_o = `ReadDisable;
              reg1_addr_o = inst_i[25:21];
              reg2_addr_o = inst_i[20:16];
              imm = {16'h0,inst_i[15:0]};
            end
            default: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 = `ReadDisable;
                reg2_read_o = `ReadDisable;
                reg1_addr_o = inst_i[25:21];
                reg2_addr_o = inst_i[20:16];
                imm = `ZeroWord;
            end
          endcase
        end
    end

//确定进行运算的操作数1
always @(*) begin
    if(rst == `RstEnable) begin
      reg1_o = `ZeroWord;
    end
    else if(reg1_read_o == 1'b1) begin
      reg1_o = reg1_data_i;
    end
    else if(reg1_read_o == 1'b0) 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 == 1'b1) begin
      reg2_o = reg2_data_i;
    end
    else if(reg2_read_o == 1'b0) begin
      reg2_o = imm;
    end
    else begin
      reg2_o = `ZeroWord;
    end
end

endmodule

译码/执行模块

将译码阶段信息在下一个时钟周期给执行阶段,其 I/O 端口如下 

 模块代码:

`include "defines.v"

module id_ex(
    input wire              clk,
    input wire              rst,

    //从译码阶段传递过来的信息
    input wire[`AluSelBus]  id_alusel,
    input wire[`AluOpBus]   id_aluop,
    input wire[`RegBus]     id_reg1,
    input wire[`RegBus]     id_reg2,
    input wire[`RegAddrBus] id_wd,  //执行阶段的指令要写入的目的寄存器的地址
    input wire              id_wreg,//执行阶段的指令是否有要写入的目的寄存器

    //传递到执行阶段的信息
    output reg[`AluSelBus]  ex_alusel,
    output reg[`AluOpBus]   ex_aluop,
    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_alusel <= `EXE_RES_NOP;
          ex_aluop <= `EXE_NOP_OP;
          ex_reg1 <= `ZeroWord;
          ex_reg2 <= `ZeroWord;
          ex_wd <= `NOPRegAddr;
          ex_wreg <= `WriteDisable;
        end
        else begin
          ex_alusel <= id_alusel;
          ex_aluop <= id_aluop;
          ex_reg1 <= id_reg1;
          ex_reg2 <= id_reg2;
          ex_wd <= id_wd;
          ex_wreg <= id_wreg;
        end
    end

endmodule

执行模块

根据 ID/EX 得到的数据进行运算,其 I/O 端口如下 

 模块代码:

`include "defines.v"

module ex(
    input wire              rst,

    //译码阶段送到执行阶段的信息
    input wire[`AluSelBus]  alusel_i,
    input wire[`AluOpBus]   aluop_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;

    //根据aluop指示的运算子类型进行运算,此处只有逻辑或运算
    always @(*) begin
        if(rst == `RstEnable) begin
          logicout = `ZeroWord;
        end
        else begin
            case(aluop_i)
                `EXE_OR_OP:  logicout = reg1_i | reg2_i;
                default:    logicout = `ZeroWord;
            endcase
        end  
    end

    //根据alusel指示的运算类型,选择一个运算结果作为最终结果
    //此时只有逻辑运算结果
    always @(*) begin
        wd_o = wd_i;
        wreg_o = wreg_i;
        case(alusel_i)
            `EXE_RES_LOGIC:     wdata_o = logicout;
            default:            wdata_o = `ZeroWord;
        endcase
    end

endmodule

执行/访存模块

将执行阶段得到的结果在下一个时钟周期传到访存阶段,其 I/O 端口如下 

 模块代码:

`include "defines.v"

module ex_mem(
    input wire              clk,
    input wire              rst,

    //来自执行阶段的信息
    input wire[`RegAddrBus] ex_wd,
    input wire              ex_wreg,
    input wire[`RegBus]     ex_wdata,

    //送到访存阶段的信息
    output reg[`RegAddrBus] mem_wd,
    output reg              mem_wreg,
    output reg[`RegBus]     mem_wdata
);

    always @(posedge clk) begin
        if(rst == `RstEnable) begin
          mem_wd <= `NOPRegAddr;
          mem_wreg <= `WriteDisable;
          mem_wdata <= `ZeroWord;
        end
        else begin
          mem_wd <= ex_wd;
          mem_wreg <= ex_wreg;
          mem_wdata <= ex_wdata;
        end
    end

endmodule

访存模块

由于ori指令在访存阶段不需要访问数据寄存器,所以在访存阶段不做任何事,只是简单传递数据到回写阶段,其 I/O 端口如下 

模块代码:

`include "defines.v"

module mem(
    input wire                  rst,

    //来自执行阶段的信息
    input wire[`RegAddrBus]     wd_i,
    input wire                  wreg_i,
    input wire[`RegBus]         wdata_i,

    //访存阶段的结果
    output reg[`RegAddrBus]     wd_o,
    output reg                  wreg_o,
    output reg[`RegBus]         wdata_o
);

    always @(*) begin
        if(rst == `RstEnable) begin
          wd_o = `NOPRegAddr;
          wreg_o = `WriteDisable;
          wdata_o = `ZeroWord;
        end
        else begin
          wd_o = wd_i;
          wreg_o = wreg_i;
          wdata_o = wdata_i;
        end
    end

endmodule

 访存/回写阶段

将访存阶段的结果在下一时钟周期传到回写阶段,其 I/O 端口如下 

模块代码:

`include "defines.v"

module mem_wb(
    input wire                  clk,
    input wire                  rst,

    //访存阶段的结果
    input wire[`RegAddrBus]     mem_wd,
    input wire                  mem_wreg,
    input wire[`RegBus]         mem_wdata,

    //送到回写阶段的信息
    output reg[`RegAddrBus]     wb_wd,
    output reg                  wb_wreg,
    output reg[`RegBus]         wb_wdata
);

    always @(posedge clk) begin
        if(rst == `RstEnable) begin
          wb_wd <= `NOPRegAddr;
          wb_wreg <= `WriteDisable;
          wb_wdata <= `ZeroWord;
        end
        else begin
          wb_wd <= mem_wd;
          wb_wreg <= mem_wreg;
          wb_wdata <= mem_wdata;
        end
    end

endmodule

回写阶段 

参考上面五级流水线,此时这个阶段实际上是在Regfile模块中实现的,将上一模块得到的值传到Regfile。

顶层模块

每个模块都完成后,我们现在需要将各个模块进行例化、连接,连接的关系还是看上面的图。

例化其实也就相当于面向对象语言中实例化一个对象出来,然后将各个对象连接起来就可以得到我们的顶层模块

下面我们看看顶层模块的端口

当然,我们现在只是实现一条简单的ori指令,所以顶层模块会比较简单,等到后期指令增加、增加协处理器、中断处理的时候顶层模块就会复杂很多,不过还是像上面说的一样--看图,连线

模块代码:

`include "defines.v"

module openmips(
    input wire                  clk,
    input wire                  rst,
    
    input wire[`InstBus]        rom_data_i,
    output wire[`InstAddrBus]   rom_addr_o,
    output wire                 rom_ce_o
);

    //连接IF/ID模块与译码阶段ID模块的变量
    wire[`InstBus]  id_inst_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;
    //连接译码阶段ID模块输出与ID/EX模块的输入的变量
    wire [`AluOpBus] id_aluop_o;
    wire [`AluSelBus] id_alusel_o;
    wire [`RegBus] id_reg1_o;
    wire [`RegBus] id_reg2_o;
    wire id_wreg_o;
    wire [`RegAddrBus] id_wd_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_o;
    wire [`RegAddrBus] wb_wd_o;
    wire wb_wreg_o;

    //pc_reg例化
    pc_reg pc_reg0(
    .clk(clk),    .rst(rst),    .pc(rom_addr_o),    .ce(rom_ce_o)
    );
    
    //IF/ID模块例化
    if_id if_id0(
    .rst(rst),    .clk(clk),    .if_inst(rom_data_i),    .id_inst(id_inst_i)
    );

    //译码阶段ID模块例化
    id id0(
    .rst(rst),    .inst_i(id_inst_i),

    .reg1_data_i(reg1_data),    .reg2_data_i(reg2_data),

    .reg1_read_o(reg1_read),    .reg2_read_o(reg2_read),
    .reg1_addr_o(reg1_addr),    .reg2_addr_o(reg2_addr),

    .alusel_o(id_alusel_o),    .aluop_o(id_aluop_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_o),    .waddr(wb_wd_o),    .wdata(wb_wdata_o),

    .re1(reg1_read),    .raddr1(reg1_addr),    .rdata1(reg1_data),

    .re2(reg2_read),    .raddr2(reg2_addr),    .rdata2(reg2_data)
    );

    //ID/EX模块例化
    id_ex id_ex0(
    .clk(clk),    .rst(rst),

    .id_alusel(id_alusel_o),    .id_aluop(id_aluop_o),
    .id_reg1(id_reg1_o),    .id_reg2(id_reg2_o),
    .id_wd(id_wd_o),      .id_wreg(id_wreg_o),

    .ex_alusel(ex_alusel_i),    .ex_aluop(ex_aluop_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),

    .alusel_i(ex_alusel_i),    .aluop_i(ex_aluop_i),
    .reg1_i(ex_reg1_i),    .reg2_i(ex_reg2_i),
    .wd_i(ex_wd_i),    .wreg_i(ex_wreg_i),

    .wd_o(ex_wd_o),    .wreg_o(ex_wreg_o),    .wdata_o(ex_wdata_o)
    );

    //EX/MEM模块例化
    ex_mem ex_mem0(
    .clk(clk),    .rst(rst),

    .ex_wd(ex_wd_o),    .ex_wreg(ex_wreg_o),    .ex_wdata(ex_wdata_o),

    .mem_wd(mem_wd_i),    .mem_wreg(mem_wreg_i),    .mem_wdata(mem_wdata_i)
    );

    //MEM模块例化
    mem mem0(
    .rst(rst),

    .wd_i(mem_wd_i),    .wreg_i(mem_wreg_i),    .wdata_i(mem_wdata_i),

    .wd_o(mem_wd_o),    .wreg_o(mem_wreg_o),    .wdata_o(mem_wdata_o)
    );

    //MEM/WB模块例化
    mem_wb mem_wb0(
    .clk(clk),    .rst(rst),

    .mem_wd(mem_wd_o),    .mem_wreg(mem_wreg_o),    .mem_wdata(mem_wdata_o),

    .wb_wd(wb_wd_o),    .wb_wreg(wb_wreg_o),    .wb_wdata(wb_wdata_o)
    );

endmodule

 代码看着比较长,但实际其本质都是一样的,懂了一块其他模块都懂了(不要放弃,加油!)

指令存储器ROM的实现

顾名思义,只读存储器,与openMIPS相连再构成最小SOPC

 模块代码:

`include "defines.v"

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初始化寄存器,依据自己的路径给data文件改成绝对路径
    initial $readmemh ("D:/inst_rom.data",inst_mem);

    //当复位信号无效时,依据输入的地址,给出指令存储器ROM中对应的元素
    always @(*) begin
        if(ce == `ChipDisable) begin
            inst <= `ZeroWord;
        end
        else begin
            //指令寄存器的每个地址是32bit的字,所以要将OpenMips给出的指令地址除以4再使用
            inst <= inst_mem[addr[`InstMemNumLog2+1:2]];
        end
    end

endmodule

⚠️注意注意!

这个读取文件的路径一定要用绝对路径!!!!

最小SOPC的实现

上面说过,将openMIPS与inst_rom连接成为一个最小SOPC

              

 建立Test Bench文件

在上一篇文章讲过Test Bench文件

将各个模块设计完成后,通过test Bench文件,test Bench文件为测试或仿真一个Verilog HDL程序搭建了一个平台,我们被测试的模块施加激励信号,通过观察被测试模块的输出响应,从而判断逻辑是否正确。

模块代码:

//时间单位是1ns,精度是1ps
`timescale 1ns/1ps
`include "defines.v"

module openmips_min_sopc_tb();

    reg CLOCK_50;
    reg rst;

    //每隔10ns,CLOCK_50信号翻转一次,所以一个周期是20ns,对应50MHz
    initial begin
        CLOCK_50 = 1'b0;
        forever #10 CLOCK_50 = ~CLOCK_50;
    end

    //最初时刻,复位信号有效,在第195ns,复位信号无效,最小SOPC开始运行
    //运行1000ns后,暂停仿真
    initial begin
        rst = `RstEnable;
        #195 rst = `RstDisable;
        #1000 $stop;
    end

    //例化最小SOPC
    openmips_min_sopc openmips_min_sopc0(
        .clk(CLOCK_50),
        .rst(rst)
    );

endmodule

之后将所有文件放在一起仿真就可以得到结果啦!

 

 总结

·看图将各个模块根据图的描述写出来,再将各个模块例化连接起来(顶层模块),将顶层模块与存储器连接后建立最小SOPC,最后给SOPC激励信号进行仿真。

·交叉编译环境在这里还没有提到,其实就是通过GNU工具链对你的源代码(汇编代码)进行编译、链接、得到bin文件 最后将格式转化就可以得到我们需要的存储器文件inst_rom.data

宏定义代码

//全局宏定义
`define RstEnable 1'b1          //复位信号有效
`define RstDisable 1'b0         //复位信号无效
`define ChipEnable 1'b1         //芯片使能
`define ChipDisable 1'b0        //芯片禁止
`define ZeroWord 32'h00000000   //32位的数值0
`define WriteEnable 1'b1        //使能写
`define WriteDisable 1'b0       //禁止写
`define ReadEnable 1'b1         //使能读
`define ReadDisable 1'b0        //禁止读
`define AluSelBus 2:0           //译码阶段的输出alusel_o的宽度
`define AluOpBus 7:0            //译码阶段的输出aluop_o的宽度
`define InstValid 1'b1          //指令有效
`define InstInvalid 1'b0        //指令无效

//与指令存储器相关的定义
`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 RegNum 32               //通用寄存器的数量
`define RegNumLog2 5            //寻址通用寄存器所用的地址位数
`define NOPRegAddr  5'b00000

//与具体指令相关的宏定义
`define EXE_ORI     6'b001101   //指令ori的指令码
`define EXE_NOP     6'b000000

//AluOp
`define EXE_OR_OP   8'b00100101
`define EXE_NOP_OP  8'b00000000

//AluSel
`define EXE_RES_LOGIC   3'b001
`define EXE_RES_NOP     3'b000

猜你喜欢

转载自blog.csdn.net/weixin_52259822/article/details/124544582