简体   繁体   中英

Why is my MIPS base converter printing out the values from a previous loop after the current values?

I'm very new to MIPS and this has me completely baffled. I made a program to convert bases and it works fine the first time through, but when it loops, its displaying the values from the other registers from the previous iterations of the loop. The output is below. I've tried everything that I can think of and I'm out of ideas...

Enter a decimal number: 10
The number in base 2 is 00000000000000000000000000001010
The number in base 4 is 0000000000000022
The number in base 16 is 0000000A
The number in base 8 is 0000000012

Would you like to input another number? 1

Enter a decimal number: 11
The number in base 2 is 0000000000000000000000000000101100000000000000220000000A0000000012

The number in base 4 is 00000000000000230000000A0000000012

The number in base 16 is 0000000B0000000012

The number in base 8 is 0000000013

Would you like to input another number?

    .text
    .globl __start

__start:
    la $a0, prompt              # Prompt for a base10 integer
    li $v0, 4
    syscall

    li $v0, 5                   
    syscall

    move $a0, $v0               

    jal bin                     
    jal base4
    jal hex
    jal base8

    la $a0, endl                
    li $v0, 4
    syscall     

    la $a0, repeat              
    li $v0, 4
    syscall

    li $v0, 5                
    syscall

    beqz $v0, eop               

    la $a0, endl                
    li $v0, 4
    syscall

    j __start                

eop:    
    li $v0,10                       # End Of Program
        syscall     



##########################################################
#
#   BASE 16
#
##########################################################  

hex:    
    sub $sp, $sp, 24            # Push register onto stack
    sw $a0, 0($sp)
    sw $s0, 4($sp)
    sw $s1, 8($sp)
    sw $s2, 12($sp)
    sw $s3, 16($sp)
    sw $s4, 20($sp)

    move $s2, $a0               # Move a0 to s2

    la $a0, ans3                # Display string before hex answer
    li $v0, 4
    syscall

    li $s0, 8                   # 8 digits for hex word
    la $s3, hexresult           # Hex string set up here

hexloop:
    rol $s2, $s2, 4             # Start with leftmost digit
    and $s1, $s2, 0xf           # Mask 15 digits in s2 and place results in s1
    ble $s1, 9, hexprint        # If s1 <= 9, go to print
    add $s1, $s1, 7             # Else s1 = s1 + 7 (to get A-F)

hexprint:
    add $s1, $s1, 48            # Add 48 (30 hex) to get ascii code
    sb $s1,($s3)                # Store byte in result. s3 -> result
    add $s3, $s3, 1             # s3 = s3 + 1
    add $s0, $s0, -1            # s0 = s0 - 1
    bnez $s0, hexloop           # If s0 != 0, go to hexloop
    la $a0, hexresult           # display result

    li $v0, 4
    syscall

    jr $ra                      # Return
##########################################################
#
#   BASE 2
#
#########################################################

bin:    
    sub $sp, $sp, 24            # Push register onto stack
    sw $a0, 0($sp)
    sw $s0, 4($sp)
    sw $s1, 8($sp)
    sw $s2, 12($sp)
    sw $s3, 16($sp)
    sw $s4, 20($sp)

    move $s2, $a0               # Move a0 to s2

    la $a0, ans1                # Display string before bin answer
    li $v0, 4
    syscall

    li $s0, 32                  # 32 digits for base4 word
    la $s3, binresult           # Bin string set up here

binloop:
    rol $s2, $s2, 1             # Start with leftmost digit
    and $s1, $s2, 1             # Mask one digit in s2 and place results in s1


binprint:
    add $s1, $s1, 48            # Add 48 (30 hex) to get ascii code
    sb $s1,($s3)                # Store byte in result. s3 -> result
    add $s3, $s3, 1             # s3 = s3 + 1
    add $s0, $s0, -1            # s0 = s0 - 1
    bnez $s0, binloop           # If s0 != 0, go to binloop
    la $a0, binresult           # display result

    li $v0, 4
    syscall

    la $a0, endl
    li $v0, 4
    syscall

    jr $ra                      # Return

##########################################################
#
#   BASE 4
#
#########################################################       

base4:  
    sub $sp, $sp, 24            # Push register onto stack
    sw $a0, 0($sp)
    sw $s0, 4($sp)
    sw $s1, 8($sp)
    sw $s2, 12($sp)
    sw $s3, 16($sp)
    sw $ra, 20($sp)

    move $s2, $a0               # Move a0 to s2

    la $a0, ans2                # Display string before BASE 4 answer
    li $v0, 4
    syscall

    li $s0, 16                  # 16 digits for base4 word
    la $s3, base4result         # Bin string set up here

base4loop:
    rol $s2, $s2, 2             # Start with leftmost digit
    and $s1, $s2, 3             # Mask one digit in s2 and place results in s1

fourprint:
    add $s1, $s1, 48            # Add 48 (30 hex) to get ascii code
    sb $s1,($s3)                # Store byte in result. s3 -> result
    add $s3, $s3, 1             # s3 = s3 + 1
    add $s0, $s0, -1            # s0 = s0 - 1
    bnez $s0, base4loop         # If s0 != 0, go to binloop

    la $a0, base4result         # display result
    li $v0, 4
    syscall

    la $a0, endl
    li $v0, 4
    syscall

    jr $ra                      # Return

##########################################################
#
#   BASE 8
#
#########################################################           

base8:  
    sub $sp, $sp, 24            # Push register onto stack
    sw $a0, 0($sp)
    sw $s0, 4($sp)
    sw $s1, 8($sp)
    sw $s2, 12($sp)
    sw $s3, 16($sp)
    sw $ra, 20($sp)

    move $s2, $a0               # Move a3 to s2

    la $a0, endl
    li $v0, 4
    syscall     

    la $a0, ans4                # Display string before bin answer
    li $v0, 4
    syscall

    li $s0, 10              #  digits for octal word
    la $s3, octresult           # Bin string set up here

    rol $s2, $s2, 2             # Start with leftmost digit
    and $s1, $s2, 0x7           # Mask 7 digits in s2 and place results in s1

base8loop:
    rol $s2, $s2, 3             # Start with leftmost digit
    and $s1, $s2, 0x7           # Mask 7 digits in s2 and place results in s1


base8print:
    add $s1, $s1, 48            # Add 48 (30 hex) to get ascii code
    sb $s1,($s3)                # Store byte in result. s3 -> result
    add $s3, $s3, 1             # s3 = s3 + 1
    add $s0, $s0, -1            # s0 = s0 - 1
    bnez $s0, base8loop         # If s0 != 0, go to binloop
    la $a0, octresult           # display result

    li $v0, 4
    syscall     


    jr $ra                      # Return


.data

binresult:  .space 32
base4result:.space 16
hexresult:  .space  8
octresult:  .space 10
endl:       .asciiz "\n"
prompt:     .asciiz "Enter a decimal number: "
ans1:       .asciiz "The number in base 2 is "
ans2:       .asciiz "The number in base 4 is "
ans3:       .asciiz "The number in base 16 is "
ans4:       .asciiz "The number in base 8 is "
repeat:     .asciiz "Would you like to input another number? "

The strings you print with syscall 4 need to be ASCIIZ, ie ASCII with a zero terminator. So you need to store a byte with the value zero after the last character in each string. And to be able to store that extra byte, you need to reserve one additional byte for each string (ie .space 33 for binResult , etc).

Actually, just increasing the number of bytes reserved with .space should be enough, as .space should zero-initialize the memory. But adding an extra sb per string just to be sure wouldn't hurt much.

I had some difficulty making sense of all the code with some conflicting comments and register usage (eg enter 27 and hex comes back 0). When I ran it, stepping through it, I think I saw the rol trash things. Dunno for sure as I only ran it once or twice.

So, I did a recode using a different method. The code for all four bases is now common. I did the hex and octal. I left the base 4 and base 2 for you to do.

Anyway, here's the code [please pardon the gratuitous style cleanup]:

    .text
    .globl  main

main:
    la      $a0,prompt              # Prompt for a base10 integer
    li      $v0,4
    syscall

    # get the value
    li      $v0,5
    syscall
    move    $s7,$v0

    ###jal      bin
    ###jal      base4
    jal     hex
    jal     oct

    la      $a0,endl
    li      $v0,4
    syscall

    la      $a0,repeat
    li      $v0,4
    syscall

    li      $v0,5
    syscall

    beqz    $v0,eop

    la      $a0,endl
    li      $v0,4
    syscall

    j       main

eop:
    li      $v0,10                  # End Of Program
    syscall

#   BASE 16
hex:
    la      $a0,hexmsg              # Display string before hex answer
    li      $a1,0x0F                # mask for hex digit
    li      $a2,28                  # initial right shift amount
    li      $a3,4                   # right shift decrement
    j       numdump

#   BASE 8
oct:
    la      $a0,octmsg              # Display string before hex answer
    li      $a1,0x07                # mask for octal digit
    li      $a2,30                  # right shift amount
    li      $a3,3                   # right shift decrement
    j       numdump

# numdump -- dump out a number in an alternate base
#
# arguments:
#   a0 -- pointer to string for prefix
#   a1 -- mask for digit
#   a2 -- initial right shift amount
#   a3 -- amount to decrement shift by
#   s7 -- number value
numdump:
    li      $v0,4
    syscall

    la      $t3,result              # output string set up here

numloop:
    srlv    $t0,$s7,$a2             # slide the digit right
    and     $t0,$t0,$a1             # mask the digit
    lb      $t0,digits($t0)         # get the ascii value

    sb      $t0,0($t3)              # store into result buffer
    addi    $t3,$t3,1               # advance result pointer

    sub     $a2,$a2,$a3             # reduce shift amount -- more to do?
    bgez    $a2,numloop             # yes, loop

    sb      $zero,0($t3)            # store end of string

    la      $a0,result              # display result
    li      $v0,4
    syscall

    la      $a0,endl
    syscall

    jr      $ra                     # Return

    .data

result:     .space      40
digits:     .asciiz     "0123456789ABCDEF"

endl:       .asciiz     "\n"
prompt:     .asciiz     "Enter a decimal number: "
b2msg:      .asciiz     "The number in base 2 is "
b4msg:      .asciiz     "The number in base 4 is "
hexmsg:     .asciiz     "The number in base 16 is "
octmsg:     .asciiz     "The number in base 8 is "
repeat:     .asciiz     "Would you like to input another number? "

Here's a slightly more compact version that requires one less argument to the common function:

    .text
    .globl  main

main:
    la      $a0,prompt              # Prompt for a base10 integer
    li      $v0,4
    syscall

    # get the value
    li      $v0,5
    syscall
    move    $s7,$v0

    ###jal      bin
    ###jal      base4
    jal     hex
    jal     oct

    la      $a0,endl
    li      $v0,4
    syscall

    la      $a0,repeat
    li      $v0,4
    syscall

    li      $v0,5
    syscall

    beqz    $v0,eop

    la      $a0,endl
    li      $v0,4
    syscall

    j       main

eop:
    li      $v0,10                  # End Of Program
    syscall

#   BASE 16
hex:
    la      $a0,hexmsg              # Display string before hex answer
    li      $a1,4                   # number of bits in a digit
    li      $a2,28                  # initial right shift amount
    j       numdump

#   BASE 8
oct:
    la      $a0,octmsg              # Display string before hex answer
    li      $a1,3                   # number of bits in a digit
    li      $a2,30                  # right shift amount
    j       numdump

# numdump -- dump out a number in an alternate base
#
# arguments:
#   a0 -- pointer to string for prefix
#   a1 -- number of bits in a digit
#   a2 -- initial right shift amount
#   s7 -- number value
#
# registers:
#   a3 -- digit mask
numdump:
    li      $v0,4
    syscall

    la      $t3,result              # output string set up here

    # create digit mask from number of bits in a digit
    li      $a3,1                   # mask = 1
    sllv    $a3,$a3,$a1             # mask <<= digit width (for hex, 0x10)
    subiu   $a3,$a3,1               # bump down for mask (for hex, 0x0F)

numloop:
    srlv    $t0,$s7,$a2             # slide the digit right
    and     $t0,$t0,$a3             # mask the digit
    lb      $t0,digits($t0)         # get the ascii value

    sb      $t0,0($t3)              # store into result buffer
    addi    $t3,$t3,1               # advance result pointer

    sub     $a2,$a2,$a1             # reduce shift amount -- more to do?
    bgez    $a2,numloop             # yes, loop

    sb      $zero,0($t3)            # store end of string

    la      $a0,result              # display result
    li      $v0,4
    syscall

    la      $a0,endl
    syscall

    jr      $ra                     # Return

    .data

result:     .space      40
digits:     .asciiz     "0123456789ABCDEF"

endl:       .asciiz     "\n"
prompt:     .asciiz     "Enter a decimal number: "
b2msg:      .asciiz     "The number in base 2 is "
b4msg:      .asciiz     "The number in base 4 is "
hexmsg:     .asciiz     "The number in base 16 is "
octmsg:     .asciiz     "The number in base 8 is "
repeat:     .asciiz     "Would you like to input another number? "

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM