MIPS: перевод кода C в проблему MIPS при вызовах функций и возвратах - PullRequest
1 голос
/ 15 апреля 2020

Мне нужно изменить код C снизу на код MIPS, но я новичок в MIPS и застрял с ним.

Вот код C:

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);
}

Вот код MIPS, который я написал, который не работает (я знаю, что есть серьезные ошибки и ошибки). Поскольку я не знаком с языком, мои главные проблемы - использование стека, возврат и вызов функций.

.data
    a:.word 8
    b:.word 8
    result:.word 0
main:
    li $s0 a
    li $s1 b
    li $s3 result
    beq $s0,$s1,Resultmul ELSE
    add $s3,$s3,assess

assess:
    blt $s1,$s0,upgrade
    bge $s1,$0,demote
Resultmul :
    mul $s3,$s1,$0

upgrade:
    addi $sp,$sp,-4
    sw $0,0($sp)
    add $t1,$a0,$a1
    mul $t1,$t1,4
    add $v0,$s0,$zero
    lw $s0,0($sp)
    addi $sp,$sp,4
    jr $ra
demote:
    addi $sp,$sp,-4
    sw $0,0($sp)
    sub $t1,$a0,$a1
    mul $t1,$t1,4
    add $v0,$s0,$zero
    lw $s0,0($sp)
    addi $sp,$sp,4
    jr $ra

Если кто-то может помочь, это спасет жизнь.

1 Ответ

1 голос
/ 16 апреля 2020

Я не собираюсь давать вам полное решение, чтобы вы могли извлечь уроки из упражнения, но я рекомендую вам работать с шаблоном, как, например, в этом.

Я использовал код 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.

Существует две основные причины для хранения переменных:

  1. Вызов функции хочет неосознанно изменить один из ваших $s0-$s7 -регистров.
  2. Другие функции могут быть вызваны в текущей функции, с их собственной обработкой стека, поэтому снова не нужно беспокоиться о регистрах. Может быть интересно узнать, прежде чем создавать 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 может вызвать ошибку.

...