Calculation group experiment 2 mips simple multiplier simulation experiment

Preface

The last time I did MIPS experiment 1: Underworld instruction set MIPS introduction: assembly, IO, procedure call and bubble sorting , if you still don’t understand mips IO and other operations, you can Kangkang. . .

So today, let’s record the experiment of the team. . .

This experiment is divided into two parts: the first part, use an adder to design a multiplier that does not consider overflow; the second part, use an adder to design a multiplication that considers overflow

Principle of addition

This is something even elementary school students know

Refer to vertical addition, but the base is different. We do a few things in a loop, generally 32-bit multiplication loops 32 times:

  1. Analyzing multiplierlast bit is 1, if the result is a plusmultiplicand
  2. multiplier 1 bit right
  3. multiplicand 1 bit left

As shown in the figure, the final result is cumulative. . .

Insert picture description here

Ignore overflowed multipliers

First, we have to understand how the multiplier is designed by the adder. Here, we take 32-bit multiplication as an example. There are 4 steps in total:

  1. Test whether the lowest bit of the multiplier is 1, if yes, add the multiplicand to the product, and write the result to the product register;
  2. The multiplicand register is shifted to the left by 1 bit;
  3. The multiplier register is shifted one bit to the right;
  4. Judge whether it has looped 32 times, if yes, end, otherwise return to step 1.

The flow chart of the algorithm is as follows:

Insert picture description here

We start coding, first we write the data in the .data section and allocate some stack space:

.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"

Then we write some helper functions to read int, print int and print string. See notes for their usefulness:

#   @function readInt   : read an int from terminal
#   @param arg0         : address of int to be read
#   @return             : ----
readInt:
    daddi $sp, $sp, -4  # assign stack
    sw $ra, ($sp)       # store return address

    daddi $t0, $zero, 8     # t0 = 8
    lw $t1, DATA($zero)     # t1 = 0x10008
    lw $t2, CONTROL($zero)  # t2 = 0x10000
    sw $t0, ($t2)           # CONTROL = 8
    lw $t1, ($t1)           # t1 = DATA
    sw $t1, ($a0)           # M[arg0] = DATA

    lw $ra, ($sp)       # restore return address
    daddi $sp, $sp, 4   # backwards stack
    jr $ra

#   @function printInt  :
#   @param arg0         : value of int to be print
#   @return             : ----
printInt:
    daddi $sp, $sp, -4  # sp -= 4
    sw $ra, ($sp)       # save return address

    daddi $t0, $zero, 2     # t0 = 2
    lw $t1, DATA($zero)     # t1 = 0x10008
    lw $t2, CONTROL($zero)  # t2 = 0x10000
    sw $a0, ($t1)           # DATA = arg0
    sw $t0, ($t2)           # CONTROL = 2

    lw $ra, ($sp)       # restore return address
    daddi $sp, $sp, 4   # sp += 4
    jr $ra              # return

#   @function printStr  :
#   @param a0           : sratr address of string
#   @return             : ----
printStr:
    daddi $sp, $sp, -4      # sp -= 4
    sw $ra, ($sp)           # save return address
    daddi $t0, $zero, 4     # t0 = 4
    dadd $t1, $zero, $a0    # t1 = arg0
    lw $t2, DATA($zero)     # t2 = M[DATA] = 0x10008
    lw $t3, CONTROL($zero)  # t3 = M[CONTROL] = 0x10000
    sw $t1, ($t2)           # M[0x10008] = t1 = arg0
    sw $t0, ($t3)           # M[0x10000] = t0 = 4
    lw $ra, ($sp)           # restore return address
    daddi $sp, $sp, 4       # sp += 4
    jr $ra                  # return

Then we start to write the initialization code, which is the code in the .text section. First, we print the prompt string, and then read two integers from the keyboard to the data area:

.text
main:
    daddi $sp, $zero, STACKTOP  # assign stack
 
    daddi $a0, $zero, STR       # print str
    jal printStr

    daddi $a0, $zero, NUM1      # read num1
    jal readInt

    daddi $a0, $zero, NUM2      # read num2
    jal readInt

    daddi $a0, $zero, RES       # print res
    jal printStr

    daddi $s0, $zero, 32    # s0 = i
    lw $s1, NUM1($zero)     # s1 = num1
    lw $s2, NUM2($zero)     # s2 = num2

Finally we can start writing the loop logic. First read two integers, and then we loop through the flowchart.

  1. Each cycle determines whether the last digit of the multiplicand is 1, if yes, the result is added to the multiplier.
  2. Each cycle needs to shift the multiplier and the multiplicand to the left/right
  3. Finally fetch the result register:

Note that our num1/num2 are placed in the s1, s2 registers. In addition, the s4 register is used to store the result:

loop:
    beq $s0, $zero, end
    daddi $s0, $s0, -1

    andi $s3, $s1, 1        # s3 = s1 lowbit
    beq $s3, $zero, notadd  # lowbit = 0 --> not add

    dadd $s4, $s4, $s2      # ans += s2
notadd:
    dsll $s2, $s2, 1        # s3<<1
    dsrl $s1, $s1, 1        # s1>>1
    
    j loop
end:
    daddi $a0, $s4, 0       # print s4
    jal printInt
    halt 

An example of running and displaying the running result is as follows. Since we are showing a multiplication that ignores overflow, there are two results:

1. Less than 32 bits;
2. More than 32 bits. Screenshot of the first case:

Insert picture description here
Screenshot of the second case:

Insert picture description here

According to the above program code and screenshots, we can clearly see that when the result is less than 32 bits, the result is normal; when the result is greater than 32 bits, the result only intercepts the low 32-bit result, and the high 32-bit result is directly Ignore it.

Multiplier with overflow hint

The above program implements 32-bit multiplication by addition, but the lack of consideration for overflow is a drawback. Here, let's improve the above multiplier so that the multiplier will prompt when the result overflows.

In fact, this small optimization is very simple. It only needs to check the upper 32 bits of the 64-bit register. When the upper 32 bits are 0, the result does not overflow , otherwise, the result overflows.

Let's write the judgment logic: when we get the result, we additionally judge whether the high 32 bits are not zero. We shift s4 to the right by 32 bits, and then determine whether it is 0. Before the end of the halt, add:

# overflow detection
    dsrl $s4, $s4, 8        # high 32 bit
    dsrl $s4, $s4, 8        
    dsrl $s4, $s4, 8        
    dsrl $s4, $s4, 8        
    beq $s4, $zero, halt    # high 32 = 0 --> halt
    daddi $a0, $zero, OFSTR # print overflow
    jal printStr
halt:
    halt 

Insert picture description here

There are also two results of the above code, one is the result of no overflow, and the other is the result of overflow. First, let's look at the results without overflow:

Insert picture description here

The result is correct. Secondly, if we look at the result of the overflow, we can see that R4 is still not zero after being shifted by 32 bits, indicating overflow:

Insert picture description here

As you can see, when the result overflows, the program will give a prompt "warning: result overflow".

Complete code

.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 stack
 
    daddi $a0, $zero, STR       # print str
    jal printStr

    daddi $a0, $zero, NUM1      # read num1
    jal readInt

    daddi $a0, $zero, NUM2      # read num2
    jal readInt

    daddi $a0, $zero, RES       # print res
    jal printStr

    daddi $s0, $zero, 32    # s0 = i
    lw $s1, NUM1($zero)     # s1 = num1
    lw $s2, NUM2($zero)     # s2 = num2

loop:
    beq $s0, $zero, end
    daddi $s0, $s0, -1

    andi $s3, $s1, 1        # s3 = s1 lowbit
    beq $s3, $zero, notadd  # lowbit = 0 --> not add

    dadd $s4, $s4, $s2      # ans += s2
notadd:
    dsll $s2, $s2, 1        # s3<<1
    dsrl $s1, $s1, 1        # s1>>1
    
    j loop
end:
    daddi $a0, $s4, 0       # print s4
    jal printInt

    # overflow detection
    dsrl $s4, $s4, 8        # high 32 bit
    dsrl $s4, $s4, 8        
    dsrl $s4, $s4, 8        
    dsrl $s4, $s4, 8        
    beq $s4, $zero, halt    # high 32 = 0 --> halt
    daddi $a0, $zero, OFSTR # print overflow
    jal 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 stack
    sw $ra, ($sp)       # store return address

    daddi $t0, $zero, 8     # t0 = 8
    lw $t1, DATA($zero)     # t1 = 0x10008
    lw $t2, CONTROL($zero)  # t2 = 0x10000
    sw $t0, ($t2)           # CONTROL = 8
    lw $t1, ($t1)           # t1 = DATA
    sw $t1, ($a0)           # M[arg0] = DATA

    lw $ra, ($sp)       # restore return address
    daddi $sp, $sp, 4   # backwards stack
    jr $ra

#   @function printInt  :
#   @param arg0         : value of int to be print
#   @return             : ----
printInt:
    daddi $sp, $sp, -4  # sp -= 4
    sw $ra, ($sp)       # save return address

    daddi $t0, $zero, 2     # t0 = 2
    lw $t1, DATA($zero)     # t1 = 0x10008
    lw $t2, CONTROL($zero)  # t2 = 0x10000
    sw $a0, ($t1)           # DATA = arg0
    sw $t0, ($t2)           # CONTROL = 2

    lw $ra, ($sp)       # restore return address
    daddi $sp, $sp, 4   # sp += 4
    jr $ra              # return

#   @function printStr  :
#   @param a0           : sratr address of string
#   @return             : ----
printStr:
    daddi $sp, $sp, -4      # sp -= 4
    sw $ra, ($sp)           # save return address
    daddi $t0, $zero, 4     # t0 = 4
    dadd $t1, $zero, $a0    # t1 = arg0
    lw $t2, DATA($zero)     # t2 = M[DATA] = 0x10008
    lw $t3, CONTROL($zero)  # t3 = M[CONTROL] = 0x10000
    sw $t1, ($t2)           # M[0x10008] = t1 = arg0
    sw $t0, ($t3)           # M[0x10000] = t0 = 4
    lw $ra, ($sp)           # restore return address
    daddi $sp, $sp, 4       # sp += 4
    jr $ra                  # return

Guess you like

Origin blog.csdn.net/weixin_44176696/article/details/109500195