2016-11-03 12 views
1

私はmipsでいくつかの簡単な再帰を行うプログラムを作成しようとしていますが、iveは他のすべての記事と質問を私が見つけることはできますが、役に立たない。とにかく私は自分の名前を後ろに印刷しようとしています。だから私は一度に私の文字列の最後に0を探して、私はそれが私が解凍を開始し、私が保存したバイトを印刷見つけることを見つける1バイトを読んでいます。 事前にお手伝いします。MIPSアセンブリの単純な再帰で問題が発生する

コード:

.data 
    # print name backwards 
    Yn: .asciiz "frodobaggins" #yn stands for your name 
.text 
main: 
    li $v0, 4   #the v registers tell system what to do 4 == 
    print_string 
    la $a1, Yn   #load Yn's address into a0 
    addi $sp, $sp, -4 #increment stack pointer, always initially points to garbage 
    sw $a1, 0($sp)  #store address of a1 (Yn) into stack pointer 
    jal recurse   #recursive func call 
    addi $sp, $sp, 4 #increment sp back to beggining 
    addi $v0, $0, 10 #v0 = exit 
    syscall    #exit 

recurse: 
    lw $a3, 0($sp)  #load my name into reg $a3 
    lw $t6, 0($a3)  #read byte 
    addi $sp, $sp, -12 #increment stack ptr 
    sw $ra, 8($sp)  #store address of $ra onto stack 
    sw $t6, 4($sp)  #store the byte loaded into $t6 onto stack 
    bne $t6, $0, otherwise #if t6 == 0 goto otherwise 
    add $a3, $a3, 1  #a1 = a1 + 1 
    sw $a3, 0($sp)  #store the word, without the byte $t6 used, onto the stack 
    jal recurse 
    lw $t6, 4($sp)  #load the byte that was stored into $t6 
    lw $ra, 8($sp)  #get $ra ready for returning 
    addi $v0, $0, 4  #setup $v0 to tell pc to print to console 
    lw $a0, 0($t6)  #console always reads from $a0 
    syscall 
    addi $sp, $sp, 12 #put stack pointer back 
    jr $ra    #string is finished, return. 

otherwise: 
    #because this is just returning, i need to get the ra that was just stored on the stack 
    lw $ra 8($sp) 
    jr $ra    #go back to original call of jal 
+0

ご質問はありませんか? – tofro

+1

'lw $ t6、0($ a3)#read byte' 'lw'はバイトをロードしません。 _word_(4バイト)をロードします。 – Michael

+0

私はもともとlbとして持っていましたが、今のところ実行されていますが、実際には何も印刷しないので、少なくともlwに変更しました。 – Supercatfishpro

答えて

0

いくつかの問題がありました。

ロード$t6は、バイト操作でなければなりません。 otherwiseへの条件分岐に不正な意味がありました。印刷するsyscallは11 [putc]であり、4 [puts]ではありません。 otherwiseに復元されたスタックフレームには問題がありました。

私は3つのバージョンを作成しました。バグを示す注釈付きバージョン。クリーンアップされた、動作しているバージョン。そして、私は最初から作成したバージョンです。

.data 
Yn:   .asciiz  "frodobaggins" # yn stands for your name 
# print name backwards 
    .text 

main: 
    li  $v0,4     # syscall for print string 
    la  $a1,Yn     # load Yn's address into a0 
    addi $sp,$sp,-4    # increment stack pointer 
    sw  $a1,0($sp)    # store address of a1 (Yn) into stack pointer 
    jal  recurse     # recursive func call 
    addi $sp,$sp,4    # increment sp back to beggining 
    addi $v0,$0,10    # v0 = exit 
    syscall       # exit 

recurse: 
    lw  $a3,0($sp)    # load my name into reg $a3 

# NOTE/BUG: this should be lb 
# NOTE/BUG: by loading $t6 _before_ we've saved it, we are destroying the 
# value that _caller_ set 
    ###lw  $t6,0($a3)    # read byte 
    lb  $t6,0($a3)    # read byte 

    addi $sp,$sp,-12    # increment stack ptr 
    sw  $ra,8($sp)    # store address of $ra onto stack 
    sw  $t6,4($sp)    # store the byte loaded into $t6 onto stack 

# NOTE/BUG: this should be beq and _not_ bne 
    ###bne  $t6,$0,otherwise  # if t6 == 0 goto otherwise 
    beq  $t6,$0,otherwise  # if t6 == 0 goto otherwise 

    add  $a3,$a3,1    # a1 = a1 + 1 
    sw  $a3,0($sp)    # push the word, without the byte $t6 used 

    jal  recurse 

    lw  $t6,4($sp)    # load the byte that was stored into $t6 
    lw  $ra,8($sp)    # get $ra ready for returning 

# NOTE/BUG: this is the puts syscall -- what we want is putc (i.e. 11) 
    ###addi $v0,$0,4    # setup $v0 to tell pc to print to console 
    addi $v0,$0,11    # setup $v0 to tell pc to print to console 

# NOTE/BUG: we want to load the byte into $a0 
# NOTE/BUG: at this point $t6 has the byte value and _not_ a pointer 
    ###lw  $a0,0($t6)    # console always reads from $a0 
    move $a0,$t6 

    syscall 
    addi $sp,$sp,12    # put stack pointer back 
    jr  $ra      # string is finished, return. 

otherwise: 
    # because this is just returning, i need to get the ra that was just 
    # stored on the stack 
    lw  $ra,8($sp) 
# NOTE/BUG: by _not_ restoring the $t6 value of _caller_ things are broken 
    jr  $ra      # go back to original call of jal 

ここで動作するバージョンがあります:


ここで注釈付きバージョンは、[無償スタイルのクリーンアップをご容赦ください]です。初期のスタックフレームの設定と完全なスタックフレームのポップアップはotherwiseです。これはやや一般的です。つまり、スタックフレームを確立するための唯一の場所です。そして、1フレームをポップして返すために一つだけの場所:

.data 
Yn:   .asciiz  "frodobaggins" # yn stands for your name 
# print name backwards 
    .text 

main: 
    li  $v0,4     # syscall for print string 
    la  $a1,Yn     # load Yn's address into a0 

    addi $sp,$sp,-4    # increment stack pointer 
    sw  $a1,0($sp)    # store address of a1 (Yn) into stack 

    jal  recurse     # recursive func call 

    addi $sp,$sp,4    # increment sp back to beggining 

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

recurse: 
    lw  $a3,0($sp)    # load my name into reg $a3 
    lb  $t6,0($a3)    # read byte 

    addi $sp,$sp,-12    # establish stack frame 
    sw  $ra,8($sp)    # store address of $ra onto stack 
    sw  $t6,4($sp)    # store the byte loaded into $t6 onto stack 

    beq  $t6,$0,otherwise  # if t6 == 0 goto otherwise 

    add  $a3,$a3,1    # a1 = a1 + 1 

    sw  $a3,0($sp)    # push the word, without the byte $t6 used 
    jal  recurse 

    lw  $t6,4($sp)    # load the byte that was stored into $t6 
    lw  $ra,8($sp)    # get $ra ready for returning 

    addi $v0,$0,11    # setup $v0 to tell pc to print to console 
    move $a0,$t6 
    syscall 

otherwise: 
    lw  $ra,8($sp)    # restore return address from stack 
    lw  $t6,4($sp)    # store the byte loaded into $t6 onto stack 
    addi $sp,$sp,12    # put stack pointer back 
    jr  $ra      # string is finished, return. 

ここに私のリファクタリングのバージョンがあります。これはもう少しmips ABIに準拠しています。可能な若干のバリエーションがあります:

.data 
name: .asciiz  "frodobaggins" 
nl:  .asciiz  "\n" 

    .text 
    .globl main 
main: 
    li  $v0,4     # print string syscall 
    la  $a0,name    # string address 
    syscall 

    li  $v0,4     # print string syscall 
    la  $a0,nl     # string address 
    syscall 

    la  $a0,name    # string address 
    jal  recurse1 

    li  $v0,4     # print string syscall 
    la  $a0,nl     # string address 
    syscall 

    li  $v0,10 
    syscall 

# recurse1 -- reverse print string 
# 
# arguments: 
# a0 -- current string pointer 
recurse1: 
    sub  $sp,$sp,8    # create stack frame 
    sw  $ra,4($sp)    # save return address 
    sw  $a0,0($sp)    # save current string pointer 

    lb  $t0,0($a0)    # get current byte 
    beqz $t0,recurse1_exit  # is it EOS? if yes, fly 

    addu $a0,$a0,1    # advance to next char 
    jal  recurse1    # print other chars 
    subu $a0,$a0,1    # go back to our character 

    lb  $a0,0($a0)    # get current byte 
    li  $v0,11     # putc syscall number 
    syscall 

recurse1_exit: 
    lw  $ra,4($sp)    # restore return address 
    lw  $a0,0($sp)    # restore current string pointer 
    add  $sp,$sp,8    # pop stack frame 
    jr  $ra      # return 

# recurse2 -- reverse print string 
# 
# arguments: 
# a0 -- current string pointer 
recurse2: 
    sub  $sp,$sp,8    # create stack frame 
    sw  $ra,4($sp)    # save return address 
    sw  $a0,0($sp)    # save current string pointer 

    lb  $t0,0($a0)    # get current byte 
    beqz $t0,recurse2_exit  # is it EOS? if yes, fly 

    addu $a0,$a0,1    # advance to next char 
    jal  recurse2    # print other chars 
    lw  $a0,0($sp)    # restore our pointer 

    lb  $a0,0($a0)    # get current byte 
    li  $v0,11     # putc syscall number 
    syscall 

recurse2_exit: 
    lw  $ra,4($sp)    # restore return address 
    lw  $a0,0($sp)    # restore current string pointer 
    add  $sp,$sp,8    # pop stack frame 
    jr  $ra      # return 

# recurse3 -- reverse print string 
# 
# arguments: 
# a0 -- current string pointer 
recurse3: 
    sub  $sp,$sp,8    # create stack frame 
    sw  $ra,4($sp)    # save return address 

    lb  $t0,0($a0)    # get current byte 
    sw  $t0,0($sp)    # save current char value 
    beqz $t0,recurse3_exit  # is it EOS? if yes, fly 

    addu $a0,$a0,1    # advance to next char 
    jal  recurse3    # print other chars 

    lw  $a0,0($sp)    # get current byte 
    li  $v0,11     # putc syscall number 
    syscall 

recurse3_exit: 
    lw  $ra,4($sp)    # restore return address 
    add  $sp,$sp,8    # pop stack frame 
    jr  $ra      # return 
関連する問題