2010-02-19 4 views
1

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

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 
+0

Я снова написал свой ответ, $ s0 .. $ s7 являются Вызывающий сохраненные регистры – Tom

ответ

2

$ SX регистры гарантированно будут неизменными вызовами функций accross, поэтому его вызываемое (функция суммы) Ответственной спасти их, только если его будет менять свое значение.

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

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

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

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

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 (временных).

+0

не должны звонящий сохранить регистр $ t0- $ t7 вместо $ s регистров? – aherlambang

+0

vbsme вот вызывающая функция sum правильно? – aherlambang

+0

vbsme caller, sum callee – Tom

1

Александр,

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

Caller Stack Сохранить:

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 

Caller Stack Восстановление

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. Это даст вам представление о том, как использовать макрокоманду.

веселит

Смежные вопросы