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

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

本章将实现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-7.4节给出了简单算术操作指令的格式、作用,介绍了实现思路,并修改OpenMIPS代码以实现简单算术操作指令,最后通过ModelSim仿真验证是否实现正确。

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

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

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

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

7.1 简单算术操作指令说明

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

  1、add、addu、sub、sub、slt、sltu指令

这6条指令的格式如图7-1所示。从图中可以发现这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时,表示是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的通用寄存器中。

      2、addi、addiu、slti、slti指令

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

  • 当指令码是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的通用寄存器中。

      3、clo、clz指令

这2条指令的格式如图7-3所示,从图中可以发现这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‘b100001时,表示是clo指令,计数运算

指令用法为:clo rd, rs

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

  4、multu、mult、mul指令

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

  • 当指令码为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之第七阶段(1)——简单算术操作指令说明

时间: 2024-10-08 05:44:49

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

自己动手写CPU之第七阶段(3)——简单算术操作指令实现过程(续)

将陆续上传本人写的新书<自己动手写CPU>,今天是第26篇,我尽量每周四篇 China-pub的预售地址如下(有目录.内容简介.前言): http://product.china-pub.com/3804025 亚马逊的预售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 为了实现简单算术指令,需要修改译码阶段的ID模块.执行阶段的EX模块,上一篇博文中已经介绍了对译码阶段ID模块的

自己动手写CPU之第九阶段(9)——修改OpenMIPS以实现ll、sc指令

将陆续上传新书<自己动手写CPU>,今天是第48篇. 9.8 修改OpenMIPS以实现ll.sc指令 9.8.1 LLbit寄存器的实现 LLbit寄存器在LLbit模块中实现,模块接口如图9-30所示,各接口描述如表9-8所示. LLbit寄存器的代码如下,源文件是本书光盘Code\Chapter9_2目录下的LLbit_reg.v文件. module LLbit_reg( input wire clk, input wire rst, // 异常是否发生,为1表示异常发生,为0表示没有异

自己动手写CPU之第九阶段(6)——修改最小SOPC

将陆续上传新书<自己动手写CPU>,今天是第45篇. 这几天事情多,好久没更新了 前几篇实现了加载存储指令,今天将修改最小SOPC,用以测试加载存储指令是否实现正确.闲话少说,进入正题. 9.4 修改最小SOPC 为了验证上一节添加的加载存储指令是否实现正确,需要修改在第4章中设计的最小SOPC,为其添加数据存储器RAM. 9.4.1 添加数据存储器RAM 数据存储器RAM的接口如图9-24所示,还是采用左边是输入接口,右边是输出接口的方式绘制,这样便于理解.接口含义如表9-7所示. 数据存储

自己动手写CPU之第四阶段(3)——MIPS编译环境的建立

将陆续上传本人写的新书<自己动手写CPU>(尚未出版).今天是第13篇.我尽量每周四篇 4.4 MIPS编译环境的建立 OpenMIPS处理器在设计的时候就计划与MIPS32指令集架构兼容,所以能够使用MIPS32架构下已有的GNU开发工具链.本节将说明怎样安装使用GNU开发工具链以及怎样制作Makefile文件.从而以更加方便.快捷.自己主动的方式对測试程序进行编译.并得到指令存储器ROM的初始化文件inst_rom.data. 4.4.1 VisualBox的安装与设置 GNU工具链要安装

《自己动手写cpu》读书笔记

本文来自<自己动手写cpu>一书的总结.原来自己看过原作者的<步步惊芯--软核处理器分析>以及其他关于or1200的书.本次粗略浏览了该书,就某些感兴趣的部分详细分析,并总结成此文. 关于5级流水的架构,可以自己去参考<计算机接口>一书.本文重点不在此. 1.如何从rom里面取地址 简化版的最基本的sopc的框图如下: module openmips( input wire clk, input wire rst, input wire[`RegBus] rom_dat

自己动手写CPU之第七阶段(7)——乘累加指令的实现

将陆续上传本人写的新书<自己动手写CPU>,今天是第30篇,我尽量每周四篇 亚马逊的销售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 China-pub的销售地址如下: http://product.china-pub.com/3804025 北发的销售地址如下: http://book.beifabook.com/Product/BookDetail.aspx?Plucode=

自己动手写CPU之第七阶段(4)——验证简单算术操作指令实现效果

将陆续上传本人写的新书<自己动手写CPU>,今天是第27篇,我尽量每周四篇 China-pub的预售地址如下(有目录.内容简介.前言): http://product.china-pub.com/3804025 亚马逊的预售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 7.4 测试简单算术操作指令实现效果 本节通过实验来检验我们修改后的代码是否实现了简单算术操作指令,测试程序如下

自己动手写CPU之第七阶段(11)——除法指令实现过程2

将陆续上传本人写的新书<自己动手写CPU>,今天是第33篇,我尽量每周四篇 亚马逊的销售地址如下,欢迎大家围观呵! http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4 在当当.京东.互动.北发等网上书店均有! 除法指令的实现过程有点长,分两篇博文介绍,今天是第二篇. 7.12.2 修改译码阶段的ID模块 译码阶段的ID模块要增加对除法指令的分析,根据图7-15给出的指令格式可知,除法指令都是SPECIAL类指令,

自己动手写CPU之第四阶段(2)——验证第一条指令ori的实现效果

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第12篇,我尽量每周四篇 书名又之前的<自己动手写处理器>改为<自己动手写CPU> 4.3 验证OpenMIPS实现效果 4.3.1指令存储器ROM的实现 本节将验证我们的OpenMIPS是否实现正确,包含:流水线是否正确.ori指令是否实现正确.在验证之前,需要首先实现指令存储器,以便OpenMIPS从中读取指令. 指令存储器模块是只读的,其接口如图4-7所示,还是采用左边是输入接口,右边是输出接口的方式绘

自己动手写CPU之第六阶段(3)——移动操作指令的实现

将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第22篇,我尽量每周四篇 6.3 修改OpenMIPS以实现移动操作指令 6.3.1 HI.LO寄存器的实现 在HILO模块中实现HI.LO寄存器,HILO模块的接口描述如表6-1所示. HILO模块的代码如下,源文件是本书附带光盘Code\Chapter6目录下的hilo_reg.v.整个代码很简单:在时钟上升沿,如果复位信号无效,那么就判断输入的写使能信号we是否为WriteEnable,如果是WriteEnable,那么就将输