So I am new to MIPS and I wanted to implement simple modulo arithmetic functions. I am unable to see why the program is not jumping according to the jump statements in the code. Any help would be appreciated.
.data
text_enquiry : .asciiz "Enter operation code (1-add, 2-subtract, 3-multiply, 4-exponentiation, 5-inversion, 6-exit): "
text_a : .asciiz "Enter a: "
text_b : .asciiz "Enter b: "
text_m : .asciiz "Enter m: "
text_result : .asciiz "Result = "
new_line : .asciiz "\n"
.text
main:
## t0 = code, t1 = a, t2 = b, t3 = m
#print operation message
la $a0, text_enquiry
li $v0, 4
syscall
#read code
li $v0, 5
syscall
move $t0, $v0
#if code == 6
beq $t0, 6, exit
j rest
exit:
li $v0, 10
syscall
#else, continue procedure
#print 'a, b, m' messages and read them
rest:
la $a1, text_a
li $v0, 4
syscall
li $v0, 5
syscall
move $t1, $v0
la $a1, text_b
li $v0, 4
syscall
li $v0, 5
syscall
move $t2, $v0
la $a1, text_m
li $v0, 4
syscall
li $v0, 5
syscall
move $t3, $v0
j mod
## t0 = code, t1 = a, t2 = b, t3 = m, t4 = un-modded result, t5 = modded result, t6 =
mod:
beq $t0, 1, func_add
beq $t0, 2, func_sub
beq $t0, 3, func_mul
# beq $t0, 4, func_exp
func_add:
add $t4, $t1, $t2
div $t4, $t3
mfhi $t5
#print accordingly
la $a3, text_result
li $v0, 4
syscall
move $a3, $t5
li $v0, 1
syscall
la $a3, new_line
li $v0, 4
syscall
j main
func_sub:
sub $t4, $t1, $t2
div $t4, $t3
mfhi $t5
#print accordingly
la $a3, text_result
li $v0, 4
syscall
move $a3, $t5
li $v0, 1
syscall
j main
func_mul:
mult $t1, $t2
mflo $t4
div $t4, $t3
mfhi $t5
#print accordingly
la $a3, text_result
li $v0, 4
syscall
move $a3, $t5
li $v0, 1
syscall
j main
As you can see, the code works fine when the code is '6' but doesn't work for any other code value.
I am unable to see why the program is not jumping according to the jump statements in the code. Any help would be appreciated.
Your program is jumping according to the input.
What you are unable to see is what it really does and why your further text output fails, and you are unable to see that, because you didn't even look (in debugger, single-stepping over every instruction).
Would you take a look, you would clearly see that for example for input "3", the code will reach instruction after label rest:, so the branching is correct.
That code later is not doing what you expect, because it doesn't print the other helper prompts, because it is calling syscall with wrong arguments (the code sets a1 with string address, instead of a0, and in a0 is still the original operation-prompt address), but it is executed as planned.
Generally deciding on assembly code correctness only by checking input/output is very bad practice, as you can often have correct output "by accident", while the code is already doing also something different than planned, which may just bite you later, if you keep extending your code, or if you use different inputs.
To decide if your assembly code is correct, you should rather spend quite some time in debugger, verifying different inputs, and thinking how the code works and if really works as planned/assumed, while you were writing it - on per-instruction basis!
The final code should consist only of instructions which you know exactly what they are doing, and why they are part of the code, and why they are placed where they are. If anything works "by accident" without you truly understand it, you must fix it (either by understanding how it works, or by rewriting it in a way you understand how it works), it's still bug, even if the output is correct.
Related
This is the C++ code I am trying to convert to MIPS with
int count_painted(int *wall, int width, int radius, int coord) {
int row = (coord & 0xffff0000) >> 16;
int col = coord & 0x0000ffff;
int value = 0;
for (int row_offset = -radius; row_offset <= radius; row_offset++) {
int temp_row = row + row_offset;
if (width <= temp_row || temp_row < 0) {
continue;
}
for (int col_offset = -radius; col_offset <= radius; col_offset++) {
int temp_col = col + col_offset;
if (width <= temp_col || temp_col < 0) {
continue;
}
value += wall[temp_row*width + temp_col];
}
}
return value;
}
and this is my code I wrote below. I want to know how to make sure my program is accurate, readable and efficient with usage of registers.
.globl count_painted
count_paint:
#think about moving variables initialized inside to within the for loop
#initializes all variables
li $v0, 0 # int value = 0
li $t0, 0 # int row = 0
li $t1, 0 # int col = 0
li $t2, 0 # int i = 0
li $t3, 0 # int row _offset = 0
li $t4, -1 # negative one to multiply with row_offset
li $t5, 0 # int temp_row = 0
li $t6, 0 # int col_offset = 0
li $t7, 0 # int temp_col = 0
andi $t0, $a3, 0xffff0000
srl $t0, $t0, 16 # now int row = (coord & 0xffff0000) >> 16 (double check this...prob need a temp register to store before modifying both)
andi $t1, $a3, 0x0000ffff # now int col = coord & 0x0000ffff
mul $t3 , $a2, $t4. # row_offsett = -1 * radius
mul $t6 , $a2, $t4. # col_offsett = -1 * radius
#for loop 1
count_paint_for_loop_one:
bgt $t3, $a2, count_painted_end # if row_offset > radius (bgt since it can only be greater)
add $t5, $t0, $t3 # int temp_row = row + row_offset;
sle $t9, $a1, $t5 # returns 1 if width <= temp_row is true
slt $s2, $t5, 0 # returns 1 if temp_row < 0 is true
or $t9, $t9, $s2 # or the result of the 2 if statment functions
bgt $t9, 0, count_paint_for_loop_one_iterator #if 1 > 0 then condition is true and we iterate and then loop
j count_paint_for_loop_two
#iterator
add $t3, $t3, 1 # adds 1 to row_offset i.e iterates for loop
#dont forget to do the ++ for all iterators
count_paint_for_loop_two:
bgt $t6, $a2, count_paint_for_loop_one # if col_offset > radius (bgt since it can only be greater)
add $t7, $t1, $t6 # int temp_col = col + col_offset;
sle $s3, $a1, $t7 # returns 1 if width <= temp_colis true
slt $s4, $t7, 0 # returns 1 if temp_col < 0 is true
or $s3, $s3, $s4 # or the result of the 2 if statment functions
bgt $s3, 0, count_paint_for_loop_two_iterator #if 1 > 0 then condition is true and we iterate and then loop
#bgt $a1 $t7, count_paint_for_loop_one #if statement with or inside (for loop 2)
#bge $t7, 0, count_paint_for_loop_one
#
mul $t8, $t5, $a1 # multiplies temp_row and width and stores in $t8
add $t8, $t8, $t7 # adds the product of temp_row and width and adds it to temp_col and stores it in temp register $t9
#t8 is index for wall array
#ran out of temp registers use saved registers
sll $s0, $t8, 2
add $s0, $a0, $s0
lw $s1, 0($s0) # $s1 contains wall[temp_row*width + temp_col]
add $v0, $v0, $s1
add $t6. $t6, 1 # adds 1 to col_offset i.e iterates for loop
j count_paint_for_loop_two # restarts inner for loop
count_paint_for_loop_one_iterator:
add $t3, $t3, 1 #iterate through loop
j count_paint_for_loop_one
count_paint_for_loop_two_iterator:
add $t6, $t6, 1 #iterate through loop
j count_paint_for_loop_two
count_painted_end:
jr $ra # returns value
I use up all the t registers and I was forced to use s registers to store temp variables and I was hoping to learn a more useful method of writing my MIPS code
I am new to using the stack and functions in MIPS, for an assignment we are translating a c++ program into MIPS in order to learn how functions work. My problem is translating this c++ code into MIPS, intArr[valsToDo - i] = GetOneIntByVal(entIntPrompt);.
I will show what I have so far but keep getting address out of range error.
# intArr[valsToDo - i] = GetOneIntByVal(entIntPrompt);
addi $a0, $sp, 41
jal GetOneIntByVal
sw $v0, 41($sp)
lw $a1, 77($sp)
sub $a3, $t1, $t1 #$a3 has valsToDo - i
sll $a3, $a3, 2 #$a3 has (valsToDo - i) * 4
add $a3, $a3, $a1 #$a3 has &intArr[valsToDo - i]
lw $a2, 0($a3) #$a2 has intArr[valsToDo - i]
What am I doing wrong?
I'm trying to do a mips interactive exercise (BubbleSort). I have to read 20 integers from the user and store them into an array,then sort the array with the method of BUBBLESORT.
I have a problem with storing the integers into the array.
Here is a bit of my code:
.data
prompt:.asciiz "enter the integer one by one \n "
.text
addi $sp,$sp,-88 #space on the stack
lui $s0, 0x0040 #s0=adress of array
sw $s0,-84($sp) #store s0 on the stack
sw $ra,-80($sp) #store ra on the stack
readInt:
#prompt the user
li $v0, 4 #op code to print string
la $a0, prompt
syscall
#get the array's integer
addi $t0,$zero,0 #t0=compteur
addi $a1,$zero,80 #a1=size of array*4 (20 int)
move $a0,$s0 #a0= adress of array
loop:
beq $t0,$a1,BubbleSort #if t0 = size of array ==>BubbleSort
li $v0,5 #opcode to read int
syscall
**sw $v0,0($a0)** ERROR HERE !!!! :(
addi $a0,$a0,4 #increment a0 (next int)
addi $t0,$t0,4 #incrementer t0 (counter +=4)
j loop
I'm trying to convert a function I wrote in C++ into MIPS. The function tests whether a char array is a palindrome, a string that is symmetric in its characters (ex: "heeh" and "gtrertg" are palindromes, "hey" is not). In MIPS, the string is being passed through $a0 and the return value should be passed in $v0. This is my C++ code:
#include <iostream>
using namespace std;
int palindrome(char s[])
{
int j;
j = 0;
int i;
i = -1;
//finding length of string...
while(s[i+1] != '\0')
{
i++;
}
//while the two opposite chars are equal...
while(s[j] == s[i])
{
//if the chars are at the same index...
if(i == j)
{
//palindrome
return 1;
}
//if the left index passes the right index...
if(j > i)
{
//palindrome
return 1;
}
//increment left index
j++;
//decrement right index
i--;
}
//not palindrome
return 0;
}
I have tested my C++ code and it works just fine. This is my MIPS code:
#$a0 contains the address of the string
.data
.text
.globl palindrome
palindrome:
li $t0, 0 #j = 0
li $t1, -1 #i = -1
addi $t2, $a0, 0 #a[0]
L1:
addi $t2, $t2, 1 #a[i + 1]
addi $t1, $t1, 1 #i++
bne $t2, $zero, L1 #exit loop when '\0' is found
add $t2, $a0, $t0 #a[j]
add $t3, $a0, $t1 #a[i]
L2A:
bne $t1, $t0, If2 #if i does not equal j jump to next if
j Return1 #jump to Return1 label
If2:
ble $t1, $t0, L2B #if j<= i, skip if statement
j Return1 #jump to Return1 label
L2B:
addi $t0, $t0, 1 #j++
addi $t1, $t1, -1 #i--
beq $t2, $t3, L2A #exit loop when a[j] != a[i]
Return1:
addi $v0, $zero, 1 #return 1
j Exit
Return0:
addi $v0, $zero, 0 #return 0
j Exit
Exit:
jr $ra #return
I'm getting an error in my first loop when determining the size of the string when checking for the \0 character. Can someone help? Also, I have to convert the characters of the string into the same case. Would I need another loop in the beginning to go and check for their int ASCII representation and increment or decrement it by a certain number depending on the case? If you see any other mistakes, including conventional mistakes, please point them out. The file that tests the palindrome file has been error checked and works as it should.
hello everyone i need some help converting the following C code into MIPS:
main()
{
int i;
for (i=0;i<5;++i)
power(2,1)
factorial(i)
return 0;
}
int power(int base,int n)
{
int i,p;
p=0;
for(i=1;i<=n;++i)
p=p*base;
return p;
}
int factorial(int a)
{
if(a==1)
return 1;
else
{
a *=factorial(a-1);
return a;
}
}
i have only done the factorial part so far but i'm stuck at a*=factorial(a-1), i under stand that multi is used to multiply two registers together but how can it take the input of a recursive loop? also is it possible to multi to multiply with a constant instead of another register?
factorial:
addi $sp, $sp, -8 #adjust stack for 2 items
sw $ra, 4($sp) #save return address
sw $a0, 0($sp) #save argument
bne $a0, 1, Else #if !(a==1), go to else address
addi $v0, $zero, 1 #result is 1
addi $sp, $sp, 8 #pop 2 items from stack
jr $ra #return
Else: addi $a0, $a0, -1 #decrement s-1
jal factorial #recursive call
lw $a0, 0($sp) #restore original a
lw $ra, 4($sp) #and return address
addi $sp, $sp, 8 #pop two items from stack
Here is a code that I wrote, I think it will fit your purpose.
.text
factorial:
li $t0,13 # load 13 to check for overflow
blt $a0,$t0,no
li $v1,1
no:
bgtz $a0,find # if $a0>0 goto generic case
li $v0, 1 # base case, 0! = 1
jr $ra
find: sub $sp,8 # make room for $s0 and $ra
sw $s0,($sp) # store argument $s0=n
sw $ra,4($sp) # store return address
move $s0, $a0 # save argument
sub $a0, 1 # factorial(n-1)
jal factorial # v0 = (n-1)!
mul $v0,$s0,$v0 # n*(n-1)!
lw $s0,($sp) # restore $s0=n
lw $ra,4($sp) # restore $ra
add $sp,8 # reduce stack size
jr $ra # return
main:
la $a0,input
li $v0,4
syscall
li $v0,5
syscall
move $a0,$v0
jal factorial
move $t0,$v1
bnez $t0,overflow1
move $a0,$v0
li $v0,1
syscall
b end
overflow1:
la $a0,overflow
li $v0,4
syscall
end:
li $v0,10
syscall
.data
input:.asciiz"Input a number:"
overflow:.asciiz"There is an overflow!!"
It's complete with comments and explanations so there shouldn't be problems.