本章将实现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功能码的值进一步判断是哪一种指令。

  • 当功能码是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指令码的值判断是哪一种指令。

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

  • 当功能码是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。

  • 当指令码为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模块

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

对任一指令而言,译码工作的主要内容是:确定要读取的寄存器情况、要执行的运算、要写入的目的寄存器等三个方面的信息。下面对其中几个典型指令的译码过程进行解释。
  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指令)

  4. slti指令的译码过程

  5. mult指令的译码过程

  6. mul指令的译码过程

  7. clo指令的译码过程

7.3.2修改执行阶段的EX模块

第七章 算术操作指令的实现相关推荐

  1. 自己动手写CPU(8)加载存储指令的实现

    自己动手写CPU(8)加载存储指令的实现 好久没更新blog了,暑假提前放了.现在收假也该收收心了,继续捡起之前的CPU,自己开的坑不管咋样把它填完吧. 指令介绍 1.加载指令 2.存储指令 修改系统 ...

  2. 《自己动手写CPU》--第九章--学习笔记

    章将实现MIPS32指令集架构中定义的加载存储指令,分两步:首先实现除ll.sc指令外的一般加载存储指令,其次实现比较特殊的加载存储指令ll.sc. 9.1加载存储指令说明 MIPS32指令集架构中定 ...

  3. 【自己动手写CPU】加载存储指令的实现

    目标 修改之前一直做测试的sopc,为其添加数据RAM,测试一般加载指令的实现,加入特殊加载存储指令. 探讨由于加载指令引起的load相关问题,给出OpenMIPS的解决方法,验证解决效果. 加载存储 ...

  4. 自己动手写CPU(5)——移动指令说明

    移动指令说明 移动操作指令 特殊寄存器HI.LO 移动指令确定过程 移动操作指令 不涉及特殊寄存器LO.HI: movn:判断地址为rt的通用寄存器的值,如果不为零,将地址为rs的通用寄存器的值赋给地 ...

  5. 自己动手写CPU(5)简单算术操作指令实现_1

    自己动手写CPU(5)简单算数操作指令实现_1 指令介绍 MIPS32指令集架构定义的所有算术操作指令,共有21条 共有三类,分别是: 简单算术指令 乘累加.乘累减指令 除法指令 算术指令操作介绍 一 ...

  6. 自己动手写CPU之第七阶段(5)——流水线暂停机制的设计与实现

    将陆续上传本人写的新书<自己动手写CPU>,今天是第28篇.我尽量每周四篇 China-pub的预售地址例如以下(有文件夹.内容简单介绍.前言): http://product.china ...

  7. 自己动手写CPU之第七阶段(10)——除法指令实现过程1

    将陆续上传本人写的新书<自己动手写CPU>,今天是第33篇,我尽量每周四篇 亚马逊的销售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/r ...

  8. 【自己动手写CPU】异常相关指令的实现

    MIPS架构中定义的异常类型 MIPS32架构中,有些事情打断程序的正常的执行流程,这些事情称为中断.陷阱.系统调用以及其他打断程序执行流程的情况,统称为异常. 此处的OpenMIPS处理器只实现了其 ...

  9. 自己动手写CPU(2)流水线数据相关问题

    自己动手写CPU(2)流水线数据相关问题 问题定义 流水线中经常有一些被称为"相关"的情况发生,它使得指令序列中下一条指令无法按照设计的时钟周期执行,这些"相关" ...

  10. 自己动手写CPU(1)五级流水线及CPU第一条指令ori

    自己动手写CPU(1)五级流水线及CPU第一条指令ori 动机 不知为何研一的自由时间突然多起来,可能人一闲下来就容易焦虑吧,hhhhhh.正好之前看到一本<自己动手写CPU>,就按照此书 ...

最新文章

  1. CVPR 2021接收结果出炉!录用1663篇,接受率显著提升,你的论文中了吗?(附论文下载)...
  2. tensorflow 1.0 学习:十图详解tensorflow数据读取机制
  3. CString的部分实现剖析
  4. 507. Perfect Number(Python)
  5. php连mssql 中文乱码,PHP连接MSSQL显示中文时为乱码_PHP教程
  6. asp.net JavaScriptSerializer实现序列化和反序列化
  7. 苹果推出“轻触支付”新方式 目前仅面向美国
  8. 计算机系统-电路设计06-振荡器的内部电路实现
  9. HAOI2012高速公路bzoj2752 (线段树,数学)
  10. 检测制定代码部分的profiler
  11. Chrome浏览器下载
  12. matlab画三维图像(plot3,mesh,surf)
  13. 通过高德地图获取 经纬度 以及地理位置等
  14. STM32F103_study57_The punctual atoms(STM32 Port multiplexing and remapping configuration)
  15. 无限火力跳跳机器人_英雄联盟无限火力小拳拳升降机蒸汽机器人
  16. 三极管自激振荡升压电路笔记
  17. python可以开发软件_python可以开发软件吗
  18. Transformer对接公司需求的调研报告
  19. java校园快递代领系统 小程序
  20. matlab模拟Fraunhofer衍射,基于Matlab的夫琅禾费衍射光学仿真.doc

热门文章

  1. html盒子背景图,CSS盒子模型以及背景图
  2. 张亚勤寄语哥伦比亚大学2020年毕业生:引领未知时代
  3. java 打印 xps_使用PrintTicket打印XPS,OutputColor PagesPerSheet无效
  4. linux同名文件会覆盖吗,linux下面覆盖文件,如何实现直接覆盖,不提示
  5. 大前端技术发展趋势刨析
  6. 面试官:说说你最大的优缺点? (25题汇总版)
  7. 视频编码中CBR编码和VBR编码的区别
  8. DCDC和LDO的区别
  9. STM32 CAN编程详解
  10. 数据仓库实施步骤与关键成功因素