MIPS multu overflow - mips

As part of a hex to decimal program I'm writing in MIPS using QT spim I load the value of 16^7 (268435456) into a generic register. I then multiply this number by 1-15 depending on the character, add the result to a running total, and divide 16^7 by 16.
However, I encounter what I assume to be overflow issues when multiplying 268435456. For instance, the code
li $t0, 10
li $t1, 268435456
multu $t0, $t1
mflo $t2
li $v0, 10
syscall
Which is intended to multiply 268435456 by 10 and store the result in $t2 stores -1610612736 instead of 2684354560. Any ideas on how to fix this code to store the correct value?

multu is the unsigned version of mult, which means that it is not going to generate an overflow because the result is taken as an unsigned number. When you show the value through a syscall it is taken as a signed number, so the signed value is shown (which in this case is negative).
You didn't give much info regarding what you are trying to achieve, but if you mean to perform a signed multiplication (meaning you want to keep the sign of the result) and store the result in a 32 bit register then you are going to run into limitations. If this is the case you will need to check whether the operation is possible within these bounds before printing the results, meaning you have to check whether the overflow happened:
li $t0, 10
li $t1, 268435456
multu $t0, $t1
mflo $t2
li $t3, 31
srl $t0, $t0, $t3
srl $t1, $t1, $t3
srl $t2, $t2, $t3
xor $t0, $t0, $t1
xor $t0, $t0, $t2
bgtz $t0, noOperationRoutine
li $v0, 10
syscall
noOperationRoutine:
....
The above solution performs a check on the leftmost bit (obtained by shifting right by 31 bits), which is indicative of the sign (1 for negative and 0 for positive). If one and only one of the operands is negative, then the result should be negative. If both are negative or positive, then the result should be positive. I think you can see how the two xors perform this check.
If you want to work with results that are bigger than the maximum size of a signed number then you have to keep in mind that mult stores the low part of the result in LO and the high part in HI. At this point you are going to deal with 64 bits numbers, which occupy two words/registers each.

Related

Trouble sign extending a register in MIPS

Currently I have
lh $t1, 0($t1)
for sign extending $t1 from 16 bit to 32 bits, but this doesn't work. Is there a simple way to sign extend registers in MIPS?
The way I understand your question, even though you had attempted to use lh you actually wanted to sign-extend the halfword value of $t1 rather than the halfword $t1 is pointing to.
You can accomplish this with two shifts:
sll $t1, $t1, 16
sra $t1, $t1, 16
If you started out with 0x8000, you'd get 0x80000000 after the first shift, and 0xffff8000 after the second.
If you started out with 0x7fff, you'd get 0x7fff0000 after the first shift, and 0x7fff after the second.
lh does work but you need to be sure what you're loading from is defined by .half and not .word because of width and little-endian considerations:
main:
la $t5,myhalf
lh $t1,0($t5)
nop
.data
myhalf: .half 0x8000 # this works
# these do _not_
myword: .word 0x80000000
myword2: .word 0x8000

Replacing left logical shifts with other instructions in MIPS

So let's say that we have two registers $s0 and $s1. Register $s0 can take values from 0 to 31 and is used to show how many bits register $s1 will be shifted left. How can i do this without using sll or srl. I know that left logical shift by n bits is the same as multiplying with 2^n. This exercise gives a hint that this can be done with 4 instructions only. Both registers are 32-bit.
You can add $s1 to itself $s0 times (each time it will multiply its value by 2 which shifts its bits left once).
The code would look like this:
beqz $s0, end
loop:
add $s1, $s1, $s1
subu $s0, $s0, 1
bnez $s0, loop
end:
The first conditional branch is to ensure no action is taken to $s1 when $s0 holds value zero.

writing iteration in MIPS

I am writing this program in MIPS to calculate 2 to a power given by me and sum the sequential powers down to 0. For example, if I put 4 in $a0 like in the code below, I want it to calculate (4^2)+(3^2)+(2^2)+(1^2) which should come out to be 15. It should stop before it reaches zero. This is what I have written so far
main:
addi $a0, $zero, 4 #put k in $a0 in this case
addi $a1, $zero, 0 #put 0 in current sum
addi $v1, $v1, 0 #tally the total in $v1
for:
lw $10, $a0 #load k into reg $10
lw $11, $a1 #load sum into $11
addi $10, $10, -1 #subtracts 1 from k
li $9, 0 #sets i in for loop ($9) to 0
done:
li $v0, 10
syscall
I'm new to MIPS and could use a lot of help on finishing this, I know I want to use a for loop, but I don't know how to go through it while subtracting 1 from k and also calculating the sum. How would I bring 2 to a power of k, because I guess there is no power operation in mips. At this point in the course I can only use add, sub, and, or, slt, addi, j, beq, lw, sw, and sll. Can you not use a constant when using sub? Thank you for any help
A power is a multiplication, and a multiplication is a sum. So you can write a function that does a multiplication by adding, and another function that does power by multiplicating. For example, the multiplication function:
multiply: # $a0 first factor, $a1 second factor, $v0 result of multiplication
or $t0, $zr, $zr
or $t1, $a1, $a1
or $t3, $zr, $zr
loop:
beq $t1, $zr, end
add $t0, $t0, $a0
addi $t1, $t1, -1
j loop
nop
end:
or $v0, $t0, $0
jr $ra
nop
(Please note I haven't tested this, and this will not work with negative numbers)
As a side note, you have MUL instruction as well, but I don't know if you saw that already.
I think the concept your instructor is trying to show you is that sll, in effect, multiplies by 2. You've got to think in binary. For example, let's start with 1:
0000 0000 0000 0000 0000 0000 0000 0001
Do a 'sll' on that, and what do you end up with? 0010 = 2. sll again and you get 0100 = 4. And so on, until you shift all the way over and have 0x80000000.
So the answer to the question, "How would I bring 2 to a power of k?", is simpler than you might have thought: you shift 1 by k.
# $t0 contains 'k', the amount we want to shift by
addi $t1, $zero, 1
sllv $t3, $t1, $t0
Note: I had to double-check that you can shift by a variable amount, but this link says sllv is valid. However, since it's not in your list of allowed functions, you'll have to do sll $t1, $t1, 1 in a loop. (Be sure to put your check at the start of the loop, in case the amount you want to shift by is zero!)
Quick question:
Are you doing 2^4+2^3.. etc? or 4^2+3^2 etc?
Just a quick note:
2^4+2^3+2^2+2^1+2^0 = 15.
4^2+3^2+2^2+2^1 != 15.
(If it is the first, you do need 2^0 because you need to contemplate for odd numbers, 2^0 = 1. This is how we get odd numbers in binary.)
In this case, the answer about left shift (lls) is correct. When you left shift a binary number you increase the exponent of base 2 by 1.
so:
0001 = 1
0010 = 2
0100 = 4
1000 = 8
These summed give you 15.
So you could shift left, and add the result of each shift to a register.

MIPS: Integer Multiplication and Division

So I'm building a calculator program in MIPS and I'm trying to write the multiply and divide functions.
Currently I read in the integers in a loop like so:
li $v0, 5
syscall
and then eventually call my functions multi and dividepending on which action the user wants to do.
So assuming I have the integers in $a0 and $a1, what would be a clean way to multiply $a0 by $a1 and/or divide $a0 by $a1? I've been looking around online but I can't find a clean and easy way to do this, because I have to send the resulting answer back in $v0
To multiply, use mult for signed multiplication and multu for unsigned multiplication. Note that the result of the multiplication of two 32-bit numbers yields a 64-number. If you want the result back in $v0 that means that you assume the result will fit in 32 bits.
The 32 most significant bits will be held in the HI special register (accessible by mfhi instruction) and the 32 least significant bits will be held in the LO special register (accessible by the mflo instruction):
E.g.:
li $a0, 5
li $a1, 3
mult $a0, $a1
mfhi $a2 # 32 most significant bits of multiplication to $a2
mflo $v0 # 32 least significant bits of multiplication to $v0
To divide, use div for signed division and divu for unsigned division. In this case, the HI special register will hold the remainder and the LO special register will hold the quotient of the division.
E.g.:
div $a0, $a1
mfhi $a2 # remainder to $a2
mflo $v0 # quotient to $v0

Finding offset from a code snippet

I am a bit stuck up with the following question,
Consider the following MIPS code and answer the questions that follow.
addi $t1, $s0, 400
loop: lw $s1, 0($s0)
add $s2, $s2, $s1
lw $s1, 4($s0)
add $s2, $s2, $s1
addi $s0, $s0, 8
bne $t1, $s0, loop
What value is the label loop translated to in the conditional branch
instruction?
Now I know the mathematical formula for Branch Target Address. But here as memory addressing is not done so I found out the offset by counting the lines between the target address and PC. This gives the answer to be 7 (word offset). Am I right with this approach?
A quick experiment with MARS simulator http://courses.missouristate.edu/KenVollmar/MARS/download.htm gave me the answer-6, -5 for number of lines difference and another -1 because PC is increased by 1 after the instruction.
AFAIK, I'm afraid not.
As MIPS instruction reference says:
An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
is added to the address of the instruction following the branch (not
the branch itself), in the branch delay slot, to form a PC-relative
effective target address.
So as I understand, the distance from the branch instruction to the loop label is negative (because the label is before the branch, thus the address is lower). The distance is calculated in number of words (hence the 2 bits left shift). As all MIPS instructions are 4 bytes, this would be 6 instructions before, hence -6 is the value that should appear in the branch instruction offset (lower half-word). In binary: 1111 1111 1111 1010 (two's complement). In hexadecimal: FFFA.
Checked with simulator and seems that my reasoning is correct since the instruction is coded as 0x1530FFFA.