MIPS Programs with more than 4 arguments - function
The following is my code and the final test case. main and printStats are both given, I had to qrite average (which is at the bottom), so look there for problems. This case changes the value of all registers in $f, $t, $a, and $s and adds 2 items to the top of its stack in order to ensure that the average method is preserving properly the values it will need to run its calculations following the $jr from printStats.
The problem I am having is recurring in a few test cases where there are 3 batters. Batter 3 uses arbitrarily large integers.
# printStats puts two values at the top two spots in its stack. This is where
# the number of homeruns and outs were placed when printStats
# is called. A function is allowed to change its own stack.
# Changes the $s registers used by main. The average function should be
# getting arguments from the $a registers and the stack, and not relying
# on what is in the $s registers.
# From test12:
# Tests if $t registers are preserved (if needed) by average.
# printStats puts values into every $t register.
# From test13:
# Tests if $a registers used correctly when average calls printStats.
# printStats changes the contents of $a1, $a2, and $a3 before returning
# test with three batters, both average and slugging percentage
# First batter has no hits, but does have outs
# Second batter has hits and outs, with realistic values
# Third hitter has large values for some of the hits and for the
# outs. This means the hits and outs *have* to be converted from int's
# to float's in order to get the right answer.
.data
mainNumBatters:
.word 3
mainBatter1:
.word 27 # walks
.word 0 # singles
.word 0 # doubles
.word 0 # triples
.word 0 # home runs
.word 423 # outs
mainBatter2:
.word 27 # walks
.word 101 # singles
.word 22 # doubles
.word 4 # triples
.word 10 # home runs
.word 423 # outs
mainBatter3:
.word 102322 # walks
.word 8000000 # singles
.word 22 # doubles
.word 500000 # triples
.word 10 # home runs
.word 23000000 # outs
.data
mainNewline:
.asciiz "\n"
mainBatterNumber:
.asciiz "Batter number: "
mainBattingAverage:
.asciiz "Batting average: "
mainSluggingPercentage:
.asciiz "Slugging percentage: "
mainOnbasePercentage:
.asciiz "On-base percentage: "
.text
main:
# Function prologue -- even main has one
addiu $sp, $sp, -24 # allocate stack space -- default of 24 here
sw $fp, 0($sp) # save frame pointer of caller
sw $ra, 4($sp) # save return address
addiu $fp, $sp, 20 # setup frame pointer of main
# for (i = 0; i < mainNumBatters; i++)
# compute batting average
# compute slugging average
la $s1, mainNumBatters
lw $s6, 0($s1) # $s6 = number of batters
addi $s0, $zero, 0 # $s0 = i = 0
la $s1, mainBatter1 # $s1 = addr of current batter's stats
mainLoopBegin:
slt $t0, $s0, $s6 # $t0 = i < number of batters
beq $t0, $zero, mainDone
la $a0, mainBatterNumber
addi $v0, $zero, 4
syscall
addi $a0, $s0, 1
addi $v0, $zero, 1
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
# Compute the batting average
addi $a0, $zero, 1 # $a0 = 1 = compute batting average
lw $a1, 0($s1) # $a1 = walks
lw $a2, 4($s1) # $a2 = singles
lw $a3, 8($s1) # $a3 = doubles
lw $s2, 12($s1) # $s2 = triples
lw $s3, 16($s1) # $s3 = home runs
lw $s4, 20($s1) # $s4 = outs
sw $s4, -4($sp) # put outs at top of average's stack
sw $s3, -8($sp) # put homeruns 2nd fm top of average's stack
sw $s2, -12($sp) # put triples 3rd fm top of average's stack
jal average
# Print the batting average
mtc1 $v0, $f12 # get result fm $v0 before we print string
la $a0, mainBattingAverage
addi $v0, $zero, 4
syscall
addi $v0, $zero, 2 # print the average
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
syscall
# do it for the slugging percentage
addi $a0, $zero, 2 # $a0 = 2 = compute slugging average
lw $a1, 0($s1) # $a1 = walks
lw $a2, 4($s1) # $a2 = singles
lw $a3, 8($s1) # $a3 = doubles
lw $s2, 12($s1) # $s2 = triples
lw $s3, 16($s1) # $s3 = home runs
lw $s4, 20($s1) # $s4 = outs
sw $s4, -4($sp) # put outs at top of average's stack
sw $s3, -8($sp) # put homeruns 2nd fm top of average's stack
sw $s2, -12($sp) # put triples 3rd fm top of average's stack
jal average
# Print the slugging percentage
mtc1 $v0, $f12 # get result fm $v0 before we print string
la $a0, mainSluggingPercentage
addi $v0, $zero, 4
syscall
addi $v0, $zero, 2 # print the percentage
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
syscall
# do it again for the on-base percentage
addi $a0, $zero, 3 # $a0 = 3 = compute slugging average
lw $a1, 0($s1) # $a1 = walks
lw $a2, 4($s1) # $a2 = singles
lw $a3, 8($s1) # $a3 = doubles
lw $s2, 12($s1) # $s2 = triples
lw $s3, 16($s1) # $s3 = home runs
lw $s4, 20($s1) # $s4 = outs
sw $s4, -4($sp) # put outs at top of average's stack
sw $s3, -8($sp) # put homeruns 2nd fm top of average's stack
sw $s2, -12($sp) # put triples 3rd fm top of average's stack
jal average
# Print the slugging percentage
mtc1 $v0, $f12 # get result fm $v0 before we print string
la $a0, mainOnbasePercentage
addi $v0, $zero, 4
syscall
addi $v0, $zero, 2 # print the percentage
syscall
la $a0, mainNewline
addi $v0, $zero, 4
syscall
syscall
addi $s0, $s0, 1 # i++
addi $s1, $s1, 24 # $s1 = addr of next batter's stats
j mainLoopBegin
mainDone:
# Epilogue for main -- restore stack & frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer for caller
addiu $sp, $sp, 24 # restore frame pointer for caller
jr $ra # return to caller
.data
printStatsOuts:
.asciiz "Outs: "
printStatsWalks:
.asciiz "Walks: "
printStatsSingles:
.asciiz "Singles: "
printStatsDoubles:
.asciiz "Doubles: "
printStatsTriples:
.asciiz "Triples: "
printStatsHomeruns:
.asciiz "Home runs: "
printStatsNewline:
.asciiz "\n"
.text
printStats:
# Function prologue
addiu $sp, $sp, -32 # allocate stack space
sw $a3, 20($sp) # save $a0 thru $a3
sw $a2, 16($sp)
sw $a1, 12($sp)
sw $a0, 8($sp)
sw $ra, 4($sp) # save return address
sw $fp, 0($sp) # save frame pointer of caller
addiu $fp, $sp, 28 # setup frame pointer of average
# printStats expects to find the following:
# $a0 = walks
# $a1 = singles
# $a2 = doubles
# $a3 = triples
# 5th argument = homeruns
# 6th argument = outs
# print the outs
la $a0, printStatsOuts
syscall
lw $a0, 0($fp) # the outs are at the top of our stack
addi $v0, $zero, 1
syscall
la $a0, printStatsNewline
addi $v0, $zero, 4
syscall
# print the walks
la $a0, printStatsWalks
addi $v0, $zero, 4
syscall
lw $a0, 8($sp) # the walks were passed in $a0
addi $v0, $zero, 1
syscall
la $a0, printStatsNewline
addi $v0, $zero, 4
syscall
# print the singles
la $a0, printStatsSingles
addi $v0, $zero, 4
syscall
addi $a0, $a1, 0 # the singles were passed in $a1
addi $v0, $zero, 1
syscall
la $a0, printStatsNewline
addi $v0, $zero, 4
syscall
# print the doubles
la $a0, printStatsDoubles
addi $v0, $zero, 4
syscall
addi $a0, $a2, 0 # the doubles were passed in $a2
addi $v0, $zero, 1
syscall
la $a0, printStatsNewline
addi $v0, $zero, 4
syscall
# print the triples
la $a0, printStatsTriples
addi $v0, $zero, 4
syscall
addi $a0, $a3, 0 # the doubles were passed in $a3
addi $v0, $zero, 1
syscall
la $a0, printStatsNewline
addi $v0, $zero, 4
syscall
# print the homeruns
la $a0, printStatsHomeruns
addi $v0, $zero, 4
syscall
lw $a0, -4($fp) # the homeruns are 4 bytes below the top of our stack
addi $v0, $zero, 1
syscall
la $a0, printStatsNewline
addi $v0, $zero, 4
syscall
# Put -1 in $t0, then copy that value to each of the $f registers
addi $t0, $zero, -1
mtc1 $t0, $f0
mtc1 $t0, $f1
mtc1 $t0, $f2
mtc1 $t0, $f3
mtc1 $t0, $f4
mtc1 $t0, $f5
mtc1 $t0, $f6
mtc1 $t0, $f7
mtc1 $t0, $f8
mtc1 $t0, $f9
mtc1 $t0, $f10
mtc1 $t0, $f11
mtc1 $t0, $f12
mtc1 $t0, $f13
mtc1 $t0, $f14
mtc1 $t0, $f15
mtc1 $t0, $f16
mtc1 $t0, $f17
mtc1 $t0, $f18
mtc1 $t0, $f19
mtc1 $t0, $f20
mtc1 $t0, $f21
mtc1 $t0, $f22
mtc1 $t0, $f23
mtc1 $t0, $f24
mtc1 $t0, $f25
mtc1 $t0, $f26
mtc1 $t0, $f27
mtc1 $t0, $f28
mtc1 $t0, $f29
mtc1 $t0, $f30
mtc1 $t0, $f31
# Put various values in the $t registers
addi $t0, $zero, -1111
addi $t1, $zero, -2222
addi $t2, $zero, -3333
addi $t3, $zero, -4444
addi $t4, $zero, -5555
addi $t5, $zero, -6666
addi $t6, $zero, -7777
addi $t7, $zero, -8888
addi $t8, $zero, -9999
addi $t9, $zero, -1111
# Put various values in the $a registers.
addi $a0, $zero, -1111
addi $a1, $zero, -1111
addi $a2, $zero, -2222
addi $a3, $zero, -3333
# Put two values at the top two spots in our stack. This is where
# the number of homeruns and outs were placed when printStats
# is called. A function is allowed to change its own stack.
addi $t7, $zero, -1234
sw $t7, 0($fp)
sw $t7, -4($fp)
printStatsDone:
# Epilogue for printStats -- restore stack & frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore frame pointer for caller
addiu $sp, $sp, 32 # restore frame pointer for caller
jr $ra # return to caller
# Your code goes below this line
average:
#takes 7 arguments
#Arguments $a0-$a3 are put on the Caller's stack
#arguments 5-7 are put on the Callee's stack and called
# Prologue: set up stack and frame pointers for average
addiu $sp, $sp, -36 # allocate stack space -- 36 needed here
sw $fp, 0($sp) # save caller's frame pointer
sw $ra, 4($sp) # save return address
# save parameter values $a0-$a3 on the stack
sw $a0, 8($sp) # designates which calculation to do
sw $a1, 12($sp) # walks
sw $a2, 16($sp) # singles
sw $a3, 20($sp) # doubles
addiu $fp, $sp, 32 # setup average frame pointer
#Allocate proper locations of arguments for printStats
#arguments 5 and 6 (home runs and outs will be placed on stack)
addi $t5, $a0, 0 #$t5 designates which calculation to run
addi $a0, $a1, 0 #walks of printStats
addi $a1, $a2, 0 #singles of printStats
addi $a2, $a3, 0 #doubles of printStats
lw $a3, 24($sp) #triples of printStats
lw $t1, 28($sp) #home runs of printStat
sw $t1, -8($sp) #home runs now 2nd from top of stack
lw $t2, 32($sp) #outs of printStats
sw $t2, -4($sp) #out now top of stack
jal printStats
#restore registers used in average
lw $t2, 32($sp) #outs
lw $t1, 28($sp) #homeruns
lw $a3, 24($sp) #triples
lw $a2, 20($sp) #doubles
lw $a1, 16($sp) #singles
lw $a0, 12($sp) #walks
lw $t5, 8($sp) #compare which calculation to run
#convert outs to float
mtc1 $t2, $f4 #outs = $f4
#hits
#hits = singles + doubles + triples + home runs
add $t3, $a1, $a2 # hits = singles + doubles
add $t3, $t3, $a3 # hits = $t3 + triples
add $t3, $t3, $t1 # hits = $t3 + home runs
mtc1 $t3, $f1 #convert hits to float $f1
#atBats
#atBats = hits + outs
add.s $f2, $f1, $f4 # atBats = hits + outs
mfc1 $t4, $f2 #convert atBats to int for compare
#Compare $t5
#if $t5 == 1, computer batting average
#if $t5 == 2, compute slugging percentage
#if $t5 == 3, compute on-base percentage
addi $t0, $zero, 1 #$t0 = 1
beq $t5, $t0, averageBattingAverage
addi $t0, $zero, 2 #$t0 = 2
beq $t5, $t0, averageSluggingPercentage
addi $t0, $zero, 3 #$t0 = 3
beq $t5, $t0, averageOnBasePercentage
averageBattingAverage:
#batting average
#batting average = hits/atBats
#if atBats == 0, average = 0
#compare atBats
beq $t4, $zero, averageBattingSluggingZero
#batting
div.s $f3, $f1, $f2 #batting average = hits/atBats
#Set to print
mfc1 $v0, $f3 #return $v0 the batting average
j averageDone #done
averageSluggingPercentage:
#Slugging percentage
#slugging percentage = (singles + doubles*2 + triples*3
# + home runs*4)/atBats
#if atBats == 0, percentage = 0
#compare atBats
beq $t4, $zero, averageBattingSluggingZero
#slugging
add $t5, $a2, $a2 #doubles*2
add $t6, $a3, $a3 #$t6 = triples * 2
add $t6, $t6, $a3 #$t6 = triples * 3
add $t7, $t1, $t1 #$t7 = home runs * 2
add $t7, $t7, $t7 #$t7 = home runs * 4
add $t8, $a1, $t5 #$t8 = singles + doubles*2
add $t8, $t8, $t6 #$t8 = $t8 + triples*3
add $t8, $t8, $t7 #$t8 = $t8 + home runs*4
mtc1 $t8, $f1 #convert $t8 to float $f1
div.s $f3, $f1, $f2 #slugging percentage = $f1/atBats
#set to print
mfc1 $v0, $f3 #return $v0 the slugging percentage
j averageDone #done
averageOnBasePercentage:
#On-base percentages
#on-base percentages = (hits + walks)/(atBats + walks)
#if atBats + walks is zero, percentage is zero
add $t6, $t3, $a0 #$t6 = hits + walks
add $t7, $t4, $a0 #$t7 = atBats + walks
#compare atBats + walks
beq $t7, $zero, averageOnBaseZero
#on-base
mtc1 $t6, $f1 #convert $t6 to float $f6
mtc1 $t7, $f2 #convert $t7 to float $f7
div.s $f3, $f1, $f2 #on-base percentage = $f6/$f7
#set to print
mfc1 $v0, $f3 #return $v0 the on-base percentage
j averageDone #done
averageBattingSluggingZero:
#if atBats is zero, batting average and slugging
#percentage are both zero
addi $t0, $zero, 0 #$t0 = 0
mtc1 $t0, $f0 #convert 0 to float $f0
#set to print
mfc1 $v0, $f0 #return $v0 = 0
j averageDone #done
averageOnBaseZero:
#if atBats + walks is zero, on-base percentage
# is also zero
addi $t0, $zero, 0 #$t0 = 0
mtc1 $t0, $f0 #convert 0 to float $f0
#set to print
mfc1 $v0, $f0 #return $v0 = 0
j averageDone #done
averageDone: # Epilogue: restore stack and frame pointers and return
lw $ra, 4($sp) # get return address from stack
lw $fp, 0($sp) # restore the caller's frame pointer
addiu $sp, $sp, 36 # restore the caller's stack pointer
jr $ra # return to caller's code
My outputs are not lining up and I don't get why.
The following is the correct output for batter 3.
Batter number: 3
Outs: 23000000
Walks: 102322
Singles: 8000000
Doubles: 22
Triples: 500000
Home runs: 10
Batting average: 0.26984200
Outs: 23000000
Walks: 102322
Singles: 8000000
Doubles: 22
Triples: 500000
Home runs: 10
Slugging percentage: 0.30158967
Outs: 23000000
Walks: 102322
Singles: 8000000
Doubles: 22
Triples: 500000
Home runs: 10
On-base percentage: 0.27220613
And here's my output, with a ! to mark the inconsistencies
Batter number: 3
Outs: 23000000
Walks: 102322
Singles: 8000000
Doubles: 22
Triples: 500000
Home runs: 10
!Batting average: 0.22532867
Outs: 23000000
Walks: 102322
Singles: 8000000
Doubles: 22
Triples: 500000
Home runs: 10
!Slugging percentage: 0.25183919
Outs: 23000000
Walks: 102322
Singles: 8000000
Doubles: 22
Triples: 500000
Home runs: 10
!On-base percentage: 0.22559348
How are my calculations off for this one batter, and what can I do to fix it?
There are multiple calling conventions, you should figure out which one you are supposed to follow. If you have no documentation, you could look at compiler-generated assembly code, or use a debugger.
That said, judging from the fact that only 4 arguments are passed on the stack, you seem to be using the O32 calling convention. This means, the stack upon entry to your function contains 4 argument slots for saving the first 4 arguments which are passed in the registers $a0-$a3. Following them are all the remaining arguments. So, upon entry to your function, the 5th argument (the first one that is not passed via register) will be at address 16($sp) with the 6th at 20($sp) and the 7th at 24($sp). (This is assuming your arguments are 1 word each.) You subtract 36 from $sp to make space for your locals, thus after that all the offsets increase by that amount, i.e. 5th argument at 52($sp) and so on. You can access them using these addresses.
You then set $fp to $sp + 32. I don't think calling convention mandates any particular value for $fp, so that should be fine. If you subsequently wish to access your arguments relative to $fp, you need to adjust the offsets again to compensate, this time by -32. Thus, 5th argument should be at 20($fp), followed by the rest.
Related
Why is MIPS printing memory locations on the second time around
[Solved] We were tasked with writing a bubble sort in MIPS and printing both the unsorted and sorted arrays I've written the following code to accomplish this. But when I go to run it, the original array prints as I would expect Original Array [34, 23, -1, -2, 0] But then it prints this for the sorted array. Sorted Array [173496791, 1818324585, 1920090400, 686433, 1919898378] (the Unicode squares do print) array: .word 34, 23, -1, -2, 0, 89 length: .word 6 original: .asciiz "Original Array\n" sorted: .asciiz "\nSorted Array\n" .text # main() main: la $a2, length lw $a2, 0($a2) # a2 <= n_element add $t9, $0, $0 # t9 : counter la $a1, array # a1 = &array[0] addi $t0, $0, 0 # for t0=0 to addi $a2, $a2, -1 # because we do [i+1] #says prints original array la $a0, original li $v0, 4 syscall #prints array jal print #printing the string saying sorted la $a0, sorted li $v0, 4 syscall #after printing original we reset the values? la $a2, length lw $a2, 0($a2) # a2 <= n_element add $t9, $0, $0 # t9 : counter add $t8, $0, $0 # t10 : counter 2 la $a1, array # a1 = &array[0] addi $t0, $0, 0 # for t0=0 to addi $a2, $a2, -1 # because we do [i+1] #see if that worked it did li $s0, 1 #boolean swapped = false 0=false 1=true outerLoop: beqz $s0, exit #if flag is false exit li $s0, 0 addi $a1, $a1, 4 # next array offset addi $t9, $t9, 1 # counter++ move $t8 $0 sub $s2, $a2, $t9 innerLoop: bge $t8, $s2, exitInner lw $t7, 0($a1) # t7 = array[i] lw $t8, 4($a1) # t8 = array[i+1] ble $t7, $t8, skip #if array[i]<= arr[i+1] skip the swapping sw $t8, 0($a1) #a[i+1] = a[1] sw $t7, 4($a1) #a[i] = a[i+1] li $s0, 1#flag update skip: addi $t8, $t8, 1 #count addi $a1, $a1, 4 j innerLoop exitInner: j outerLoop exit: la $a2, length lw $a2, 0($a2) # a2 <= n_element add $t9, $0, $0 # t9 : counter addi $a2, $a2, -1 # because we do [i+1] jal print j quit#end Program #print array print: lw $t7,0($a1) # t7 = array[i] lw $t8,4($a1) # t8 = array[i+1] add $a0, $t7, 0 addi $v0, $0, 1 #print int using system call the value stored in a0 syscall addi $a0, $0, 0x20 # ascii 0x20 = ' ' addi $v0, $0, 11 syscall addi $a1, $a1, 4 # next array offset addi $t9, $t9, 1 # counter++ beq $t9, $a2, return #return to the where we were we were at beforehand j print return: jr $ra quit: addi $v0, $0, 10 syscall I think these are memory locations? I'm not sure why it's printing that as it is because I reset my counter values before trying to print. So the question is. Why am I printing memory locations? if that is what is happening I was sorting in place so I had to reset the array before the print function.
Practice to convert c to Mips
Does anyone know how to convert this into mips 32? Please show the code and explain for me. Thank you so much int service (int n) { if (n <= 10) return n; else return n + service(n+1) + service (n+2); }
Please pay attention on comments and try to understand what is happening instruction by instruction. service: lw $t0, $a0 # Load word from memory to $t0. $a0 is the argument of the function (int n). addi $t1, 10 # $t1 = 10 bne $t0, $t1, cont # If n != 10 , continue slti $t2, $t1, $t0 # If 10 < n $t2 = 1, else $t2 = 0 bne $t2, $t0, cont # If $t2 != 0 , then $t2 = 1 so 10 < n , so continue addi $v0, $t0, $0 # Else return n; jr $ra cont: addi $sp, $sp, -4 # Room on stack for 4 bytes sw $ra, 0($sp) # Save $ra, recursion addi $a0, $a0, 1 # n+1 jal service # Call service(n+1) addi $a0, $a0, 1 # (n+1) + 1 = n+2 jal service # Call service(n+2) lw $ra, 0($sp) # restore $sp addi $sp, $sp, 4 # Restore room on stack jr $ra
Here's my try with clarifications # assuming $a0 is the parameter n service: bgt $a0, 10, else # if $a0 > 10 branch to else part move $v0, $a0 # $v0 = $a0, to return the value jr $ra # return n; else: addiu $sp, $sp, -8 # using stack to store $ra, $a0 each 4 bytes we need 8 bytes sw $a0, 0($sp) # store the value of a0 in the stack sw $ra, 4($sp) # store the caller addrs. addiu $a0, $a0, 1 # parameter of the first function call (n+1) jal service # service(n+1) move $s0, $v0 # s0 = result of service(n+1) lw $a0, 0($sp) # $a0 = n addiu $a0, $a0, 2 # parameter of the second function call (n+2) jal service # service(n+1) move $s1, $v0 # s1 = result of service(n+1) lw $a0, 0($sp) # $a0 = n addu $v0, $a0, $s0 # $v0 = n + service(n+1) addu $v0, $v0, $s1 # $v0 = n + service(n+1) + service(n+2) lw $ra, 4($sp) # $ra = old caller return addrs. addiu $sp, $sp, 8 # freeing the stack jr $ra # return
Binary Search using recursion in Mips assembly
I have a trouble. I tried to make a binary search algorithm using recursion in mips assembly, but I have some errors that I don't understand how to solve them. I have an array of 10 integers and I assume that the array is sorted. this is my code, I appreciate any help and thanks in advance.. .data arr: .word 40 arrMsg: .asciiz "Enter the array : \n" posMsg: .asciiz "This value exist in the array and its position is " pos: .word 0 newline: .asciiz "\n" valMsg: .asciiz "Enter the value you search for : \n" val: .word 0 notfound:.asciiz "the value doesn't exist in the array !! \n" .text main: # print the array message li $v0, 4 la $a0, arrMsg syscall # read the array from the user # put $s0 = i add $s0, $zero, $zero # i = 0 for: beq $s0, 40, end li $v0, 5 syscall sw $v0, arr($s0) # input arr[i] addi $s0, $s0, 4 # i = i + 4 j for end: # print value message li $v0, 4 la $a0, valMsg syscall # read the value from the user li $v0, 5 syscall # store the value in the val variable sw $v0, val ################################################ ## put $s0 = start , $s1 = middle , $s2 = end ## ################################################ li $s0, 0 li $s2, 9 jal BinarySearch li $v0, 10 syscall ############################################################################################################ BinarySearch: # middle = (start + end ) / 2 add $t0, $s0, $s2 # $t0 = start + end sra $s1, $t0, 1 # $s1 = $t0 / 2 # save $ra in the stack addi $sp, $sp, -4 sw $ra, 0($sp) # base case ble $s2, $s0, returnNegative1 # if (end <= start) lw $t1, arr($s1) # $t1 = arr[middle] lw $t2, val # $t2 = val beq $t1, $t2, returnMiddle # if (arr[middle] == val) blt $t2, $t1, returnFirstPart # if (val < arr[middle]) bgt $t2, $t1, returnLastPart # if (val > arr[middle]) returnNegative1: li $v0, -1 j Exit returnMiddle: move $v0, $s1 # return middle j Exit returnFirstPart: move $t3, $s1 # temp = middle addi $t3, $t3, -1 # temp -- move $s2, $t3 # end = temp jal BinarySearch j Exit returnLastPart: move $t3, $s1 # temp = middle addi $t3, $t3, 1 # temp++ move $s0, $t3 # start = temp jal BinarySearch j Exit Exit: lw $ra, 0($sp) addi $sp, $sp, 4` jr $ra
lw $t1, arr($s1) # $t1 = arr[middle] this is the problem as it is not really the right index as integer takes 4 bytes so the middle you get from add $t0, $s0, $s2 # $t0 = start + end sra $s1, $t0, 1 # $s1 = $t0 / 2 is just the logical address not the real one you will need to multiply it with 4 mul $s4, $s1,4 and then use $s4 as an address lw $t1, arr($s4) # $t1 = arr[middle] also there is a mistake with the stopping condition it should be if (end < start) not (<=) and sorry for my English
mergesort recursion in mips
I am working with mergesort mips operating on Mars i run it, the array is arranged but it has some troubles and it announces that error in : invalid program counter value: 0x00000000 Go: execution terminated with errors please help me thank you very much .data # Data declaration section text1: .asciiz "My array" text2: .asciiz "Sorted Array" newline: .asciiz "\n" space: .asciiz " " Myarray: .word 9 5 6 8 7 2 mangx: .word 0:20 mangy: .word 0:20 .text main: la $a0, Myarray # load dia chi myarray $a1 addi $t1, $zero,4 # size=20 and $a1, $zero, $zero # l=0 a1 addi $a3,$zero,3 #r=19 li $v0, 4 la $a0, text1 #in text1 syscall li $v0, 4 la $a0, newline #in newline syscall and $t4, $zero, $zero # khoi tao i=0 $t4 j LoopPrintUn # nhay den ham in myarray LoopPrintUn: la $a0, Myarray # load dia chi myarray $a1 #While (i < length) slt $t6, $t4, $t1 # neu i < size thi $t6=1, neu khong thi $t6=0 beq $t6, $zero, call # neu $t6=0 thi re qua ham in Sortedarray # Load Array[i] and print it sll $t0, $t4, 2 # i * 4 add $t6, $a0, $t0 # chuyen den dia chi phan tu thu i li $v0, 1 # ham in integer lw $a0, 0($t6) # load gia tri tai dia chi thu i syscall # in li $v0, 4 la $a0, space syscall #in khoang trang addi $t4, $t4, 1 # i ++ j LoopPrintUn # lap ham in myarray MergeSort: addi $sp, $sp, -20 sw $ra,0($sp) sw $a3, 12($sp) # r sw $a1, 8($sp) # l sw $a0, 4($sp) # a[] slt $t6, $a1, $a3 # neu l < r $t6=1 neu khong $t6=0 beq $t6, $zero, Exit2 # $t6=0 thi exit2 add $t1, $a1, $a3 # temp1 = l + r div $t1, $t1, 2 # temp1 = temp1 / 2 add $a3,$t1,$zero sw $t1,16($sp) # add $a3, $a2, $zero # m=(l+r)/2 (m thay cho cho r trong mergesort(arr,l,r)) jal MergeSort # mergesort(arr,l,m) lw $a1,16($sp) #load m addi $a1,$a1,1 lw $a3,12($sp)#load r #addi $sp, $sp, 24 jal MergeSort # mergesort(arr,m+1,r) lw $a0, 4($sp) lw $a1, 8($sp) lw $a2, 16($sp) lw $a3, 12($sp) jal merge # merge(a,l,m,r) Exit2: lw $ra,0($sp) lw $a0, 4($sp) lw $a1, 8($sp) lw $a2, 16($sp) lw $a3, 12($sp) addi $sp, $sp, 20 jr $ra merge: addi $sp,$sp,-32 sw $ra,0($sp) sw $s0,4($sp) # bien i sw $s1,8($sp) # bien j sw $s2,12($sp) # bien k sw $s3,16($sp) # bien n1 sw $s4,20($sp) # bien n2 sw $s5,24($sp) # mang X sw $s6,28($sp) # mang y la $s5,mangx la $s6,mangy sub $s3,$a2,$a1 # m-l addi $s3,$s3,1 #m-l+1 sub $s4,$a3,$a2 # r-m move $t0,$0 # bien dem o move $t1,$0 # bien dem p loop1: slt $t3,$t0,$s3 # so sanh o<n1 beq $t3,$0,loop2 # go to toi loop 2 neu $t3=0 sll $t2,$t0,2 # o*4 add $t2,$s5,$t2 # X[0] add $t5,$a1,$t0 # l+o sll $t5,$t5,2 # (l+o)*4 add $t5,$a0,$t5 # arr[l+o] lw $t5,0($t5) sw $t5,0($t2) # x[o]=arr[l+o] addi $t0,$t0,1 #o++ j loop1 loop2: # xuly slt $t4,$t1,$s4 # so sanh o<n1 beq $t4,$0,exit # go to toi exit neu $tt4=0 addi $t6,$a2,1 # m+1 add $t6,$t6,$t1 #m+1+p sll $t6,$t6,2 #(m+1+p)*4 sll $t7,$t1,2 # p*4 add $t6,$a0,$t6 # arr[m+1+p] lw $t6,0($t6) add $t7,$s6,$t7 # y[p] sw $t6,0($t7) # y[p]=arr[m+1+p] addi $t1,$t1,1 #o++ j loop2 #------------- exit: move $s0,$0 #i=0 move $s1,$0 # j=0 add $s2,$a1,$0 #k=l while: slt $t0,$s0,$s3 #i<n1 beq $t0,$0,loop3 slt $t1,$s1,$s4 #j<n2 beq $t1,$0,loop3 sll $t2,$s0,2 #i*4 sll $t3,$s1,2 #j*4 add $t2,$s5,$t2 #x[i] lw $t2,0($t2) add $t3,$s6,$t3 #y[j] lw $t3,0($t3) slt $t6,$t2,$t3 # x[i]<y[j] beq $t6,$0,else #x[i] >y[j] thì làm else còn x[i] <= y[j] lam if sll $t7,$s2,2 #k*4 add $t7,$a0,$t7 #arr[k] sw $t2,0($t7) #arr[k]=x[i] addi $s0,$s0,1 #i++ addi $s2,$s2,1 #k++ else: sll $t7,$s2,2 #k*4 add $t7,$a0,$t7 #arr[k] sw $t3,0($t7) #arr[k]=y[j] addi $s1,$s1,1 #j++ addi $s2,$s2,1 #k++ j while loop3: slt $t0,$s0,$s3 #i<n1 beq $t0,$0,loop4 sll $t1,$s2,2 #k*4 add $t1,$a0,$t1 #arr[k] sll $t2,$s0,2 #i*4 add $t2,$s5,$t2 #x[i] lw $t2,0($t2) sw $t2,0($t1) #arr[k]=x[i] addi $s0,$s0,1 #i++ addi $s2,$s2,1 #k++ j loop3 loop4: slt $t0,$s1,$s4 #j<n2 beq $t0,$0,exit1 sll $t1,$s2,2 #k*4 add $t1,$a0,$t1 #arr[k] sll $t2,$s1,2 #j*4 add $t2,$s6,$t2 #y[j] lw $t2,0($t2) sw $t2,0($t1) #arr[k]=y[j] addi $s1,$s1,1 #j++ addi $s2,$s2,1 #k++ j loop4 exit1: lw $ra,0($sp) addi $sp,$sp,32 jr $ra call: jal MergeSort
MIPS: fetch address not aligned on word boundary 0x400fffff
I'm writing a mips program to calculate exponent, but get an error: Runtime exception at 0x00400158: fetch address not aligned on word boundary 0x400fffff Any ideas? The problem line is lw $v0, 0($t0) # $v0 = rev_binary[idx] .data prompt1: .asciiz "Enter a base: " prompt2: .asciiz "Enter an exponential: " b: .word 0 e: .word 0 rev_binary: .word 0 i: .word 0 result: .word 1 .text main: la $a0, prompt1 # print prompt1 addi $v0, $0, 4 syscall addi $v0, $0, 5 # read b syscall move $t0, $v0 # $t0 = b la $a0, prompt2 # print prompt2 addi $v0, $0, 4 syscall addi $v0, $0, 5 # read e syscall move $t1, $v0 # $t1 = e addi $sp, $sp, -8 # 2 * 4 = 8 bytes sw $t1, 4($sp) sw $t0, 0($sp) jal power move $a0, $v0 addi $v0, $0, 1 syscall # print the return value j end power: # save $ra and $fp addi $sp, $sp, -8 sw $ra, 4($sp) sw $fp, 0($sp) #copy $sp to $fp addi $fp, $sp, 0 # allocate local variables addi $sp, $sp, -20 # save $sp into $fp move $fp, $sp #rev_binary = [ 0 ] * e lw $a0, 32($sp) sll $a0, $a0, 2 # $a0 = 4 * e(e << 2) addi $a0, $a0, 4 # $a0 = 4 * e + 4 addi $v0, $0, 9 # $v0 = 9 syscall # allocate memory sw $v0, 0($sp) lw $t0, 32($sp) # $t0 = e sw $t0, 0($v0) #store the size of rev_binary sw $0, 4($sp) while0: # while e != 0 lw $t0, e # $t0 = e beq $t0, $0, while0_end # break if e == 0 # e_half = e >> 1 lw $t0, 32($sp) # allocate e_half srl $t1, $t0, 1 # $t1 = $t0 >> 1 sw $t1, 8($sp) # e_half = $t1 # rev_binary[i] = e - 2 * e_half lw $t0, 8($sp) # $t0 = e_half sll $t0, $t0, 1 # $t0 = e_half * 2 lw $t1, e # $t1 = e sub $t0, $t1, $t0 # $t0 = e - e_half * 2 lw $t1, 4($sp) # $t1 = i sll $t1, $t1, 2 addi $t1, $t1, 4 # $t1 = i * 4 + 4 lw $t2, rev_binary # $t3 = the address of rev_binary add $t1, $t1, $t2 # $t1 = the address of rev_binary[i] sw $t0, 0($t1) # rev_binary[i] = $t0 # i += 1 lw $t0, 4($sp) # $t0 = i addi $t0, $t0, 1 # $t0 += 1 sw $t0, 4($sp) # i = $t0 # e = e_half lw $t0, 8($sp) # $t0 = e_half sw $t0, 32($sp) # e = $t0 addi $sp, $sp, 4 # release local variable n_half j while0 while0_end: # rev_binary = rev_binary[:i] lw $t0, 0($sp) # $t0: the address of rev_binary lw $t1, 4($sp) # $t1 = i sw $t1, 0($t0) # set the size of rev_binary to i # result = 1 addi $t0, $0, 1 # $t0 = 1 sw $t0, 12($sp) # result = $t0 # for j in range(i - 1, -1, -1): addi $sp, $sp, -4 # allocate j lw $t0, i # $t0 = i addi $t0, $t0, -1 # $t0 -= 1 sw $t0, 0($sp) # j = $t0 = i - 1 # idx = len(rev_binary) - 1 lw $t0, 4($sp) # $t0 = i = len(rev_binary) addi $t0, $t0, -1 # $t0 -= 1 sw $t0, 16($sp) # idx = $t0 while1: # while idx >= 0 lw $t0, 16($sp) # idx = $t0 blt $t0, $0, while1_end # break if idx < 0 # result = result * result lw $t0, 12($sp) # t0 = result mul $t0, $t0, $t0 sw $t0, 12($sp) # $t0 = result # if rev_binary[idx] lw $t0, 16($sp) # $t0 = idx sll $t0, $t0, 2 # $t0 = idx * 4 addi $t0, $t0, 4 # $t0 = idx * 4 + 4 lw $t1, 0($sp) # $t1 = the address of rev_binary add $t0, $t1, $t0 # $t0 = the address of rev_binary[idx] lw $v0, 0($t0) # $v0 = rev_binary[idx] if: beq $t0, $0, end_if # end if if (idx == 0) # result = result * b lw $t0, 12($sp) # $t0 = result lw $t1, 28($sp) # $t1 = b mul $t0, $t0, $t1 # $t0 = $t0 * $t1 sw $t0, 12($sp) # result = $t0 end_if: # idx = idx - 1 lw $t0, 16($sp) # $t0 = idx addi $t0, $t0, -1 # $t0 -= 1 sw $t0, 16($sp) # idx = $t0 j while1 # loop while1_end: lw $v0, 12($sp) # $v0 = result lw $t0, 20($sp) # reset old $fp move $fp, $t0 lw $t0, 24($sp) # reset old $ra move $ra, $t0 addi $sp, $sp, 36 # release local variables jr $ra # return end: # exit
You can only load words from aligned addresses. The address also looks strange since it has 0xffff in the end. Looking at the code you have lw $t1, 0($sp) # $t1 = the address of rev_binary but before that you store j to (0)$sp, so that can't contain the address of rev_binary. Maybe you need la $t1, rev_binary # $t1 = the address of rev_binary instead?