Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 25 days ago.
Improve this question
i need to convert a code from java to assembly, but it only prints the first message. but the last two message dosent print neither the message nor the numbers of the result.
the two code in java and assembly are that i wrote as follow :
the code in java:
/**
* this program count how many 10s can be in a givin number the return the extra or the remain that less than 10
*/
Scanner input=new Scanner(System.in);
System.out.println("enter num: ");//print input message
int num=input.nextInt();// user input
int numOf10=0;//counter
while(num>9){ //start of while loop
num-=10;//subtruct 10 from the input number
numOf10++;//add one to the counter
}
System.out.println("number of 10 is: "+numOf10);//print message contain
System.out.println("the remain: "+num);//print message contain
////////////////////////////////////////////////////////////////////////////////////
the code in assembly:
.data
EnterMessage: .asciiz"Enter the number:\n "
ResultMessage: .asciiz"number of 10 is:\n"
remainMessage: .asciiz"the remain:\n "
.text
main:
#ask user to enter input
li $v0,4
la $a0,EnterMessage
syscall
#read user input
li $v0,5
syscall
#save input
move $t0,$v0
#creat variables
#$t2=9
addi $t2,$zero,9
#counter=$t3=0
addi $t3,$zero,0
#jal loop
#while loop
loop:
ble $t1,$t2,exit
subi $t0,$t0,10
addi $t3,$t3,1
j loop
print:
#print ResultMessage num
li $v0,1
move $a0,$t3
syscall
#print ResultMessage
li $v0,4
la $a0,ResultMessage
syscall
#print remainMessage num
li $v0,1
move $a0,$t0
syscall
#print remainMessage
li $v0,4
la $a0,remainMessage
syscall
#close the program
exit:
#end
li $v0,10
syscall
Your problem is here:
ble $t1,$t2,exit
There are a couple of problems here. First, exit leads to:
#close the program
exit:
#end
li $v0,10
syscall
So you've jumped to the end without doing anything.
Second, you've chosen $t1 as one of your registers for the compare, which you never set up. So its value is currently unknown (most likely the kernel or OS or whatever zeroed all your registers prior to main but it's not a good practice to assume that.)
Let's think about what's being asked:
while(num>9){ //start of while loop
num-=10;//subtruct 10 from the input number
numOf10++;//add one to the counter
}
When translating a high-level language to assembly we don't have to do everything the same way it was written in the source language. In terms of goto we can think of this as:
loop_begin:
if (num <= 9) goto loop_exit;
num -= 10;
numOf10++;
goto loop_begin;
loop_exit:
You've got the right idea for the most part. The nice thing about MIPS is that the branching syntax isn't nearly as obtuse as other assembly languages, since you don't have to remember whether carry clear means less than or greater than etc.
loop:
ble $t0,$t2,print # if $t0 (num) <= 9 goto print
subi $t0,$t0,10 # num = num - 10
addi $t3,$t3,1 # counter++
j loop # goto loop
Edit: Fixed typo in comments in last section
Related
I am really struggling with assembly language and, unfortunately, have gotten into the habit of treating it more like an assignment than a learning objective. I am now being tasked with writing some code that asks a user for an input (in this case, an integer) and then prints a response based on that integer.
Directions:
Ask a user for an integer-- if the integer is '8', print "Great!". If it's not 8, print "Try again" and then ask them to submit one more time. If they don't print the integer, '8', on the second attempt, simply type game over.
.data
message: .asciiz "Please enter an integer:"
correct_str: .asciiz "Great!\n"
incorrect_str: .asciiz "Game over! \n"
li $t0,8 #this is the correct answer
li $t1,0 # creates a counter of two attempts
loopcheck:
la $a0, message # prompt user
li $v0, 4
syscall
li $v0, 5
syscall
move $s1, $v0 # s1 becomes what user inputs
#this is where we check to see if it's 8, printing game over or looping again and printing game over if not correct on second time
printGameOver:
la $a0, wrong_str
li $v0, 4
syscall
j done
printright:
la $a0, right_str
li $v0, 4
syscall
done: #exit
li $v0, 10
syscall
How would I go about asking a user for continuous input? Basically I want to capture only numbers greater than 0, anything less than 0 I want to print an error message followed by the enter number message.
How would you go about solving this in high-level language pseudocode? One way is -
while true
print("Enter a number: ")
n = read_a_number()
if n < 0
print("Error. Negative number")
else
# process the non-negative number (>= 0)
# detect when to break while loop
Once the above is clear, it is fairly easy to translate this to MIPS.
.data
prompt: .asciiz "Enter a number: "
error: .asciiz "Error. Negative number\n"
.text
while:
la $a0, prompt # print prompt to enter a number
li $v0, 4 # $v0 = 4 to print string with address in $a0
syscall
li $v0, 5 # to read an int. Read in $v0
syscall
bltz $v0, negative # is the input negative?
j non_negative # else, handle non_negative
negative:
la $a0, error # print error
li $v0, 4
syscall
j next # and goto 'next'
non_negative:
# process the non-negative number (>= 0)
j next # and goto 'next'
next:
# detect when to break while loop (or do that at the start of the loop)
j while # continue loop
after_while: # after the loop
li $v0, 10 # $v0=10 to exit
syscall
I want to convert a while loop like that:
i=0;
while ( (s[i]!='t') && (i<=20) ) {
d[i]=c[i];
i++;
}
with 2 conditions to assembly code.
how can i do that?
below is the version with 1 condition in the while.
#################################################
# lab3_3a.s #
# while loop char!=ASCII 0 #
#################################################
.text
.globl __start
__start: # execution starts here
li $t1,0 # counter for string
li $s0,'t' # chararacter to end copy
while: lbu $t0,string($t1) # load a character
sb $t0,copy($t1) # copy character
beq $t0,$s0,end # if character to end copy then exit loop
addi $t1,$t1,1 # increment counter
b while # repeat while loop
end: li $t2,0
sb $t2,copy($t1) # append end character to copied string
la $a0,copy # display copy
li $v0,4
syscall
li $v0,10 # exit
syscall
.data
string: .asciiz "Mary had a little lamb"
copy: .space 80
thanks guys.
So, you've already successfully inverted one of the conditions and used it to jump out of the loop. Does it occur to you that you can do the same for the other?
li $t1,0 # counter for string
li $s0,'t' # chararacter to end copy
li $s1,20 # count to end copy
while: lbu $t0,string($t1) # load a character
sb $t0,copy($t1) # copy character
beq $t0,$s0,end # if character to end copy then exit loop
bgt $t1,$s1,end # if count exceeds limit then exit loop
addi $t1,$t1,1 # increment counter
b while # repeat while loop
i=0;
while ( (s[i]!='t') && (i<=20) ) {
d[i]=c[i];
i++;
}
Would contain two bugs, if s would be defined as char s[20];, first the (i<=20) would be one-too-much. It's very unusual to use <= in array length tests, it may be still correct if char s[21]; is defined, but then you have two different "magic numbers" in source, 20 and 21. And the second bug is, even if you have correct length test, the (s[i]!='t') will execute ahead of i validation, so at the last character you will have out-of-bounds access.
Anyway, that C be written in C in a bit more "assembly-like" way like this:
i=0;
while(true) { // Your "b while" is doing this already
if (20 < i) break; // test length first, to avoid s[21] (out of bounds)
if ('t' == s[i]) break; // test for "terminator" character
//^^ Yoda notation, to catch typo like (s[i]='t') as error
d[i]=c[i];
++i; // pre-increment form is more accurate to your intent
// As you don't need original value after incrementation
}
// breaks will jump here.
This should be easy to rewrite in assembly, try it...
edit: and your original assembly is not "while", but "do-while", i.e. copy of first byte will execute under all circumstances, which is not what the C example is doing.
edit2: meanwhile of course this assumes you know the boolean logic algebra, as every programmer has to. I.e. you know that:
!(A && B) <=> (!A) || (!B)
I am confused on how to convert C code to MIPS. I seem to to get the loops confused and I think I am possibly using the wrong command. The C code I made to do this is as follows:
int main()
{
int x, y;
int sum = 0;
printf("Please enter values for X and Y:\n ");
scanf("%d %d",&x,&y);
if (x > y)
{
printf("\n** Error");
exit(0);
}
while (x <= y)
{
if (x%2 == 0)
sum += x;
x++;
}
printf("\nThe sum of the even integers between X and Y is: %d\n\n",sum);
return 0;
}
My attempt at the MIPS translation is as follows:
.data
Prompt: .asciiz "Please enter values for X and Y:\n"
Result: .asciiz "The sum of the even integers between X and Y is: \n"
.text
li $v0,4 #load $v0 with the print_string code.
la $a0, Prompt #load $a0 with the message to me displayed
syscall
li $v0,5 #load $v0 with the read_int code for X
syscall
move $t0,$v0
li $v0,5 #load $v0 with the read_int code for Y
syscall
move $t1, $v0
while:
slt $t2, $t1,$t0 #$t1 = y $t0 = x
li $t3,2
div $t2,$t3
beq $t2,$0,else
add $s1,$s1,$t0 #s1 = s1 + x
addi $t0,$t0,1 #x++
j while
else:
li $v0,4
la $a0, Result
syscall
move $a0,$s1
li $v0,1
syscall
I think my error is in the loop in my MIPS code. My result keeps producing zero and I think my code is checking the loop and then just jumping to my else statement.
After further work, I got it to calculate the sum of all integers and I'm not exactly sure why it is doing so. Here is my most recent update:
while:
sle $t2, $t0,$t1 #$t1 = y $t0 = x
li $t3,2 #t3 = 2
div $t2,$t3 #$t2/2
beq $t2,$0, else #if ($t2/2 == 0), jump to the else, otherwise do else
add $s1,$s1,$t0 #s1 = s1 + x
addi $t0,$t0,1 #x++
j while
So now, if I enter 1 and 5, it calculates 1 and 3 is gives me 6 instead of just the even sum which should be just 2.
To answer my own question, the main confusion was with the the branches. I now understand that they kind of work like opposites so for example, I had to set the "beq" in my while loop to bnez so it would do the calculations when $t2 was != 0. Another minor fix was adding the increment outside of the loop. So, when $t2 != 0, I jump to my "else" which then incremented to find the next number. However, if the remainder was 0, it did the math of sum=sum + x. In conclusion, the main confusion came from thinking opposite about the branches. I now understand that if I wanted to say:
while(a1 < a2)
I would have to write it as
while:
bgeu $a1,$a2, done
addi "whatever"
b while
done:
do done stuff
Before this understanding, I was writing it as ble $a1,$a2,done and that is not the way it is to be typed. Logically, that says if a1 < a2...but it is really saying if a1 < a2, jump to the "done" and skip calculations. So I just had to think opposite.
In class we were learning how to convert C code to MIPS instructions, but i ran into a small problem. Just wanted some clarification as far as to what exactly the last line of the MIPS instructions was actually saying.
c:
do{
i=i-2;
}while(i>1);
mips:
DO: addi s1,s1,-2 // i=i-2
addi t0,t0, 1 // 1
slt t1,t0,s1 // 1<i
bne t1,$zero,DO // ???
do{
i=i-2;
}while(i>1);
The assembly code for while and do while loops test the opposite condition of the one given in high-level code. If that opposite condition is TRUE, the while loop exit.
addi $s1,$0,0 # i = 0
addi $t1,$0,1 # j = 1
while:
addi $s1,$s1,-2 #i = i -2
beq $s1,$t1,done #Branch to done If i = 1 (the opposite)
j while # jump to while for loop through again
done: