【手写CPU】7.7 累乘加、累乘减指令

本文已收录于 MIPS架构CPU设计 系列,共计 7 篇,本篇是第 4 篇

在上一节我们实现了 流水线暂停机制,就是为本节累乘加、累乘减这种两周期指令服务的。

 

累乘加、累乘减指令介绍

关于指令本身的手册规定可参考书本P180页。如果没有纸质书可以参考作者博客电子版书籍:https://blog.csdn.net/leishangwen/article/details/39004839

 

如何保存(暂存)第一个时钟周期计算出来的值

是直接保存在寄存器中?还是另起一个新的暂存寄存器合适呢?

如果我们直接保存在寄存器中,相当于多指令操作,显然不是我们需要的。

在本处理中,我们采用后者的方式,另起一个新的临时寄存器存储值,保存下列两个信息:

  1. 一共是两个周期执行完毕,那么现在是第几个时钟周期?
  2. 临时存储的值

 

修改译码阶段

视频讲解

 

修改执行阶段

这里我们不以书本的思路实现,书本的思路我理解较为困难,下面来讲下我的思路。

有符号数和无符号数补码乘法计算算法

程序中的正数,负数,经过编译器处理(都转换为补码)后存储在寄存器中。所以在CPU中,所有的数值都看作补码。因为寄存器中本身就是补码,我们直接采用补码乘法即可。

  • 针对32位有符号数计算,需要先将32位以上截断,然后根据第32位做有符号扩展。
  • 针对无符号数,直接计算,超过32位不用截断处理。直接存储在64位变量中,高32位放在hi。低32位放在lo。

所以在本节中,我们可以参考执行阶段“EXE_MULT_OP”即mult指令的执行步骤:

`EXE_MULT_OP: begin
                // 与上面的乘法一样,不同点是结果保存在特殊寄存器 hi lo 中。
                
                // mult_temp_counts <= reg1_i * reg2_i;    // mult_temp_counts 是一个64位寄存器。
                // 上面这一行计算结果是错误的,因为 reg1_i * reg2_i 结果可能是超过32位的,本应该截断却被保留进 64位的 mult_temp_counts 中了。
                
                // 有符号数和无符号数补码乘法计算算法:
                // 针对32位有符号数计算,需要先将32位以上截断,然后根据第32位做有符号扩展。
                // 针对无符号数,直接计算,超过32位不用截断处理。直接存储在64位变量中,高32位放在hi。低32位放在lo。
                // 所以应该截断到32位:
                mult_32_result <= reg1_i * reg2_i;
                mult_temp_counts <= {{32{mult_32_result[31]}}, mult_32_result[31:0]};
                // 需要写到特殊寄存器 hi lo中。
                whilo_o <= 1'b1;					
                hi_o <= mult_temp_counts[63:32];				
                lo_o <= mult_temp_counts[31:0];               
            end

视频讲解

 

实现临时保存作用的寄存器

我们计划,第一个时钟周期计算出 rs × rt 的值并输出到临时寄存器中,并且将当前时钟周期数保存在cnt_i中。以便于第二个时钟周期继续进行加法/减法运算。

两个时钟周期所做的事情:

  • 第一个时钟周期:进行乘法运算
  • 第二个时钟周期:乘法结果与{hi, lo}寄存器进行加/减法

根据 图 7-12 ,连接图中的线,修改openmips.v 上层模块。

视频讲解

 

第二个时钟周期做的事情

在第六章我们新增了hi lo寄存器,我们看下数据流图:

在执行阶段(EX)中,我们可以获得从HILO特殊寄存器中的 hi_i 和 lo_i 端口信息。所以执行累乘加、累乘减时,第二个时钟周期计算{hi, lo} + 临时寄存器中的值。其中{hi, lo}寄存器就是我们上个指令所遗留下存在HILO寄存器中的值。

视频讲解

更正/修改:先前阶段《流水线暂停机制的实现》有问题,自行发挥的写法的是错误的,已经参考书本部分修改。具体参考视频。

现在只有下面一点区别,与书本不同,是自行发挥的。

书本上是这样:

自行发挥,砍掉后面两个模块的连接:

因为我觉得访存和回写都不需要暂停机制,因为只有执行、译码阶段才会触发暂停机制,如果有不对后面再修改。

经过不懈的努力,我们找到了 alu_op 信号归为“八个零”的原因——流水线暂停机制实现有误。

我们现在成功实现了一条双周期指令——madd(有符号累乘加指令):

后续的无符号累乘加、有负号累乘减和无符号的累乘减原理一样,直接在ex模块中复制局部改改即可,不再过多介绍。具体涉及有符号补码乘法无符号补码乘法的运算规则。可参考这里

 

作者: 高志远

高志远,23岁,男生,毕业于上海杉达学院电子商务系。

发表评论

邮箱地址不会被公开。