How to debug a MIPS code? Affectation issues [closed] - debugging

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am trying to replicate this Java function in MIPS:
static int gmul(int a, int b) {
int p = 0;
for (int i = 0; i < 8; i++) {
if ( (b & 1) == 1) p = p ^ a;
a = a << 1;
if ( a > 255 ) a = a ^ 283;
b = b >> 1;
}
return p ;
}
I have this MIPS code:
.data
demanda:
.asciiz "Enter a first number"
demandb:
.asciiz "Enter a second number"
.text
main:
la $a0, demanda
li $v0, 4
syscall
li $v0, 5
syscall
move $t2, $v0
la $a1, demandb
li $v0, 4
syscall
li $v0, 5
syscall
move $a1, $v0
move $a0, $t2
li $v0, 0 # this is p in the java version
li $t0, 0
jal for
li $v0, 1 # Print p
syscall
li $v0, 10
syscall
for:
bge $t0,8,finfor # if i>=8
addi $t0, $t0, 1 # Incrementation
andi $t2, $a1,1 # Preliminary condition calculation: (b & 1) == 1 in Java
beq $t2,0, bEven # if ( (b & 1) == 1) in java
xor $v0, $a0, $v0 # Execution p = p ^ a in Java
bEven:
sll $a0, $a0, 1 # Execution a = a << 1 in java
blt $a0,256, aSmall # if ( a > 255 )
xori $a0, $a0, 283 # Execution a = a ^ 283 in Java
aSmall:
srl $a1, $a1, 1 # Execution b = b >> 1 in java
j for
finfor:
jr $ra
I think the formulas are OK, as the program runs, but it does not returns p as expected. It seems that it rather return a (which is in $a0), which I don't understand as I have put p in $v0 and try to print this one.
But it is not the first time I am struggling with registers and affectations in MIPS.
Any help is welcome and thanks in advance.

Found it. The trick in MIPS is that the print out command li $v0, 1 can override the value that you may want to print in $v0, that was my mistake. The work around is to store the data in another register first:
move $a2, $v0
...
move $a0 $a2
li $v0, 1
syscall
Or preferably, not using $v0 for the variable you need to handle.
And the step by single-step functionality really helps to find out mistakes.

Related

MIPS find end of string

I have the following mips code (running it in QTSPIM), that is supposed to count the number of characters in a string and print them.
The logic behind it is very simple but is does not work as it should. Everything goes well until it reaches the end of the string and then it continues counting even though I compare each element to $zero to find the end of string (\0).
Is there something wrong with my condition to exit the loop, or my_string does not contain \0 in the end so it won't exit?
.data
endl: .asciiz "\n"
my_string: .asciiz "thisisastring"
star: .asciiz "*"
str_end: .word 0
space: .asciiz " "
.text
.globl main
main:
la $a0, my_string
li $v0, 4
syscall
la $a0, endl
li $v0, 4
syscall
la $t0, my_string # load mystring to $t0
li $t1, 0 # make $t1 = 0, character counter
lb $t2, ($t0) # make $t2 point to the first character of "my_string"
li $t3, 1 # $t3 is the ++ register to go to the next character
li $t4, 0 # character counter
la $t5, str_end
cont:
beqz $t0, print # if \0 is found print and exit
addi $t4, $t4, 1 # increase the counter
lbu $a0, ($t0) # print current character
li $v0, 11
syscall
addi $t0, $t0, 1 # go to next char
#move $t2, $t0
j cont
print:
move $a0, $t4
li $v0, 1
syscall
j exit
exit:
li $v0, 10
syscall
The problem is in the order of the instructions, the logic of the code.
Here is the corrected version with no redundant code:
.data
endl: .asciiz "\n"
my_string: .asciiz "thisisastring"
str_end: .word 0
.text
.globl main
main:
la $a0, my_string
li $v0, 4 # print the string
syscall
la $a0, endl # print endl
li $v0, 4
syscall
la $t0, my_string # load mystring to $t0
li $t1, 0 # make $t1 = 0, character counter
lb $t2, 0($t0) # make $t2 point to the first character of "my_string"
la $t5, str_end
cont:
lb $a0, 0($t0) # print current character
beqz $a0, print # if \0 is found print and exit
addi $t1, $t1, 1 # increase the counter
addi $t0, $t0, 1 # go to next char
li $v0, 11
syscall
j cont
print:
move $a0, $t1
li $v0, 1
syscall
j exit
exit:
li $v0, 10
syscall

write russian peasant multiplication with mips

i want to write a program that use russian peasant multiplication with mips but i face some problems
/ A method to multiply two numbers using Russian Peasant method
unsigned int russianPeasant(unsigned int a, unsigned int b)
{
int res = 0; // initialize result
// While second number doesn't become 1
while (b > 0)
{
// If second number becomes odd, add the first number to result
if (b & 1)
res = res + a;
// Double the first number and halve the second number
a = a << 1;
b = b >> 1;
}
return res;
}
I translated it in mips with MARS environment
.data
msg1: .asciiz "give your first number"
msg2: .asciiz "give the second number"
.text
#a = $t1
#b = $t2
li $t3,0 #p
li $s1,1
li $s2,2
#display msg1
li $v0,4
la $a0,msg1
syscall
#read first number
li $v0,5
syscall
move $t1,$v0
#display msg2
li $v0,4
la $a0,msg2
syscall
#read second number
li $v0,5
syscall
move $t2,$v0
WHILE:
bgt $t2,$zero,DO
move $a0,$t3
li $v0,1
syscall
li $v0,10
syscall
DO:
div $t2,$s2
mfhi $s0 #r $s0 = $t2 / $s2
beq $s0,$s1,INC # IF b MOD 2 = 1 I jump to INC
#a = 2xa
mul $t1,$t1,$s2
div $t2,$s2
mflo $t2 # b = $t2/$s2
j WHILE
# i = i+ 1
INC:
add $t3,$t3,$t1
jr $ra
please , someone could help me ?
to fix "Error in : invalid program counter value: 0x00000000"
i searched how to fix it but i have a problem with $ra
how to save propertly the return address in $ra ?
the jr $ra will jump to the address stored in register $ra, which was not set by your code, so it is still zero (initial register value from MARS before running your code). The CPU will then jump to address zero, which is failure, and reports that.
To use jr $ra to "return" from some code, you have to first use jal instruction (or other instruction modifying $ra content) to set up $ra. Also when you want to nest several jal "subroutines calls", you have to store/restore the $ra of the outer calls around to not lose the value by the next nested jal.
Following code is example of both using paired jal+jr $ra for "subroutine"-like call, and also example how straightforward the implementation of such algorithm is in assembly (because actually that C source is more like assembly in C, so your inexperience made you take a very convoluted and complex approach of something what can be implemented in assembly almost 1:1 with the original C source):
.text
main: # just minimal "main" to verify the code works
# read two integers as input
li $v0,5
syscall
move $a0, $v0 # $a0 = a
li $v0,5
syscall
move $a1, $v0 # $a1 = b
# call the russianPeasant subroutine
jal russianPeasant # $v0 = a * b
nop
# output result
move $a0, $v0
li $v0, 1
syscall
# terminate
li $v0, 10
syscall
And the subroutine itself, which can be called with arguments in a0 and a1 and returns result in v0.
# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant:
li $v0, 0 # res = 0
beq $a1, $zero, russianPeasant_b_zero
nop # neutralize "Delayed branching" setting ("nop" works with both ON/OFF setting)
russianPeasant_while_b:
andi $at, $a1, 1 # test if b is odd, for even b skip the res = res + a
beq $at, $zero, russianPeasant_b_even
nop # but such neutralization comes with performance cost of course
add $v0, $v0, $a0 # res = res + a
russianPeasant_b_even:
sll $a0, $a0, 1 # a = a << 1
srl $a1, $a1, 1 # b = b >> 1
bne $a1, $zero, russianPeasant_while_b # repeat when (b != 0)
nop # on real MIPS production code the instructions are reordered to avoid useless nop
russianPeasant_b_zero:
jr $ra # return res
nop
The code is intentionally putting after each branch nop instruction to make it work with both delayed branching setting ON or OFF.
Try to use MARS help (F1) with instruction description to figure out, how it works, also use the single-step feature of the debugger to watch out the code in action, one instruction at time, observing all the register values and code flow.
On real MIPS CPU with the delayed branching the code can be optimized like this (you can switch "Delayed branching" ON in MARS settings to make it simulate real MIPS CPU with this somewhat confusing behaviour .. from your original source it looks like you are learning the MIPS assembly without delayed branching, which is certainly reasonable approach for somebody just starting with assembly, but that's not how real MIPS CPU works):
# input: $a0 = a, $a1 = b
# output: $v0 = a * b
russianPeasant_real_MIPS: # second variant supporting delayed branching like real MIPS CPU
beq $a1, $zero, russianPeasant2_b_zero
li $v0, 0 # res = 0
russianPeasant2_while_b:
andi $at, $a1, 1 # test if b is odd, for even b skip the res = res + a
beq $at, $zero, russianPeasant2_b_even
srl $a1, $a1, 1 # b = b >> 1
add $v0, $v0, $a0 # res = res + a
russianPeasant2_b_even:
bne $a1, $zero, russianPeasant2_while_b # repeat when (b != 0)
sll $a0, $a0, 1 # a = a << 1
russianPeasant2_b_zero:
jr $ra # return res
nop

Subtracting two user input numbers, with a move and display the result

I'm new to MIPS and I'm using MARS. I can't get my move right and when I execute it gives me some nuts o number. Here is what I have so far, any help would be appreciated.
.data
message1: .asciiz "Enter the any number to subtract :"
message2: .asciiz "\nEnter the any number to subtract :"
n1 : .word 0
n2 : .word 0
message3: .asciiz "\nThe subtraction of the two numbers is "
.text
main:
li $v0 4 #print out message1
la $a0 message1
syscall
li $v0 5 #read message1 as number1
syscall
sw $v0 n1 #store number
li $v0 4 #print out message2
la $a0 message2
syscall
li $v0 5 #read message2 as number2
syscall
sw $v0 n2 #store number
li $v0 4
la $a0 message3
syscall
lw $t0 n1
lw $t1 n2
sub $t0, $v0, $v0 # t0 = number1 s1 - number2 s2
li $v0, 1 # print integer
move $t0, $a0 # move t0 to a0
syscall # run
Your code is doing well until here sub $t0, $v0, $v0.When you subtract you should put the the result in the argument register $a0then you can use move to put that result in return register $v0 for printing.
change them as following it will work.
sub $t2, $t0, $t1 # t2 = t0 - t1
move $a0, $t2 # copy t2 to a0
li $v0, 1 # print integer
syscall #
Another way of doing this subtraction is that you don't need .word and lwat all. As following
.data
message1: .asciiz "Enter the any number to subtract :"
message2: .asciiz "\nEnter the any number to subtract :"
message3: .asciiz "\nThe subtraction of the two numbers is "
.text
main:
li $v0 4 #print out message1
la $a0 message1
syscall
li $v0 5 #read message1 as number1
syscall
move $t0,$v0 # set $t0 to the content of $v0
li $v0 4 #print out message2
la $a0 message2
syscall
li $v0 5 #read message2 as number2
syscall
move $t1,$v0
li $v0 4
la $a0 message3
syscall
sub $a0, $t0, $t1 # t0 = number1 t1 = number2
li $v0, 1 # print integer
syscall # run

How to design a program that finds the sum of the integers from 1 to N, where N is a value read on the keyboard?

This is my first attempt at MIPS and I designed a pseudocode description of a possible algorithm. The code outline is as follows:
main: Print: "Please input a value for N ="
read v0
If(v0 >0)
{
t0 = 0
while(v0 > 0) do
{
t0 = t0 + v0
v0 = v0 +v0 -1
}
print: The sum of integers from 1 to N is = ", t0
go to main
}
else
print: "Honest Abe"
so, with this outline, I made somewhat of an attempt to translate this into MIPS but the whole storing variables and reading them in is confusing me. My attempt of the real code is:
.data
Prompt: .asciiz "\n Please input a value for N="
Result: .asciiz "\n The sum of integers from 1 to N is "
Bye: .asciiz "\n ***Honest Abe***"
.text
main:
li $v0,4 #load $v0 with print_string code
la $a0, Prompt #load $a0 with the message to be displayed
syscall
bgz $v0, else
li $t0, 0
while:
bgz $v0
add $t0,$t0,$v0
addi $v0,$vo -1
From here, I do not understand how the for loops work in MIPS and I do not understand if this is even the correct approach. The whole idea of reading in numbers and then storing the integers isn't processing in my head. Also, I am unsure if I am using the appropriate commands for the loop. Help to any of these questions would be great!
Your algorithm seems a bit odd and too much of a hassle, if I got right what you wanted to do.
You can compute a sum until a certain number with a simple for loop. As in C:
scanf("%d", &num);
for(i=0;i<num;i++)
sum=sum+i;
like an array.
With a little help from the reference card of MARS, you can end up with something like this:
.text
main:
li $v0, 5 #read a number from the keyboard
syscall
addi $s0, $v0, 1 #s0= the number from the keyboard + 1 (the limit)
li $t0, 1 #counter set to 1
loop:
beq $t0, $s0, exit #if the counter becomes equal tothe limit, exit the loop
add $t1, $t1, $t0 #add the counter to the sum to this point
addiu $t0, $t0, 1 #add 1 to the counter for each loop
j loop #go to the "loop" label above
exit:
li $v0, 1
move $a0, $t1
syscall
li $v0, 10
syscall

comparing a string in MIPS

Could someone tell me what is wrong with my code so far. I am trying to make a program that takes input from the user (roman numerals) and then converts it to integers. So far this is what I have:
.data
buffer: .space 20
onlyCaps: .asciiz "Please enter only Capital Numbers\n"
enter1: .asciiz "Number out of range. Please enter another number\n"
enter2: .asciiz "Please enter your roman numeral: "
debug: .asciiz "reach"
M: .asciiz "1000"
D: .asciiz "500"
C: .asciiz "100"
L: .asciiz "50"
X: .asciiz "10"
V: .asciiz "5"
I: .asciiz "1"
.text
main:
la $a0, onlyCaps # "Enter Only Capital numbers"
li $v0, 4
syscall
la $a0, enter2 #prompt user with "Please enter a roman numeral:"
li $v0, 4
syscall
la $a0, buffer #load byte space into address
li $a1, 3 # allot the byte space for string
li $v0, 8 #read user input, j
syscall
li $t4, 1
loop:
lb $t0, 0($a0) # Save $v0 value to $t0
beqz $t4, done # if it is equal to zero end the loop
add $a0, $a0, $t4 #increment the address
j mCheck
#while loop ends here
mCheck:
beq $t0, 'M', mChar # if $t0 equal M go to mChar
bne $t0, $t1, dCheck # move to see if equals D
dCheck:
beq $t0, 'D', dChar # if $t0 equal D go to dChar
bne $t0, $t1, cCheck
cCheck:
beq $t0, 'C', cChar # if $t0 equal C go to cChar
bne $t0, $t1, lCheck
lCheck:
beq $t0, 'L', lChar # if $t0 equal L go to lChar
bne $t0, $t1, xCheck
xCheck:
beq $t0, 'X', xChar # if $t0 equal X go to xChar
bne $t0, $t1, vCheck
vCheck:
beq $t0, 'V', vChar # if $t0 equal V go to vChar
bne $t0, $t1, iCheck
iCheck:
beq $t0, 'I', iChar # if $t0 equal I go to iChar
bne $t0, $t1, error
mChar:
la $a0, M #puts one hundred in $t3
li $v0, 4
syscall
j loop
dChar:
la $a0, D # prints out 500
li $v0, 4
syscall
j loop
cChar:
la $a0, C # prints out 500
li $v0, 4
syscall
j loop
lChar:
la $a0, L # prints out 500
li $v0, 4
syscall
j loop
xChar:
la $a0, X # prints out 500
li $v0, 4
syscall
j loop
vChar:
la $a0, V # prints out 500
li $v0, 4
syscall
j loop
iChar:
la $a0, I # prints out 500
li $v0, 4
syscall
j loop
error:
la $a0, enter1 # Print error meg. then back to main
li $v0, 4
syscall
j done
done:
li $v0, 10 # Exit
syscall
My question is how can you take input from the user and put it in $a0, and then use a while loop after that? I can't get the bytes to go to the next spot (i.e. MXX to go from M to X.) currently the program reads M, but not X. Eventually I will switch the program to sum these numbers and to also check to see if the number before is less (i.e. IV) to account for those roman numerals but I need help with the while loop first.

Resources