Mips программный бесконечный l oop выпуск - PullRequest
1 голос
/ 09 марта 2020

В настоящее время я пытаюсь выяснить, почему моя программа mars для создания массива застревает в бесконечном l oop. Я пытаюсь создать массив, используя разные функции, и в функции создания массива программа должна перейти в функцию получения чисел и вернуть значение, чтобы сохранить его в массиве, но счетчик, похоже, не уменьшается и просто продолжает спрашивать для элемента для массива. Вот код:

.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

    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

    jal readnum
    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

1 Ответ

0 голосов
/ 09 марта 2020

РЕДАКТИРОВАТЬ: После повторного чтения кода, причиной ошибки на самом деле является следующий код:

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
...