第七章 算术操作指令的实现

本章将实现MIPS32指令集架构定义的所有算数指令,共有21条,按照OpenMIPS实现这些指令的方式,可以分为三类,分别介绍如下:

(1)简单算数操作指令
共有15条,包括加法、减法、比较、乘法等指令,这些指令在流水线执行阶段都只需要一个时钟周期,而且实现思路很直观,与第4章添加逻辑操作指令类似,只需修改译码阶段的ID模块,执行阶段的EX模块,即可实现。
(2)乘累加、乘累减治令
共有4条:乘累加(madd)、无符号乘累加(maddu)、乘累减(msub)、无符号乘累减(msubu)。其中madd、maddu要求操作数相乘后,再与HI、LO寄存器的值相加,msub、msubu指令要求操作数相乘后,再与HI、LO寄存器的值相减。也就是说,这4条指令都要做两次运算,一次乘法,一次加(减)法,如果将这两次运算放在流水线执行阶段的一个时钟周期中完成,那么会使流水线的执行阶段所需要的时间明显增加,从而降低OpenMIPS工作时钟的频率,因此,OpenMIPS设计在流水线执行阶段使用两个时钟周期完成这类指令,一个时钟周期进行乘法,下一个时钟周期进行加(减)法。

(3)除法指令
共有2条:有符号除法(div)、无符号除法(divu)。OpenMIPS计划采用试商法运算,对于32位的除法,流水线执行阶段至少需要32个时钟周期。也就是说,除法指令需要多个时钟周期才能完成,所以单独作为一类。

7.1简单算数操作指令说明

简单算数操作指令一共有15条,具体包括add、addi、addiu、addu、sub、subu、clo、clz,slt,sltu,mul,mult,multu,各指令的格式及作用说明如下:

1.add,addu,sub,subu,slt,sltu指令
这6条指令的格式如图所示,这6条指令都是R类型指令,并且指令码都是6’b000000,即SPECIAL类。另外,第6-10bit都为0,需要依据指令中第0-5bit功能码的值进一步判断是哪一种指令。
第七章 算术操作指令的实现_第1张图片

  • 当功能码是6’b100000,表示add指令,加法运算
    指令用法为:add rd,rs,rt。
    指令作用为:rd <- rs + rt。将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值进行加法运算,结果保存到地址为rd的通用寄存器中,但是有一种特殊情况:如果加法运算溢出,那么会产生溢出异常,同时不保存结果。

  • 当功能码是6’b100001,表示addu指令,加法运算。
    指令用法为:addu rd,rs,rt。
    指令作用为:rd <- rs + rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值进行加法运算,结果保存到地址为rd的通用寄存器中,与add指令不同之处在于addu指令不进行溢出检查,总是将结果保存到目的寄存器。

  • 当功能码是6’b100010,表示sub指令,减法运算
    指令用法为:sub rd,rs,rt。
    指令作用为:rd <- rs - rt。将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值进行减法运算,结果保存到地址为rd的通用寄存器中,但是有一种特殊情况:如果减法运算溢出,那么会产生溢出异常,同时不保存结果。

  • 当功能码是6’b100011,表示usbu指令,减法运算
    指令用法为:subu rd,rs,rt.
    指令作用为:rd <- rs - rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值进行减法运算,结果保存到地址为rd的通用寄存器中,与sub指令不同之处在于subu指令不进行溢出检查,总是将结果保存到目的寄存器。

  • 当功能码是6’101010,表示slt指令,比较运算。
    指令用法为:slt rd,rs,rt。
    指令作用为:rd <- (rs < rt)。将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值按照有符号数进行比较,如果前者小于后者,那么将1保存到地址为rd的通用寄存器中,反之,将0保存到地址为rd的通用寄存器中。
    2.addi addiu slti sltiu指令
    这4条指令的格式如图所示,从图中可以发现这4条指令都是1类型指令,能够依据指令中第26-31bit指令码的值判断是哪一种指令。
    第七章 算术操作指令的实现_第2张图片第七章 算术操作指令的实现_第3张图片第七章 算术操作指令的实现_第4张图片
    3.clo、clz指令
    这2条指令的格式如图所示,从图中可以发现者 条指令都是R类型指令,并且指令码都是6’b011100,在MIPS32指令集架构中表示SPECIAL2类。另外,第6-10bit都为0,需要依据指令中第0-5bit功能码的值进一步判断是哪种指令。

第七章 算术操作指令的实现_第5张图片

  • 当功能码是6’b100000,表示clz指令,计数运算。
    指令用法为:clz rd,rs。
    指令作用为:rd <- coun_leading_zeros rs,对地址为rs的通用寄存器的值,从其最高位开始向最低位方向检查,直到遇到值为“1”的位,将该位之前“0”的个数保存到地址为rd的通用寄存器中,如果地址为rs的通用寄存器的所有位都为0(即0x00000000),那么将32保存到地址为rd的通用寄存器中。

  • 当功能码是6’b1000001,表示clo指令,计数运算
    指令用法为:clo rd,rs。
    指令作用为:rd <- coun_leading_ones rs,对地址为rs的通用寄存器的值,从其最高位开始向最低位方向检查,直到遇到值为“0”的位,将该位之前“1”的个数保存到地址为rd的通用寄存器中,如果地址为rs的通用寄存器的所有位都为1(即0xFFFFFFFF),那么将32保存到地址为rd的通用寄存器中。
    4.multu、mult、mul指令
    这3条指令的格式如图所示,可知这3条都是R类型指令,并且mul指令的指令码是SPECIAL2,mult和multu指令码是SPECIAL。
    第七章 算术操作指令的实现_第6张图片

  • 当指令码为SPECIAL2,功能码为6’b000010,表示mul指令,乘法运算
    指令用法为:mul rd,rs,rt。
    指令作用为:rd <- rs * rt。将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作有符号相乘,乘法结果的低32bit保存到地址为rd的通用寄存器中。

  • 当指令码为SPECIAL,功能码为6’b011000时,表示mult指令,乘法运算。
    指令用法为:mult rs,rt
    指令作用为:{hi,lo} <- rs * rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为有符号相乘,乘法的低32bit保存到LO寄存器中,高32bit保存到HI寄存器中。

  • 当指令码为SPECIAL,功能码为6’b011001,表示multu指令,乘法运算。
    指令用法为:multu rs,rt。
    指令作用为:{hi,lo} <- rs * rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值做无符号相乘,乘法的低32bit保存到LO寄存器中,高32bit保存到HI寄存器中,与mult指令的区别在于:multu指令执行中将操作数做无符号数进行运算。

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

虽然简单算数操作指令的数目较多,有15条,但实现方式都是相似的,与前几章逻辑、移位操作指令的实现方式也类似,不需要增加新的模块和新的接口,只需要修改流水线译码阶段的ID模块,执行阶段的EX模块即可,实现思路如下:

(1)修改流水线译码阶段的ID模块,添加对上述简单算术操作指令的译码,给出运算类型alusel_o、运算子类型aluop_o、要写入的目的寄存器地址wd_o等信息;同时根据需要,读取地址为rs、rt的通用寄存器的值。
(2)修改流水线执行阶段的EX模块,依据传入的信息进行运算,得到运算结果,确定要写入目的寄存器的信息(包含:是否写、写入的目的寄存器地址、写入的值),并将这些信息传递到访存阶段。
(3)上述信息会一直传递到回写阶段,最后修改目的寄存器。

7.3.1 修改译码阶段的ID模块

在译码阶段要增加算数操作指令的分析,分析的前提是能判断出指令的种类:

第七章 算术操作指令的实现_第7张图片

对任一指令而言,译码工作的主要内容是:确定要读取的寄存器情况、要执行的运算、要写入的目的寄存器等三个方面的信息。下面对其中几个典型指令的译码过程进行解释。
  1. add指令的译码过程
    add指令译码需要设置的三方面内容如下(addu、sub、subu指令的译码过程可以参考add指令)
    (1)要读取的寄存器情况:add指令需要读取rs、rt寄存器的值,所以设置reg1_read_o、reg2_read_o为1.默认通过regfile模块读端口1读取的寄存器地址reg1_addr_o的值是指令的第21-25bit,正是add指令中的rs,默认通过regfile模块读端口2读取的寄存器地址reg2_addr_o的值是指令的第16-20bit,正是add指令中的rt所以最终译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是地址为rt的寄存器的值。
    (2)要执行的运算:add指令是算数运算中的加法操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETIC,aluop_o赋值给EXE_ADD_OP
    (3)要写入的目的寄存器:add指令需要将结果写入目的寄存器,所以设置wreg_o为WriteEnable,设置wd_o为要写入的目的寄存器地址,默认是指令字的第11-15bit ,正是add指令中的rd。

  2. addi指令的译码过程
    addi指令译码需要设置的三方面内容如下(addiu、subi、subiu指令的译码过程可以参考addi指令)
    (1)要读取的寄存器情况:addi只需要读取rs寄存器的值,所以设置reg1_read_o为1、reg2_read_o为0.默认通过regfile模块读端口1读取的寄存器地址reg1_addr_o的值是指令的第21-25bit,正是addi指令中的rs。设置reg2_read_o为0,表示使用立即数作为参与运算的第二个操作数。imm就是指令中的立即数进行符号拓展后的值。所以最终译码阶段的输出reg1_o就是地址为rs的寄存器的值,reg2_o就是imm的值。
    (2)要执行的运算:addi指令是算术运算中的加法操作,所以此处将alusel_o赋值为EXE_RES_ARITHMETIC,aluop_o赋值为EXE_ADDI_OP。
    (3)要写入的目的寄存器:addi指令需要将结果写入目的寄存器,所以设置wreg_o为WriteEnable,设置要写入的目的寄存器地址wd_o是指令中第16-20bit的值,正是addi指令中的rt。

  3. slt指令的译码过程
    slt指令的译码需要设置三方面内容如下(sltu指令的译码过程可以参考slt指令)
    第七章 算术操作指令的实现_第8张图片

  4. slti指令的译码过程
    第七章 算术操作指令的实现_第9张图片

  5. mult指令的译码过程
    第七章 算术操作指令的实现_第10张图片

  6. mul指令的译码过程
    第七章 算术操作指令的实现_第11张图片

  7. clo指令的译码过程
    第七章 算术操作指令的实现_第12张图片

7.3.2修改执行阶段的EX模块

第七章 算术操作指令的实现_第13张图片在这里插入图片描述在这里插入图片描述第七章 算术操作指令的实现_第14张图片

你可能感兴趣的:(芯片,自己动手写CPU,单片机,cpu,verilog,芯片,嵌入式硬件)