lui $v0,%hi(length)
lw $v1,%lo(length)($v0)
li $v0,3 # 0x3
bne $v0,$zero,1f
div $zero,$v1,$v0
break 7
mfhi $v0
mflo $v0
sw $v0,28($fp)
lw $a1,28($fp)
lui $v0,%hi(game_over)
addiu $a0,$v0,%lo(game_over)
jal printf
nop
When I try running this for my MIPS code, it comes up with this error:
Your program produced these errors:
spim: (parser) Unknown character on line 180 of file measurement.s
lui $v0,%hi(length)
spim: (parser) syntax error on line 181 of file measurement.s
Instruction references undefined symbol at 0x00400038
[0x00400038] 0x0c000000 jal 0x00000000 [init_measure] ; 159: jal init_measure
Do I need to substitute %hi and $lo for something else in the code?
EDIT For the following code:
sw $v0,16($fp)
lui $a0,%hi(grid)
lw $v1,12($fp)
nop
move $v0,$v1
sll $v0,$v0,4
subu $v0,$v0,$v1
addiu $v1,$a0,%lo(grid)
addu $v1,$v0,$v1
lw $v0,16($fp)
And
lui $v0,%hi(column)
lb $v0,%lo(column)($v0)
nop
sw $v0,12($fp)
lui $v0,%hi(column)
addiu $v1,$v0,%lo(column)
lw $v0,8($fp)
nop
addiu $v1,$v0,-1
lui $v0,%hi(growth)
sw $v1,%lo(growth)($v0)
b true
nop
Will I be substituting %hi and % lo it in a similar manner or differently?
Those seem to be operators not supported by spim. %LO(label) should give you the lowest half of the address of label, and %HI(label) the upper half.
You can substitute these two instructions:
lui $v0,%hi(length)
lw $v1,%lo(length)($v0)
with this:
la $v0,length
lw $v1,0($v0)
So we use la pseudoinstruction to load the whole address of the label onto a register (in the example $v0) then you directly load its memory contents using 0 as the lw offset. Note that la pseudoinstruction would use 2 instructions for an arbitrary label address (and leave $at with the upper half address).
Also note that in your code $v0 would still hold the upper half of the label address whereas in the second snippet it will contain the whole address.
Similarily, instead of
lui $v0,%hi(game_over)
addiu $a0,$v0,%lo(game_over)
you can just issue:
la $a0, game_over
In this case, your code would end with $a0 having the address of game_over label (as in the second snippet), and $v0 holding the lower half of that address. la pseudoinstruction will leave the upper half of the label on $at
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
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.
Develop a project that will search a word within the paragraph, and can perform the two different operations. One is to find the word present or not. Other one is to replace with another word of same size using MIPS.
got a program to find length of word see if it helps:
.data
string:
.asciiz "In a distant galaxy eons before the creation of the
mythical planet known as earth, vast civilizations have eveolved and
ruling the galaxy is an interstellar Empire created from the ruins of an
Old Republic that held sway for generations"
return:
.asciiz "\n"
wordcntmsg:
.asciiz "the word count of the length x \n"
newline:
.asciiz "\n"
wordlength:
.ascii " character word = "
.align 4
TABLE: .space 100
.text
.globl main
main:
la $t0, string # stores the address for string in $t0
la $s1, TABLE
addi $t2, $0, 32 # stores the ascii value for space in $t2
LOOP:
lbu $t1, 0($t0) # load the next charater
beq $t1, $0, DONE # END of STRING
nop
beq $t1,$t2,RESETWLC # space
nop
addi $s0,$s0,1 #inclement word length cnt.
addi $t0,$t0,1 #point next character.
j LOOP
nop
RESETWLC:
#inclement the word lenght cnt of that word length
# from the memory location.($s1)
# find memory location.
beq $s0,$0,PreviousSF
nop
# address computation
add $t3,$0,$s0 #
addi $t3,$t3,-1
sll $t3,$t3,2 # multiply 4 to get byte address.
add $t3,$t3,$s1 # get momory address.
lw $t4,0($t3) # get previous word length cnt from the memory.
addi $t4,$t4,1
sw $t4,0($t3) # inclement and store the cnt back.
add $s0,$0,$0 #reset word length cnt
PreviousSF:
addi $t0,$t0,1 #point next character.
j LOOP
nop
DONE: # print and Exit..
beq $s0,$0,PRINT
nop
# address computation
add $t3,$0,$s0 #
addi $t3,$t3,-1
sll $t3,$t3,2 # multiply 4 to get byte address.
add $t3,$t3,$s1 # get momory address.
lw $t4,0($t3) # get previous word length cnt from the memory.
addi $t4,$t4,1
sw $t4,0($t3) # inclement and store the cnt back.
PRINT:
la $a0, wordcntmsg
li $v0, 4
syscall
li $t0,26
li $t1,1
P_LOOP: move $a0,$t1
li $v0,1
syscall
la $a0,wordlength
li $v0,4
syscall
add $t3,$0,$t1 #
addi $t3,$t3,-1
sll $t3,$t3,2 # multiply 4 to get byte address.
add $t3,$t3,$s1 # get momory address.
lw $a0,0($t3) # get previous word length cnt from the memory.
li $v0,1
syscall
la $a0,newline
li $v0,4
syscall
addi $t1,$t1,1
beq $t1,$t0,EXIT
nop
j P_LOOP
nop
EXIT: addi $v0, $0, 10
syscall # Exits program
LB_SUB: #
add $t4, $0, $a0 #
srl $t4, $t4, 2 #
sll $t4, $t4, 2 #
sub $t5, $a0, $t4 #
addi $t7, $0, 8 #
mul $t6, $t5, $t7 #
lw $v0, 0($t4) #
addi $t8, $0, 24 #
sub $t8, $t8, $t6 #
sll $v0, $v0, $t8 #
srl $v0, $v0, 24 #
jr $ra #
.data
para: .space 1000 # Pre allocate space for the input paragraph
copypara: .space 1000 #copy the original paragraph
input: .space 30 # Pre allocate space for the input word
copy: .space 30 # Duplicate string to store the word
replace: .space 30 # The alternative word
replacemsg: .asciiz "Enter the word you want to replace with the word you want to find: \n" #display the msg to enter the alternative word
ask: .asciiz "Enter the paragraph:\n" # Display msg to enter the paragraph
askwd: .asciiz "Enter the word you want to find:\n" # Display msg to enter the word you want to find
nomatch: .asciiz "Sorry...The word is not present in the given paragraph.\n"
match: .asciiz "Number of times the word present in the paragraph is :-\n"
line: .asciiz "\n"
origpar: .asciiz "\nTHE ORIGINAL PARAGRAPH IS:- \n-----------------------------------------------------------------------------\n"
result: .asciiz "-----------------------------------------------------------------------------\nTHE MODIFIED PARAGRAPH IS:-\n-----------------------------------------------------------------------------\n"
error: .asciiz "Sorry...The word you you want to replace with is not the same size of the word you want to find.\n"
#======================================================================================================================================================================
#-----------------------------------------------------------------------------------------------------
# USE OF REGISTERS:
#
# $s5- Stores characters of copypara
# $t5- Stores ascii value of new line
# $s2- Stores characters of word to find
# $s4- Stores characters of word to replace
# $s0- Stores characters of copy,.i.e , the extracted word
# $s1- Stores characters of the entered paragraph
# $t4- Counts the number of characters in the word to find and also acts as a counter
# $t7- Stores the number of times the find word is found
# $t6- Counts the number of characters in the extracted word
# $t0- Stores the characters of the input paragraph and is also used in the case comparision
# $t8- Stores the characters of the input paragraph
# $t2- Stores the characters of the word to find and the extracted word
# $t3- Stores the characters of the extracted word and also used in case comparision
# $s7- Stores the numer of characters of the word to find and the extracted word that are equal
#
#----------------------------------------------------------------------------------------------------
.text
main:
# print the msg to enter the paragraph
li $v0,4
la $a0,ask
syscall
# Take the input paragraph
la $a0,para
li $a1,1000 # allocate 1000 empty space
li $v0,8
syscall
la $s5,copypara #load the the base address of the copypara
# print the msg to enter the word you want to find
li $v0,4
la $a0,askwd
syscall
# take the word
la $a0,input
li $a2,30 # create 30 empty spaces
li $v0,8
syscall
move $s2,$a0 # move the adress of the input word from $a0 to $s2
# print the msg to enter the word you want to replace
li $v0,4
la $a0,replacemsg
syscall
# take the word
la $a0,replace
li $a2,30
li $v0,8
syscall
move $s4,$a0 # the alternative word address is on $s4
# Assign the recquired ascii values in registers and load the base address of the recquired variables in their respective registers
li $t5,10 # ascii value of new line
la $s0,copy # loading the addresses of copy of extracted word and the original para
la $s1,para # loading the address of the paragraph
li $t4,1 # count the number of letters present in input word
li $t7,0 # count the number of times the word present
# Count the number of letters prsent in the input word
lb $t6,0($s2)
count:
beq $t6,10,countreplace
addiu $s2,$s2,1
lb $t6,0($s2)
addi $t4,$t4,1
j count
# This block count the number of letters present in replace word
countreplace :
la $s4,replace
li $t1,1
lb $t3,0($s4)
counting:
beq $t3,10,minor
addiu $s4,$s4,1
lb $t3,0($s4)
addi $t1,$t1,1
j counting
# This minor restores the variable containts in their respecive registers
minor:
li $t6,1 # count the number of letters present in the extracted word
la $s2,input # load the base address of the input word
lb $t0,0($s1) # loading the first character of the para
j extract
# This block stores the the replace word in place of the input word iff the word is found
store2:
la $s4,replace
li $t0,1
storing2:
beq $t0,$t4,intr
lb $t2,0($s4)
sb $t2,0($s5)
addiu $t0,$t0,1
addiu $s4,$s4,1
addiu $s5,$s5,1
j storing2
j intr
# This block is used to restore the original word present in the paragraph if the input word is not found
store1:
li $t0,1
la $s0,copy
storing1:
beq $t0,$t6,intr
lb $t2,0($s0)
sb $t2,0($s5)
addiu $t0,$t0,1
addiu $s0,$s0,1
addiu $s5,$s5,1
j storing1
# This block is used to re-initialize the register containt after one itteration
intr:
la $s4,replace
lb $t0,0($s1)
beq $t0,10,Display
la $s0,copy
li $t6,1
addiu $s1,$s1,1
lb $t0,0($s1)
sb $t8,0($s5)
addiu $s5,$s5,1
# This block is used to extract each word from the paragraph and store it in another variable called copy
extract:
lb $t8,0($s1)
beq $t0,32,compare
beq $t0,46,compare
beq $t0,10,compare
beq $t0,44,compare
beq $t0,40,compare
beq $t0,41,compare
beq $t0,39,compare
beq $t0,34,compare
beq $t0,45,compare
beq $t0,58,compare
beq $t0,59,compare
beq $t0,63,compare
beq $t0,33,compare
beq $t0,123,compare
beq $t0,125,compare
beq $t0,91,compare
beq $t0,93,compare
beq $t0,96,compare
beq $t0,95,compare
sb $t0,0($s0)
addi $t6,$t6,1
addiu $s0,$s0,1
addiu $s1,$s1,1
lb $t0,0($s1)
j extract
#Compare the extracted word and the input word
compare:
sb $t5,0($s0)
la $s2,input
la $s0,copy
lb $t2,0($s2)
lb $t3,0($s0)
bne $t6,$t4,store1
li $s7,0
check:
bne $t2,$t3,checkagain
backagain:
addi $s7,$s7,1
beq $s7,$t4,success
addiu $s2,$s2,1
addiu $s0,$s0,1
lb $t2,0($s2)
lb $t3,0($s0)
j check
# This block is used to handle the case sensitiveness of the program
checkagain:
addi $t3,$t3,32
addi $t0,$t3,-64
beq $t2,$t3,backagain
beq $t2,$t0,backagain
j store1
# This block is used to count the number of times the word is present in the paragraph
success:
addi $t7,$t7,1
j store2
# This block display the messeges according to their results
Display:
bne $t4,$t1,errormsg
beq $t7,0,msg
li $v0,4
la $a0,match
syscall
li $v0,1
la $a0,($t7)
syscall
li $v0,4
la $a0,line
syscall
li $v0,4
la $a0,origpar
syscall
li $v0,4
la $a0,para
syscall
li $v0,4
la $a0,result
syscall
li $v0,4
la $a0,copypara
syscall
j exit
msg:
li $v0,4
la $a0,nomatch
syscall
li $v0,4
la $a0,origpar
syscall
li $v0,4
la $a0,para
syscall
j exit
errormsg:
li $v0,4
la $a0,match
syscall
li $v0,1
la $a0,($t7)
syscall
li $v0,4
la $a0,line
syscall
li $v0,4
la $a0,error
syscall
li $v0,4
la $a0,origpar
syscall
li $v0,4
la $a0,para
syscall
# The exit block
exit:
li $v0,10
syscall