Функция MIPS внутри функции - PullRequest
1 голос
/ 19 февраля 2010

Я пытаюсь, чтобы функция vbsme вызывала другую функцию с именем sad ... Правильна ли следующая процедура для сохранения регистров и адреса возврата ??вызывающий должен сохранить регистр $ t0- $ t7, но где и как мне это сделать?

vbsme: li $v0, 0   # reset $v0 
     li $v1, 0   # reset $v1
     li  $t0, 1   # i(row) = 1 
     li  $t1, 1   # j(col) = 1
     lw  $t2, 0($a0)  # row size
     lw  $t3, 4($a0)  # col size
     mul  $t4, $t2, $t3  # row * col
     li  $t5, 0   # element = 0
    loop:   bgeq  $t5, $t4, exit  # if element >= row * col then exit

     addi $sp, $sp, -16  # create space on the stack pointer
     sw $ra, -12($sp)  # save return address
     sw $s6, -8($sp)  # save return address
     sw $s7, -4($sp)  # save return address
     subi $s7, $t0, 1  # 1st parameter: i-1
     subi $s6, $t1, 1  # 2nd parameter: j-1
     jal  sad   # calculate the sum of absolute difference using the frame starting from row a0 and col a1
     lw $ra, -12($sp)  # restore return address
     lw $s6, -8($sp)  
     lw $s7, -4($sp)
     addi $sp, $sp, 16  # restore stack pointer
     jr $ra

Ответы [ 2 ]

2 голосов
/ 19 февраля 2010

$ sx регистры гарантированно остаются неизменными при вызовах функций, поэтому вызываемый объект (функция sum) отвечает за их сохранение, только если он собирается изменить их значение.

$ tx регистров наС другой стороны, не гарантируется, что они будут неизменными при вызовах функций, поэтому ответственность вызывающего абонента (vbsme) за их сохранение.

Вы должны сохранить $ sx в стеке вызываемого.

Таккогда вы начинаете кодировать функцию суммы, вы должны сэкономить место в стеке. Если вы хотите сохранить n регистров, то сохраните n * 4.

Пространство в стеке сохраняется путем вычитания из регистра $ sp, которыйуказывает на основание стека.Перед кодом вашей функции вы должны создать стек для этой функции, сохраняя все регистры, сохраненные вызывающей стороной, регистры адресов и регистры глобального указателя, когда это необходимо

sum:
       #stack frame creation. Caller registers saved, 
       # return address and frame pointer

       subu $sp,$sp,36 #Save space in the stack for registers $s0, $s7 + $ra
       sw   $ra,32($sp)
       sw   $s0,0($sp)
       sw   $s1,4($sp)
       #and so on. Note that also you should save the $ra register only if you are
       # going to call another function

       #do something with $sx  

       #stack frame destruction
       #restore $sx and $ra registers
       lw  $ra,32($sp)
       lw  $s0,0($sp)
       lw  $s1,4($sp)
       ...
       lw  $s7,28($sp)

        jr $ra

Кстати, по соглашению, регистры $ a0, $a3 должен хранить аргументы функции, которую вы вызываете.Также обратите внимание, что, поскольку вы используете регистры $ s0, $ s7, вам необходимо проделать дополнительную работу.Конвенция гласит, что если вы не используете их, вам не следует их сохранять, поэтому, возможно, вы могли бы вместо этого использовать регистры $ tx (временные).

1 голос
/ 22 февраля 2010

Александр

То, что сказал Том, в значительной степени правильно, важно отметить, что при программировании на ассемблере все условно. Хотя в MIPS общее соглашение - это то, что заметил Том, это не единственное соглашение. Например, если вы используете макрос (который, если вы собираетесь писать более 1 или 2 функций в сборке, гораздо проще использовать макросы), вы можете определить соглашение о вызовах в макросе. Самый простой способ сделать это, вместо того, чтобы вызываемый объект сохранял стек, - это заставить вызывающего сохранить стек. Это менее эффективно, потому что иногда (возможно, много раз) сохраняются неиспользуемые регистры, однако это избавит вас от душевных страданий, потому что ваше соглашение применяется последовательно.

Сохранение стека вызовов:

    sw $fp 0($sp) # save the old frame pointer
    addu $fp $sp $0 # move the frame pointer to point at top of frame
    subu $sp $sp 44 # move the stack pointer down 44
    sw $fp 40($sp) # save the old stack pointer
    sw $ra 36($sp) # save the return address
    sw $s0 32($sp) # save registers $s0 - $s7
    sw $s1 28($sp)
    sw $s2 24($sp)
    sw $s3 20($sp)
    sw $s4 16($sp)
    sw $s5 12($sp)
    sw $s6 8($sp)
    sw $s7 4($sp)

вызов функции

    jal my_func

Восстановление стека вызовов

    subu $sp $fp 44 # move the stack pointer to the orginal unmodified bottom
    lw $ra 36($sp) # load the return address
    lw $s0 32($sp) # load registers $s0 - $s7
    lw $s1 28($sp)
    lw $s2 24($sp)
    lw $s3 20($sp)
    lw $s4 16($sp)
    lw $s5 12($sp)
    lw $s6 8($sp)
    lw $s7 4($sp)
    lw $fp 44($sp) # load the old frame pointer
    lw $sp 40($sp) # load the old stack pointer

Ваша функция:

my_func:
    do some stuff
    jr $ra             # return to the previous function

Как я уже сказал, лучший способ применить это соглашение - использовать макросы. Я сделал проект в SPIM (который вы можете использовать или не использовать) для класса. В рамках проекта мы написали макро-движок (он также выполняет другие интересные вещи) для SPIM, вы можете получить его здесь: http://github.com/timtadh/mpp Я также рекомендовал бы проверить http://github.com/timtadh/jist, которая является игрушечной операционной системой, написанной поверх SPIM. Это даст вам представление о том, как использовать механизм макросов.

ура

...