Trying to get this program to work but I can't figure out why I keep getting an error. The program is suppose to take an entry of 11 characters, then output the reversed input. The error is as below.
Runtime exception at 0x00400034: store address not aligned on word boundary 0x7fffeffb
The code is posted below. I also need to store the final reversed string into 'revstr'. I am just having trouble with the reversal.
.data
str: .space 12
revstr: .space 12
prompt: .asciiz "Enter in string, max 11 characters: "
.text
main:
la $a0, prompt #calling opening prompt
li $v0, 4
syscall
li $v0, 8
la $a0, str
li $a1, 12
syscall
li $t0, 0
subu $sp, $sp, 1
sw $t0, ($sp)
li $t1, 0
bump1:
lbu $t0, str($t1)
beqz $t0, stend
subu $sp, $sp, 4
sw $t0, ($sp)
addu $t1, $t1, 1
j bump1
stend: li $t1, 0
populate:
lw $t0, ($sp)
addu $sp, $sp, 4
beqz $t0, done
sb $t0, str($t1)
addu $t1, $t1, 1
j populate
done:
li $v0, 4
la $a1, str
syscall
li $v0, 10
syscall
You are using a 32-bit machine, you should use offsets that are multiples of 4 bytes
=> 4*8=32
for you words to be aligned
otherwise your instructions must be byte oriented (lb sb lbu etc.. not lw..)
also correct these:
lw $t0, ($sp) it is better to specify the offset to avoid confusion
The code you posted confused me pretty good. You are modifying $sp in the middle of a function which is generally a no-go, and I couldn't figure out why you were doing it. Also, you say you want to store the reversed string in revstr but all sb instructions are pointed at str.
It's a good idea when communicating assembly to others to give them some pseudo-code to show them the general approach you are attempting to use. Here's mine:
str := user_input()
$t1 := len(str)
$t2 := 0
while ($t1 >= 0) {
revstr[$t2] := str[$t1]
$t1 := $t1 - 1
$t2 := $t2 + 1
}
With that mental picture, it should be fairly easy to understand how I've modified your assembly:
str: .space 12
revstr: .space 12
prompt: .asciiz "Enter in string, max 11 characters: "
.text
main:
la $a0, prompt #calling opening prompt
li $v0, 4
syscall
li $v0, 8
la $a0, str
li $a1, 12
syscall
li $t1, 0
bump1:
lbu $t0, str($t1)
beqz $t0, stend
addu $t1, $t1, 1
j bump1
stend:
li $t2, 0
addi $t1, $t1 -1
populate:
blt $t1, $zero, done
lb $t3, str($t1)
sb $t3, revstr($t2)
sub $t1, $t1, 1
add $t2, $t2, 1
j populate
done:
sb $zero, revstr($t2) #null terminate revstr
li $v0, 4
la $a0, revstr
syscall
li $v0, 10
syscall
Related
I'm writing a function that should return the square root of a perfect square recursively as part of a longer assignment.
I was following this mathematical method before I reverted to an even simpler algorithm to see if the error would repeat itself and it did.
The following code:
.data
prompt: .asciiz "num2sqrt: "
.text
.globl main
sqrt:
# save return address & t0
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t0, 4($sp)
# t0 = n
move $t0, $a0
# a0 = n/2
srl $a0, $t0, 1
jal sqrtRecursor
#restore return address & t0
lw $t0, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
sqrtRecursor:
# save return address & t1
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $t1, 4($sp)
# square test
mult $a0, $a0
mflo $t1
beq $t1, $t0, returnAnswer
bne $t1, $t0, newGuess
#restore return address & t1
lw $t1, 4 ($sp)
lw $ra, 0 ($sp)
addi $sp, $sp, 8
jr $ra
returnAnswer:
move $v0, $a0
newGuess:
# t1 = (((x+1)*guess)/x)/2
# x+1
addi $t1, $t0, 1
# *guess
mult $a0, $t1
mflo $t1
# /x
div $t1, $t0
mflo $t1
# /2
srl $t1, $t1, 1
move $a0, $t1
jal sqrtRecursor
main:
#print "Enter num2sqrt: "
la $a0, prompt
li $v0, 4
syscall
#input num2sqrt
li $v0, 5
syscall
move $s1, $v0
move $a0, $s1
jal sqrt
# print result
move $a0, $v0
li $v0, 1
syscall
# end
li $v0, 10
syscall
returns the following error on QTSpim:
Can't expand stack segment by 12 bytes to 524288 bytes. Use -lstack # with # > 524288
which then hangs the app for a minute or so.
I've double checked that I'm saving and returning all my return addresses and used variables, and also attempted implementing the same algorithm in Java separately (which worked), but have yet been unable to figure out what I need to fix and where.
I've been able to implement a power function before this so I'm not a complete novice and am asking after putting in approximately 5 hours of research and debugging on this.
It could be a stack management problem or an if/else implementation error from the intuition I have about my own code.
Here is my code that calculates the sum of two arrays and then prints them in a message to the the console. I would now like to compare my two array sums and return the correct message prompt depending on which array is larger. I feel like I'm very close because I tried to follow the logic from the first printed statements but how can I compare register $s7 & $s8 and then declare one the larger array through my message prompt I have set up? I'm using this emulator: https://cpulator.01xz.net/?sys=mipsr5-spim
.data
x: .word 1,2,3,4,5,6,7,8,9,10
iterator: .word 0
size: .word 9
prompt: .asciiz "The total sum of the array is equal to: "
.text
main:
la $s0, prompt
la $t0, x
lw $t1, iterator
lw $t2, size
begin_loop:
bgt $t1, $t2, exit_loop
sll $t3, $t1, 2
addu $t3, $t3, $t0
lw $t6, 0($t3)
addu $s7, $s7, $t6
addi $t1, $t1, 1
j begin_loop
exit_loop:
li $v0, 4
la $a0, prompt
syscall
li $v0, 1
la $a0, ($s7)
syscall
.data
x2: .word 5,6,7,8,9,10,11,12,13,14
iterator2: .word 0
size2: .word 9
prompt2: .asciiz "The total sum of array 2 is equal to: "
prompt3: .asciiz "The larger array is array 1"
prompt4: .asciiz "The larger array is array 2"
.text
main2:
la $s0, prompt2
la $t0, x2
lw $t1, iterator2
lw $t2, size2
begin_loop2:
bgt $t1, $t2, exit_loop2
sll $t3, $t1, 2
addu $t3, $t3, $t0
lw $t6, 0($t3)
addu $s8, $s8, $t6
addi $t1, $t1, 1
j begin_loop2
exit_loop2:
li $v0, 4
la $a0, prompt2
syscall
li $v0, 1
la $a0, ($s8)
syscall
slt $t1,$s7,$s8 # checks if $s0 > $s1
beq $t1,1,prompt3 # if $s7 > $s8, goes to prompt3
beq $t1,$zero,prompt4 # if $s8 < $s7, goes to prompt4
li $v0, 4
la $a0, prompt3
syscall
li $v0, 4
la $a0, prompt4
syscall
So I have created this program to count the number of lowercase letters in a string. The problem I am having is that when I reach the end of the string and the nl character is reached, the line beq $t0, $t1, end is not being executed; it just continues indefinitely. I'm not sure what I'm doing incorrectly.
.data
msg1: .word 0:24
.text
.globl main
main:
addu $s0, $0, $ra
li $v0, 8
la $a0, msg1
la $a1, 100
syscall
loop:
lb $t0, 4($a0)
li $t1, 0x0a
beq $t0, $t1, end
continue:
li $t1, 'a'
blt $t0, $t1, count
li $t1, 'z'
bgt $t0, $t1, count
count:
addi $t4, $t4, 1
j loop
end:
li $v0, 1
addu $a0, $t2, $0
syscall
jr $ra
You compare 4($a0) with 0x0a on each iteration of the loop, but you never change $a0 in the loop, so you are not advancing through your string and never look at the \n at the end of the string.
There also are a few other bugs in your code.
Use this at the start of your loop:
loop:
lb $t0, 0($a0)
addiu $a0, $a0, 1
...
I'm writing a MIPS program (assembly language) that takes in 10 integers and prints out a histogram represented by asterisks.
E.g.:
User input of 1, 2, 3, 4
Output:
*
**
***
****
I have most of this code written already in MIPS. The problem I am running into is printing out the correct length of asterisks. As of now it is simply printing out the a histogram all of the same length; the FIRST user inputed integer.
# program functionality:
.data
menu: .asciiz "\n1. New Histogram\n2. Print Histogram\n3. Quit\n"
prompt: .asciiz "\nEnter 10 numbers between 0 and 50 (inclusive):\n"
prompt1: .asciiz "\nEnter a valid number:\n"
asterisk: .asciiz "*"
space: .asciiz "\n"
array: .word 0:10
.text
main:
do:
jal print_menu
li $v0, 5
syscall
beq $v0, 1, new
beq $v0, 2, print
beq $v0, 3, quit
j do # end do
new:
jal new_user
j do
print:
jal print_user
j do
j quit
print_menu:
la $a0, menu
li $v0, 4
syscall
jr $ra
new_user:
la $a0, prompt
li $v0, 4
syscall
enter_loop:
la $t0, array
li $t1, 10
enter_loop_2:
la $a0, prompt1
li $v0, 4
syscall
li $v0, 5
syscall
sw $v0, ($t0)
addi $t1, $t1, -1
beqz $t1, end_loop_2
addi $t0, $t0, 4
j enter_loop_2
end_loop_2:
jr $ra
print_user:
la $t0, array
li $t1, 10
pLoop:
la $a0, space
li $v0, 4
syscall
asterisk_fun:
li $v0, 1
lw $a0, ($t0)
syscall
counter:
la $a0, asterisk
li $v0, 4
syscall
addi $a0, $a0, -1
beqz $a0, asterisk_end
j counter
asterisk_end:
jr $ra
addi $t1, $t1, -1
beqz $t1, endpLoop
addi $t0, $t0, 4
j pLoop
endpLoop:
jr $ra
quit:
li $v0, 10
syscall
The problems is that you are overwriting register $a0 in counter with the address of the asterisk, and you also used $a0 to count the number of items in that bucket.
Easy solution is to use other register (e.g. $a1) to count the number of items:
That would be:
#... your code
asterisk_fun:
li $v0, 1
lw $a1, ($t0) # Load number in $a1
move $a0, $a1 # move to $a0 just to print it
syscall
la $a0, asterisk
counter:
li $v0, 4
syscall
addi $a1, $a1, -1 # we use $a1 to keep the counter
beqz $a1, asterisk_end
j counter
asterisk_end:
# ... more of your code
I trying to write a MIPS program that gets an unsigned integer as argument and returns the sum of all decimal digits in the integer recursively. For example if the argument is 75080 then the sum to be returned is 20 (7+5+0+8+0). Here is my code so far. Any help would be appreciated.
My way of thinking was to divide the number by 10 leaving me with the last integer in the number, add the reminder using mfhi.
.data
prompt: .asciiz "Enter a string of integer: "
output: .asciiz "\nThe total sum is: "
.text
.globl main
main:
la $a0, prompt
li $v0, 4
syscall
li $v0, 5
syscall
move $t2, $v0
la $a0, output
li $v0, 4
syscall
Loop:
div $t2, $t2, 10
mflo, $t1
mfhi, $t3
beqz $t1, Exit
add $t1, $t1, 0
b additive
additive:
add $t0, $t1, $t1
j Loop
Exit:
la $a0, output
li $v0, 4
syscall
la $v0, 10
syscall
What's this supposed to be doing? Adding 0 to the register won't change its value:
add $t1, $t1, 0
After dividing and copying to $t1 and $t3, the quotient is in $t1 and the remainder is in $t3. You're treating it the other way around when you add to the total.
This is actually going to give you $t0 = 2 * $t1: you're adding $t1 to itself and storing the result in $t0.
add $t0, $t1, $t1
You probably actually want:
add $t0, $t0, $t3
You're checking for $t1 == 0 before adding the remainder to the total, so the most significant digit will never get added. You don't really need a subroutine for adding to the total either. You can also use bnez Loop instead of beqz Exit -> b Loop. Lastly, you don't even need $t1, because the quotient is already in $t2.
Get rid of additive and replace Loop with this:
Loop:
div $t2, $t2, 10
mfhi, $t3
add $t0, $t0, $t3
bnez $t2, Loop
Your Exit is weird: you're printing the output string a second time instead of printing the integer.
Change it to this:
Exit:
move $a0, $t0
la $v0, 1
syscall
la $v0, 10
syscall
The approach is quite simple. You need recursive function, I named it SumDigits that will take the last digit and repeat procedure for all digits in the argument. After the recursive call returns you'll add digit to the previous result. The code is commented for easier understanding. The code follows:
.text
#calculates sum of digits recursively
SumDigits:
sub $sp, $sp, 12 #alloocate 12B on stack
sw $ra 0($sp) #save return address
sw $a0, 4($sp) #save argument
beq $a0, $0, exit_sumdigits #when there is no more digits return 0
rem $t0, $a0, 10 #get last digit
sw $t0, 8($sp) #save it on stack
div $a0, $a0, 10 #divide argument by 10
jal SumDigits #repeat procedure
lw $t0, 8($sp) #read digit from stack
add $v0, $v0, $t0 #add digit to previous result
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
exit_sumdigits:
li $v0, 0 #there are no more digits, return 0
lw $ra, 0($sp) #load return address
addi $sp, $sp, 12 #free stack
jr $ra #return
main:
li $a0, 75080 #load number in $a0
jal SumDigits #call SumDigits
move $a0, $v0 #set a0 = result of SumDigits
li $v0, 1 #set $v0 for print int system call
syscall
li $v0, 10 #set $v0 for exit system call
syscall
.data