QtSpim not responding when I load my own file and throws errors when loading other files - mips

I'm trying to load this file but QtSpim stops responding when doing so
# Description : This program reads two user inserted integers and asks the
# user which is their greatest common divisor.
# If the user answers correctly the program congratulates the user, if
# not, the user is asked to try again.
.text
.globl _start
_start:
la $a0, str1 # loads str1 address to $a0
li $v0, 4 # loads $v0 with the contents of $a0 to print it
syscall # prints str1
li $v0, 5 # reads the first user inserted integer from the console and
# stores it to $v0
add $a1, $v0, $zero # stores the first integer from $v0 to $a1
syscall # executes the previous commands
la $a0, str2 # loads str2 address to $a0
li $v1, 4 # loads $v1 with the contents of $a0 to print it
syscall # prints str2
li $v1, 5 # reads the second user inserted integer from the console
# and stores it to $v1
add $a2, $v1, $zero # stores the second integer from $v1 to $a2
syscall # executes the previous commands
la $a0, str3 # loads str3 address to $a0
li $v0, 4 # loads $v0 with the contents of $a0 to print it
syscall # prints str3
jal gcd # calls the method named gcd
syscall
gcd:
# y = a % b;
rem $a3, $a1, $a2 # stores the remainder of the division of the
# first integer with the second to $a3
# while (y != 0) {
# a = b;
# b = y;
# y = a % b;
# }
again:
# y = 0; break;
beq $a3, $zero goto exit # if the contents of $a3 equal zero,
# go to exit
syscall
# a = b;
add $a1, $a2, $zero # stores the contents of the 2nd integer to
# the register of the 1st
syscall
# b = y;
add $a2, $a3, $zero # stores the contentnts of y to the register
# of the 2nd integer
syscall
# y = a % b;
rem $a3, $a1, $a2 # stores the remainder of the division of
# the first integer with the second to $a3
j again # jumps to again to do the next iteration of the
# loop
syscall
exit:
jal printQuestion # calls the method named printQuestion
syscall
printQuestion:
loop:
li $v0, 5 # reads the user's answer from the console and
# stores it to $v0
add $s0, $v0, $zero # stores the user's answer from $v0 to $s0
syscall #executes the previous commands
# s = b;
beq $s0, $a2 goto end # if the contents of $s0 are equal with
# the contents of $a2
la $a0, str5 # loads str5 address to $a0
li $v1, 4 # loads $v1 with the contents of $a0 to print it
syscall # prints str5
la $a0, str6 # loads str6 address to $a0
li $v1, 4 # loads $v1 with the contents of $a0 to print it
syscall # prints str6
j loop # jumps to loop
end:
la $a0, str4 # loads str4 address to $a0
li $v1, 4 # loads $v0 with the contents of $a0 to print it
syscall # prints str4
.data
str1: .asciiz "Please insert the first integer : \n"
str2: .asciiz "Please insert the second integer : \n"
str3: .asciiz "Which is the GCD of the first and second integer? \n"
str4: .asciiz "Congratulations! \n"
str5: .asciiz "Wrong answer. Please try again. \n"
str6: .asciiz "Which is the GCD? \n"
However, when a different file (that I copy pasted to see if it works) does load and I try to run it, I'll get these errors:
Exception occurred at PC=0x00000000
Bad address in text read: 0x00000000
Attempt to execute non-instruction at 0x80000180
Is it my code's fault or is something else wrong?
Edit: I'm using the Simple Machine setting.

Spim expects the user code to start at label main, so without it, it will error when running the code.
So you need to change the _start to main in the label and .global.
The beq $a3, $zero goto exit used in two places in invalid as the beq command expects a comma after the $zeroo, and the label to go to - not 'goto label'
You also have a number of syscall statements, but don't set the values v0 value - you are assuming its still the same, or forgot to do it ? Also in some places it looks like you are seeting v1 when you probally meant to set v0 for the syscall.
For example:
la $a0, str1 # loads str1 address to $a0
li $v0, 4 # loads $v0 with the contents of $a0 to print it
syscall # prints str1
Is setting v0 to 4, getting ready for the print string system, which expects the string it will print in a0 (which you set up)
The next lines:
li $v0, 5 # reads the first user inserted integer from the console and
# stores it to $v0
add $a1, $v0, $zero # stores the first integer from $v0 to $a1
syscall # executes the previous commands
Setting v0 to 5 is getting ready for the reading systecall - not sure what add a1, v0 is supposed to be doing, but after the syscall,, v0 will hold the read value. that now needs be stored somewhere.
Next lines:
la $a0, str2 # loads str2 address to $a0
li $v1, 4 # loads $v1 with the contents of $a0 to print it
syscall # prints str2
You want to print str2 similar to how you printed atr1, so a0 is set to the address str2 (which toy did), v0 needs to be 4 (Not v1)
There are repeated instances of that throught the code, as well as places where you do a syscall without setting v0 at all.

Related

Swapping every two characters in a string and fixing exception error

I'm getting an exception error and I'm not sure why. I need some help with the fix for the exception and how to swap chars in the user inputted string?
The input and output should look something like this:
Input : Apples
Output : pAlpse
.text
main:
#Prompt user for string
la $a0, promptStr
li $v0, 4
syscall
#Get String
li $v0,8
la $a0, buffer
li $a1, 20
syscall
move $t0, $a0
#Initialize pointer to start of string (specify register)
la $t0, buffer
#Get a char from the string (register)
loop: lb $t1, ($t0)
I'm getting Instruction references undefined here and I have no idea why because I've used it in similar problems to branch out of a loop when at the end of a string.
Here's the error message
Instruction references undefined symbol at 0x00400058
[0x00400058] 0x11200000 beq $9, $0, 0 [strEnd-0x00400058]; 48: beqz $t1, strEnd
#IF at end of the string branch to endStr
beqz $t0, strEnd
#Add 1 to the string pointer
add $t0, 1#Fixed
#get the next char in the string
lb $t2, ($t0)
I don't know if this code is right. I just need help understanding
how to swap chars and what the code will look like.
#Swap the 2 chars by writing them back to the original string
sb $t2, ($t0)
sb $t1, ($t0)
#Add 1 to the string pointer
add $t0, 1 #Fixed
#Jump back to loopStart
j loop
#Display modified string
endStr: la $a0,ans
li $v0, 4
syscall
move $a0,$t2
li $v0, 4
syscall
#Blankline
la $a0, end
li $v0, 4
syscall
#Exit porgram
li $v0, 10
syscall
.data
buffer: .space 20
promptStr: .asciiz "Input a string : "
blankLine : .asciiz "\n"
The issue with your error beqz $t0, strEnd is a typo: the label you meant is endStr. The error itself tells you this, highlighting [strEnd-0x00400058] as undefined. Additionally, spim warns me on load:
The following symbols are undefined:
end
ans
After fixing the missing labels, the logic is not quite correct, although it looks like you're on the right track. The idea is to step over the string in character pairs, swapping elements and exiting when hitting a null character (and, optionally, a newline depending on how you want to handle that--stripping/chomping it is probably best).
For starters and a rather minor point, there is a dead instruction near the top of your program:
move $t0, $a0 # $t0 will be overwritten by the next la
#Initialize pointer to start of string (specify register)
la $t0, buffer
Stepping into the loop and the main logic, the code beqz $t0, strEnd uses the address of the string which will never be 0 as the branch condition rather than the byte at that address, $t1. This gives an infinite loop.
Next, there is a problem with $t0, the pointer that walks the string. The logic
sb $t2, ($t0)
sb $t1, ($t0)
doesn't work because $t0 was already incremented so the code loses track of the previous byte address after
#Add 1 to the string pointer
add $t0, 1#Fixed
A solution is to store $t0 in a temporary register before any add $0, 1 operations. Something like:
move $t3 $t0 # save the address of buf for swap
# ... later on, after incrementing `$t0` ...
sb $t2, ($t3)
sb $t1, ($t0)
You could also use an indexing strategy here by adding/subtracting offsets or using an index to walk the string.
Lastly, I'm not sure what move $a0,$t2 should do towards the end of the program when you're printing.
Here's one possible solution that addresses these issues and generally cleans up the logic:
.text
main:
# prompt user for string
la $a0 prompt
li $v0 4
syscall
# get string
la $a0 buffer
li $a1 20
li $v0 8
syscall
move $s0 $a0 # incrementable pointer to buf
loop:
# t1 = *(buf++) and exit if '\0' or '\n'
move $t0 $s0 # save the address of buf for swap
lb $t1 ($t0) # t1 = *buf
beqz $t1 end # break if '\0'
beq $t1 10 end # break if '\n'
add $s0 1 # buf++
# t2 = *buf and exit if '\0' or '\n'
lb $t2 ($s0) # t2 = *buf
beqz $t2 end # break if '\0'
beq $t2 10 end # break if '\n'
# swap the chars
sb $t2 ($t0) # *prev_buf = curr_buff_char
sb $t1 ($s0) # *buf = prev_buff_char
# increment pointer and continue to the next pair
add $s0 1 # buf++
j loop
end:
# display modified string
la $a0 buffer
li $v0 4
syscall
# exit program
li $v0 10
syscall
.data
buffer: .space 20
prompt: .asciiz "Input a string : "
Sample runs:
$ spim -f swap_alternating_chars.s
Input a string : Apple
pAlpe
$ spim -f swap_alternating_chars.s
Input a string : Apples
pAlpse

creating a check for a loop in driver

I created code for a procedure that outputs the factoral of a number given. But it needs to ask the user for a number until they enter a negative before it exits.
So that it looks something like this
Enter a value for n (or a negative value to exit): 6
6! is 720
Enter a value for n (or a negative value to exit): 9
9! is 362880
Enter a value for n (or a negative value to exit): 11
11! is 39916800
Enter a value for n (or a negative value to exit): 20
20! is -2102132736
Enter a value for n (or a negative value to exit): 100
100! is 0
Enter a value for n (or a negative value to exit): -1
Thanks for Testing!
Instead of something like this.
Enter the value of a number (or negative to exit): 5
Value returned is 120
Thanks for testing!
fact:
slti $t0, $a0, 1 # test for n < 1
beq $t0, $zero, L1 # if n >= 1, go to L1
li $v0, 1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp, $sp, -8 # adjust stack for 2 items
sw $ra, 4($sp) # save the return address
sw $a0, 0($sp) # save the argument n
addi $a0, $a0, -1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0, 0($sp) # return from jal: restore argument n
lw $ra, 4($sp) # restore the return address
addi $sp, $sp, 8 # adjust stack pointer to pop 2 items
mul $v0, $a0, $v0 # return n * fact (n – 1)
jr $ra # return to the caller
main:
la $a0, nreq # get value of n
li $v0, 4
syscall
li $v0, 5 # read value of n
syscall
move $a0, $v0 # place value n in $a0
jal fact # invoke fact
move $s0, $v0 #save value returned by facts
la $a0, ans # display
li $v0, 4
syscall
move $a0, $s0
li $v0, 1
syscall
la $a0, cr #display closing
li $v0, 4
syscall
li $v0, 10 # exit
syscall
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
cr: .asciiz "\nThanks for testing!\n"
Overall, pretty close. However, one or two things.
I'd move main to the top, above fact, as some simulators start at the lowest .text address rather than the given symbol main. For example, in mars, this didn't seem to work until I reversed the order.
main was missing the test for negative input and didn't loop on itself.
Here's a version that seems to work [please pardon the gratuitous style cleanup]:
.text
.globl main
main:
la $a0,nreq # get value of n
li $v0,4
syscall
li $v0,5 # read value of n
syscall
# NOTE/BUG: add this
bltz $v0,exit # exit program on negative
move $a0,$v0 # place value n in $a0
jal fact # invoke fact
move $s0,$v0 # save value returned by facts
la $a0,ans # display
li $v0,4
syscall
move $a0,$s0
li $v0,1
syscall
# NOTE: add this
li $v0,4
la $a0,nl
syscall
j main
exit:
la $a0,cr # display closing
li $v0,4
syscall
li $v0,10 # exit
syscall
fact:
slti $t0,$a0,1 # test for n < 1
beq $t0,$zero,L1 # if n >= 1, go to L1
li $v0,1 # return 1
jr $ra # return to instruction after jal
L1:
addi $sp,$sp,-8 # adjust stack for 2 items
sw $ra,4($sp) # save the return address
sw $a0,0($sp) # save the argument n
addi $a0,$a0,-1 # n >= 1; argument gets (n – 1)
jal fact # call fact with (n – 1)
lw $a0,0($sp) # return from jal: restore argument n
lw $ra,4($sp) # restore the return address
addi $sp,$sp,8 # adjust stack pointer to pop 2 items
mul $v0,$a0,$v0 # return n * fact (n – 1)
jr $ra # return to the caller
.data
nreq: .asciiz "Enter a value for n (or negative to exit): "
ans: .asciiz "Value returned is "
nl: .asciiz "\n"
cr: .asciiz "\nThanks for testing!\n"

Why am i getting Runtime exception: fetch address not aligned on word boundary

I had task for my schoolwork that included this code and i need to fix it but i can't continue now... The code is supposed to move one array t
.data
source: .word 3, 1, 4, 1, 5, 9, 0
dest: .word 0, 0, 0, 0, 0, 0, 0
countmsg: .asciiz " values copied. "
.text
main: la $a0,source
la $a1,dest
loop: lw $v1, 0($a0) # read next word from source
addiu $v0, $v0, 1 # increment count words copied
sw $v1, 0($a1) # write to destination
addiu $a0, $a0, 1 # advance pointer to next source
addiu $a1, $a1, 1 # advance pointer to next dest
bne $v1, $zero, loop# loop if word copied not zero
loopend:
move $a0,$v0 # $a0 <- count
jal puti # print it
la $a0,countmsg # $a0 <- countmsg
jal puts # print it
li $a0,0x0A # $a0 <- '\n'
jal putc # print it
finish:
li $v0, 10 # Exit the program
syscall
### The following functions do syscalls in order to print data (integer, string, character)
#Note: argument $a0 to syscall has already been set by the CALLEE
puti:
li $v0, 1 # specify Print Integer service
syscall # Print it
jr $ra # Return
puts:
li $v0, 4 # specify Print String service
syscall # Print it
jr $ra # Return
putc:
li $v0, 11 # specify Print Character service
syscall # Print it
jr $ra # Return
It returns Runtime exception at 0x00400010: fetch address not aligned on word boundary 0x10010001
The error is on line 11 i think but i can't solve it.
Shouldn't it be addiu $a0, $a0, 4 as you have to jump to next word
You are advancing pointers wrong.
If the elements of your array are words, then you have to use lw/sw to read/write elements from/to the array and take into account that each element occupies 4 bytes (thus, 1 word). So to advance the pointer you have to add 4 to the pointer ($a0 and $a1 in your code).
If you were trying to use an array of bytes then you'd use .byte directive to define your array, lb/sb and advance the pointer by increment it 1 position at a time (as you are doing in your code).

MIPS Calculator

I'm trying to finish up this MIPS calculator, super basic, my first mips program. It doesn't have to handle overflow or anything like that, just has to work on small, positive numbers.
I've not checked my algorithms for multiply and divide, because I am just trying to get add working.
I cannot for the life of me figure out why the ints will not read in and also I'm getting a memory out of bounds when I call lb $a0, op to display the operator for output and don't understand why.
I'm new to this so anything is probably helpful. Thanks in advance.
.data
# const string for welcome
welc: .asciiz "Welcome to SPIM Calculator 1.0!\n"
p_int: .asciiz "\nPlease give an integer: "
p_op: .asciiz "\nPlease give an operator: "
i_err: .asciiz "\nInput Incorrect, bad operator!\n"
again_str: .asciiz "Another calculation? (y/n)"
rmndr: .asciiz " r: "
new_line: .asciiz "\n"
int1: .word 1 # space to hold int 1
int2: .word 1 # space to hold int 2
raw_in: .space 1 # space to hold raw input
op: .space 1 # space to hold operator char
a_char: .space 1 # space to hold again char
out: .word 1 # space to hold output
remain: .word 1 # space to hold remainder
#operator constants
c_plus: .ascii "+" # const for +
c_min: .asciiz "-" # const for -
c_mult: .asciiz "*" # const for *
c_divi: .asciiz "/" # const for /
c_eq: .asciiz "=" # const for =
c_no: .asciiz "n" # const for n
.text
.globl main
main: li $v0, 4 # syscall 4, print string
la $a0, welc # give argument: string
syscall # actually print string
calc: la $t6, remain # load remainder variable
move $t6, $zero # store 0 in remainder (reset)
li $v0, 4 # syscall 4, print string
la $a0, p_int # give argument: string
syscall # actually print string
li $v0, 5 # tell syscall we want to read int 1
syscall # actually read in int 1
la $s1, int1 # load int1 into $s1
move $s1, $v0 # copy the integer from $v0 to int1
li $v0, 4 # syscall 4, print string
la $a0, p_int # give argument: string
syscall # actually print string
li $v0, 5 # tell syscall we want to read int 2
syscall # actually read in int 2
la $s2, int2 # give $s2 the address to hold int 2
move $s2, $v0 # copy the integer from $v0 to $s2
li $v0, 4 # syscall 4, print string
la $a0, p_op # give argument: string
syscall # actually print string
li $v0, 8 # tell syscall we want to read operator
la $a0, op # give $a0 the address to hold the operator
syscall # actually read in operator
lb $t0, op # load the first byte of op
li $t1, '+' # load const for plus
li $t2, '-' # load const for minus
li $t3, '*' # load const for multiplying
li $t4, '/' # load const for dividing
la $s0, out # load out to $s0
beq $t0, $t1, plus # we're adding
beq $t0, $t2, minus # we're subtracting
beq $t0, $t3, multi # we're multiplying
beq $t0, $t4, divi # we're dividing
# else
j error # incorrect input
plus: add $s0, $s1, $s2 # add our ints, store in $t0
j print
minus: sub $s0, $s1, $s2 # subtract our ints, store in $t0
j print
multi: slt $t1, $t2, $s2 # if our counter is less than int2, set $t1 to 1
beq $t1, $zero, print # if we've reached int2, we're done
add $s0, $s1, $s1 # add int1 and int1, store in out
j multi # loop
divi: la $t0 remain # load remainder into $t0
move $t0, $s1 # set remainder to dividend
add $s0, $zero, $zero # set out to 0, just in case
loop: slt $t1, $t0, $s2 # if remainder is less than divisor, set 1
beq $t1, $zero, print # if we're done branch to done
sub $t0, $t0, $s2 # sub divisor from remainder, store in remainder
addi $s0, $s0, 1 # increment quotient by 1
j loop # loop
print: li $v0, 1 # tell syscall we want to print int
la $a0, int1 # give syscall int1 to print
syscall # actually print int
li $v0, 4 # tell syscall we want to print string
lb $a0, op # tell syscall we want to print operator
syscall # actually print string
li $v0, 1 # tell syscall we want to print int
la $a0, int2 # give syscall int2 to print
syscall # actually print int
li $v0, 4 # tell syscall we want to print string
la $a0, c_eq # tell syscall we want to print operator
syscall # actually print string
li $v0, 1 # tell syscall we want to print integer
la $a0, out # give syscall our output
syscall # actually print int
la $t0, remain # load remainder
beq $t0, $zero, again # if we have no remainder, finish printing
li $v0, 4 # tell syscall we want to print string
la $a0, rmndr # tell syscall we want to print remainder string
syscall # print "r: "
li $v0, 1 # tell syscall we want to print int
la $a0, remain # give syscall our remainder to print
syscall # print remainder
again: li $v0, 4 # tell syscall we want to print string
la $a0, new_line # tell syscall to print new line
syscall
la $a0, again_str # load prompt for again string for syscall
syscall
li $v0, 8 # tell syscall we want to read string
la $a0, a_char # tell syscall to put it in $a0
syscall
lb $t0, a_char
li $t1, 'n' # get n char so we can compare
beq $t0, $t1, exit # if we are done, exit
#else loop
j calc # jump to beginning
error: li $v0, 4 # tell syscall we want to print string
la $a0, i_err # give syscall what to print
syscall # actually print
j again # go to prompt for retry
exit: li $v0, 10 # exit code
syscall #exit!
screenshot
The problem is that you don't use the appropriate instruction to handle memory.
Instead of move you should use sw (store word). This code will not store the int into int1:
la $s1, int1 # load int1 into $s1
move $s1, $v0 # copy the integer from $v0 to int1
instead, you should write:
la $s1, int1 # load address of int1 into $s1
sw $v0, 0($s1) # copy the integer from $v0 to int1
Like storing, loading from memory require two instructions:
la $s1, p_op # or whatever register you choose to use
lb $a0, 0($s1) # load byte from the address stored in $s0 (in index 0)
if you want to load the address of p_op into $a0, you should use la $a0, p_op, not lb

Mips div.s syntax error

I am using QtSpim 9.9.1 to write my Computer Architecture course homework
i had a syntax error when use div.s operator but it's OK when I use div. Another error appears when try to get float from user but it also disappears when get integer. Here is my code :
.text
main:
# Print "This program solves an equation of style a*x + c = 0, print out the result on console."
la $a0, hello_msg # load the address of hello_msg into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
# Print "Enter (a) value please :"
la $a0, enter_a_msg # load the address of enter_a_msg into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
## Get (a) from user, put into $t0.
li $v0, 6 # load syscall read_float into $v0.
syscall # make the syscall.
move $t0, $f0 # move the number read into $t0.////////here got error//////
# Print "Enter (c) value please :"
la $a0, enter_c_msg # load the address of enter_c_msg into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
## Get (c) from user, put into $t1.
li $v0, 6 # load syscall read_float into $v0.
syscall # make the syscall.
move $t1, $f0 # move the number read into $t1.///////also here
# Compute (x), put into $t2.
neg $t3, $t1 # get -c into $t3.
div.s $t2, $t3, $t0 # get x = -c / a into $t2.//// also here Error
# Print "Value of (x) is :"
la $a0, result_msg # load the address of result_msg into $a0.
li $v0, 4 # 4 is the print_string syscall.
syscall # do the syscall.
# Print (x) value .
move $a0, $t2 # move (x) value into $a0.
li $v0, 1 # load syscall print_int into $v0.
syscall # make the syscall.
li $v0, 10 # 10 is the exit syscall.
syscall # do the syscall.
# Data for the program:
.data
hello_msg: .asciiz "This program solves an equation of style a*x + c = 0,\nprints out the result on console.\n"
enter_a_msg: .asciiz "Enter (a) value please :"
enter_c_msg: .asciiz "Enter (c) value please :"
result_msg: .asciiz "Value of (x) is :"
# end Equation.asm
move $t0, $f0
To convert a floating-point register to an integer and move it to a general-purpose register you should use something like this:
cvt.w.s $f0, $f0
mfc1 $t0, $f0
If you wanted to move $f0 to another floating-point register you should use e.g.:
mov.s $f1,$f0
div.s $t2, $t3, $t0
div.s works with floating-point registers ($f0-$f31), not with the general-purpose registers ($an, $tn, $vn and so on). Refer to the MIPS floating-point instruction set list.