2016-09-21 6 views
1

私はMIPSの初心者で、擬似ランダム配列の最大数の値を見つけるプログラムを試しています。しかし、私はかなりのメモリが割り当てられていたと確信していました。スケルトンコード、コメントなどのほとんどが与えられました、私はちょうどfind_max関数を書こうとしています。私は問題を与えているラインでコメントしました。MARS MIPSが範囲外のエラー

.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 

答えて

1

オーケー配列インデックス計算するときに、あなたが書かなければならなかった機能が間違ったレジスタを使用していました:

変更:

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

を中へ:

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

しかし、あなたの機能にはさらに多くのものがありましたひどいバグ。関数の先頭に戻り、処理中にの複数のスタックフレームを作成していました。私はあなたがExit: [mainの一部です]にジャンプして機能を補償して終了しようとした理由を、これをあるレベルで認識したと思います。

また、計算機能は、最初の最大値を見つけた後も早期に終了します。 ではなく、は、より良い(つまり大きな)値を見つけるために配列の残りの部分をループし続けます。

他にも多数のバグがありました。

私はあなたのプログラムの2つのバージョンを作成しました。バグに関する注釈付きのもの。そして、2番目のバージョンは、クリーンアップし、作業しています。ここで


注釈付きバージョンは、[無償スタイルのクリーンアップをご容赦ください]である。ここで

.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 

は固定し、実行しているバージョンです。私は不足しているinit_arrayprint_arrayの機能と結果の印刷を追加しました。あなたが与えたボイラープレートコードにも、私が修正したいくつかの[マイナー]バグがありました。私はあなたのfind_maxコードに忠実にしようとしましたが、残念ながら、私はそれをリファクタリングする必要がありました。

はまた、MIPSの下ABIは、$v*$a*、および$t*いかなる目的のために呼び出される関数で使用することができるという事実をメモしておきます。したがって、$s*レジスタを変更することは、内部的には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 
関連する問題