MIPS32 Multiplication of Three 32-bit Integers - mips32

I am trying to write a MIPS32 program that will multiply three numbers together. For example: (A * B * C) where A, B, and C are 32 bit signed numbers.
I know from this link that I need to do the following to multiply A*B (assume A is stored in $s0, B is stored in $s1, and C is stored in $2):
mult $s0, $s1
mfhi $t0
mflo $t1
If I am assuming my result of the multiplication of A * B is 64 bits, how do I calculate the result of (A * B) with C?

Related

Fibonacci Function in RISC V

Implementing the fibonacci function using RISC - V, so that f(0) = 0 ,
f(1) = 1, ..., up to f(47).
My output matches everything up to 46. But when i try to calculate f(47) i get: -1323752223.
Here's the output:Output from Code below with n=47
Is there some sort of Overflow because i get a negative Integer value? Where should i look into to try and fix the error?
.data
n: .word 47
.text
.globl main
main:
li x2, 0 # Used to determine if n (x7) equals 0
li x3, 1 # Used to determine if n (x7) equals 1
li x5, 0 # First number
li x6, 1 # Second number
lw x7, n # Limit
li x8, 1 # Counter
beq x7, x2, DO # If n == 0 then jump to DO (Which shoud print 0). Implements f(0) = 0
beq x7, x3, WRITE # if n == 1 then jump to WRITE (Which should print 1). Implements f(1) = 1
LOOP: beq x8, x7, EXIT # Comparse the counter x8 which starts with 1 to n (limit). If x8 == x7 jump to EXIT
add x4, x5, x6 # Add x5 to x6 and store in x4
ori x5, x6, 0 # Assign the second number to my first number
ori x6, x4, 0 # Assign the sum of x5 and x6 to my second number
addi x8, x8, 1 # Add 1 to my counter
j LOOP # Jump to loop
EXIT:
li x17, 1 # Load constant 1 to x17
add x10,x4,x0 # Add x4 (which contains the result after the above coe) to x10
ecall # Issue an SystemCall which prints an integer (Because of the 1 in x17)
li x17, 5
ecall
li x17, 10
ecall # Reads an int from input console (Because of the 10 in x17)
DO:
li x4, 0 # load 0 in x10 (x10 will be used by the SysCall to print) and print
add x10,x4,x0
li x17, 1
ecall
li x17, 5
ecall
li x17, 10
ecall
WRITE: li x4, 1 # load 1 in x10 and print
add x10,x4,x0
li x17,1
ecall
li x17, 5
ecall
li x17, 10
ecall
Yes, you have found the boundary of what signed 32-bit integers can hold.
fib(47) = 2971215073 won't fit in 32-bit integers as signed, but will fit as unsigned — however, RARS does not have an "unsigned int" print function.
fib(48) = 4807526976 won't fit in 32-bit form, even as unsigned.
List of fibonacci numbers:
https://www.math.net/list-of-fibonacci-numbers
If you want to represent larger numbers, you will need a strategy.
if precision is not important, you can switch to floating point, where the results with such large numbers will be inexact.
use two integers together for 64-bit arithmetic — you'll be good up to fib(92) = 7540113804746346429.
use variable length integers for precision limited only by computer memory and compute time
a complex combination of the above
And finally, you can detect and issue an error on overflow of your chosen arithmetic data type.  Overflow detection on RISC V is somewhat simple but not really obvious.
Technically, addition of 2 arbitrary 32-bit numbers results in a 33 bit answer — but no more than 33 bits, so we can use that knowledge of math in detecting overflow.
First, in a 32-bit number the top bit is either the sign bit (when signed data type), or the magnitude bit (when unsigned data type).
If you add two positive numbers (as is the case with fib) and the sign bit is set, you have signed overflow — but a proper bit pattern, if interpreted as unsigned.  However, you won't be able to print the number properly using the ecall #1, because it will print the number as signed and interpret as negative.  You can write your own unsigned number print; you can also look for this case and simply stop the program from printing and issue an error instead.
Going beyond that you can check for overflow in 32-bit unsigned addition by seeing if the resulting value is less than one of the input operands.
The last approach is also used in multiword addition to make a carry from the lower word(s) to higher word(s).

How to count the number of cycles in code by hand?

We are learning pipeline processing and I have an exercise, where I have to count the number of cycles a MIPS code runs for - by hand. We have the following code in C and MIPS:
0. for (i=0; i<10; i++)
1. som = som + a[i];
0. add $t0, $zero , $zero
1. L:
2 sll $t1 , $t2, 2
3 add $t1 , $a0 , $t1
4 lw $t1, 0($t1)
5 add $v0, $v0, $t1
6 slti $t2, $t0, 9
7 addi $t0, $t0, 1
8 bne $t2, $zero, L
9 nop
The code inside the loop has 7 instructions and it is executed 10 times, therefore we get 70 cycles. Then we have a stall cycles in line 5 because of the load use hazard on $t1. Again the code runs 10 times, thus an additional 10 cycles. In total we now have 80 cycles. Because of the bne, we have 9 flushes (not 10 because after 9 we don't come back down). Therefore, now we have 89 cycles. We then have 1 cycle for the one NOP and 1 cycle for the initialisation of the variable i. This gives us a total of 91 cycles. In the MIPS reference sheet, it says to always add 4, because of the first line of code, thus bringing our total to 95 cycles.
Assuming I'm right, which I should be, is there a faster way to count the number of cycles in any MIPS code? I could use the equation CPI = # of cycles / clock rate but assuming we're not given that information and only have the given code, is there a way? I found that if you use the following equation, you get the right answer for the given code.
# of cycles = 4 + # of instructions x (# of pipeline levels - 1) + # of NOPs
However, I'm not sure if this works in general or I got lucky with my specific example. BTW - # refers to the number of.

MIPS overflow logic

Good evening. I am trying to figure out how to determine if an integer qualifies 16 bit integer in MIPS.
I understand that 2^15-1 =32767 or 2^(16-1)-1=32767 and that we want 16 bit values for binary number. Anyway, I am trying to determine if an integer passes the test. I wrote this:
addi $s3, $zero, 32767
bgt $t2, $s3, else #branch to else if t2>s3
move $v0, $t2 #if no overflow; place t2 in v0
addi $v1, $zero, 0 #if no overflow; place zero in v1
else:
addi $v0, $zero, 0 #if overflow; place 0 in v0
addi $v1, $zero, -1 #if overflow; place -1 in v1
Anyway, There's a problem with my logic when I try and evaluate negative numbers. I have assignment due tomorrow. I am learning MIPS programming. I am not a programming snob so any helpful advice is appreciate. Thank you for your time.
This is too late for you assignment1.
It's a bit unclear whenever you want to test a) if a number N encoded as a 32-bit two's complement number can be also encoded as a 16-bit two's complement number or if you want to test b) if a 32-bit number can be encoded as a 16-bit number.
In the case of b) you just need to test if any bit higher than the 16th is set:
#Assume $t0 is the number to test
lui $t1, 0xffff #$t1 = 0xffff0000
and $t1, $t1, $t0 #$t1 is zero if all higher bits of $t0 are zero
beq $t1, $0 fits16bits #Jump to label if fits
#Here the number doesn't fit 16 bits
For the case a) the key is to understand that just like the number 0x00f1 and the number 0x0000000f1 are the same, the leading zeros are not significant, the number 0xffff and the number 0xffffffff are the same number in two's complement (the number -1).
To extend a 16-bit two's complement number to 32-bit we need to perform a sign extension, i.e. replicate the most significant bit (the sign bit) of the original number in the upper 16 bits.
So 0x7fff becomes 0x00007fff, 0xc000 becomes 0xffffc0000.
A simple way to test that all the upper 17 bits are equal is to shift them right arithmetically so that if they actually are equal we end up with 0x00000000 or 0xffffffff.
sra $t1, $t0, 15 #Shift right 16 bits duplicanting the MSb
beqz $t1, $0, fits16bits #Jump to label if fits (All zero)
addiu $t1, 1 #Add 1
beqz $t1, $0, fits16bits #Jump to label if fits (Before +1 was all ones)
#Here the numbers doesn't fit
1 Maybe it's better this way.

Memory Access in MIPS assembly language

I got this question on a midterm, and I want to know what the right answer is.
Here is the question:
Let x[] be an array of integers and k be an integer. suppose that the memory address of x and k are specified by the two labels "x" and "k" respectively. implement the following statement in the mips assembly language x[4] = x[5] +k
Here is my attempt of answering, and i only got half mark:
//addresses of x, k, 4, and 5
la $s0, x
la $s1, k
li $s2, 4
li $s3, 5
//assume $s1 = x[4] and $s2 = x[5]
la $s3, k
add $s1, $s2, $s3 //x[4] = x[5] + k
the feedback said i should have lw and sw but i'm not sure what to do with them.
Assuming an "integer" means a 32-bit word size, x[4] is at address (x+16) and x[5] is at address (x+20).
You were probably supposed to do something like this :
la $s0, x
la $s1, k
lw $s2, 0($s1) ; Get "k" from its memory location
lw $s3, 20($s0) ; Get "x[5] from its memory location
add $s2, $s2, $s3 ; Compute k + x[5]
sw $s2, 16($s0) ; Store result at location "x[4]"

Using a random number generator in MIPS?

So I was reading a few threads on this site and I found one on how to make one..
But I can't really find a link that explains more about how to code it..
My textbook for the course didn't provide any information about RNG at all so no help there.
The code was
li $a1, 4
li $v0, 42
add $a0, $a0, 1
is this correct for asking for a range between 1-3?
I tried outputting what random number it was but it gave me the same number constantly.
#sw $a0, 0($s0)
li $a1, 4
li $v0, 42
add $a0, $a0, 1
#syscall
li $v0, 4
la $a0, Checking
syscall
li $v0, 1
move $t0, $a0
syscall
I saw the sw $a0, 0($s0) but I'm not sure what that does -- is it needed to output? (I took it out because after I pushed a key to go to the RNG, it said the program crashed)
I keep getting the output of 268501267 which I'm not sure what that means
edit: now it started giving me 268500992 all the time
Can anyone help explain this a little more in depth?
Logically speaking -- I understand the where the 42 comes from and why I need to add +1 (This is so I won't get the value of 0)
From there, I have no clue on why the code won't output a number in the range I gave.
As stated by MARS documentation (in the GUI Help > Syscalls):
random int 41 $a0 = i.d. of pseudorandom number generator (any int).
$a0 contains the next pseudorandom, uniformly distributed int value
from this random number generator's sequence
So
li $v0, 41 ; Service 41, random int
li $a0, 0 ; Select random generator 0
syscall ; Generate random int (returns in $a0)
li $v0, 1 ; Service 1, print int
syscall ; Print previously generated random int
Works fine for me, every time a different number is printed.
You don't need to initialize or seed a random stream before using it, you can just use stream 0.

Resources