D'accord, la fonction que vous deviez écrire utilisait le registre mal lors du calcul de l'index de tableau:
Change:
sll $t2,$t2,2 # compute 4i in $t2
en:
sll $t2,$t1,2 # compute 4i in $t2
Mais, votre fonction a également eu un bug beaucoup plus sévère. Vous revenez en boucle à la fonction en commençant et en créant plusieurs cadres de pile dans le processus. Je pense que vous avez peut-être réalisé cela à un certain niveau, c'est pourquoi vous avez essayé de compenser et de quitter la fonction avec un saut à Exit:
[qui fait partie de main
].
Votre fonction de calcul se terminerait également prématurément après avoir trouvé le premier maximum. Il ne continuerait pas à parcourir le reste de la matrice pour trouver de meilleures valeurs (c'est-à-dire plus grandes).
Il y avait aussi un certain nombre d'autres bogues.
J'ai créé deux versions de votre programme. Un avec des annotations concernant les bugs. Et, une deuxième version, nettoyée, et de travail.
Voici la version annotée [s'il vous plaît pardonnez le nettoyage de style gratuit]:
.data # data segment
nl: .asciiz "\n" # ASCII for a new line
separator: .asciiz ":" # string that seprates index from number
msg1: .asciiz "The function returned "
# NOTE/BUG: these "li" are misplaced and have no meaning
msg2: .asciiz "\nThe maximum value is "
###li $v0,$t5
msg3: .asciiz "\nThe address of the word is "
# .asciiz
# .asciiz
###li $v0,$t6
.align 2 # important for words
###buffer: .space 4096 # allocate space for 1K words
buffer: .space 128 # allocate space for 1K words
bufe:
.text # Code segment
.globl main # declare main to be global
main:
addi $sp,$sp,-4 # allocate space on the stack for $s0
sw $s0,($sp) # save $s0
# specify the size of the array, must be less than 1024
la $s1,bufe # get address of array end
la $a0,buffer # get address of array
subu $s1,$s1,$a0 # get byte length of array
srl $s0,$s1,2 # get word count of array
# NOTE/BUG: "name" is undefined
###la $a0,name # load the address of "name" into $a0
###li $v0,4 # system call, type 4, print an string, *$a0
###syscall # call the "OS"
# call
la $a0,buffer
move $a1,$s0
jal init_array # initialize the array with random values
la $a0,buffer
move $a1,$s0
jal print_array # call print. You can comment it out.
# call your find_max function
la $a0,buffer
move $a1,$s0
# NOTE/BUG: these serve no purpose
lw $t0,0($a0)
la $t5,0($a0)
jal find_max # call find_max
# NOTE/BUG: these serve no purpose
lw $v0,0($t0)
lw $v1,0($t5)
# NOTE/BUG: the messages are printed below, but not the actual values
# add code to print the results
# print the returned value
la $a0,msg1 # print mssage 1
li $v0,4
syscall
# print the maximum value
la $a0,msg2 # print mssage 2
li $v0,4
syscall
# print the address of the value (in hex).
la $a0,msg3 # print mssage 3
li $v0,4
syscall
la $a0,nl # print end of line
syscall
# restore $s0. You can check $sp here to make sure the stack is maintained correctly.
lw $s0,($sp) # load $s0
addi $sp,$sp,4 # restore $sp
Exit:
# NOTE/BUG: these serve no purpose
lw $v0,0($t5)
lw $v1,0($t6)
# NOTE/BUG: the "li" should _not_ be commented out
# li $v0,10 # System call, type 10, standard exit
syscall # ...and call the OS
# your implementation of find_max
#
# arguments:
# a0 -- buffer address
# a1 -- buffer count
#
# registers:
#
find_max:
addi $sp,$sp,-16 # allocate stack space for four registers
sw $s0,($sp) # save $s0
sw $s1,4($sp) # save $s1
sw $s2,8($sp) # save $s2
sw $s3,12($sp) # save $s3
# NOTE/BUG: the "max" value is never initialized to anything
# put your code below.
# You can use temporary registers and $s0 to $s3
# NOTE/BUG: $t1 has _not_ been initialized
add $t1,$t1,1 # increment index i by 1
# NOTE/BUG: we just want to exit the function and _not_ the program -- this
# bug is linked to the one below
beq $t1,$s0,Exit # if all elements examined, quit
# NOTE/BUG: this should be:
# sll $t2,$t1,2
###sll $t2,$t2,2 # compute 4i in $t2
sll $t2,$t1,2 # compute 4i in $t2
add $t2,$t2,$s1 # form address of A[i] in $t2
# THIS IS THE LINE GIVING PROBLEMS
# NOTE/FIX: with the bugfix it won't
lw $t3,0($t2) # load value of A[i] into $t3
slt $t4,$t0,$t3 # maximum < A[i]?
# NOTE/BUG: this should _not_ loop back to find_max as that will create
# _multiple_ stack frames -- it is because of _this_ bug that you
# tried to compensate and leave this function by jumping to Exit
beq $t4,$zero,find_max # if not, repeat with no change
# NOTE/BUG: if you set a new maximum, you still have to loop back and _not_
# just exit this function. you may have found the _first_ maximum but there
# could be others (i.e. larger values)
addi $t0,$t3,0 # if so, A[i] is the new maximum
addi $t5,$t2,0
# restore saved registers.
# make sure $sp is restored if you changed it.
lw $s0,($sp)
lw $s1,4($sp)
lw $s2,8($sp)
lw $s3,12($sp)
addi $sp,$sp,16 # restore $sp
jr $ra # return to calling routine
# init_array -- initialize array with random values
#
# arguments:
# a0 -- array address
# a1 -- array count
#
# registers:
# t0 -- array address
# t1 -- array count
init_array:
move $t0,$a0 # prevent value from being clobbered
move $t1,$a1 # prevent value from being clobbered
init_loop:
li $v0,41 # syscall for random int
li $a0,0 # specify which generator to use
syscall
sw $a0,0($t0) # store into array
addiu $t0,$t0,4 # advance to next array element
subi $t1,$t1,1 # decrement count
bgtz $t1,init_loop # more to do? if yes, loop
jr $ra # return
# print_array -- initialize array with random values
#
# arguments:
# a0 -- array address
# a1 -- array count
#
# registers:
# t0 -- array address
# t1 -- array index
print_array:
move $t0,$a0 # prevent value from being clobbered
li $t1,0 # array index
print_array_loop:
move $a0,$t1 # index value
li $v0,1 # syscall for print int
syscall
la $a0,separator
li $v0,4
syscall
lw $a0,0($t0) # get array value
li $v0,1 # syscall for print int
syscall
# output a newline
la $a0,nl
li $v0,4
syscall
addiu $t0,$t0,4 # advance to next array element
addi $t1,$t1,1 # increment index
blt $t1,$a1,print_array_loop # more to do? if yes, loop
jr $ra # return
est ici la version fixe et en cours d'exécution. J'ai ajouté les fonctions manquantes init_array
et print_array
ainsi que l'impression des résultats. Le code standard que vous avez reçu a aussi quelques bugs [mineurs] que j'ai corrigés. J'ai essayé de rester fidèle à votre code find_max
, mais, malheureusement, j'avais besoin de le refactoriser.
En outre, notez le fait que, dans les mips ABI, le $v*
, $a*
et $t*
peut être utilisé par la fonction appelée pour toute fin. Donc, modifier les registres $s*
n'a jamais été un problème interne pour find_max
.
.data # data segment
.align 2 # important for words
###buffer: .space 4096 # allocate space for 1K words
buffer: .space 128 # allocate space for 1K words
bufe:
nl: .asciiz "\n" # ASCII for a new line
separator: .asciiz ":" # string that seprates index from number
msg1: .asciiz "The function returned "
msg2: .asciiz "\nThe maximum value is "
msg3: .asciiz "\nThe address of the word is "
.text # Code segment
.globl main # declare main to be global
main:
addiu $sp,$sp,-4 # allocate space on the stack for $s0
sw $s0,($sp) # save $s0
# specify the size of the array, must be less than 1024
la $s0,bufe # get address of array end
la $a0,buffer # get address of array
subu $s0,$s0,$a0 # get byte length of array
srl $s0,$s0,2 # get word count of array
la $a0,buffer
move $a1,$s0
jal init_array # initialize the array with random values
la $a0,buffer
move $a1,$s0
jal print_array # call print. You can comment it out.
# call your find_max function
la $a0,buffer
move $a1,$s0
jal find_max # call find_max
move $t0,$v0 # save address
move $t1,$v1 # save value
# add code to print the results
# print the maximum value
la $a0,msg2 # print mssage 2
li $v0,4
syscall
move $a0,$t1 # get max value
li $v0,1
syscall
la $a0,nl
li $v0,4
syscall
# print the address of the value (in hex).
la $a0,msg3 # print mssage 3
li $v0,4
syscall
move $a0,$t0 # get address of max value
li $v0,34
syscall
la $a0,nl
li $v0,4
syscall
# restore $s0. You can check $sp here to make sure the stack is maintained correctly.
lw $s0,($sp) # load $s0
addiu $sp,$sp,4 # restore $sp
li $v0,10 # exit program
syscall # ...and call the OS
# your implementation of find_max
#
# RETURNS:
# v0 -- address of maximum value
# v1 -- maximum value
#
# arguments:
# a0 -- buffer address
# a1 -- buffer count
#
# registers:
# t0 -- current value
# t1 -- test/temporary
find_max:
addiu $sp,$sp,-16 # allocate stack space for four registers
sw $s0,($sp) # save $s0
sw $s1,4($sp) # save $s1
sw $s2,8($sp) # save $s2
sw $s3,12($sp) # save $s3
# put your code below.
# You can use temporary registers and $s0 to $s3
# initialize the maximum value from the first element
move $v0,$a0 # get the address
lw $v1,0($a0) # get the value
find_max_loop:
addiu $a0,$a0,4 # advance buffer pointer
subi $a1,$a1,1 # decrement remaining count
blez $a1,find_max_done # more to do? if no, return
lw $t0,0($a0) # get current value
slt $t1,$v1,$t0 # got new maximum?
beqz $t1,find_max_loop # no, loop
move $v0,$a0 # set new maximum pointer
move $v1,$t0 # set new maximum value
j find_max_loop # try next value
# restore saved registers.
# make sure $sp is restored if you changed it.
find_max_done:
lw $s0,($sp)
lw $s1,4($sp)
lw $s2,8($sp)
lw $s3,12($sp)
addiu $sp,$sp,16 # restore $sp
jr $ra # return to calling routine
# init_array -- initialize array with random values
#
# arguments:
# a0 -- array address
# a1 -- array count
#
# registers:
# t0 -- array address
# t1 -- array count
init_array:
move $t0,$a0 # prevent value from being clobbered
move $t1,$a1 # prevent value from being clobbered
# seed the generator
li $v0,40
li $a0,0
li $a1,0x12345678
syscall
init_loop:
li $v0,41 # syscall for random int
li $a0,0 # specify which generator to use
syscall
sw $a0,0($t0) # store into array
addiu $t0,$t0,4 # advance to next array element
subi $t1,$t1,1 # decrement count
bgtz $t1,init_loop # more to do? if yes, loop
jr $ra # return
# print_array -- initialize array with random values
#
# arguments:
# a0 -- array address
# a1 -- array count
#
# registers:
# t0 -- array address
# t1 -- array index
print_array:
move $t0,$a0 # prevent value from being clobbered
li $t1,0 # array index
print_array_loop:
move $a0,$t1 # index value
li $v0,1 # syscall for print int
syscall
la $a0,separator
li $v0,4
syscall
lw $a0,0($t0) # get array value
li $v0,1 # syscall for print int
syscall
# output a newline
la $a0,nl
li $v0,4
syscall
addiu $t0,$t0,4 # advance to next array element
addi $t1,$t1,1 # increment index
blt $t1,$a1,print_array_loop # more to do? if yes, loop
jr $ra # return