zoukankan      html  css  js  c++  java
  • 自己动手写CPU之第七阶段(2)——简单算术操作指令实现过程

    将陆续上传本人写的新书《自己动手写CPU》。今天是第25篇。我尽量每周四篇

    亚马逊的预售地址例如以下,欢迎大家围观呵!

    http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4

    China-pub的预售地址例如以下:

    http://product.china-pub.com/3804025


    7.2 简单算术操作指令实现思路

          尽管简单算术操作指令的数目比較多。有15条。但实现方式都是相似的,与前几章逻辑、移位操作指令的实现方式也非常类似,不须要添加新的模块、新的接口,仅仅须要改动流水线译码阶段的ID模块、运行阶段的EX模块就可以。

    实现思路例如以下。

          (1)改动流水线译码阶段的ID模块,加入对上述简单算术操作指令的译码。给出运算类型alusel_o、运算子类型aluop_o、要写入的目的寄存器地址wd_o等信息。同一时候依据须要读取地址为rsrt的通用寄存器的值。

          (2)改动流水线运行阶段的EX模块,根据传入的信息。进行运算。得到运算结果,确定终于要写目的寄存器的信息(包括:是否写、写入的目的寄存器地址、写入的值),并将这些信息传递到訪存阶段。

          (3)上述信息会一直传递到回写阶段。最后改动目的寄存器。

    7.3 改动OpenMIPS以实现简单算术操作指令

    7.3.1 改动译码阶段的ID模块 

          在译码阶段要添加对简单算术操作指令的分析,分析的前提是能推断出指令种类,依据图7-17-4能够给出如图7-5所看到的的确定指令种类的过程。


          当中涉及的宏定义例如以下。正是图7-5中各个指令的指令码或功能码。

    在本书附带光盘CodeChapter7_1文件夹下的defines.v文件里能够找到这些宏定义。

    `define EXE_SLT   6'b101010
    `define EXE_SLTU  6'b101011
    `define EXE_SLTI  6'b001010
    `define EXE_SLTIU 6'b001011
    `define EXE_ADD   6'b100000
    `define EXE_ADDU  6'b100001
    `define EXE_SUB   6'b100010
    `define EXE_SUBU  6'b100011
    `define EXE_ADDI  6'b001000
    `define EXE_ADDIU 6'b001001
    `define EXE_CLZ   6'b100000
    `define EXE_CLO   6'b100001
    
    `define EXE_MULT  6'b011000
    `define EXE_MULTU 6'b011001
    `define EXE_MUL   6'b000010
    ......
    `define EXE_SPECIAL_INST  6'b000000
    `define EXE_REGIMM_INST   6'b000001
    `define EXE_SPECIAL2_INST 6'b011100

          改动ID模块的代码例如以下,完整代码位于本书附带光盘CodeChapter7_1文件夹下的id.v文件。

    module id(
      ......
    );
    ......
    always @ (*) begin	
    if (rst == `RstEnable) begin
    	  ......
    end else begin
      aluop_o     <= `EXE_NOP_OP;
      alusel_o    <= `EXE_RES_NOP;
      wd_o        <= inst_i[15:11];           // 默认目的寄存器地址wd_o
      wreg_o      <= `WriteDisable;
      instvalid   <= `InstInvalid;
      reg1_read_o <= 1'b0;
      reg2_read_o <= 1'b0;
      reg1_addr_o <= inst_i[25:21];           // 默认的reg1_addr_o
      reg2_addr_o <= inst_i[20:16];           // 默认的reg2_addr_o
      imm         <= `ZeroWord;
      case (op)
        `EXE_SPECIAL_INST: begin              // op等于SPECIAL
          case (op2)                        
            5'b00000: begin               // op2等于5'b00000
              case (op3)
                ......
               `EXE_SLT: begin                       // slt指令
                  wreg_o      <= `WriteEnable;
                  aluop_o     <= `EXE_SLT_OP;
                  alusel_o    <= `EXE_RES_ARITHMETIC;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                end
               `EXE_SLTU: begin                      // sltu指令
                  wreg_o      <= `WriteEnable;
                  aluop_o     <= `EXE_SLTU_OP;
                  alusel_o    <= `EXE_RES_ARITHMETIC;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                end
                `EXE_ADD: begin                       // add指令
                  wreg_o      <= `WriteEnable;
                  aluop_o     <= `EXE_ADD_OP;
                  alusel_o    <= `EXE_RES_ARITHMETIC;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                end
                `EXE_ADDU: begin                      // addu指令
                  wreg_o      <= `WriteEnable;
                  aluop_o     <= `EXE_ADDU_OP;
                  alusel_o    <= `EXE_RES_ARITHMETIC;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                end
               `EXE_SUB: begin                        // sub指令
                  wreg_o      <= `WriteEnable;
                  aluop_o     <= `EXE_SUB_OP;
                  alusel_o    <= `EXE_RES_ARITHMETIC;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                end
               `EXE_SUBU: begin                      // subu指令
                  wreg_o      <= `WriteEnable;
                  aluop_o     <= `EXE_SUBU_OP;
                  alusel_o    <= `EXE_RES_ARITHMETIC;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1;
                  instvalid   <= `InstValid;
                end
               `EXE_MULT: begin                      // mult指令
                  wreg_o      <= `WriteDisable;
                  aluop_o     <= `EXE_MULT_OP;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1; 
                  instvalid   <= `InstValid;
                end
               `EXE_MULTU: begin                      // multu指令
                  wreg_o      <= `WriteDisable;
                  aluop_o     <= `EXE_MULTU_OP;
                  reg1_read_o <= 1'b1;
                  reg2_read_o <= 1'b1; 
                  instvalid   <= `InstValid;
                end 
                default:	begin
                end
             endcase  // end case op3
            end
         default: begin
         end
        endcase	    // end case op2
      end	 
          ......
         `EXE_SLTI: begin                        // slti指令
            wreg_o      <= `WriteEnable;
            aluop_o     <= `EXE_SLT_OP;
            alusel_o    <= `EXE_RES_ARITHMETIC; 
            reg1_read_o <= 1'b1;	
            reg2_read_o <= 1'b0;
            imm         <= {{16{inst_i[15]}}, inst_i[15:0]};
            wd_o        <= inst_i[20:16];
            instvalid   <= `InstValid;
          end
        `EXE_SLTIU:	begin                        // sltiu指令
            wreg_o      <= `WriteEnable;
            aluop_o     <= `EXE_SLTU_OP;
            alusel_o    <= `EXE_RES_ARITHMETIC; 
            reg1_read_o <= 1'b1;
            reg2_read_o <= 1'b0;
            imm         <= {{16{inst_i[15]}}, inst_i[15:0]};
            wd_o        <= inst_i[20:16];
            instvalid   <= `InstValid;
          end
        `EXE_ADDI: begin                         // addi指令
            wreg_o      <= `WriteEnable;
            aluop_o     <= `EXE_ADDI_OP;
            alusel_o    <= `EXE_RES_ARITHMETIC; 
            reg1_read_o <= 1'b1;
            reg2_read_o <= 1'b0;
            imm         <= {{16{inst_i[15]}}, inst_i[15:0]};
            wd_o        <= inst_i[20:16];	
            instvalid   <= `InstValid;
          end
         `EXE_ADDIU:	begin                       // addiu指令
             wreg_o      <= `WriteEnable;
             aluop_o     <= `EXE_ADDIU_OP;
             alusel_o    <= `EXE_RES_ARITHMETIC; 
             reg1_read_o <= 1'b1;	reg2_read_o <= 1'b0;
             imm         <= {{16{inst_i[15]}}, inst_i[15:0]};
             wd_o        <= inst_i[20:16];
             instvalid   <= `InstValid;
          end
         `EXE_SPECIAL2_INST:		begin          // op等于SPECIAL2
             case ( op3 )
              `EXE_CLZ: begin                          // clz指令
                 wreg_o      <= `WriteEnable;	
                 aluop_o     <= `EXE_CLZ_OP;
                 alusel_o    <= `EXE_RES_ARITHMETIC; 
                 reg1_read_o <= 1'b1;
                 reg2_read_o <= 1'b0;
                 instvalid   <= `InstValid;	
               end
              `EXE_CLO: begin                         // clo指令
                 wreg_o      <= `WriteEnable;
                 aluop_o     <= `EXE_CLO_OP;
                 alusel_o    <= `EXE_RES_ARITHMETIC; 
                 reg1_read_o <= 1'b1;
                 reg2_read_o <= 1'b0;
                 instvalid   <= `InstValid;
               end
              `EXE_MUL: begin                         // mul指令
                 wreg_o      <= `WriteEnable;
                 aluop_o     <= `EXE_MUL_OP;
                 alusel_o    <= `EXE_RES_MUL; 
                 reg1_read_o <= 1'b1;
                 reg2_read_o <= 1'b1;
                 instvalid   <= `InstValid;
               end
              default:	begin
              end
            endcase      //EXE_SPECIAL_INST2 case
           end	
         default: begin
         end
    endcase		  //case op
    		  
    ......
    
    endmodule

          对任一条指令而言,译码工作的主要内容是:确定要读取的寄存器情况、要运行的运算、要写的目的寄存器等三个方面的信息。以下对当中几个典型指令的译码过程进行解释。

    1add指令的译码过程

          add指令译码须要设置的三个方面内容例如以下。addusubsubu指令的译码过程能够參考add指令。

          (1)要读取的寄存器情况:add指令须要读取rsrt寄存器的值,所以设置reg1_read_oreg2_read_o1。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是add指令中的rs,默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit。正是add指令中的rt。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是地址为rt的寄存器的值。

          (2)要运行的运算:add指令是算术运算中的加法操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETICaluop_o赋值为EXE_ADD_OP

          (3)要写入的目的寄存器:add指令须要将结果写入目的寄存器,所以设置wreg_oWriteEnable。设置wd_o为要写入的目的寄存器地址,默认是指令字的11-15bit。正是add指令中的rd

    2addi指令的译码过程

          addi指令译码须要设置的三个方面内容例如以下。addiusubisubiu指令的译码过程能够參考addi指令。

          (1)要读取的寄存器情况:addi指令仅仅须要读取rs寄存器的值。所以设置reg1_read_o1reg2_read_o0。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是addi指令中的rs

    设置reg2_read_o0,表示使用马上数作为參与运算的第二个操作数。imm就是指令中的马上数进行符号扩展后的值。

    所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是imm的值。

          (2)要运行的运算:addi指令是算术运算中的加法操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETICaluop_o赋值为EXE_ADDI_OP

          (3)要写入的目的寄存器:addi指令须要将结果写入目的寄存器。所以设置wreg_oWriteEnable,设置要写入的目的寄存器地址wd_o是指令中16-20bit的值,正是addi指令中的rt

    3slt指令的译码过程

          slt指令译码须要设置的三个方面内容例如以下,sltu指令的译码过程能够參考slt指令。

          (1)要读取的寄存器情况:slt指令须要读取rsrt寄存器的值,所以设置reg1_read_oreg2_read_o1

    默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是slt指令中的rs。默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit,正是slt指令中的rt。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。reg2_o就是地址为rt的寄存器的值。

          (2)要运行的运算:slt指令是算术运算中的比較操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETICaluop_o赋值为EXE_SLT_OP

          (3)要写入的目的寄存器:slt指令须要将结果写入目的寄存器。所以设置wreg_oWriteEnable,设置wd_o为要写入的目的寄存器地址,默认是指令11-15bit的值,正是slt指令中的rd

    4slti指令的译码过程

          slti指令译码须要设置的三个方面内容例如以下。sltiu指令的译码过程能够參考slti指令。

          (1)要读取的寄存器情况:slti指令仅仅须要读取rs寄存器的值。所以设置reg1_read_o1reg2_read_o0。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是slti指令中的rs。设置reg2_read_o0,表示使用马上数作为运算的第二个操作数。imm就是指令中的马上数进行符号扩展后的值。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是imm的值。

          (2)要运行的运算:slti指令是算术运算中的比較操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETICaluop_o赋值为EXE_SLT_OP

          (3)要写入的目的寄存器:slti指令须要将结果写入目的寄存器,所以设置wreg_oWriteEnable,设置要写入的目的寄存器地址wd_o是指令中16-20bit的值,正是slti指令中的rt

    5mult指令的译码过程

          mult指令译码须要设置的三个方面内容例如以下,multu指令的译码过程能够參考mult指令。

          (1)要读取的寄存器情况:mult指令须要读取rsrt寄存器的值。所以设置reg1_read_oreg2_read_o1。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit。正是mult指令中的rs。默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit,正是mult指令中的rt。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。reg2_o就是地址为rt的寄存器的值。

          (2)要运行的运算:mult指令是乘法操作,而且乘法结果不须要写入通用寄存器。而是写入HILO寄存器,所以此处将alusel_o保持为默认值EXE_RES_NOPaluop_o赋值为EXE_MULT_OP

          (3)要写入的目的寄存器:mult指令不须要写通用寄存器。所以设置wreg_oWriteDisable

    6mul指令的译码过程

          mul指令译码须要设置的三个方面内容例如以下。 

          (1)要读取的寄存器情况:mul指令须要读取rsrt寄存器的值,所以设置reg1_read_oreg2_read_o1

    默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是mul指令中的rs,默认通过Regfile模块读port2读取的寄存器地址reg2_addr_o的值是指令的16-20bit,正是mul指令中的rt

    所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。reg2_o就是地址为rt的寄存器的值。

          (2)要运行的运算:mul指令是乘法操作,而且乘法结果是写入通用寄存器,所以此处将alusel_o赋值为EXE_RES_MULaluop_o赋值为EXE_MUL_OP

          (3)要写入的目的寄存器:mul指令须要将结果写入目的寄存器,所以设置wreg_oWriteEnable,设置wd_o为要写入的目的寄存器地址。默认是指令字的11-15bit,正是mul指令中的rd

    7clo指令的译码过程

          clo指令译码须要设置的三个方面内容例如以下。clz指令的译码过程能够參考clo指令。

          (1)要读取的寄存器情况:clo指令仅仅须要读取rs寄存器的值,所以设置reg1_read_o1reg2_read_o0。默认通过Regfile模块读port1读取的寄存器地址reg1_addr_o的值是指令的21-25bit,正是clo指令中的rs。所以终于译码阶段的输出reg1_o就是地址为rs的寄存器的值。

          (2)要运行的运算:clo指令是算术运算中的计数操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETICaluop_o赋值为EXE_CLO_OP

          (3)要写入的目的寄存器:clo指令须要将结果写入目的寄存器。所以设置wreg_oWriteEnable,设置wd_o为要写入的目的寄存器地址。默认是指令字的11-15bit,正是clo指令中的rd


    为了实现简单算术指令,今天改动了译码阶段,下一次将改动运行阶段,敬请关注。


  • 相关阅读:
    SCILAB简介[z]
    UG OPEN API编程基础 2约定及编程初步
    Office 2003与Office 2010不能共存的解决方案
    UG OPEN API 编程基础 3用户界面接口
    NewtonRaphson method
    UG OPEN API编程基础 13MenuScript应用
    UG OPEN API编程基础 14API、UIStyler及MenuScript联合开发
    UG OPEN API编程基础 4部件文件的相关操作
    UG OPEN API编程基础 1概述
    16 UG Open的MFC应用
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6784812.html
Copyright © 2011-2022 走看看