2016-09-21 2 views
1

Je suis un débutant à MIPS et je tente un programme pour trouver la valeur du nombre max dans un tableau pseudo-aléatoire. Cependant, je reçois une erreur hors de portée sur une ligne dont j'étais à peu près sûr qu'on lui avait alloué la mémoire appropriée et autres. La plupart du code du squelette, des commentaires, etc ont été donnés, je suis juste en train d'essayer d'écrire la fonction find_max. J'ai commenté à la ligne me donnant des problèmes.MARS MIPS Erreur hors plage

.data    #data segment 
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 " 
li $v0, $t5 
#.asciiz 
msg3: .asciiz "\nThe address of the word is " 
#.asciiz 
li $v0, $t6 

.align 2  # important for words 
buffer: .space 4096  # allocate space for 1K words 

.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 

li $s0, 16  # specify the size of the array, must be less than 1024 

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 
lw $t0, 0($a0) 
la $t5, 0($a0) 
jal find_max # call find_max 
lw $v0, 0($t0) 
lw $v1, 0($t5) 
# 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: lw $v0, 0($t5) 
lw $v1, 0($t6) 
#li $v0,10  # System call, type 10, standard exit 
syscall   # ...and call the OS 

find_max: # your implementation of find_max 
addi $sp, $sp, -16 # allocate space on the stack 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 
add $t1,$t1,1 # increment index i by 1 

beq $t1,$s0,Exit # if all elements examined, quit 

sll $t2,$t2,2 # compute 4i in $t2 

add $t2,$t2,$s1 # form address of A[i] in $t2 
# THIS IS THE LINE GIVING PROBLEMS 
lw $t3,0($t2) # load value of A[i] into $t3 

slt $t4,$t0,$t3 # maximum < A[i]? 

beq $t4,$zero,find_max # if not, repeat with no change 

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 

Répondre

1

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