The following assembly code is given in my text book.
Loop:
sll $t1, $t0, 2
add $t2, $a0, $t1
sw $zero, 0($t2)
addi $t0, $t0, 1
slt $t3, $t0, $a1
bne $t3, $zero, Loop
# return where we were
jr $ra
From this code I have two question to ask.
The first question is about the second line from the top. I get that the instruction sll is shift left logical which shifts bit to the left. Since the shift amount is 2, it will make 0000 -> 0100 = 4 in decimal. But I don't get it after the first loop. If we shift this to the left by 2, isn't it multiplied by more than 4??
And the second question is if it is possible to optimize this code?? In my opinion, I can modify sll and add parts in the code but I am not sure.
Any comment??
Shifting left will insert 0's, not 1's. So 0000 would still be 0000, 0001 will become 0100 after the shift
[is it] possible to optimize this code?
A more compact way of doing the same thing would be:
sll $a1, $a1, 2
addu $a1, $a1, $a0 # $a1 = $a1 * 4 + $a0
Loop:
sw $zero, ($a0)
addiu $a0, $a0, 4
bne $a0, $a1, Loop
I'm making these assumptions:
The original values of $a0 and $a1 are not needed anymore after the loop ends. If they are needed, save the original values somewhere (in other registers or on the stack) before entering the loop, and restore them afterwards.
$t0 starts out at zero. If not, you'll have to add $t0 * 4 to $a0 before the loop. I'm also assuming that the value of $t0 after exiting the loop is irrelevant.
Consider the following binary:
0000 0001
If you shift the bits left by 1 digit you get:
0000 0010
If you shift again to the left by 1 digit:
0000 0100
And again:
0000 1000
The binary values above are equivalent to 1; 1x2=2; 2x2=4; 4x2=8.
Shifting bits to the left is multiplying the value by 2^N if N is the number of bits you are shifting.
Another example of shifting:
Assume $t1 contains 0000 1111
sll $t0, $t1, 3 # $t0 = $t1 * 2^3
Now $t0 contains 0111 1000
You can verify this by performing decimal multiplication. 15 * 8 = 120.
Related
does someone know the translation of this code in c to mips?
I have tried to do it but I don't undertand how to divide or how to do the modulus
d = a – 3 / (b + c + 8);
c = a – 3 % (b + c + 8);
You can make use of these instructions div ,mfhi ,mflo
The hi register contains the remainder of your division operation using the div instruction. In terms of modulo, that's where the modulo value will be saved.
The lo register contains the quotient of your division operation.
.data
#Assign your labels values here, I have put zero as placeholder
a: .word 0
b: .word 0
c: .word 0
.text
# a-3
lw $t0 a #load label value a to register $t0
subi $t0 $t0 3 #subtract them by 3
# b+c+8
lw $t1 b
lw $t2 c
add $t2 $t1 $t2
addi $t2 $t2 8
div $t0 $t2 #divide the value at $t0 by $t2
mflo $t0 #quotient value of div operand will be moved to $t0. Here I'll use d as $t0
#this block is for c = a – 3 % (b + c + 8)
# c= a-3
lw $t1 a
subi $t1 $t1 3
# b+c+8
lw $t2 v
lw $t3 c
add $t2 $t2 $t3
addi $t2 $t2 8
#divide the values computed and stored just now in their respective registers
div $t1 $t2
mfhi $t1 #move hi register value to $t1. That's where the modulo value is stored. $t1 now holds c value
I would assume you're familiar with other instructions in mips so I do not need to explain the addition and subtraction process here
This is boiling my brain, I've just started learn MIPS. The assignment asks us to use loops and maybe even a stack to do a simple multiplication by squaring a three digit number. For the assignment to be correct, the program needs to run for a minimum of 30 seconds doing the same calculation over and over.
Obviously I'm not asking for you to do my assignment (I want to learn), however I'm stumped on how to implement nested loops in MIPS, there isn't much online. I found something on Stack Overflow and tried to implement the same style but it doesn't work. A single loop works fine, it only runs for one second though so its nowhere near close enough. My problem is how to input a second loop really.
Here's my code:
.data
enterNumber: .asciiz "Enter three digit number \n"
.text
main:
addi $t3, $zero, 0
addi $t1, $zero, 0 #counter for second for loop
#asks for number
li $v0, 4
la $a0, enterNumber
syscall
#receives number
li $v0, 5
syscall
move $t0, $v0 #move number to t0
For1:
beq, $t3, $t0, exit #if counter= t0 then loop ends
For2:
beq, $t1, $t0, For1 #if counter= t0 then loop ends
addi $t2, $zero, 0 #resets t2 to 0
mul $t2, $t0, $t0 #multiply number multiplied by number
addi $t1, $t1, 1 #add 1 to counter
j For2 #jump back to the top
addi $t2, $zero, 0 #resets t2 to 0
mul $t2, $t0, $t0 #multiply number multiplied by number
addi $t3, $t3, 1 #add 1 to counter
j For1 #jump back to for loop
exit:
li $v0, 1
move $a0, $t2 #print out multiplication
syscall
#tell system to stop
li $v0, 10
syscall
The program runs through the inner loop (For2) fine, but its not incrementing the outer loop at all. Thanks in advance
The only problem with your code is that everything you've written in the outer loop(For1), after the inner loop (For2) will never be executed, because of the way you've written the conditions in For2. You only need to make a small change to your loops code: make For2 jump to the last part of your For1 loop in case counter = t0 instead of making it jump to For1.
For1:
beq, $t3, $t0, exit #if counter= t0 then loop ends
For2:
beq, $t1, $t0, exit2 #if counter= t0 then loop ends
addi $t2, $zero, 0 #resets t2 to 0
mul $t2, $t0, $t0 #multiply number multiplied by number
addi $t1, $t1, 1 #add 1 to counter
j For2 #jump back to the top
exit2:
addi $t2, $zero, 0 #resets t2 to 0
mul $t2, $t0, $t0 #multiply number multiplied by number
addi $t3, $t3, 1 #add 1 to counter
j For1 #jump back to for loop
You need to make a small change to your loops code.
Make For2 jump to the last part of your For1 loop in case counter = t0 instead of making it jump to For1.
write below code under For1 loop.
For2exit:
addi $t2, $zero, 0 #resets t2 to 0
mul $t2, $t0, $t0 #multiply number multiplied by number
addi $t3, $t3, 1 #add 1 to counter
j For1 #jump back to for loop
and make change in the for2. make it jump to For2exit rather to For1.
Im trying to get the number of 1's on the left side (bits 16-31) This code seems to work but im getting 1 extra count on my 1's from certain integers.
For example:
1536 in binary is 0000 0000 0000 0000 | 0000 0110 0000 0000
and im getting 0 1's on the left side which is correct.
Also:
100000 left side binary is 0000 0000 0000 0001
and my result is 1. which is also correct.
However:
1000000000 in binary is 0011 1011 1001 1010 | 1100 1010 0000 0000
and im getting 10 1's on the left side instead of 9.
Ive tested other numbers as well but they also have an extra count.
#Displays number of 1's on left half
li $v0, 4
la $a0, left
syscall
li $t2, 0 #i = 0
srl $t3, $s0, 16 #shifts users number to the right by 16 bits
Counter:
and $t4, $t3, 1 #Mask off bit
beq $t4, 1, Count #if mask = 1 go to count
srl $t3, $t3, 1 #if mask != 1 (aka 0) shifts right by 1
beq $t3, 0, Exit #once the shifted bits = 0 go to exit
Count:
add $t2, $t2, 1 #increment i++
srl $t3, $t3, 1 #shifts right by 1
j Counter
Exit:
li $v0, 1 #Displays number of 1's
move $a0, $t2
syscall
Not sure if the code is even correct since im new to mips. Could be possible that the whole thing is wrong.
You may use clz/clo to count the number of leading zeros and ones, and use that to count the number of ones. The idea is to consume the leading zeroes, then count the leading ones (shifting those bits out of the register) until the input data is zero.
i.e.:
li $t1, 0x4F044321 % $t1 Input number
srl $t1, $t1, 16
sll $t1, $t1, 16 % Discard least significant bits
li $t2, 0 % $t2 will hold number of 1s
count:
beqz $t1, done
clz $t3, $t1
sllv $t1, $t1, $t3
clo $t3, $t1
addu $t2, $t2, $t3
sllv $t1, $t1, $t3
b count
done:
This is part of my code, and I don't know why, $t1 always ends up with 10, when it should be 16. At this point, the data is the following:
$t5 = 4
$t3 = 1
$t2 = 0
and $t1 is 0
(and $t0 is an address)
This is the part of the code:
mul $t1, $t3 , $t5
add $t1, $t1, $t2
mul $t1, $t1, 4
**From here, $t1 should be 16, but it always turns out 10 even if I do li $t1, 16****
add $t1, $t1, $t0
lw $t6, ($t1)
I'm using MIPS 32 with QTSpim
If you set registers->Decimal, the result will be 16. I guess, going from the information you give.
I have this code that goes through an array of 5000 ASCII values of characters and then counts the number of each character and stores it into an array in alphabetical order.
.text
la $s7,results
array1 is the array of 5000 ASCII characters
la $s6,array1
main:
addi $s0,$zero, 5000
addi $s3, $zero,96
addi $s4, $zero,65
loop:lw $s2,0($s6)
addi,$t1,$zero,0
addi $s6,$s6,4
addi, $s5,$zero, 0
addi $s0,$s0, -1
bge $s2, $s3, convert
The substaction of of $s2, - $s4($s4 is # )is to get the positon of where the count needs to be stored
ex F - # = 6
sub $s5, $s2, $s4
I was wondering if this was right for it getting to the correct position and to increment the count?
addi $t1, $t1, 1
loop2: addi $s7, $s7, 4
lw $t0,($s7)
add $t0, $t0, $t1
sw $t0,($s7)
addi, $s5,$s5, -1
beq $s5, $zero, loop2
bne $s0,$zero, loop
This converts the character to an upper case ASCII value.
convert: subi $s2,$s2, 32
addi $s5, $s5, 0
sub $s5, $s2, $s4
j loop2
.data
results: .space 128 # Words to be used to store results