将陆续上传本人写的新书《自己动手写CPU》,今天是第33篇,我尽量每周四篇

亚马逊的销售地址如下,欢迎大家围观呵!

http://www.amazon.cn/dp/b00mqkrlg8/ref=cm_sw_r_si_dp_5kq8tb1gyhja4

China-pub的销售地址如下:

http://product.china-pub.com/3804025

在京东、北发等网上书店均有!

除法指令的实现过程有点长,分两篇博文介绍,今天是第一篇。

7.12 修改OpenMIPS以实现除法指令

7.12.1 增加DIV模块

DIV模块的接口如图7-17所示,各接口的含义如表7-5所示。

DIV模块的主要部分是一个状态机,共有四个状态,如下,状态转换如图7-18所示。

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

复位的时候,DIV模块处于DivFree状态,当输入信号start_i为DivStart,且输入信号annul_i为0时,表示除法操作开始。

  • 如果除数opdata2_i为0,那么进入DivByZero状态,直接给出除法结果,这里设置为0,余数也为0,然后进入DivEnd状态,并通知EX模块除法运算结果得到,后者会设置DIV模块的输入信号start_i为DivStop,除法运算结束。
  • 如果除数opdata2_i不为0,那么进入DivOn状态,使用试商法,经过32个时钟周期,得出除法结果,然后进入DivEnd状态,并通知EX模块除法运算结果得到,后者会设置DIV模块的输入信号start_i为DivStop,除法运算结束。

DIV模块的代码如下,源文件是本书附带光盘Code\Chapter7_3目录下的div.v。

module div(input  wire       clk,input  wire     rst,input  wire             signed_div_i,input  wire[31:0]       opdata1_i,input  wire[31:0]       opdata2_i,input  wire             start_i,input  wire             annul_i,output reg[63:0]        result_o,output reg              ready_o
);wire[32:0] div_temp;reg[5:0]   cnt;          //记录试商法进行了几轮,当等于32时,表示试商法结束reg[64:0]  dividend;reg[1:0]   state;reg[31:0]  divisor; reg[31:0]  temp_op1;reg[31:0]  temp_op2;//dividend的低32位保存的是被除数、中间结果,第k次迭代结束的时候dividend[k:0]
//保存的就是当前得到的中间结果,dividend[31:k+1]保存的就是被除数中还没有参与运算
//的数据,dividend高32位是每次迭代时的被减数,所以dividend[63:32]就是图7-16
//中的minuend,divisor就是图7-16中的除数n,此处进行的就是minuend-n运算,结
//果保存在div_temp中
assign div_temp = {1'b0,dividend[63:32]} - {1'b0,divisor};always @ (posedge clk) beginif (rst == `RstEnable) beginstate    <= `DivFree;ready_o  <= `DivResultNotReady;result_o <= {`ZeroWord,`ZeroWord};end else begincase (state)//*******************   DivFree状态    ***********************//分三种情况://(1)开始除法运算,但除数为0,那么进入DivByZero状态//(2)开始除法运算,且除数不为0,那么进入DivOn状态,初始化cnt为0,如//     果是有符号除法,且被除数或者除数为负,那么对被除数或者除数取补码。//     除数保存到divisor中,将被除数的最高位保存到dividend的第32位,//     准备进行第一次迭代//(3)没有开始除法运算,保持ready_o为DivResultNotReady,保持//    result_o为0//***********************************************************`DivFree:   begin                     // DivFree状态if(start_i == `DivStart && annul_i == 1'b0) beginif(opdata2_i == `ZeroWord) beginstate <= `DivByZero;          // 除数为0end else beginstate <= `DivOn;              // 除数不为0cnt <= 6'b000000;if(signed_div_i == 1'b1 && opdata1_i[31] == 1'b1 ) begintemp_op1 = ~opdata1_i + 1;  // 被除数取补码end else begintemp_op1 = opdata1_i;endif(signed_div_i == 1'b1 && opdata2_i[31] == 1'b1 ) begintemp_op2 = ~opdata2_i + 1;  // 除数取补码end else begintemp_op2 = opdata2_i;enddividend <= {`ZeroWord,`ZeroWord};dividend[32:1] <= temp_op1;divisor <= temp_op2;endend else begin                      // 没有开始除法运算ready_o <= `DivResultNotReady;result_o <= {`ZeroWord,`ZeroWord};endend//*******************   DivByZero状态    ********************//如果进入DivByZero状态,那么直接进入DivEnd状态,除法结束,且结果为0//***********************************************************`DivByZero:     begin               //DivByZero状态dividend <= {`ZeroWord,`ZeroWord};state <= `DivEnd;              end//*******************   DivOn状态      ***********************//分三种情况://(1)如果输入信号annul_i为1,表示处理器取消除法运算,那么DIV模块直//    接回到DivFree状态。//(2)如果annul_i为0,且cnt不为32,那么表示试商法还没有结束,此时//    如果减法结果div_temp为负,那么此次迭代结果是0,参考图7-16;如//    果减法结果div_temp为正,那么此次迭代结果是1,参考图7-16,dividend//    的最低位保存每次的迭代结果。同时保持DivOn状态,cnt加1。//(3)如果annul_i为0,且cnt为32,那么表示试商法结束,如果是有符号//    除法,且被除数、除数一正一负,那么将试商法的结果取补码,得到最终的//    结果,此处的商、余数都要取补码。商保存在dividend的低32位,余数//    保存在dividend的高32位。同时进入DivEnd状态。//***********************************************************`DivOn:        begin                //DivOn状态if(annul_i == 1'b0) beginif(cnt != 6'b100000) begin     //cnt不为32,表示试商法还没有结束if(div_temp[32] == 1'b1) begin //如果div_temp[32]为1,表示(minuend-n)结果小于0,//将dividend向左移一位,这样就将被除数还没有参与运算的//最高位加入到下一次迭代的被减数中,同时将0追加到中间结果dividend <= {dividend[63:0] , 1'b0};end else begin//如果div_temp[32]为0,表示(minuend-n)结果大于等//于0,将减法的结果与被除数还没有参运算的最高位加入到下//一次迭代的被减数中,同时将1追加到中间结果dividend <= {div_temp[31:0] , dividend[31:0] , 1'b1};endcnt <= cnt + 1;end else begin                 //试商法结束if((signed_div_i == 1'b1) && ((opdata1_i[31] ^ opdata2_i[31]) == 1'b1)) begindividend[31:0] <= (~dividend[31:0] + 1);  //求补码endif((signed_div_i == 1'b1) && ((opdata1_i[31] ^ dividend[64]) == 1'b1)) begin              dividend[64:33] <= (~dividend[64:33] + 1); //求补码endstate <= `DivEnd;             //进入DivEnd状态cnt <= 6'b000000;             //cnt清零endend else beginstate <= `DivFree;   //如果annul_i为1,那么直接回到DivFree状态end end//*******************   DivEnd状态    ***********************//除法运算结束,result_o的宽度是64位,其高32位存储余数,低32位存储商,//设置输出信号ready_o为DivResultReady,表示除法结束,然后等待EX模块//送来DivStop信号,当EX模块送来DivStop信号时,DIV模块回到DivFree//状态//**********************************************************`DivEnd:       begin               //DivEnd状态result_o <= {dividend[64:33], dividend[31:0]};  ready_o <= `DivResultReady;if(start_i == `DivStop) beginstate <= `DivFree;ready_o <= `DivResultNotReady;result_o <= {`ZeroWord,`ZeroWord};           end         endendcaseend
endendmoduleDIV模块中涉及的宏定义,在defines.v中定义,如下:
`define DivFree            2'b00
`define DivByZero          2'b01
`define DivOn              2'b10
`define DivEnd             2'b11
`define DivResultReady     1'b1
`define DivResultNotReady  1'b0
`define DivStart           1'b1
`define DivStop            1'b0

本篇实现了除法模块DIV,下一篇将把DIV模块嵌入到流水线中,以最终实现除法指令,敬请关注!

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

  1. 自己动手写CPU(3)逻辑、移位操作与空指令

    自己动手写CPU(3)逻辑.移位操作与空指令 指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条: and.andi.or.ori.xor.xori.nor.lui,其中 ori指令已经实现. ...

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

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

  3. 自己动手写CPU(11)——加载存储指令说明

    加载存储指令说明 加载指令(7) lb.lbu.lh.lhu.lw.lwl.lwr 存储指令(5) sb.sh.sw.swl.swr 补充 加载指令(7) lb.lbu.lh.lhu.lw.lwl.l ...

  4. 自己动手写cpu 光盘_自己动手写CPU配套源码

    自己动手写CPU的源代码,一共15章,可以完整实现MIPS的指令 文件:n459.com/file/25127180-476886294 以下内容无关: ----------------------- ...

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

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

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

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

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

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

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

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

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

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

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

    自己动手写CPU(6)流水线暂停.乘累加减与除法器的实现 流水线暂停 因为OpenMIPS设计乘累加.乘累减.除法指令在流水线执行阶段占用多个时钟周期,因此需要暂停流水线,以等待这些多周期指令执行完毕 ...

最新文章

  1. Android系统移植与调试之-------如何修改Android设备添加重启、飞行模式、静音模式等功能(一)...
  2. 美国科学家成功恢复老年人工作记忆,望奠定认知干预疗法基础
  3. [PKUSC2018]真实排名——线段树+组合数
  4. scikit-image安装 from numpy.lib.arraypad import _validate_lengths ImportError: cannot import name ‘_va
  5. 你是一个有价值的产品经理吗?
  6. Socket 实现聊天功能
  7. Nginx使用SSL配置HTTPS
  8. eDiary电子日记本
  9. MvcMusicStore学习中常出现的一个BUG
  10. django之关系及查询,数据类型,约束,分页
  11. Joining Byte Blocks(哈希+带花树)
  12. TCP协议中的三次握手和四次挥手(图解)【转】
  13. 建议推出专门用于开发的电脑
  14. polar函数--Matplotlib
  15. C++小游戏数字炸弹
  16. 数仓建模—事实表和维度表设计规范
  17. CSS字体样式属性调试
  18. PPT文件该怎么压缩大小
  19. 总有一条适合你|程序猿的女朋友
  20. 数据结构与算法--哈夫曼树应用

热门文章

  1. 基于STM32F429的SDRAM使用
  2. C语言中get_put函数详解,C++ get()和put()读写文件详解
  3. 20211220使用Hiburn给小熊派刷机
  4. 为什么很多人在说做嵌入式驱动没前途?搜工作还是发现有很多招嵌入式的职位啊,linux驱动就真的没有前途吗?
  5. 阿福家的电费(杭电慕课作业)
  6. Java 动态判断数组维数并取值
  7. 自动生成接口文档之JApiDocs教程
  8. 新华三 VDI java,鱼和熊掌兼得:新华三vGPU云桌面方案革新VDI性能体验
  9. Sine Sweep(正弦扫频信号)
  10. 单片机51---步进电机的设计(4相5线步进电机的驱动控制)