自己动手写CPU(6)流水线暂停、乘累加减与除法器的实现

流水线暂停

因为OpenMIPS设计乘累加、乘累减、除法指令在流水线执行阶段占用多个时钟周期,因此需要暂停流水线,以等待这些多周期指令执行完毕。OpenMIPS采用的是一种改进的方法:假如位于流水线第n阶段的指令需要多个时钟周期,进而请求流水线暂停,那么需保持取指令地址PC的值不变,同时保持流水线第n阶段、第n阶段之前的各个阶段的寄存器不变,而第n阶段后面的指令继续运行。

为实现CPU的流水线暂停功能,我们设计添加了CTRL模块,其作用是接收各阶段传递过来的流水线暂停请求信号,从而控制流水线各阶段的运行。CTRL模块对译码和执行阶段的暂停请求信号进行判断,然后输出流水线暂停信号stall。下图是为了实现流水线暂停机制而对系统结构所做的修改。具体代码修改之处见文末的项目链接。

指令介绍

乘累加、乘累减指令共有4条,包括: madd、maddu、msub、msubu,各指令的格式如下图所示。从图中可知,这4条指令的指令码都是SPECIAL2,第6~15bit都为0,可以依据第0~5bit的功能码确定是哪一种指令。

  • 当功能码是6’b000000时,表示是madd指令,有符号乘累加运算。指令用法为:madd rs, rt。指令作用为:{HI, LO}<-{HI, LO}+ rs x rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为有符号数进行乘法运算,运算结果与{HI, LO}相加,相加的结果保存到{HI, LO}中。此处{HI, LO}表示 HI、LO寄存器连接形成的64位数,HI是高32位,LO是低32位。
  • 当功能码是6’b000001时,表示是 maddu指令,无符号乘累加运算。指令用法为:maddu rs, rt。指令作用为: {HI, LO} <- {HI, LO} + rs × rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为无符号数进行乘法运算,运算结果与{HI, LO}相加,相加的结果保存到{HI,LO}中。
  • 当功能码是6’b000100时,表示是msub指令,有符号乘累减运算。指令用法为:msub rs, rt。指令作用为:{HI, LO}<-{HI,LO} - rs × rt,将地址为rs 的通用寄存器的值与地址为rt的通用寄存器的值作为有符号数进行乘法运算。然后使用{HI,LO}减去乘法结果,相减的结果保存到{HI,LO}中。
  • 当功能码是6’b000101时,表示是 msubu指令,无符号乘累减运算。指令用法为:msubu rs, rt。指令作用为:{HI, LO} <-{HI, LO} - rs × rt,将地址为rs的通用寄存器的值与地址为rt的通用寄存器的值作为无符号数进行乘法运算。然后使用{HI,LO}减去乘法结果,相减的结果保存到{HI,LO}中。

修改之处

实现思路

乘累加与乘累减指令计划在流水线阶段采用两个时钟周期完成运算,所以必须要保存两个信息:(1)、当前是第几个时钟周期;(2)、乘法结果。所以OpenMIPS通过在EX/MEM模块添加两个寄存器cnt、hilo,分别保存上述信息。修改系统结构框图如下所示:

1.修改译码阶段的ID模块

译码阶段的ID模块要添加对乘累加、乘累减指令的分析,根据给出的指令格式可知,这4条指令都是 SPECIAL2类指令,可以依据功能码确定是哪一种指令。确定指令的过程如下图所示。

涉及的宏定义如下(因为不涉及对通用寄存器的回写,所以无需“_OP”的宏定义)

`define EXE_MADD            6'b000000
`define EXE_MADDU           6'b000001
`define EXE_MSUB            6'b000100
`define EXE_MSUBU           6'b000101

这4条指令的译码过程都是相似的,简单说明如下。

  1. 因为最终结果都是写入HI、LO寄存器,而不是写入通用寄存器,所以设置wreg_o为WriteDisable。
  2. 因为都要读取两个寄存器的值,所以设置regl_read_o、reg2_read_o为1‘b1。默认通过Regfile模块读端口1读取的寄存器地址reg1_addr_o的值是指令的第2125bit,正是指令中的rs;默认通过Regfile模块读端口⒉读取的寄存器地址reg2_addr_o的值是指令的第1620bit,正是指令中的rt;所以最终译码阶段的输出reg1_o就是地址为rs 的寄存器的值,reg2_o就是地址为rt的寄存器的值。
  3. 运算类型alusel_o的值都设置为EXE_RES_MUL,不过由于没有要写的通用寄存器。所以此处alusel_o的值并没有作用,也可以设置为EXE_RES_NOP。
  4. 运算子类型aluop _o的值设置为与具体的指令对应。

2.修改执行阶段的EX模块

  1. 计算从通用寄存器中读出的两个寄存器的乘法结果,保存在mulres 中。
  2. 以乘累加指令为例进行讲解。乘累减指令与此类似。如果 cnt_i为2’b00,表示是乘累加指令的第一个执行周期,此时将乘法结果mulres通过接口 hilo_temp_o输出到EX/MEM模块,以便在下一个时钟周期使用。同时,设置变量stallreq_for_madd_msub为Stop,表示乘累加指令请求流水线暂停;如果 cnt _i为 2’b01,表示是乘累加指令的第二个执行周期,此时EX模块的输入hilo_temp_i就是上一个时钟周期得到的乘法结果,所以将 hilo_temp_i与 HI、LO寄存器的值相加,得到最终的运算结果,保存到变量 hilo_temp1中。同时,设置变量stallreq_for_madd_msub为NoStop,表示乘累加指令执行结束,不再请求流水线暂停。最后,设置cnt_o为2’b10,而不是直接设置为2’b00,目的是:如果因其他原因导致流水线保持暂停,那么由于cnt_o为2’b10,所以EX阶段不再计算,从而防止乘累加指令重复运行。
  3. 给出信号stallreq的值,目前只有乘累加、乘累减指令会导致流水线暂停,所以stallreq就直接等于变量stallreq for madd msub的值。
  4. 由于乘累加、乘累减指令要将最终结果写入 HI、LO寄存器,所以在第四段给出了对HI、LO寄存器的写信息。

3.修改EX/MEM模块

增加两个输入接口hilo_i,cnt_i,增加两个输出接口hilo_o,cnt_o,在流水线执行阶段暂停的时候,将输入信号hilo_i通过输出接口hilo_o送出,输入信号cnt i通过输出接口cnt_o送出。其余时刻,hilo_o为0,cnt_o也为0。

除法器

采用"试商法"实现除法运算,对于32位的除法,至少需要32个时钟周期才能得到除法结果。

实现思路

新建一个模块 DIV,在其中实现采用试商法的32位除法运算。当流水线执行阶段的EX模块发现当前指令是除法指令时,首先暂停流水线,然后将被除数、除数等信息送到DIV模块,开始除法运算。DIV模块在除法运算结束后,通知EX模块,并将除法结果送到EX模块,后者依据除法结果设置HI、LO寄存器的写信息,同时取消暂停流水线。

修改后的系统部分框图如下

DIV模块的主要部分是一个状态机,共有四个状态

  • DivFree:除法模块空闲;
  • DivByZero:除数是0;
  • DivOn:除法运算进行中;
  • DivEnd:除法运算结束;

作者使用的是一段式的状态机,里面阻塞和非阻塞赋值交替使用,对于我这个硬件小白来说还是难度太高,我还是老老实实用三段式重新实现了,中间过程还算有点复杂,输出的逻辑既有组合逻辑也有时序逻辑,好在调试了一会之后总算通过了。

仿真结果

乘累加、乘累减测试指令

   .org 0x0.set noat.global _start
_start:ori  $1,$0,0xffff                  sll  $1,$1,16ori  $1,$1,0xfffb           # $1 = -5ori  $2,$0,6                # $2 = 6mult $1,$2                  # hi = 0xffffffff# lo = 0xffffffe2madd $1,$2                  # hi = 0xffffffff# lo = 0xffffffc4maddu $1,$2                 # hi = 0x5# lo = 0xffffffa6msub $1,$2                  # hi = 0x5# lo = 0xffffffc4   msubu $1,$2                 # hi = 0xffffffff# lo = 0xffffffe2

由波形图可见,乘累加、乘累减指令实现正确,同时观察到乘累加、乘累减指令都需要两个时钟周期来完成,且两个时钟周期内的PC值都保持不变。

除法模块测试指令

   .org 0x0.set noat.global _start
_start:ori  $2,$0,0xffffsll  $2,$2,16ori  $2,$2,0xfff1          # $2 = -15ori  $3,$0,0x11            # $3 = 17div  $zero,$2,$3           # hi = 0xfffffff1,lo = 0x0divu $zero,$2,$3           # hi = 0x00000003,lo = 0x0f0f0f0ediv  $zero,$3,$2           # hi = 2,lo = 0xffffffff

实验心得

执行阶段的EX模块对HI、LO寄存器的写操作为什么不引入cnt_i来进行判断呢?即cnt_i=2’b01(执行阶段的第二个周期)再加上功能码的定义来进行对HI、LO寄存器是否写入的决策呢?

联系前后模块发现,EX模块发出暂停流水线的请求后,EX_MEM模块收到来自EX模块的暂停流水线请求后就把HI、LO寄存器的写使能关闭了,也就是说我们在乘累加、乘累减的第一阶段的写指令是传不到HILO寄存器堆的,所以就不用加上cnt_i这个冗余指令的判断过程了。

三段式状态机还需多多训练,多注意时序上的问题,哪些变量在上升沿赋值,哪些变量是组合逻辑赋值。

乘累加、乘累减项目
除法运算项目

自己动手写CPU(6)流水线暂停、乘累加减与除法器的实现相关推荐

  1. 自己动手写CPU(7)流水线暂停机制+乘累加累减+除法指令

    流水线暂停机制 因为OpenMIPS设计乘累加.乘累减.除法指令在流水线执行阶段占用多个时钟周期,因此需要暂停流水线,以等待这些多周期指令执行完毕. OpenMIPS采用的是一种改进的方法:假如位于流 ...

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

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

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

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

  4. 自己动手写CPU之第五阶段(1)——流水线数据相关问题

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第15篇,我尽量每周四篇 上一章建立了原始的OpenMIPS五级流水线结构,可是仅仅实现了一条ori指令,从本章開始,将逐步完 ...

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

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

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

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

  7. 自己动手写CPU(2)第一条ori指令

    本博客内容基于<自己动手写CPU>这本书 上一篇文章介绍了一下流水线思想.设计流程等,下面我们可以实操一下实现第一条ori指令. 其实实现一条ori指令不难,我目前对这一条指令的理解简单来 ...

  8. 【自己动手写CPU】第一条指令ori的实现

    验证过程 实现ori指令->建立最小SOPC->验证ori指令是否正确 ori指令说明 ori是进行逻辑"或"的运算指令 ori指令的指令码是6'b001101.处理器 ...

  9. 自己动手写CPU(7)转移指令的实现

    自己动手写CPU(7)转移指令的实现 分支延迟槽 在MIPS五级流水线中,一条指令被分成了五个阶段:取指.译指.执行.仿存.回写.当第一条指令的执行阶段结束时,第二条指令的译指阶段也已经结束了. 那么 ...

最新文章

  1. mysql persistent_MySQL关于InnoDB的几个错误
  2. 【新概念第一册】Lesson_29 Come in,Amy.
  3. ACE_Select_Reactor 一 ——入门
  4. 软件工程结构化建模的方法和工具_软件工程系列-结构化设计方法2
  5. 有些生意很偏门,也有一定门槛,但是效益非常好
  6. 解读 2018之Go语言篇(上):为什么Go语言越来越热?
  7. Atititi atiitt eam pam资产管理 购物表去年.xlsx
  8. 《数据挖掘概念与技术》读书笔记
  9. Lua教程(二):C++和Lua相互传递数据示例
  10. Ubuntu上MPI编程环境部署
  11. 腾讯云服务器备案全流程详细内容记录40天备案的血与泪
  12. PORIS门禁控制器
  13. 龙芯 python_二代龙芯派 VS 树莓派 3B+:性能孰胜一筹?
  14. PAT甲级 1037(C++)
  15. TeamCity打包部署镜像
  16. 京东面经 10.10
  17. 二、每隔 n 个顾客打折(Biweekly20)
  18. 优思学院|六西格玛黑带考试难不难?
  19. pdfh5不能用了 ?
  20. Ae 入门系列之十:关键帧动画进阶

热门文章

  1. 2015-03-17 how is task transaction type retrieved
  2. How Kyma plugin register hook to Activate and deactivate event
  3. SAP Commerce的Site列表
  4. SAP CRM里note界面默认语言的决定逻辑
  5. Netweaver的传输机制和SAP Cloud for Customer
  6. 使用SAP云平台 + JNDI访问Internet Service
  7. 这样安装python库才是最正确的哦_这样安装 Python 库才是最正确的哦~
  8. python的linux电脑上图标不见了怎么办_电脑桌面及桌面图标消失不见怎么找回?
  9. jemeter python接口自动化测试平台_ant+jmeter+Jenkins接口自动化测试实战(1)
  10. python京东注册账号_Python爬虫模拟登录京东获取个人信息