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


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


  • 相关阅读:
    C段/旁站,子域名爆破的概念
    Linux USB Printer Gadget Driver
    Multifunction Composite Gadget
    PXA2xx SPI on SSP driver HOWTO
    SPI用户空间API
    Linux内核SPI支持概述
    Industrial I/O
    I2C设备驱动程序从用户空间绑定控制(旧内核)
    I2C 10-bit 地址
    Slave I2C
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6784812.html
Copyright © 2011-2022 走看看