Reverse the order of user inputted string - mips

goodafternoon, i made this code that takes in user input and reverses the order. the code works perfectly except when there is long user input such the alphabet. in this case the output excludes the last letter, i am unsure why this is and any insight would be greatly appreciated.
.data
.align 2
array: .space 80
size: .word 20
string: .space 20000
op: .asciiz "Enter n, followed by n lines of text:"
prompt: .asciiz ""
text: .asciiz "The values are:"
newline: .asciiz "\n"
.text
.globl main
main:
#prompt user for array length
li $v0,4
la $a0,op
syscall
jal new_line #output newline
#read in array count
li $v0,5
syscall
addi $s0,$v0,0 #$v0 contains the integer we read
add $t0,$zero,$zero #index of array
addi $t1,$zero,1 #counter=1
la $s2,string #load address of string storage area
read_string:
bgt $t1,$s0,L1 #if ($t1 > length) then array is done
# prompt the user for next string
li $v0,4
la $a0,prompt
syscall
#get the string
move $a0,$s2 #place to store string
li $a1,20
li $v0,8
syscall
#store pointer to string into array
sw $a0,array($t0)
addi $t0,$t0,4 #advance offset into pointer array
addi $t1,$t1,1 #advance iteration count
addi $s2,$s2,20 #advance to next string area
j read_string
#### here i want to print the array ####
L1:
addi $t1,$zero,1 #counter = 1
#output the title
la $a0,text
li $v0,4
syscall
jal new_line
while:
addi $t0,$t0,-4 #advance array index
bgt $t1,$s0,done #if no more strings to output then done
lw $t2,array($t0) #get pointer to string
#output the string
li $v0,4
move $a0,$t2
syscall
addi $t1,$t1,1 #advance count
j while
new_line:
la $a0,newline
li $v0,4
syscall
jr $ra
done:
li $v0,10
syscall
if the user enters a n value of 26 and following lines a b c d e f g h i j k l m n o p q r s t u v w x y z then the output should be z y x v u t s r q p o n m l k j i h g f e d c b a. However what is outputted is this: z y x v u t s r q p o n m l k j i h g f e d c b. so its missing the letter a

From what I can tell, the problem is that you're ending the loop one pass too early.
while:
addi $t0,$t0,-4 #advance array index
bgt $t1,$s0,done #if no more strings to output then done
Here, you're effectively comparing $s0 to 26, since that's the whole alphabet size.
But since you started $t1 as equaling 1, you're encountering an "off-by-one" error most likely.
When compilers implement a loop like while(count < 26), often they don't do this literally like you have done here. It's usually easier to do the following:
#read in array count
li $v0,5
syscall
addi $s0,$v0,1 #$v0 contains the integer we read plus 1.
# do your other stuff here
while:
addi $t0,$t0,-4 #advance array index
lw $t2,array($t0) #get pointer to string
#output the string
li $v0,4
move $a0,$t2
syscall
addi $s0,$s0,-1
bnez $s0,while
Since you're only adding 1 to your count variable it's easier just to make it a downward for-loop (as I said eariler, a C compiler typically does this even if you declare the loop as a while.)
Sometimes you just need to adjust your loop counter by 1 and that may be enough to fix things.

Related

Mips - Array initialization and index value output

#include<stdio.h>
int main() {
int a[] = { 1,2,3,4,5,6,7,8,9,10 };
int b[] = { 1,2,3,4,5,6,7,8,9,10 };
int f = 0;
int f1 = 0;
int h = 0;
int g = 0;
printf("Please, type a number for g:");
scanf_s("%d", &g);
printf("Please, type a number for h:");
scanf_s("%d", &h);
f = -g + b[h];
f1 = a[b[g] + 1];
printf("The 1st result is:%d\n", f);
printf("The 2nd result is:%d\n", f1);
return 0;
}
I want to convert this c language into mips.I tried this, but there was an error. What should I do?
Below is my code
Maybe this code has problem at Array. I'm not used to using it.
Please tell me the problem and solution.
.globl main
.data
A: .word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
B: .word 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
str1:.asciiz"Please, type a number for g:"
str2:.asciiz"Please, type a number for h:"
str3:.asciiz"The 1st result is:"
str4:.asciiz"The 2nd result is:"
.text
main:
li $v0,4 #print str1
la $a0,str1 #str1
syscall
li $v0, 5 #input g
syscall
move $s1, $v0 #$s1= g
li $v0,4 #print str2
la $a0,str2 #str2
syscall
li $v0, 5
syscall
move $s2, $v0 # $s2 = h
sll $t0,$s2,2 # t0 = 4 * h
add $t0,$t0,$s7 # address of B[h]
lw $t0,0($t0) # t0 = B[h]
sub $s0,$t0,$s1
move $t3,$s0
sll $t0,$s1,2 # t0 = 4 * g
add $t0,$t0,$s7 # t0 = address of B[g]
lw $t0,0($t0) # t0 = B[g]
addi $t0,$t0,1 # t0 = B[g]+1
sll $t0,$t0,2
add $t0,$t0,$s6
lw $s0,0($t0) # f= A[B[g] +1]
move $t4, $s0
li $v0,4 #print str3
la $a0,str3 #str3
syscall
move $a0,$t3
li $v0,1
syscall
li $v0,4 #print str4
la $a0,str4 #str4
syscall
move $a0,$t4
li $v0,1
syscall
li $v0,10
syscall
I don't know why there's an error because I'm not very good at mips. Please help me.

MIPS - how to write a for loop while also accessing and saving arrays

I won't lie, I'm a total beginner at programming in general with my first time being last year when I started programming in Computer Programming I. A lot of this is still over my head so uh... go easy on me will ya?
The question poised is as follows:
"1. (5 pts) Translate the following C code to MIPS. Assume that the variables i and j are assigned to registers $s0 and $s1, respectively. Assume that the base address of the arrays A and B are in registers $s6 and $s7, respectively. Assume that the elements of the arrays A and B are 4-byte words:
for (i = 0; i< j; i++)
B[i] = A[i+1] - A[i];
For my program I wrote:
.data
arrayA: .word 5,8, 12, 13, 28
sizeA: .word 5
arrayB: .space 4
i: .word 0
_j: .word 5
.text
# for (i = 0; i< j; i++)
# B[i] = A[i+1] - A[i];
main:
la $s6, arrayA #loads the base address of arrayA into register s6
la $s7, arrayB #loads the base address of arrayB into register s7
lw $s0, i #Loads zero into register s0 for i
lw $s1, _j #loads the value of 4 into register s2 for j
Loop:
beq $s0, $s1, Exit #Does the operation i < j in the for-loop
addi $s0, $s0, 1 #Does the operation i++ in the for-loop
mul $t0, $s0, 4 #Get address of i
add $t1, $t0, $s6 #Finds and stores the base address of a[i]
add $t2, $t0, $s7 #Finds and stores the base address of b[i]
lw $t3, ($s6) #get the value of a[i]
lw $t4, 4($10) #get the value of a[i + 1]
sub $t5, $t4, $t3 #subtracts a[i + 1] and a[i]
sw $t5, ($t2) #Stores the above into b[i]
add $a0, $zero, $t5
li $v0, 1
syscall
J Loop #loops back to beginning
Exit:
li $v0 10
syscall #syscall to exit the program
When I run it, it spits out 33333, which means it isn't incrementing. How do I fix this?
arrayA: .word 5,8, 12, 13, 28
may be wrong. You didn't add a space between 5, and 8 while giving spaces between the other elements. My QtSpim Version 9.1.21 didn't accept that.
arrayB: .space 4
is wrong. You are allocating only 4 bytes while space for 4 words (16 bytes) is required.
_j: .word 5
is wrong. The stored value is 5 despite of the comment saying "loads the value of 4 into register s2 for j". Using value 5 is wrong also because the array a has only 5 elements.
addi $s0, $s0, 1 #Does the operation i++ in the for-loop
is in the wrong place. The increment should be after the loop body.
lw $t3, ($s6) #get the value of a[i]
lw $t4, 4($10) #get the value of a[i + 1]
is wrong. The address of a[i] is stored in $t1, so you should use that.
J Loop #loops back to beginning
may be wrong. You used an uppercase letter for instruction name only here. At least my QtSpim Version 9.1.21 didn't accept that.
li $v0 10
may be wrong. You didn't use a comma for separating the operands while you used that in previous use of li: li $v0, 1. I'm surprised by seeing my QtSpim Version 9.1.21 accepting this.
Fixed code:
.data
arrayA: .word 5, 8, 12, 13, 28
sizeA: .word 5
arrayB: .space 4 * 4
i: .word 0
_j: .word 4
.text
# for (i = 0; i< j; i++)
# B[i] = A[i+1] - A[i];
main:
la $s6, arrayA #loads the base address of arrayA into register s6
la $s7, arrayB #loads the base address of arrayB into register s7
lw $s0, i #Loads zero into register s0 for i
lw $s1, _j #loads the value of 4 into register s2 for j
Loop:
beq $s0, $s1, Exit #Does the operation i < j in the for-loop
mul $t0, $s0, 4 #Get address of i
add $t1, $t0, $s6 #Finds and stores the base address of a[i]
add $t2, $t0, $s7 #Finds and stores the base address of b[i]
lw $t3, ($t1) #get the value of a[i]
lw $t4, 4($t1) #get the value of a[i + 1]
sub $t5, $t4, $t3 #subtracts a[i + 1] and a[i]
sw $t5, ($t2) #Stores the above into b[i]
add $a0, $zero, $t5
li $v0, 1
syscall
addi $s0, $s0, 1 #Does the operation i++ in the for-loop
j Loop #loops back to beginning
Exit:
li $v0, 10
syscall #syscall to exit the program
Don't mix friendly register names with the raw register names — very confusing.
lw $t3, ($s6) #get the value of a[i]
lw $t4, 4($10) #get the value of a[i + 1]
Here you're mixing $t3, $t4, $s6, and $10, which is actually $t2.
Your assembly code is doing the following C code (modulo the above bug):
int *s6 = A;
int *s7 = B;
for ( int i = 0; i != j; ) {
i++;
int *t1 = s6 + i; // i is automatically scaled by C
int *t2 = s7 + i; // ditto
int t3 = *s6; // A[0]
int t4 = s6[1]; // A[1]
int t5 = t4 - t3;
*t2 = t5; // B[i]=...
}
Can you see why it keeps loading A[0] & A[1]?
You should have noticed these problems during single stepping debugging.  After each step, check that every effect you're expecting happens as you expect.  When it doesn't, look for typos or logic problems.

Understanding a MIPS algorithm

I'm very new into coding and we started with MIPS. We were kind of "thrown in to the cold water" and had to implement an algorithm that checks whether the elements of an array are sorted in ascending order. If it is sorted, a 1 is to be stored in $v0, otherwise a 0.
The solution that was given us:
.data
A: .word 1, 2, 3, 4, 5
l: .word 5
.text
main:
la $s0, A #address of A
lw $s1, l
add $t0, $0, $0 #counter for loop
addi $v0, $0, 1
sub $s1, $s1, $v0
for:
beq $t0, $s1, done
sll $t1, $t0, 2 #byte offset
add $t1, $t1, $s0
lw $t1, 0($t1) #$t1 = A[j]
addi $t2, $t0, 1
sll $t2, $t2, 2
add $t2, $t2, $s0
lw $t2, 0($t2) #$t2 = A[j + 1]
sub $t3, $t2, $t1 #$s3 = A[j+1] - A[j]?
slt $t4, $t3, $0
addi $t3, $0, 1
beq $t3, $t4 unsort #A isn’t sorted if A[j+1] - A[j] has a negative value
addi $t0, $t0, 1 #$t0 = $t0 + 1
j for
unsort:
add $v0, $0, $0 #set $v0 if array isn’t sorted
done:
I'm having trouble understanding this code/algorithm. First of all what is an Array and why do we need specifically 5 of them?
But much more important to me is understanding this code/algorithm. So I need someone who is kind enough and explains to me step by step and in simple word :D, how this code works.
Would be very helpful and thanks in advance.
Short answer
Basically, this program iterates over the array A in a loop with loop counter, say i. The index i is initialized with 0 and in every loop iteration incremented by 1 until it reaches l-1, where l is the size/length of the array A. In every iteration the algorithm checks if A[i] < A[i + 1] (i.e. if the i-th and the (i+1)-th element in A are in ascending order and thus are sorted). If so, it continues execution and $v0 remains 1. Otherwise it sets $v0 to 0 and terminates.
Long answer
Arrays and memory
An array is basically an ordered list of data – in this case it is an ordered list of words (a word in MIPS means: 32-bit value, and it consists of 4 bytes, each of which has 8 bits of information). So in this case, every word represents a 32-bit integer.
If we have an array A of length l, the elements are indexed from 0 to l-1. The first element in an array A (notation: A[0]) is saved at a certain address in memory, let's call it addr. The i-th element in A (A[i]) is then saved at the memory address addr + 4*i. This is because memory in MIPS is byte-addressable, i.e., every byte has his own address and because a word consists of 4 bytes, word addresses are offset by 4 (see below).
.data section
A: .word 1, 2, 3, 4, 5
l: .word 5
With that you will realize that you don't have 5 arrays but only one (called A) and it contains the values 1, 2, 3, 4 and 5. Thus, the length is 5 and it is specified in the word l. You could add more values to your array but then you would have to adjust the length because otherwise, strange things will happen (or at least the result will be random). Your data is specified in this .data section and is therefore somewhere stored in your program's memory space.
MIPS assembly
In order to understand the code in the .text section, you have to understand MIPS assembly. If I write about a register, just think about it as a placeholder for a 32-bit value. For example, $0 is the zero register and it always stores a 32-bit 0. Other registers are used to temporarily store values used in your program. The instructions you use are:
la rd, label ("load address")
(rd = address of label; stores the address of the word specified by "label" in the destination register rd)
lw rd, label ("load word")
or
lw rd, offset(rs)
(load data specified by label, or data at address rs+offset into destination register rd)
add rd, rs, rt
(rd = rs + rt; adds source registers rs and rt and stores result in destination register rd)
addi rd, rs, imm ("add immediate")
(rd = rs + imm; adds source register rs and immediate (16-bit constant) value and stores result in destination register rd)
sub rd, rs, rt ("subtract")
(rd = rs - rt; subtracts source register rt from source register rs and stores result in destination register rd)
beq rs, rt, label ("branch if equal")
(if value in rs is equal to value in rt, jump to label)
sll rd, rs, shamt ("shift logic left")
(rd = rs << 2; shift value in rs by two bits the left and store it in rd)
slt rd, rs, rt ("set less than")
(rd = (rs < rt) ? 1 : 0; if the value in rs is smaller than the value in rt, set rd to 32-bit 1, otherwise to 32-bit 0)
j label ("jump")
(jump to label)
.text section
main:
la $s0, A
lw $s1, l
add $t0, $0, $0
addi $v0, $0, 1
sub $s1, $s1, $v0
for:
beq $t0, $s1, done
sll $t1, $t0, 2 #byte offset
add $t1, $t1, $s0
lw $t1, 0($t1) #$t1 = A[j]
addi $t2, $t0, 1
sll $t2, $t2, 2
add $t2, $t2, $s0
lw $t2, 0($t2) #$t2 = A[j + 1]
sub $t3, $t2, $t1 #$s3 = A[j+1] - A[j]?
slt $t4, $t3, $0
addi $t3, $0, 1
beq $t3, $t4 unsort #A isn’t sorted if A[j+1] - A[j] has a negative value
addi $t0, $t0, 1 #$t0 = $t0 + 1
j for
unsort:
add $v0, $0, $0 #set $v0 if array isn’t sorted
done:
This assembly code is equivalent to the pseudocode (if you are not used to pseudocode or to while loops, please look it up in the internet):
s0 <- address of first element in A
s1 <- l
t0 <- 0
v0 <- 1
s1 <- s1-1
while (t0 != s1) do
t1 <- 4 * t0
t1 <- t1 + s0
t1 <- word at address t1
t2 <- t0 + 1
t2 <- 4 * t2
t2 <- t2 + s0
t2 <- word at address t2
t3 <- t2 - t1
if (t3 < 0) then t4 <- 1
else t4 <- 0
t3 <- 1
if (t3 == t4) then
v0 <- 0
return
else t0 <- t0 + 1
Hope, this helped. I think it is quite ambitious to start with assembly code if you haven't coded before. Good luck!

MIPS Palindrome Check

I am trying to write a MIPS program that checks if an input string is a palindrome. I tested the string "HelllleH" and when stepping through the program, I saw that during the first loop of PAL_CHECK t0 = 0 but t1 = 104. Logically, t0 = 0 and t1 = 0 also in the first loop. Can someone tell what's wrong in this program?
# a0 is input
# a1 is current character we are looking at
# a2 is length of string
# t0 is character at beginning of string
# t1 is character at end of string
# v0 stores whether string is palindrome or not (0 for false, 1 for true)
ispalindrome:
addi $a2, $0, 0 # length counter
FIND_LEN:
lbu $a1, 0($a0) # load character into $a1
beq $a1, $0, PAL_CHECK # Break if string is at the end
addi $a2, $a2, 1 # increment counter
addi $a0, $a0, 1 # increment str address
j FIND_LEN
PAL_CHECK:
# Is palindrome if length is less than 2
slti $t0, $a2, 2
bne $t0, $0, RETURN_TRUE
# Check first and last chars to see if they are the same
lbu $t0, 0($a0) # first char is t0
add $t1, $a2, $a0 # last char is t1
lbu $t1, 0($t1)
bne $t0, $t1, RETURN_FALSE # if they are not equal, return false
# continue recursion
addi $a2, $a2, -2
addi $a0, $a0, 1
j PAL_CHECK
RETURN_FALSE:
addi $v0, $0, 0
jr $ra
RETURN_TRUE:
addi $v0, $0, 1
jr $ra
While finding the length of the string you continually increment $a0 to point at the next character, until you find the NUL terminator at the end of the string. You never reset $a0 before the palindrome check loop, so it's still pointing at the NUL terminator when you begin that loop. So you'll actually be comparing data that's past your string.
It would make more sense to implement the check this way (I'm using C to illustrate the idea; I'll leave the MIPS translation to you):
a0 = the_string;
a1 = the_string + strlen(the_string) - 1;
while (a1 > a0) {
if (*a0 != *a1) return false;
a0++;
a1--;
}
return true;
By the way, a terminology nitpick: # continue recursion. Your implementation isn't recursive, it's iterative.

What does this MIPS program do?

I know the program loads the address of .word 5 which is the initial value, I'm getting confused as to what the program is actually doing. Is it comparing stacks of the word or adding.
.data
arg: .word 5
.text
.globl main
main:
la $t3, arg
lw $t2, 0($t3)
lw $t3, 0($t3)
addi $t1, $zero, 0
beqz $t2, fin
fori:
add $t1, $t1, $t2
addi $t3, $t3, -1
bnez $t3, fori
fin:
li $v0, 10
syscall
Looks like it does addition based on the first item in the space as it doesn't access the array from inside the loop.
So for instance if you input a character representing the ascii value of 5 (not '5' itself iirc) you might see something like this:
int t2 = 5, t3 = 5, t1 = 0;
do {
t1 += t2;
t3 -= 1;
} while(t3 > 0);
Someone has already answered but I shall provide the translation I did:
.data
arg: .word 5
.text
.globl main
main:
la $t3, arg # load-address of arg into t3
lw $t2, 0($t3) # load-word from the address in t3 + 0 offset, like t3[0]
lw $t3, 0($t3) # same but to t3
addi $t1, $zero, 0 # initialize t1 to 0? weird they don't use li
beqz $t2, fin # if t2 is zero jump to fin:
fori:
add $t1, $t1, $t2 # t1 = t1 + t2
addi $t3, $t3, -1 # t3 -= 1
bnez $t3, fori # if(t3 != 0) goto fori
fin:
li $v0, 10 # load immediate 10 into v0, which is the syscall to terminate the program
syscall
Disclaimer: I don't have any direct MIPS experience, I just have been around a number of assembly languages.
That said, I think what the program does is calculating the square of 'arg' by repeated addition - in this case 5 * 5 = 25. However, the result in $t1 doesn't seem to be stored anywhere, instead the program just exits.