2

I need to change C code from below to a MIPS code but I am new to MIPS and stuck with it.

Here is the C code:

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

Here is MIPS code that I wrote, which isn't working (I am aware there are major errors and wrongs). Because I am not familiar with the language, my main problems are using stack, return and calling the functions.

.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

If someone can help that would be a lifesaver.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
asd dsa
  • 31
  • 4
  • Does this actually assemble without errors? What tool are you using? – Erik Eidt Apr 15 '20 at 17:20
  • Mars4_5 it assembles but doesn't run as expected and when assembled text segment is empty. – asd dsa Apr 15 '20 at 17:22
  • No, it doesn't. – Erik Eidt Apr 15 '20 at 17:22
  • @ErikEidt it must be result : .word 0 not equal my bad – asd dsa Apr 15 '20 at 17:23
  • Sometimes, it helps to see what a compiler would do... https://godbolt.org/z/gDh9Je – Michael Dorgan Apr 15 '20 at 17:23
  • 1
    You're missing the `.text` directive, so it is ignoring the whole program! I have to say that is pretty odd behavior on MARS' part. Put `.text` after your data and before the code. – Erik Eidt Apr 15 '20 at 17:24
  • @ErikEidt yes you are right i changed few things now still got many errors. – asd dsa Apr 15 '20 at 17:26
  • @MichaelDorgan actually i don't understand that compiler its my third day with MIPS so ı am not good with the language – asd dsa Apr 15 '20 at 17:28
  • FYI - your C code is using undefined behavior. `a` and `b` in main() both need to have a value of some sort for things to work correctly. I used `volatile` on them to tell the compiler to read garbage and got better code for next time. – Michael Dorgan Apr 15 '20 at 17:29
  • @MichaelDorgan we will try the code with values a=8 b=8 a=3 b=5 a=5 b=3 you can assume it is 8 for both i did in my MISP code – asd dsa Apr 15 '20 at 17:36
  • I see it. Got it. – Michael Dorgan Apr 15 '20 at 17:36
  • no one got a fix for this ? – asd dsa Apr 15 '20 at 18:10
  • By convention, we use ````jr $ra```` after having called ````jal foo````. I can't find a ````jal```` here... It has been a while, and I'm seeing some things I'm not sure of are possible, but I'll try to do it my way. Also, ````b```` (branch) is being highlighted when rewriting your code; meaning it's recognized as an instruction - which probably causes other unexpected behavior. –  Apr 16 '20 at 08:48

1 Answers1

2

I'm not going to give you the full solution, so you can learn from the exercise, but I recommend you work from a template, like at this one for example.

I used Visual Studio Code (with MIPS Support and Better MIPS support for highlighting), in which every whitespace or tab, gives me the possibility of collapsing it by these whitespaces, and QtSpim on which I was able to run this and got the output 64.

Also, I'm used to coding with tabs; it's more clear to me, but it might not be to you, so I'm sorry if you have to remove all the tabs and comments.

######################## 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:

Here you made a little mistake: You already stored the words, so you should also load the words. Else, you'll have to type 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

Since they are functions in your pseudo-code, they should be treated as functions in your assembly as well. Meaning they are being called with j (for non-returning function like exit) or jal (and return with jr).

I made a completely unnecessary function multiply to show you the template, which is pretty handy for larger functions.

###################### 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)

Always store the content of the registers you are going to overwrite, so you can call other functions without losing any content. Also immediately initialize your parameters stored in $a0-$a3 in new registers, because you might overwrite the parameters when printing something using syscall.

There are two main reasons to store the variables:

  1. The function call want unknowingly change one of your $s0-$s7-registers.
  2. Other functions can be called within the current function, with their own stack handling, so again no need to worry about registers. Might be interesting to know before making an assess-function.

This is how the initialization of a function's parameters would look like:

    # 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

This is the very short body of the function. As you can tell, storing all these parameters is idiotic, so don't make these overhead functions.

    # value = A * B;
    mul     $s2, $s0, $s1

This is to handle a function's return. In larger functions, you'll need a label most of the time to jump to the return-handling. I always call labels inside a function foo like foo_thisLabel, but that's just my recommendations.

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

Note that I only wait for the function's return segment to move value into the return register, $v0.

Here is an empty template for the other functions.

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

P.S. I've renamed your variable names, because b might cause an error.