MIPS32的DIV和DIVU实现

《自己动手写CPU》一书的7.11节到7.14节实现了DIV和DIVU指令。

书中通过“试商法”实现除法,并在原有的流水线结构之外另加了状态机进行计算。

照抄书上的实现方法需要另外添加个.v,我实在有点懒,不想在运算指令实现上再另外加个文件。

而且按照书上的实现,DIV和DIVU指令跟其他的运算指令差别很大,不符合我对结构的审美。

那么就必须想想办法自己写一个别的实现方法。

于是找到了一个结构化比较好的实现方法:

http://www.cnblogs.com/AndyJee/p/4575152.html

参照这个方法,使用verilog实现需要解决2个问题:

(1)文章是无符号数的除法,对应DIVU,而DIV是有符号数除法。

这里又要分两种情况讨论。

a、DIV指令的被除数和除数是有符号数

有符号数运算时,输入的被除数和除数都是补码,做除法时需要先将补码转成原码。

正数的补码就是原码,那么只需要在负数时转成原码即可。

b、DIV指令的商和余数正负符号判断

按照初等数学的定义,商的正负取决于被除数和除数的正负,而余数取决于除数的符号。

而计算机语言中,商的正负没有变化,余数符号取决于被除数。

该问题的讨论:

http://blog.sina.com.cn/s/blog_956c84bb0101j31f.html

DIV指令下,被除数/除数为负数,则转换成原码:

  assign div_dividend = ((aluop_i == `EXE_DIV_OP) && (reg1_i[31] == 1‘b1)) ? (~reg1_i + 1) : reg1_i;
  assign div_divisor = ((aluop_i == `EXE_DIV_OP) && (reg2_i[31] == 1‘b1)) ? (~reg2_i + 1) : reg2_i;

DIV指令下,将商和余数转回为补码:

  assign div_quotient = ((aluop_i == `EXE_DIV_OP) && (reg1_i[31] ^ reg2_i[31] == 1‘b1)) ? {1‘b1, (~div_quo_o[30:0] + 1)} : div_quo_o;
  assign div_remainder = ((aluop_i == `EXE_DIV_OP) && (reg1_i[31] == 1‘b1)) ? {1‘b1, (~div_rem_o[30:0] + 1)} : div_rem_o;

(2)参考的方法通过高级语言描述,需要转化成适合verilog实现的方式。

该方法的核心是通过减法来实现除法,使用中文通俗描述的步骤如下:

基本方法

a、比较被除数和除数的大小;

b、如果被除数比较大,将被除数减去除数,商加1;

c、循环步骤a和b,直到被除数比除数小,这时候被除数剩下的就是余数,商就是结果(初值为0)。

基本方法比较“笨”,效率是最低的。

加速方法

a、比较被除数和n*除数的大小;

b、如果被除数比较大,将被除数减去n*除数,商加n;

c、循环步骤a和b,直到被除数比除数小,这时候被除数剩下的就是余数,商就是结果(初值为0)。

加速方法适合使用移位来实现(verilog中,左移1位数值乘于2)。

但是上面文章中描述的方法不适合直接用verilog实现(2层while循环,verilog实现很麻烦)。

可以通过以下几个小技巧避免在verilog中出现类似2层while循环的结构:

a、考虑DIV和DIVU指令的除数位数有限,那么可以先判断最大需要移位几次进行加速方法步骤a(数一数除数第一个1之前有几个0);

b、在最大移位范围内,按照移位次数从大到小的顺序进行操作(使n*除数中的n尽量大),以尽快收敛结果。

最后实现时,在流水线的寄存器之间进行的运算如下(核心代码):

                //core method
                if (div_rem_i < (div_divisor << div_shift_cnt_i))
                begin
                    div_quo_o = div_quo_i;
                    div_rem_o = div_rem_i;
                end
                else
                begin
                    div_quo_o = div_quo_i + (1 << div_shift_cnt_i);
                    div_rem_o = div_rem_i + (~(div_divisor << div_shift_cnt_i)) + 1;
                end
            end

这样DIV和DIVU运算所需的周期受除数影响,除数越大则运算周期越短,除数越小则运算周期越长(移位操作次数多)。

例如,当除数是1时,需要31次移位操作(31个时钟);除数是10‘b10_0000_0000时,需要22次移位(22个时钟)。

这种实现方法最大运算周期为32*时钟周期,而《自己动手写CPU》中给的例子对于32位的除法,至少需要32个时钟周期。

另外,这种实现方法与累乘加和累乘减(MADD/MADDU/MSUB/MSUBU)的结构类似,不需要另外再添加.v文件,符合懒人“初始结构以外,最好不做任何结构变动”的习惯。

最后,这种方法可以简单实现加速,即通过比较被除数和除数从bit31开始0的数量,可以在被除数和除数绝对值都较小的情况下节省很多运算周期。

时间: 2024-08-03 03:31:12

MIPS32的DIV和DIVU实现的相关文章

自己动手写处理器之第一阶段(3)——MIPS32指令集架构简介

将陆续上传本人写的新书<自己动手写处理器>(尚未出版),今天是第四篇,我尽量每周四篇 1.4 MIPS32指令集架构简介 本书设计的处理器遵循MIPS32 Release 1架构,所以本节介绍的MIPS32指令集架构指的就是MIPS32 Release 1. 1.4.1 数据类型 指令的主要任务就是对操作数进行运算,操作数有不同的类型和长度,MIPS32提供的基本数据类型如下. 位(b):长度是1bit. 字节(Byte):长度是8bit. 半字(Half Word):长度是16bit. 字(

自己动手写CPU之第七阶段(12)——检验除法指令实现效果

将陆续上传本人写的新书<自己动手写CPU>,今天是第33篇,我尽量每周四篇 感兴趣的朋友可以在亚马逊.当当.京东等查找. 7.13 测试除法指令实现效果 本节将通过一个测试程序验证为OpenMIPS添加的除法指令是否实现正确,测试程序如下,源文件是本书附带光盘Code\Chapter7_3\AsmTest目录下的inst_rom.S文件. .org 0x0 .global _start _start: ori $2,$0,0xffff sll $2,$2,16 ori $2,$2,0xfff1

计算机硬件架构五

M68000, M68K:这个摩托罗拉68000系列(也被称为680x0,M68000,m68k,或68k)是一个家庭32 复杂指令集计算机(CISC)微处理器.在80年代和90年代初,他们很受欢迎个人电脑和工作站和是主要的竞争对手因特尔的x86微处理器.他们最著名的处理器供电的早熟苹果Macintosh,司令官Amiga,的辛克莱QL,的雅达利ST,的Weatherstar,的世嘉五代(Mega Drive),和其他几个人.虽然没有现代台式电脑是基于68000系列处理器,处理器仍然广泛使用的衍

MIPS指令学习二

1.MIPS寻址方式 MIPS架构的寻址模式有寄存器寻址.立即数寻址.寄存器相对寻址和PC相对寻址4种,其中寄存器相对寻址.PC相对寻址介绍如下: 1.1.寄存器相对寻址 这种寻址模式主要被加载/存储指令使用,其对一个16位的立即数进行符号扩展,然后与指定通用寄存器的值相加,从而得到有效地址. 通用寄存器GRP   +   16位立即数做符号扩展      =       有效地址 1.2.PC相对寻址 这种寻址模式主要被转移指令使用.在转移指令中有一个16位的立即数,将其左移2位并进行符号扩展

[转]MIPS指令集

MIPS CPU的一次操作可加载或存储1到8个字节的数据.由于乘法的结果返回的速度不足以使下一条指令能够自动得到这个结果,乘法结果寄存器是互锁的(interlocked).在乘法操作完成之前试图读取结果寄存器就是导致CPU停止运行,直到完成. 和其他一些更简单的RISC体系结构相比,MIPS体系结构的目标之一是:体系结构朝着64位发展,从而使得地址的段式结构变得没有任何必要.(在64位版本的X86核PowerPC中还有这个负担) 功能分组: 空操作:nop.ssnop(不能和其他指令同时发射,至

自己动手写CPU之第七阶段(9)——除法指令说明及实现思路

将陆续上传本人写的新书<自己动手写CPU>,今天是第32篇,我尽量每周四篇 亚马逊的销售地址如下,欢迎大家围观呵! 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=

移动端俩个DIV切换,上滑加载

<!doctype html><html lang="zh-cn"><head> <meta name="viewport" content="initial-scale=1, user-scalable=0, minimal-ui" charset="gbk"> <title>随访计划与随访记录app</title> <style> *{ m

深度理解div+css布局嵌套盒子

1. 网页布局概述 网页布局的概念是把即将出现在网页中的所有元素进行定位,而CSS网页排版技术有别于传统的网页排版方法,它将页面首先在整体上使用<div>标记进行分块,然后对每个快进行CSS定位以及设置显示效果,最后在每个块中添加相应的内容.利用CSS排版方法更容易地控制页面每个元素的效果,更新也更容易,甚至页面的拓扑结构也可以通过修改相应的CSS属性来重新定位.  2. 盒子模型 盒子模型是CSS控制页面元素的一个重要概念,只有掌握了盒子模型,才能让CSS很好地控制页面上每一个元素,达到我们

现在主流网站为什么都用div+css布局而不是用table

由于刚刚接触前端,一直觉得table布局在代码上看起来比div+css更整洁,div+css布局的页面,一堆的<div><div><div>...</div></div></div>看起来都让人犯密集恐惧症,那么为什么现在的主流网站还都乐此不疲呢?为什么div+css反而成了一种主流布局方式呢?一直对此不解.这篇文章好像是解决了我的问题,先摘录过来,以便查阅. 以下内容摘自:http://www.divcss5.com/wenji/w