我是MIPS的新手,我正在尝试一个程序来查找伪随机数组中的最大数值。但是,我在一条线上得到一个超出范围的错误,我相当确定已分配了适当的内存等等。大多数骨架代码,注释等都给出了,我只是想尝试编写find_max函数。我评论了这条线给我提出了问题。
.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
答案 0 :(得分:1)
好的,你必须编写的函数是在计算数组索引时使用了错误的寄存器:
变化:
sll $t2,$t2,2 # compute 4i in $t2
分为:
sll $t2,$t1,2 # compute 4i in $t2
但是,您的功能还有更多严重的错误。您正在循环回到函数开始并在此过程中创建多个堆栈帧。我想你可能已经在某种程度上意识到了这一点,这就是为什么你试图通过跳转到Exit:
[这是main
]的一部分来补偿和退出函数的原因。
您的计算功能也会在找到第一个最大值后提前终止。 不继续遍历数组的其余部分以找到更好(即更大)的值。
还有许多其他错误。
我创建了两个版本的程序。一个有关于错误的注释。而且,第二个版本,清理和工作。
这是带注释的版本[请原谅无偿的风格清理]:
.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_array
和print_array
函数以及结果打印。您给出的样板代码也有一些我修复的[次要]错误。我试图保持对find_max
代码的忠诚,但不幸的是,我需要对其进行重构。
另外,请注意在mip ABI下,被调用函数可以使用$v*
,$a*
和$t*
any 目的。因此,修改$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