MIPS debugging help - mips

It seems that my understanding of MIPS fails me.
What I need to do is create a program that reverses a string input from terminal, using a stack, but without using $sp. Is there anyone here that knows MIPS?
Register usage
t0 - theString address start
t1 - stack address start
t2 - temp for retrieved character
t3 - counter for t0
t4 - counter for stack
t5 - newline
t6 - Length
.data
theString: .space 42
newLine: .asciiz "\n"
stack: .space 42
.globl main
.text
main:
li $v0, 8 # Set to read string
la $a0, theString
li $a1, 42 # Set size of string
syscall # Read string from terminal
la $t0, theString # Prepare t0 with theString
la $t1, stack # Prepare t1 with stack
la $t5, newLine
addi $t3, $t0, 0
addi $t4, $t1, 42
j push
push:
addi $t3, $t3, 1
addi $t4, $t4, -1
lb $t2, ($t3)
beq $t2, $t5, epush
sb $t2, ($t4)
j push
epush:
sub $t6, $t3, $t0
addi $t6, $t6, -1
addi $t3, $t0, 0
addi $t4, $t1, 0
j pop
pop:
addi $t3, $t3, 1
addi $t4, $t4, 1
lb $t2, ($t4)
beq $t2, $t5, epop
sb $t2, ($t3)
j pop
epop:
addi $t3, $t3, 1
sb $t5, ($t3)
li $v0, 4 # Set to print string
la $a0, theString # Set var to syscall output register
syscall # Print string
li $v0, 10 # Set to end program
syscall # End Program
For example, this just gives an infinite loop. (Sorry for lack of comments, I'm just tearing my hair out here)
Now, I think the problem is somewhere related to the newline character, but I don't know where?

Is there a reason you are using j and not jal? And it appears you are using SPIM, which has numerous issues.
In your pop loop, you are comparing (in beq) the address of newline (in $t5) and the address of the next character in the string. Even though they might contain the address of a location that contains "\n", the addresses might not be the same, because "\n" can be in more than one place. In fact, I can guarantee that they will never be the same, because one will refer to the address of the captured string, and the one in $t5 will be the address of the one at the beginning of the program.

Related

Printing an hourglass in mips32

I'm having problems solving this question. I want to print an hourglass using mips32. n is an integer given by user as input and the hourglass must be printed in n lines. For example, for n = 5 the output is:
*****
***
*
***
*****
Here is my code for the first part (the triangle top of the hourglass). The problem is that it prints only the first line of stars and then exits. By running my code line by line in Mars, I understood that the first line of the backToLoop1 label is run every time loop3 is run! So it causes the program to end after the first line. I really can't realize why this happens.
.data
newLine: .asciiz "\n"
.text
main:
li $v0, 5 # read n
syscall # call sysetem
addi $t2, $v0, 0 # moves n to $t2
li $t0, 1 # i= 1
loop1:
blt $t2, $t0, Exit # if n<i exit
la $a0, newLine # go to next line
addi $v0, $0, 4 # 4 represents printing string
syscall # call system
# loop2 bounds
li $t1, 1 # k= 1
subi $t3, $t0, 1 # $t3= i-1 upper bound for loop2
# loop3 bounds
li $t5, 1 # j= 1
addi $t6, $t2, 1 # t6= n+1
sub $t6, $t6, $t0 # $t6= n+1-i upper bound for loop3
loop2:
blt $t3, $t1, loop3
li $a0, ' ' # load space to $a0
la $v0, 11 # 11 represents printing character
syscall # call system
addi $t1, $t1, 1 # k++
ble $t1, $t3, loop2 # if <= i-1 loop2 again
loop3:
blt $t6, $t5, backToLoop1 # back to loop1
li $a0, '*' # load star to $a0
la $v0, 11 # 4 represents printing character
syscall # call system
addi $t5, $t5, 1 # j++
ble $t5, $t6, loop3 # if j <= n-i+1 loop3 again
backToLoop1:
addi $t0, $t0, 1 # i++
ble $t0, $t2, loop1 # if i<=n loop1 again
blt $t2, $t0, Exit
Exit: # Terminate the program
li $v0, 10 # 10 represents exit
syscall # call system
You're off to a good start. However, there doesn't appear to be a clear strategy for slanting the right side of the hourglass. Ideally we can write logic to handle drawing the bottom half without duplicating most of the logic.
My default approach for this sort of pattern is to use two pointers, a left starting at 0 and right starting at n - 1. These represent the index bounds for the asterisk characters for each row. Per row iteration, decrement the right pointer and increment the left pointer, essentially drawing an "X" pattern on the n by n grid.
This strategy gets us 95% of the way there. The last step is to temporarily swap the left and right pointers if left > right, which handles drawing the bottom half without too much spaghetti.
.data
prompt: .asciiz "enter a number: "
.text
main:
la $a0 prompt # collect n
li $v0 4
syscall
li $v0 5
syscall
move $s3 $v0 # n
li $s0 0 # left index
move $s1 $s3 # right index = n - 1
addi $s1 $s1 -1
row_loop:
bltz $s1 exit # while right-- >= 0
li $s2 0 # column index
col_loop:
beq $s2 $s3 row_loop_done # for 0..n
# if left > right, swap temporarily
move $t0 $s0
move $t1 $s1
blt $t0 $t1 pick_char
move $t2 $t0
move $t0 $t1
move $t1 $t2
pick_char:
# '*' if left <= i <= right else ' '
blt $s2 $t0 pick_space
bgt $s2 $t1 pick_space
li $a0 42 # print '*'
j print_char
pick_space:
li $a0 32 # print ' '
print_char:
li $v0 11
syscall
addi $s2 $s2 1 # column index++
j col_loop
row_loop_done:
li $a0 10 # print newline
li $v0 11
syscall
addi $s1 $s1 -1 # right--
addi $s0 $s0 1 # left++
j row_loop
exit:
li $v0 10
syscall

A MIPS palindrome

The current code that I have looks as such. It can successfully read if a string is a palindrome when punctuation is not entered.
.data
buffer: .space 80
input: .asciiz "Enter a string: "
output: .asciiz "Your string: "
paly: .asciiz "This is a palindrome "
notp: .asciiz "This is not a palindrome"
.text
main:
li $v0, 4 # system call code for print_str
la $a0, input # address of string to print
syscall # print the input
li $v0, 8 # code for syscall read_string
la $a0, buffer # tell syscall where the buffer is
li $a1, 80 # tell syscall how big the buffer is
syscall
la $a0, buffer # move buffer into a0
li $v0, 4 # print buffer
syscall
la $t1, buffer # begining of the string
la $t2, buffer # end of the string
li $t0, 0
loop:
lb $t3,($t2) # load the byte of the end of the string
beqz $t3,endl # if its equal to 0 then branch out of the loop
addu $t2, $t2,1 # if in loop the increment to next character
jal loop # repeat the loop
upper:
addi $t4,$t4,32
j lowered
lowered:
addi $t0,$t0,1
sb $t4, 0($a0)
addi $a0,$a0,1
j loop
endl:
subu $t2, $t2, 2 # subtracting 2 to move back from \0 and \n
check:
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper
bge $t1, $t2, palindrome # if both sides are equal then its a palindrome
# call palindrome
lb $t3, ($t1) # load the byte into register t3
lb $t4, ($t2) # load the end byte into register t4
bne $t3, $t4, notpaly # if the two register bytes are not equal its it not a palindrome
addu $t1, $t1, 1 # increment the beginning of the string to next char
subu $t2, $t2, 1 # decrement end of string to next char to compare
jal check # repeat the loop
palindrome:
la $a0, paly # calling paly from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
notpaly:
la $a0,notp # calling notp from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
after:
li $v0, 4
la $a0, output
syscall
la $a0, buffer
li $v0, 4
syscall
exit:
li $v0 ,10 # call to end program
syscall # call os
Now I know I need to implement code such as to make uppercase lowercase, and to remove punctuation.
With my already stored bits in check: I have some commented code, and this would be to to test if a character is uppercase, then jump to the function and lower it by adding 32. But it does not compile correctly and i am assuming this is because I am not storing the bits correctly.
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper

Mips Procedure: Infinite for loop and Exception occurred at PC

Seeing the topics on the site, however I was not able to solve my problem. I noticed that the code inside the procedure falls into an infinite for and in QTSpim I saw that the registers involved are $s0, $s1, $t2, and $t4.
After a few cycles then the message Exception occurred at PC then expection 7 Bad data address.
Here is the code, I can not figure out where mistake, I tried to write it without procedure and it works perfectly.
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
.text
.globl main
Delete_space:
addi $sp, $sp, -16
sw $s0, 0($sp)
sw $s1, 4($sp)
add $t8, $a0, $zero
lenght_string:
lb $t0, 0($t8)
beqz $t0, for #t8 contain the lenght of string
add $t8, 1
j lenght_string
for:
add $s0, $zero, $zero #i=0
add $s1, $zero, $zero #j=0
condition:
slt $t1, $s0, $t8 #i< lenght_string
beq $t1, $zero, endfor
consequence:
add $t2, $t8, $s0
lb $t3, 0($t2)
bne $t3, ' ', op1
beq $t3, ' ', else
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
op1:
add $t4, $a1, $s1
sb $t3, 0($t4)
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
else:
sub $s1, $s1, 1
addi $s0, $s0, 1
addi $s1, $s1, 1
j condition
endfor:
#end
lw $s1, 4($sp)
lw $s0, 0($sp)
addi $sp, $sp, 16
jr $ra
main:
la $a0, string
la $a1, string2
jal Delete_space
la $a0, string2
li $v0, 4
syscall
li $v0, 10
syscall
I think you're trying to copy characters from one string to the other, skipping spaces. (Maybe that's not what you're trying to do - unfortunately, I don't have time to trace the code in detail.) I think the problem is that you're copying from your source string into a data area that doesn't belong to you.
Strings aren't handled the same in Assembly as they are in a high-level language. They're nothing but a sequence of bytes - there is no concept of a String that automatically expands to contain what you put in it. And there's no concept of bounds checking.
Look at these string declarations:
.data
string: .asciiz "Hello Simon"
string2: .asciiz ""
What you've done is assigned string to a memory address containing the byte value 'H'. The subsequent memory locations contain 'e', 'l', 'l', 'o', ' ', 'S', 'i', 'm', 'o', 'n', '\0'.
Then, you've assigned string2 to a memory address containing the byte value '\0' (a null terminator).
If you write a byte to the memory address pointed to by string2, it would replace the null terminator. (You would already be in trouble at this point, because the syscall wouldn't know where your string ends.) If you then write another byte to the memory address pointed to by string2 + 1, you are now writing to memory that you didn't allocate to string2. It might belong to some other variable that's being stored - in which case, you just overwrite what was there before. That's a "buffer overflow", and it's how poorly-written programs such as Internet Explorer get exploited by hackers.
If I'm interpreting the purpose of your program correctly, you need to create a buffer for your output that's big enough to hold it. Something like this would work, assuming your output will never be longer than your input:
.data
string: .asciiz "Hello Simon"
string2: .asciiz "xxxxxxxxxxx"

MIPS prompt for a string and exchange the case of each character

I am writing a MIPS program that prompts the user for a string and then parse the string exchanging the case of each character.
for example ->
Hey You becomes hEY yOU.
My question is, how do i make it do nothing if it encounters a space ? Any help would be great!
.data
string4:.space 82 # space for input string
strPrompt:.asciiz "Please enter a string: "
.text
.globl main
main:
la $a0, strPrompt # print prompt
li $v0, 4
syscall
la $a0, string4 # read string
li $a1, 80
li $v0, 8
syscall
la $a0, string4 # print string
li $v0, 4
syscall
la $t0, string4 # $t0 = &string4[0]
li $t1, 0
loop4:
lb $t1, 0($t0)
nop
nop
beqz $t1, done4 # if $t1 == NUL, we are done
bgt $t1, 90, else # if char > 90 its a lower case
nop
addi $t1, $t1, 0x20 # if < 90 its upper case add 32
sb $t1, 0($t0)
addi $t0, $t0, 1 # add 1 to pointer
j loop4 # jump back to loop
nop
else:
addi $t1, $t1, -0x20
sb $t1, 0($t0)
addi $t0, $t0, 1
j loop4
nop
done4:
Here's a branchless way of changing the case of a character in $t1 if it's in the range A..Z or a..z, and do nothing if it's outside that range:
# if (upper($t1) >= 'A' && upper($t1) <= 'Z') $t2 = 1; else $t2 = 0;
andi $t3,$t1,0xDF # clear bit 5, if $t1 was an alphabetic character $t3 will now be uppercase
li $t2,'A'-1
sltu $t2,$t2,$t3
sltiu $t3,$t3,'Z'+1
and $t2,$t2,$t3
sll $t2,$t2,5 # $t2 = 0x20, or 0
xor $t1,$t1,$t2 # either swap case or do nothing

MIPS: removing non alpha-numeric characters from a string

I'm in the process of writing a program in MIPS that will determine whether or not a user entered string is a palindrome. It has three subroutines which are under construction.
Here is the main block of code, subroutines to follow with relevant info:
.data
Buffer: .asciiz " " # 80 bytes in Buffer
intro: .asciiz "Hello, please enter a string of up to 80 characters. I will then tell you if that string was a palindrome!"
.text
main:
li $v0, 4 # print_string call number
la $a0, intro # pointer to string in memory
syscall
li $v0, 8 #syscall code for reading string
la $a0, Buffer #save read string into buffer
li $a1, 80 #string is 80 bytes long
syscall
li $s0, 0 #i = 0
li $t0, 80 #max for i to reach
la $a0, Buffer
jal stripNonAlpha
li $v0, 4 # print_string call number
la $a0, Buffer # pointer to string in memory
syscall
li $s0, 0
jal findEnd
jal toUpperCase
li $v0, 4 # print_string call number
la $a0, Buffer # pointer to string in memory
syscall
Firstly, it's supposed to remove all non alpha-numeric characters from the string before hand, but when it encounters a character designated for removal, all characters after that are removed.
stripNonAlpha:
beq $s0, $t0, stripEnd #if i = 80 end
add $t4, $s0, $a0 #address of Buffer[i] in $t4
lb $s1, 0($t4) #load value of Buffer[i]
addi $s0, $s0, 1 #i = i + 1
slti $t1, $s1, 48 #if ascii code is less than 48
bne $t1, $zero, strip #remove ascii character
slti $t1, $s1, 58 #if ascii code is greater than 57
#and
slti $t2, $s1, 65 #if ascii code is less than 65
slt $t3, $t1, $t2
bne $t3, $zero, strip #remove ascii character
slti $t1, $s1, 91 #if ascii code is greater than 90
#and
slti $t2, $s1, 97 #if ascii code is less than 97
slt $t3, $t1, $t2
bne $t3, $zero, strip #remove ascii character
slti $t1, $s1, 123 #if ascii character is greater than 122
beq $t1, $zero, strip #remove ascii character
j stripNonAlpha #go to stripNonAlpha
strip:
#add $t5, $s0, $a0 #address of Buffer[i] in $t5
sb $0, 0($t4) #Buffer[i] = 0
#addi $s0, $s0, 1 #i = i + 1
j stripNonAlpha #go to stripNonAlpha
stripEnd:
la $a0, Buffer #save modified string into buffer
jr $ra #return
Secondly, it is supposed to convert all lowercase characters to uppercase.
toUpperCase:
beq $s0, $s2, upperEnd
add $t4, $s0, $a0
lb $s1, 0($t4)
addi $s1, $s1, 1
slti $t1, $s1, 97
#beq $t1, $zero, upper
slti $t2, $s1, 123
slt $t3, $t1, $t2
bne $t1, $zero, upper
j toUpperCase
upper:
add $t5, $s0, $a0
addi $t6, $t6, -32
sb $t6, 0($t5)
j toUpperCase
upperEnd:
la $a0, Buffer
jr $ra
The final subroutine, which checks if the string is a palindrome isn't anywhere near complete at the moment. I'm having trouble finding the end of the string because I'm not sure what PC-SPIM uses as the carriage return character.
Any help is appreciated, I have the feeling most of my problems result from something silly and stupid so feel free to point out anything, no matter how small.
Uh, this is a really old question, but the problem is that you're replacing the non-alphanumeric characters with a null character, which terminates the string at that point.
You can find out the value by doing something like this:
syscall to reading a string
mov first value to $2
check the value of $2 with PC-SPIM or a debugger