cmipsqtspimmips64

Attempting to convert the following C Code to High Level MIPS Assembly code but no output, why?


I have already tried changing the adding more space to the stack and that didn't seem to help ro change anything also in the uppercase label function I initially had the register names as $s4, $s5, $s6 which I change to $s0, $s1, and $s2 respectively but for some reason that gave me some errors. Now when I run the code there is no errors but there is no output for some reason. Does anyone possibly have any idea as to why? Thank you in advance

C Code:

#include <stdio.h>

// global array
char str[] = "Homework-10";

// switch lowercase characters in str to uppercase
char
uppercase(char ch)
{
    if ((ch >= 'a') && (ch <= 'z')) {
        ch = ch - 32;
    }
    return ch;
}

int
main()
{
    for (int i = 0; str[i] != '\0'; i++) {
        str[i] = uppercase(str[i]);
    }
    printf("%s", str);
    return 0;
}

High Level MIPS Assembly:

    .data
str:        .asciiz     "Homework-10"
a:          .byte       'a'
z:          .byte       'z'

    .text

main:
    # adjust the stack pointer
    addi    $sp,$sp,-4
    # save $ra on the stack
    sw      $ra,0($sp)

    # str[] address
    la      $s0,str

FOR:
    # str[] value
    lb      $s1,0($s0)

    beq     $s1,$0,DONE

    move    $a0,$s1

    jal     uppercase

    move    $s1,$v0                 # save the return value in s1

    # store the result back to str[i]
    sb      $s1,0($s0)

    addi    $s0,$s0,1

    j       FOR

DONE:
    # print the modified string
    la      $a0,str
    li      $v0,4
    syscall

    # restore everything
    lw      $ra,0($sp)
    addi    $sp,$sp,4
    jr      $ra

uppercase:
    # save the registers on the stack
    addi    $sp,$sp,-16
    sw      $ra,0($sp)
    sw      $s0,4($sp)              # use this for a
    sw      $s1,8($sp)              # use this for z
    sw      $s2,12($sp)             # use this for ch

    # ch argument
    move    $s2,$a0

    # load 'a' and 'z'
    lb      $s0,a
    lb      $s1,z

    # check if ch is a lowercase character
    blt     $s2,$s0,L1
    bgt     $s2,$s1,L1

    # convert ch to uppercase
    addi    $s2,$s2,-32

L1:
    # restores registers from the stack
    lw      $ra,0($sp)
    lw      $s0,4($sp)              # use this for a
    lw      $s1,8($sp)              # use this for z
    lw      $s2,12($sp)             # use this for ch
    addi    $sp,$sp,16

    move    $v0,$s2                 # return the converted character
    jr      $ra

Solution

  • You have a bug:

    In uppercase, at L1: you restore the registers and then do: move $v0,$s2 (to set the return value for the function)

    This sets $v0 to the caller's value of $s2 and not the value computed by uppercase.

    The result is that when the syscall [to print] is executed, the str array is all zeros (because caller's $s2 has zero in it).

    To fix, move the move $v0,$s2 to the first statement following L1:


    I ran this under mars (vs. spim), so this may be specific to mars.

    It printed the correct result, but, when the final jr $ra is executed in main, it jumps to location 0x00000000.

    To fix this, I added an exit syscall instead


    Here is the corrected code. It is annotated with the bugs and fixes:

        .data
    str:        .asciiz     "Homework-10"
    a:          .byte       'a'
    z:          .byte       'z'
    
        .text
    
    main:
        # adjust the stack pointer
        addi    $sp,$sp,-4
        # save $ra on the stack
        sw      $ra,0($sp)
    
        # str[] address
        la      $s0,str
    
    FOR:
        # str[] value
        lb      $s1,0($s0)
    
        beq     $s1,$0,DONE
    
        move    $a0,$s1
    
        jal     uppercase
    
        move    $s1,$v0                 # save the return value in s1
    
        # store the result back to str[i]
        sb      $s1,0($s0)
    
        addi    $s0,$s0,1
    
        j       FOR
    
    DONE:
        # print the modified string
        la      $a0,str
        li      $v0,4
        syscall
    
    # NOTE/FIX: just exit here
        li      $v0,10
        syscall
    
        # restore everything
    # NOTE/BUG: this just jumps to location 0
        lw      $ra,0($sp)
        addi    $sp,$sp,4
        jr      $ra
    
    uppercase:
        # save the registers on the stack
        addi    $sp,$sp,-16
        sw      $ra,0($sp)
        sw      $s0,4($sp)              # use this for a
        sw      $s1,8($sp)              # use this for z
        sw      $s2,12($sp)             # use this for ch
    
        # ch argument
        move    $s2,$a0
    
        # load 'a' and 'z'
        lb      $s0,a
        lb      $s1,z
    
        # check if ch is a lowercase character
        blt     $s2,$s0,L1
        bgt     $s2,$s1,L1
    
        # convert ch to uppercase
        addi    $s2,$s2,-32
    
    L1:
    # NOTE/FIX: this is the correct place to set the return value
        move    $v0,$s2                 # return the converted character
    
        # restores registers from the stack
        lw      $ra,0($sp)
        lw      $s0,4($sp)              # use this for a
        lw      $s1,8($sp)              # use this for z
        lw      $s2,12($sp)             # use this for ch
        addi    $sp,$sp,16
    
    # NOTE/BUG: s2 holds the return value but it has been restored to _caller's_
    # value -- this occurs too late
        ###move $v0,$s2                 # return the converted character
        jr      $ra