РЕДАКТИРОВАТЬ: После повторного чтения кода, причиной ошибки на самом деле является следующий код:
jal printarray
Вы никогда не делали следующий код в printarray:
jr $ra
Таким образом, go вернется к другим функциям.
Используйте $sp
(правильный способ обработки $ra
при вызове функций внутри функций)
Причиной проблемы является следующий сегмент:
syscall
jal readnum
add $t1, $v0, $0
Более конкретно, вызов jal
. Для вызова функции внутри функции требуется выполнить еще несколько шагов.
Сначала поймите, что делает инструкция jal
. Проще говоря, инструкция jal
отмечает, где вы находитесь в данный момент, и сохраняет ее в регистре $ra
. Затем он перейдет к этой функции.
Но есть проблема : вы уже хотите, чтобы регистр $ra
запомнил, где вы когда-то были, потому что вы на самом деле вызывали createarray
!
Итак, вы позвонили createarray
, сделав $ra
магазин там, где вы когда-то были, затем внутри той функции, которую вы назвали readnum
, сделав $ra
магазин, где вы находитесь в createarray
. ** Но теперь вы потеряли то, что когда-то раньше называли createarray
. Таким образом, он будет продолжать возвращаться к тому, что раньше было $ra
, что находится внутри вашей функции createarray
.
К счастью, регистр $sp
- это то, что вам нужно
Как использовать регистр $sp
Для сохранения того, где мы находимся, мы помещаем sh в стек:
addi $sp, $sp, -4 # by convention, we use negative numbers when pushing
sw $ra, ($sp)
Чтобы получить то, что мы когда-то были после того, как мы вызвали функцию (которая заменив $ra
на первое место), мы вытолкаем стек:
lw $ra, ($sp)
addi $sp, $sp, 4 # by convention, we use positive numbers when popping
Итак, в общем, вот что вы делаете:
# push to the stack
addi $sp, $sp, -4
sw $ra, ($sp)
jal theFunctionWeWantToCallInOurFunction
# pop the stack, get back our $ra
lw $ra, ($sp)
addi $sp, $sp, 4
Давайте применим это решение для вашей кодовой базы:
.data
str5: .asciiz "Please enter a number of elements for the array between 0 and 20: "
str6: .asciiz "Please enter an element: "
array: .word 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.text
main:
begin:
li $v0, 4
la $a0, str5
syscall
jal readnum
add $a0, $v0, $0
jal verify
add $a0, $v0, $0
jal createarray
la $s1, array
jal printarray # comment off this line and you won't have an infinite loop
li $v0, 10
syscall
printarray:
createarray:
add $t0, $ra, $0
add $s0, $a0, $0
add $t9, $0, $0
la $s1, array
loop:
beq $s0, 0, done
li $v0, 4
la $a0, str6
syscall
# store where we wish to come back to so that $ra can be overriden without losing data.
addi $sp, $sp, -4
sw $ra, ($sp)
# call the function. jal will replace our current $ra
jal readnum
# retrieve what our $ra once was
lw $ra, ($sp)
addi $sp, $sp, 4
add $t1, $v0, $0
sw $t1, 0($s1)
addi $s1, $s1, 4
addi $s0, $s0, -1
addi $t9, $t9, 1
j loop
done:
add $ra, $t0, $0
jr $ra
verify:
add $s0, $a0, $0
bge $s0, 20, begin
ble $s0, 0, begin
add $v0, $s0, $0
jr $ra
readnum:
li $v0, 5
syscall
jr $ra