计组实验2 mips简单乘法器模拟实验

news/2024/12/4 20:14:51/

目录

  • 前言
  • 加法原理
  • 忽略溢出的乘法器
  • 溢出提示的乘法器
  • 完整代码

前言

上一次做了 MIPS实验1:阴间指令集MIPS简介:汇编,IO,过程调用与冒泡排序,如果对mips的IO等等操作还有不懂的可以康康。。。

那么今天来记录一下计组的实验。。。

本次试验分为两个部分:第一部分、用加法器设计一个不考虑溢出的乘法器;第二部分、 用加法器设计一个考虑溢出的乘法

加法原理

这可是连小学生都知道的啊

参考竖式加法,只是进制不同。我们循环做几件事,一般32位乘法就循环32次:

  1. 判断 multiplier 最末位是否为1,如果为1则结果加上 multiplicand
  2. multiplier 右移 1 bit
  3. multiplicand 左移 1 bit

如图,最终的结果就是累加产生的。。。

在这里插入图片描述

忽略溢出的乘法器

首先,我们得了解乘法器如何由加法器设计得到,此处,我们以 32 位乘法为例。 总共分为 4 步:

  1. 测试乘数最低位是否为 1,是则给乘积加上被乘数,将结果写入乘积寄存器;
  2. 被乘数寄存器左移 1 位;
  3. 乘数寄存器右移一位;
  4. 判断是否循环了 32 次,如果是,则结束,否则返回步骤 1。

算法的流程图如下:

在这里插入图片描述

我们开始编码,首先我们编写.data 节的数据并且分配一些栈空间:

.data
CONTROL:    .word 0x10000
DATA:       .word 0x10008
NUM1:       .word 0
NUM2:       .word 0
STACKBOTTOM:   .space 20
STACKTOP:       .word 0
OFSTR:      .asciiz "warning: result overflow\n"
STR:        .asciiz "please enter two numbers:\n"
RES:        .asciiz "result:\n"

然后我们编写一些帮助函数,分别是读取 int,打印 int 和打印字符串。他们的用处见注释:

#   @function readInt   : read an int from terminal
#   @param arg0         : address of int to be read
#   @return             : ----
readInt:daddi $sp, $sp, -4  # assign stacksw $ra, ($sp)       # store return addressdaddi $t0, $zero, 8     # t0 = 8lw $t1, DATA($zero)     # t1 = 0x10008lw $t2, CONTROL($zero)  # t2 = 0x10000sw $t0, ($t2)           # CONTROL = 8lw $t1, ($t1)           # t1 = DATAsw $t1, ($a0)           # M[arg0] = DATAlw $ra, ($sp)       # restore return addressdaddi $sp, $sp, 4   # backwards stackjr $ra#   @function printInt  :
#   @param arg0         : value of int to be print
#   @return             : ----
printInt:daddi $sp, $sp, -4  # sp -= 4sw $ra, ($sp)       # save return addressdaddi $t0, $zero, 2     # t0 = 2lw $t1, DATA($zero)     # t1 = 0x10008lw $t2, CONTROL($zero)  # t2 = 0x10000sw $a0, ($t1)           # DATA = arg0sw $t0, ($t2)           # CONTROL = 2lw $ra, ($sp)       # restore return addressdaddi $sp, $sp, 4   # sp += 4jr $ra              # return#   @function printStr  :
#   @param a0           : sratr address of string
#   @return             : ----
printStr:daddi $sp, $sp, -4      # sp -= 4sw $ra, ($sp)           # save return addressdaddi $t0, $zero, 4     # t0 = 4dadd $t1, $zero, $a0    # t1 = arg0lw $t2, DATA($zero)     # t2 = M[DATA] = 0x10008lw $t3, CONTROL($zero)  # t3 = M[CONTROL] = 0x10000sw $t1, ($t2)           # M[0x10008] = t1 = arg0sw $t0, ($t3)           # M[0x10000] = t0 = 4lw $ra, ($sp)           # restore return addressdaddi $sp, $sp, 4       # sp += 4jr $ra                  # return

然后我们开始写初始化的代码,即.text 节中的代码。首先我们打印提示字符串,然后从键盘 读取两个整数到 data 区:

.text
main:daddi $sp, $zero, STACKTOP  # assign stackdaddi $a0, $zero, STR       # print strjal printStrdaddi $a0, $zero, NUM1      # read num1jal readIntdaddi $a0, $zero, NUM2      # read num2jal readIntdaddi $a0, $zero, RES       # print resjal printStrdaddi $s0, $zero, 32    # s0 = ilw $s1, NUM1($zero)     # s1 = num1lw $s2, NUM2($zero)     # s2 = num2

最后我们可以开始编写循环逻辑。首先读取两个整数,然后我们按照流程图进行循环。

  1. 每次循环判断被乘数的最后一位是否为 1,是则将结果加上乘数。
  2. 每次循环都需要分别对乘数和被乘数进行左移/右移
  3. 最后取结果寄存器即可:

注意我们的 num1/num2 放在 s1, s2 寄存器,此外,s4 寄存器被用来存放结果:

loop:beq $s0, $zero, enddaddi $s0, $s0, -1andi $s3, $s1, 1        # s3 = s1 lowbitbeq $s3, $zero, notadd  # lowbit = 0 --> not adddadd $s4, $s4, $s2      # ans += s2
notadd:dsll $s2, $s2, 1        # s3<<1dsrl $s1, $s1, 1        # s1>>1j loop
end:daddi $a0, $s4, 0       # print s4jal printInthalt 

运行显示运行结果的例子如下,由于我们这里展示的是忽略了溢出的乘法,所以结果有 两种:

1、小于 32 位;
2、大于 32 位。 第一种情况截图:

在这里插入图片描述
第二种情况截图:

在这里插入图片描述

根据上面的程序代码和截图,我们可以很清楚的看出,当结果小于32位时,结果正常;当结 果大于32位时,结果只截取了低32位的结果,而高32位的结果直接忽略掉了。

溢出提示的乘法器

上述的程序,用加法实现了 32 位乘法,但是,其中,对溢出情况没有进行考虑是其中的弊 端。这里,我们来完善上述的乘法器,使得该乘法器会在结果溢出时候提示。

其实,这个小优化是十分简单的,只需要对 64 位的寄存器中的高 32 位进行检测即可。当高 32 位为 0 时,说明结果没有溢出,否则,结果溢出。

我们来编写判断的逻辑即可:我们在得出结果的时候,额外判断其高 32 位是否不为零。我 们将 s4 右移 32 位,然后判断其是否为 0 即可。在 halt 结束之前,加上:

# overflow detectiondsrl $s4, $s4, 8        # high 32 bitdsrl $s4, $s4, 8        dsrl $s4, $s4, 8        dsrl $s4, $s4, 8        beq $s4, $zero, halt    # high 32 = 0 --> haltdaddi $a0, $zero, OFSTR # print overflowjal printStr
halt:halt 

在这里插入图片描述

上述代码运行结果也有两个,一个是没有溢出的情况下的结果,一个是溢出了的情况下 的结果。 首先,我们看没有溢出的情况结果:

在这里插入图片描述

结果正确,其次,我们看溢出的情况结果如何,可以看到 R4 移位 32 位之后任然不为 零,说明溢出:

在这里插入图片描述

可以看到,当结果溢出时,程序会给出提示“warning:result overflow”。

完整代码

.data
CONTROL:    .word 0x10000
DATA:       .word 0x10008
NUM1:       .word 0
NUM2:       .word 0
STACKBOTTOM:   .space 20
STACKTOP:       .word 0
OFSTR:      .asciiz "warning: result overflow\n"
STR:        .asciiz "please enter two numbers:\n"
RES:        .asciiz "result:\n".text
main:daddi $sp, $zero, STACKTOP  # assign stackdaddi $a0, $zero, STR       # print strjal printStrdaddi $a0, $zero, NUM1      # read num1jal readIntdaddi $a0, $zero, NUM2      # read num2jal readIntdaddi $a0, $zero, RES       # print resjal printStrdaddi $s0, $zero, 32    # s0 = ilw $s1, NUM1($zero)     # s1 = num1lw $s2, NUM2($zero)     # s2 = num2loop:beq $s0, $zero, enddaddi $s0, $s0, -1andi $s3, $s1, 1        # s3 = s1 lowbitbeq $s3, $zero, notadd  # lowbit = 0 --> not adddadd $s4, $s4, $s2      # ans += s2
notadd:dsll $s2, $s2, 1        # s3<<1dsrl $s1, $s1, 1        # s1>>1j loop
end:daddi $a0, $s4, 0       # print s4jal printInt# overflow detectiondsrl $s4, $s4, 8        # high 32 bitdsrl $s4, $s4, 8        dsrl $s4, $s4, 8        dsrl $s4, $s4, 8        beq $s4, $zero, halt    # high 32 = 0 --> haltdaddi $a0, $zero, OFSTR # print overflowjal printStr
halt:halt #   @function readInt   : read an int from terminal
#   @param arg0         : address of int to be read
#   @return             : ----
readInt:daddi $sp, $sp, -4  # assign stacksw $ra, ($sp)       # store return addressdaddi $t0, $zero, 8     # t0 = 8lw $t1, DATA($zero)     # t1 = 0x10008lw $t2, CONTROL($zero)  # t2 = 0x10000sw $t0, ($t2)           # CONTROL = 8lw $t1, ($t1)           # t1 = DATAsw $t1, ($a0)           # M[arg0] = DATAlw $ra, ($sp)       # restore return addressdaddi $sp, $sp, 4   # backwards stackjr $ra#   @function printInt  :
#   @param arg0         : value of int to be print
#   @return             : ----
printInt:daddi $sp, $sp, -4  # sp -= 4sw $ra, ($sp)       # save return addressdaddi $t0, $zero, 2     # t0 = 2lw $t1, DATA($zero)     # t1 = 0x10008lw $t2, CONTROL($zero)  # t2 = 0x10000sw $a0, ($t1)           # DATA = arg0sw $t0, ($t2)           # CONTROL = 2lw $ra, ($sp)       # restore return addressdaddi $sp, $sp, 4   # sp += 4jr $ra              # return#   @function printStr  :
#   @param a0           : sratr address of string
#   @return             : ----
printStr:daddi $sp, $sp, -4      # sp -= 4sw $ra, ($sp)           # save return addressdaddi $t0, $zero, 4     # t0 = 4dadd $t1, $zero, $a0    # t1 = arg0lw $t2, DATA($zero)     # t2 = M[DATA] = 0x10008lw $t3, CONTROL($zero)  # t3 = M[CONTROL] = 0x10000sw $t1, ($t2)           # M[0x10008] = t1 = arg0sw $t0, ($t3)           # M[0x10000] = t0 = 4lw $ra, ($sp)           # restore return addressdaddi $sp, $sp, 4       # sp += 4jr $ra                  # return

http://www.ppmy.cn/news/460571.html

相关文章

计组实验---流水线冒险

文章目录 前言实验内容实验说明一、 调整指令序列二、 Forwarding功能开启三、 结构相关优化要求指令序列调整方案 实验中修改后的高效率代码数据冒险结构冒险 选做题 前言 看了龙哥的blog&#xff0c;感觉实验报告的内容变了一点&#xff0c;这里就更新一下 龙哥的blog 实验内…

计算机体系结构 第2章 指令系统的设计(2)

文章目录 第2章 指令系统的设计2.4 指令系统的发展和改进2.4.1 沿CISC方向发展和改进指令系统2.4.1.1 面向目标程序增强指令功能2.4.1.2 面向高级语言的优化实现来改进指令系统&#xff08;缩小高级语言与机器语言的语义差距&#xff09;2.4.1.3 面向操作系统的优化实现改进指令…

高级数据分析师工作的基本职责(合集)

高级数据分析师工作的基本职责1 职责&#xff1a; 1. 负责出行平台层面司乘用户分析&#xff0c;给平台相关业务及策略建设输入洞察和方法; 2. 形成天、周和月度的分析报告&#xff0c;传递给公司管理层并进行定期汇报; 3. 可独立完成针对特定问题的分析解读&#xff0c;支持临…

如何把一个 Git 仓库的分支加入另一个无关的 Git 仓库

文章目录 笔者需要将两个无关的 Git 仓库合并&#xff0c;也就是把一个 Git 仓库的分支加入另一个无关的 Git 仓库。笔者琢磨了一下之后就实现了。方法如下。 笔者的运行环境&#xff1a; git version 2.37.0.windows.1 TortoiseGit 2.11.0.0 IntelliJ IDEA 2023.1.1 (Ultima…

将照片信息base64保存到手机

1、核心代码 export async function downloadFileBase64(fileEntry, base64) {var arr base64.split(,);var mime arr[0].match(/:(.*?);/)[1];var bstr atob(arr[1]);var n bstr.length;var u8arr new Uint8Array(n);while (n--) {u8arr[n] bstr.charCodeAt(n);}cons…

opencv 拍摄并保存照片

按键拍摄保存照片。 #include<opencv2/opencv.hpp> #include"opencv2/highgui/highgui.hpp" #include<iostream> #include<string> using namespace cv; using namespace std;int main() {int i 0;string name;//调用摄像头VideoCapture capture…

照片怎么转换jpg格式?如何将照片保存为jpg格式?

很多小伙伴都遇到过下载下来的图片打不开&#xff0c;其实这是因为图片格式不对导致的无法打开&#xff0c;其实我们可以把图片转jpg格式&#xff0c;那么怎么才能图片转格式&#xff08;https://www.yasuotu.com/geshi&#xff09;呢&#xff1f;下面分享了一个jpg图片格式转换…