简体   繁体   中英

Assembly Mips Program Main Calls

I am having trouble with my main program. I need to allow bits to be passed into the function dumpb and dumbw and dumpreg (i think). Currently I'm getting zeros as my output but I don't think that's what I'm supposed to be getting. Could someone help me please or at least point me in the right direction of where my mistakes are?

.data

n_elem: .word   10


.text
.globl main

main:
    jal dumpreg

    jal prword

    jal prchar

    #insert element to dump
    jal dumpb

    #insert element to dump
    jal dumpw

addi $v0, $0, 10    #exit program
syscall

dumpw:
    addi $sp, $sp, -16 #allocates memory
    sw $a0, 12($sp)
    sw $v0, 8($sp)
    sw $t0, 4($sp)
    sw $t1, 0($sp)

    lw $t0, 20($sp)  # load n_elem
    lw $t1, 16($sp)  # load address
looptop:    
    beq $t0, $0, bailout
    lw $a0, 0($t1)   # a0 = address[i]
    addi $v0, $0, 1
    syscall
    addi $t0, $t0, -1
    addi $t1, $t1, 4
    j  looptop
bailout:    
    lw $t1, 0($sp)
    lw $t0, 4($sp)
    lw $v0, 8($sp)
    lw $a0, 12($sp)
    addi $sp, $sp, 16
    jr $ra

dumpb:
    addi $sp, $sp, -16
    sw $a0, 12($sp)
    sw $v0, 8($sp)
    sw $t0, 4($sp)
    sw $t1, 0($sp)

    lw $t0, 20($sp)  # load n_elem
    lw $t1, 16($sp)  # load address

looptopb:    
    beq $t0, $0, bailoutb
    lb $a0, 0($t1)   # a0 = address[i]
    addi $v0, $0, 11
    syscall
    addi $t0, $t0, -1
    addi $t1, $t1, 1
    j  looptopb

bailoutb:   
    lw $t1, 0($sp)
    lw $t0, 4($sp)
    lw $v0, 8($sp)
    lw $a0, 12($sp)
    addi $sp, $sp, 16
    jr $ra

prspace:
    addi $sp, $sp, -8
    sw $a0, 0($sp)
    sw $ra, 4($sp)

    addi $a0, $0, ' '   
    addi $sp, $sp, -4   #push it
    sw   $a0, 0($sp)
    jal prchar
    addi $sp, $sp, 4

    lw $a0, 0($sp)
    lw $ra, 4($sp)
    addi $sp, $sp, 8

    jr $ra

prcomma:
    addi $sp, $sp, -8
    sw $a0, 0($sp)
    sw $ra, 4($sp)

    addi $a0, $0, ','  # 
    addi $sp, $sp, -4   #push it
    sw   $a0, 0($sp)
    jal prchar
    addi $sp, $sp, 4

    lw $a0, 0($sp)
    lw $ra, 4($sp)
    addi $sp, $sp, 8
    jr $ra

prnl:
    addi $sp, $sp, -8
    sw $a0, 0($sp)
    sw $ra, 4($sp)

    addi $a0, $0, 0x0A  # 0xA new line char
    addi $sp, $sp, -4   #push it
    sw   $a0, 0($sp)
    jal prchar
    addi $sp, $sp, 4

    lw $a0, 0($sp)
    lw $ra, 4($sp)
    addi $sp, $sp, 8
    jr $ra

prchar:
    addi $sp, $sp, -8
    sw $a0, 4($sp)
    sw $v0, 0($sp)

    lw $a0, 8($sp)
    addi $v0, $0, 11
    syscall

    lw $v0, 0($sp)
    lw $a0, 4($sp)
    addi $sp, $sp, 8
    jr $ra

prbyte:
    addi $sp, $sp, -8
    sw $a0, 4($sp)
    sw $v0, 0($sp)

    lw $a0, 8($sp)
    addi $v0, $0, 1
    syscall

    lw $v0, 0($sp)
    lw $a0, 4($sp)
    addi $sp, $sp, 8
    jr $ra

dumpreg:
    addi $sp, $sp, -4
    sw $ra, 0($sp)

    jal prnl

    addi $sp, $sp, -4
    jal prspace
    sw   $a0, 0($sp)
    jal  prword
    jal prspace
    sw   $a1, 0($sp)
    jal  prword
    jal prspace
    sw   $t0, 0($sp)
    jal  prword
    jal prspace
    sw   $t1, 0($sp)
    jal  prword
    jal prspace
    sw   $t2, 0($sp)
    jal  prword
    jal prspace
    sw   $t3, 0($sp)
    jal  prword
    jal prspace
    sw   $t4, 0($sp)
    jal  prword
    jal prspace
    sw   $s0, 0($sp)
    jal  prword
    jal prspace
    sw   $s1, 0($sp)
    jal  prword
    addi $sp, $sp, 4    

    jal prnl

    lw $ra, 0($sp)
    addi $sp, $sp, 4
    jr  $ra

prword:
    addi $sp, $sp, -8
    sw $a0, 4($sp)
    sw $v0, 0($sp)

    lw $a0, 8($sp)
    addi $v0, $0, 1
    syscall

    lw $a0, 4($sp)
    lw $v0, 0($sp)
    addi $sp, $sp, 8
    jr $ra

I was able to fix your program and get it working, but I had to do quite a bit of rework.

You were doing way too much push/pop on the stack. Note that while the code was not technically wrong [for the most part], it was contrary to the mips ABI and the spirit of mips and, thus, was complicated.

You were pushing arguments onto the stack instead of passing them in registers. This also added to the [needless] complexity. I changed all functions to pass arguments according to the ABI.

You were saving/restoring registers that are "callee owned", meaning that the callee need not preserve them and may change them at will: v*, a*, t*

Saving v0 on the stack actually breaks the ABI as it's used for return values [and syscall numbers].

Your program was incomplete (ie no array to dump) and, in main, you were calling functions without setting up the arguments for them.

I simplified the really low level functions like prchar . Take special note that the single char output functions (eg prnl ) that called it, now use "tail call optimization", so they don't need a stack frame of their own.

I changed dumpregs to pre-store the regs and then call dumpw instead of replicating the code.

I left your prword and prbyte functions intact [they are no longer used]. If you want to use them, consider removing the "push arg on stack" interface they still have and convert to using $a0 instead.

So, the code may look [quite] a bit alien to you [please pardon the gratuitous style cleanup]:

    .data

n_elem:     .word       10
array:      .word       1,2,3,4,5,6,7,8,9,10

dumpw_msg:  .asciiz     "words:"
dumpb_msg:  .asciiz     "bytes:"
dumpreg_msg:    .asciiz     "regs:"

    .text
    .globl  main

main:
    jal     prnl
    jal     dumpreg

    # dump array as words
    la      $a0,dumpw_msg
    li      $v0,4
    syscall
    la      $a0,array
    lw      $a1,n_elem
    jal     dumpw

    # dump array as bytes
    la      $a0,dumpb_msg
    li      $v0,4
    syscall
    la      $a0,array
    lw      $a1,n_elem
    sll     $a1,$a1,2           # get byte count
    jal     dumpb

    addi    $v0,$0,10               # exit program
    syscall

# dumpw -- dump array as words
#
# arguments:
#   a0 -- pointer to array
#   a1 -- number of words in array
dumpw:
    move    $t1,$a0                 # load address
    move    $t0,$a1                 # load count

dumpw_loop:
    ble     $t0,$0,dumpw_done

    # output a space
    addi    $v0,$0,11
    addi    $a0,$0,' '
    syscall

    lw      $a0,0($t1)              # a0 = address[i]
    addi    $v0,$0,1
    syscall

    addi    $t0,$t0,-1
    addi    $t1,$t1,4
    j       dumpw_loop

dumpw_done:
    # output a newline
    addi    $v0,$0,11
    addi    $a0,$0,0x0a
    syscall

    jr      $ra

# dumpb -- dump array as bytes
#
# arguments:
#   a0 -- pointer to array
#   a1 -- number of bytes in array
dumpb:
    move    $t1,$a0                 # load address
    move    $t0,$a1                 # load count

dumpb_loop:
    ble     $t0,$0,dumpb_done

    # output a space
    addi    $v0,$0,11
    addi    $a0,$0,' '
    syscall

    lb      $a0,0($t1)              # a0 = address[i]
    addi    $v0,$0,1
    syscall

    addi    $t0,$t0,-1
    addi    $t1,$t1,1
    j       dumpb_loop

dumpb_done:
    # output a newline
    addi    $v0,$0,11
    addi    $a0,$0,0x0a
    syscall

    jr      $ra

# dumpreg -- dump registers
dumpreg:
    addi    $sp,$sp,-36
    sw      $ra,0($sp)

    # pre-store the registers we wish to dump
    sw      $a0,4($sp)
    sw      $a1,8($sp)
    sw      $t0,12($sp)
    sw      $t1,16($sp)
    sw      $t2,20($sp)
    sw      $t3,24($sp)
    sw      $s0,28($sp)
    sw      $s1,32($sp)

    # output the identifying message
    la      $a0,dumpreg_msg
    li      $v0,4
    syscall

    # now, because of the pre-store, we can reuse the array dumper
    addiu   $a0,$sp,4               # point to the dumped registers array
    addi    $a1,$0,8                # get number of words to dump
    jal     dumpw

    # restore the dumped register values
    lw      $a0,4($sp)
    lw      $a1,8($sp)
    lw      $t0,12($sp)
    lw      $t1,16($sp)
    lw      $t2,20($sp)
    lw      $t3,24($sp)
    lw      $s0,28($sp)
    lw      $s1,32($sp)

    lw      $ra,0($sp)
    addi    $sp,$sp,36
    jr      $ra

# prword -- dump a word as integer (currently unused)
prword:
    addi    $sp,$sp,-8
    sw      $a0,4($sp)
    sw      $v0,0($sp)

    lw      $a0,8($sp)
    addi    $v0,$0,1
    syscall

    lw      $a0,4($sp)
    lw      $v0,0($sp)
    addi    $sp,$sp,8
    jr      $ra

# prbyte -- print a byte (currently unused)
prbyte:
    addi    $sp,$sp,-8
    sw      $a0,4($sp)
    sw      $v0,0($sp)

    lw      $a0,8($sp)
    addi    $v0,$0,1
    syscall

    lw      $v0,0($sp)
    lw      $a0,4($sp)
    addi    $sp,$sp,8
    jr      $ra

# prspace -- print a space
prspace:
    addi    $a0,$0,' '
    j       prchar

# prcomma -- print a comma
prcomma:
    addi    $a0,$0,','
    j       prchar

# prnl -- print a newline
prnl:
    addi    $a0,$0,0x0A
    j       prchar

# prchar -- print an ascii char
prchar:
    addi    $v0,$0,11
    syscall
    jr      $ra

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