自己动手写CPU之第七阶段(1)——简单算术操作指令说明

将陆续上传本人写的新书《自己动手写CPU》(尚未出版),今天是第24篇,我尽量每周四篇


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

      (1)简单算术操作指令

      共有15条,包括加法、减法、比较、乘法等指令,这些指令在流水线的执行阶段都只需要一个时钟周期,而且实现思路很直观,与第4章添加逻辑操作指令类似,只需修改译码阶段的ID模块、执行阶段的EX模块,即可实现。

      (2)乘累加、乘累减指令

      共有4条:乘累加madd、无符号乘累加maddu、乘累减msub、无符号乘累减msubu。其中maddmaddu要求操作数相乘后,再与HILO寄存器的值相加,msubmsubu指令要求操作数相乘后,再与HILO寄存器的值相减,也就是这4条指令都要做两次运算,一次乘法、一次加(减)法,如果将这两次运算放在流水线执行阶段的一个时钟周期中完成,那么会使流水线执行阶段所需要的时间明显增加,从而降低OpenMIPS工作时钟的频率,因此,OpenMIPS设计在流水线执行阶段使用两个时钟周期完成这类指令,一个时钟周期进行乘法,下一个时钟周期进行加(减)法。

     (3)除法指令

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

      本章将分别介绍上述三种类别的算术操作指令的实现过程。7.1-7.4节给出了简单算术操作指令的格式、作用,介绍了实现思路,并修改OpenMIPS代码以实现简单算术操作指令,最后通过ModelSim仿真验证是否实现正确。

      因为乘累加、乘累减、除法指令都需要在流水线执行阶段占用多个时钟周期,这就需要使流水线暂停,所以在实现这些指令之前,先要实现流水线暂停,在7.5节介绍了使流水线暂停的方法。

      7.6-7.9节给出了乘累加、乘累减指令的格式、作用,介绍了实现思路,并修改OpenMIPS代码以实现乘累加、乘累减指令,最后进行仿真测试。

      7.10-7.13节给出了除法指令的格式、作用,介绍了实现思路,并修改OpenMIPS代码以实现除法指令,最后进行仿真测试。

      7.14节给出了实现算术操作指令后的数据流图。

7.1 简单算术操作指令说明

      简单算术操作指令包括:addaddiaddiuaddusubsubucloclzsltsltisltiusltumulmultmultu,共15条指令,各指令的格式及作用说明如下。

      1addaddusubsubsltsltu指令

      这6条指令的格式如图7-1所示。从图中可以发现这6条指令都是R类型指令,并且指令码都是6'b000000,即SPECIAL类,另外第6-10bit都为0,需要依据指令中0-5bit功能码的值进一步判断是哪一种指令。

自己动手写CPU之第七阶段(1)——简单算术操作指令说明_第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时,表示是subu指令,减法运算

      指令用法为:subu rd, rs, rt

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

  •  当功能码是6'b101010时,表示是slt指令,比较运算

      指令用法为:slt rd, rs, rt

      指令作用为:rd <- (rs < rt),将地址为rs的通用寄存器的值,与地址为rt的通用寄存器的值按照有符号数进行比较,如果前者小于后者,那么将1保存到地址为rd的通用寄存器中,反之,将0保存到地址为rd的通用寄存器中。

  •  当功能码是6'b101011时,表示是sltu指令,比较运算

      指令用法为:sltu rd, rs, rt

      指令作用为:rd <- (rs < rt),将地址为rs的通用寄存器的值,与地址为rt的通用寄存器的值按照无符号数进行比较,如果前者小于后者,那么将1保存到地址为rd的通用寄存器中,反之,将0保存到地址为rd的通用寄存器中。

      2addiaddiusltislti指令

      这4条指令的格式如图7-2所示。从图中可以发现这4条指令都是I类型指令,能够依据指令中26-31bit指令码的值判断是哪一种指令。

自己动手写CPU之第七阶段(1)——简单算术操作指令说明_第2张图片

  •  当指令码是6'b001000时,表示是addi指令,加法运算

      指令用法为:addi rt, rs, immediate

      指令作用为:rt <- rs + (sign_extended)immediate,将指令中16位立即数进行符号扩展,与地址为rs的通用寄存器的值进行加法运算,结果保存到地址为rt的通用寄存器中。但是有一个特殊情况:如果加法运算溢出,那么产生溢出异常,同时不保存结果。

  •  当指令码是6'b001001时,表示是addiu指令,加法运算

      指令用法为:addiu rt, rs, immediate

      指令作用为:rt <- rs + (sign_extended)immediate,将指令中16位立即数进行符号扩展,与地址为rs的通用寄存器的值进行加法运算,结果保存到地址为rt的通用寄存器中。与addi指令的区别在于addiu指令不进行溢出检查,总是将结果保存到目的寄存器。

  •  当指令码是6'b001010时,表示是slti指令,比较运算

      指令用法为:slti rt, rs, immediate

      指令作用为:rt <- (rs < (sign_extended)immediate),将指令中16位立即数进行符号扩展,与地址为rs的通用寄存器的值按照有符号数比较,如果前者大于后者,那么将1保存到地址为rt的通用寄存器中,反之,将0保存到地址为rt的通用寄存器中。

  •  当指令码是6'b001011时,表示是sltiu指令,比较运算

      指令用法为:sltiu rt, rs, immediate

      指令作用为:rt<- (rs < (sign_extended)immediate),将指令中16位立即数进行符号扩展,与地址为rs的通用寄存器的值按照无符号数比较,如果前者大于后者,那么将1保存到地址为rt的通用寄存器中,反之,将0保存到地址为rt的通用寄存器中。

      3cloclz指令

      这2条指令的格式如图7-3所示,从图中可以发现这2条指令都是R类型指令,并且指令码都是6'b011100,在MIPS32指令集架构中表示SPECIAL2类,另外第6-10bit都为0,需要依据指令中0-5bit功能码的值进一步判断是哪一种指令。

自己动手写CPU之第七阶段(1)——简单算术操作指令说明_第3张图片

  •  当功能码是6'b100000时,表示是clz指令,计数运算

      指令用法为:clz rd, rs

      指令作用为:rd <- coun_leading_zeros rs,对地址为rs的通用寄存器的值,从其最高位开始向最低位方向检查,直到遇到值为“1”的位,将该位之前“0”的个数保存到地址为rd的通用寄存器中,如果地址为rs的通用寄存器的所有位都为0(即0x00000000),那么将32保存到地址为rd的通用寄存器中。

  •  当功能码是6'b100001时,表示是clo指令,计数运算

      指令用法为:clo rd, rs

      指令作用为:rd <- coun_leading_ones rs,对地址为rs的通用寄存器的值,从其最高位开始向最低位方向检查,直到遇到值为“0”的位,将该位之前“1”的个数保存到地址为rd的通用寄存器中,如果地址为rs的通用寄存器的所有位都为1(即0xFFFFFFFF),那么将32保存到地址为rd的通用寄存器中。

      4multumultmul指令

      这3条指令的格式如图7-4所示,可知这3条指令都是R类型指令,并且mul指令的指令码是SPECIAL2multmultu的指令码是SPECIAL

自己动手写CPU之第七阶段(1)——简单算术操作指令说明_第4张图片

  •  当指令码为SPECIAL2,功能码为6'b000010时,表示是mul指令,乘法运算

      指令用法为:mul rd, rs, st

      指令作用为:rd <- rs × rt,将地址为rs的通用寄存器的值,与地址为rt的通用寄存器的值作为有符号数相乘,乘法结果的低32bit保存到地址为rd的通用寄存器中。

  •  当指令码为SPECIAL,功能码为6'b011000时,表示是mult指令,乘法运算

      指令用法为:mult rs, st

      指令作用为:{hi, lo} <- rs × rt,将地址为rs的通用寄存器的值,与地址为rt的通用寄存器的值作为有符号数相乘,乘法结果的低32bit保存到LO寄存器中,高32bit保存到HI寄存器中。

  •  当指令码为SPECIAL,功能码为6'b011001时,表示是multu指令,乘法运算

      指令用法为:multu rs, st

      指令作用为:{hi, lo} <- rs × rt,将地址为rs的通用寄存器的值,与地址为rt的通用寄存器的值作为无符号数相乘,乘法结果的低32bit保存到LO寄存器中,高32bit保存到HI寄存器中。与mult指令的区别在于multu指令执行中将操作数作为无符号数进行运算。


你可能感兴趣的:(自己动手写CPU)