Я не собираюсь давать вам полное решение, чтобы вы могли извлечь уроки из упражнения, но я рекомендую вам работать с шаблоном, как, например, в этом.
Я использовал код Visual Studio (с поддержкой MIPS и улучшенной поддержкой MIPS для выделения), в которой каждый пробел или вкладка дает мне возможность свертывать его этими пробелами, и QtSpim, на котором я смог запустить это, и получил вывод 64
.
Также я привык к кодированию с помощью вкладок; это более понятно для меня, но это может быть не для вас, поэтому извините, если вам нужно удалить все вкладки и комментарии.
######################## pseudo ####################################
#
# int main()
# {
# int a, b, result;
# if(a == b)
# result = a*b;
# else
# result = assess(a, b);
# return result;
# }
#
# int assess(int a, int b)
# {
# if(b<a)
# return upgrade(a, b);
# else
# return demote(a, b);
# }
#
# int upgrade(int a, int b)
# {
# return 4*(a+b);
# }
#
# int demote(int a, int b)
# {
# return 4*(b-a);
# }
#
###################### DATA Segment ################################
.data
A:
.word 8
B:
.word 8
result:
.word 0
###################### CODE Segment ################################
.text
.globl main
main:
Здесь вы сделали небольшую ошибку: вы уже хранится слов, поэтому вы также должны загрузить слов. В противном случае вам нужно будет набрать li $t0, 8
.
# int A = A, B = B, result
lw $s0, A # $s0 = A
lw $s1, B # $s1 = B
lw $s2, result # $s2 = result
# if (a == b)
bne $s0, $s1, noteq # if $s0 != $s1 then noteq
# result = multiply(a,b);
move $a0, $s0 # $a0 = $s0
move $a1, $s1 # $a1 = $s1
jal multiply # jump to multiply and save position to $ra
sw $v0, result #
b end # branch to end
# else
noteq:
# result = assess(a,b);
move $a0, $s0 # $a0 = $s0
move $a1, $s1 # $a1 = $s1
# jal assess # jump to assess and save position to $ra
sw $v0, result #
b end # branch to end (this rule can be left out)
end:
# printf("%i", result)
li $v0, 1 # $v0 = 1
lw $a0, result #
syscall
# exit()
li $v0, 10 # $v0 = 10
syscall
Поскольку они являются функциями в вашем псевдокоде, они также должны рассматриваться как функции в вашей сборке. Это означает, что они вызываются с помощью j
(для невозвратной функции, такой как выход) или jal
(и возвращаются с jr
).
Я сделал совершенно ненужную функцию multiply
, чтобы показать вам шаблон, который очень удобен для больших функций.
###################### FUNC Segment ################################
###################### FUNCTION ####################################
# multiply(A, B)
#
# Purpose: <General description>
######################## i/0 #######################################
# Input:
# $a0 = A
# $a1 = B
# Output:
# $v0 = value
# Registers being used:
# $s0 = A
# $s1 = B
# $s2 = value
######################## pseudo ####################################
#
# int multiply(int A, int B)
# {
# return A * B;
# }
#
######################## <code> ####################################
multiply:#(A, B)
Всегда храните содержимое регистров, которые вы собираетесь перезаписать, чтобы вы могли вызывать другие функции без потери содержимого. Также немедленно инициализируйте ваши параметры, хранящиеся в $a0-$a3
, в новых регистрах, потому что вы можете перезаписать параметры при печати чего-либо, используя syscall
.
Существует две основные причины для хранения переменных:
- Вызов функции хочет неосознанно изменить один из ваших
$s0-$s7
-регистров. - Другие функции могут быть вызваны в текущей функции, с их собственной обработкой стека, поэтому снова не нужно беспокоиться о регистрах. Может быть интересно узнать, прежде чем создавать
assess
-функцию.
Вот как должна выглядеть инициализация параметров функции:
# store(&return, parameters that are about overwritten)
sub $sp, $sp, 16 # $sp = $sp - 16
sw $ra, 0($sp) #
sw $s0, 4($sp) #
sw $s1, 8($sp) #
sw $s2, 12($sp) #
# int A = A, B = B, value
move $s0, $a0 # $s0 = $a0
move $s1, $a1 # $s1 = $a1
Это очень короткий Тело функции. Как вы можете сказать, хранение всех этих параметров является идиотом c, поэтому не выполняйте эти служебные функции.
# value = A * B;
mul $s2, $s0, $s1
Это для обработки возврата функции. В больших функциях вам понадобится метка большую часть времени, чтобы перейти к обработке возврата. Я всегда вызываю метки внутри функции foo
, как foo_thisLabel
, но это только мои рекомендации.
move $v0, $s2 # $v0 = $s2
# restore()
lw $ra, 0($sp) #
lw $s0, 4($sp) #
lw $s1, 8($sp) #
lw $s2, 12($sp) #
addi $sp, $sp, 12 # $sp = $sp + 12
# return index
jr $ra # jump to $ra
######################## </code> ###################################
Обратите внимание, что я только жду, когда возвратный сегмент функции переместится value
в регистр возврата, $v0
.
Вот пустой шаблон для других функций.
###################### FUNCTION ####################################
# <name of function>
#
# Purpose: <General description>
######################## i/0 #######################################
# Input:
# $a0 =
# $a1 =
# $a2 =
# $a3 =
# Output:
# $v0 =
# Registers being used:
# $t0 =
# $t1 =
# $t2 =
# $s0 =
# $s1 =
# $s2 =
# $s3 =
# $s4 =
######################## pseudo ####################################
#
# int assess(int a, int b)
# {
# if(b<a)
# return upgrade(a, b);
# else
# return demote(a, b);
# }
#
######################## <code> ####################################
#
######################## </code> ###################################
PS Я переименовал ваши имена переменных, потому что b
может вызвать ошибку.