无法弄清楚如何只打印用户要求的斐波那契数量

时间:2016-09-23 04:16:36

标签: assembly mips

用户应在(3-30)之间输入一个数字,程序应输出他们要求的许多斐波纳契计算。我的程序正在打印所有30个斐波那契数字。我知道我把它设置为30,但那是看我的计算是否正确。我正在使用MIPS汇编语言。

  .data
my_string: .asciiz "How many Fibonacci numbers you would like to calculate (3-30): "
fibs: .word   3 : 30       
size: .word  30             
space:.asciiz  " "
head: .asciiz  "The Fibonacci numbers are:\n"

.text
.globl main
main:
li $v0, 4
la $a0, my_string
syscall

li $v0, 5
syscall

move $v0, $t7

    la   $t0, fibs        # load array
    la   $t5, size        
    lw   $t5, 0($t5)      
    li   $t2, 1           
    add.d $f0, $f2, $f4
    sw   $t2, 0($t0)      
    sw   $t2, 4($t0)      
    addi $t1, $t5, -2     
loop: 
lw   $t3, 0($t0)       # get values from array
    lw   $t4, 4($t0)      
    add  $t2, $t3, $t4    
    sw   $t2, 8($t0)      
    addi $t0, $t0, 4      
    addi $t1, $t1, -1     
    bgtz $t1, loop        
    la   $a0, fibs        
    add  $a1, $zero, $t5  
    jal  print            
    li   $v0, 10         
    syscall   

#print loop numbers

print:
add  $t0, $zero, $a0  
add  $t1, $zero, $a1  
la   $a0, head        
li   $v0, 4           
syscall

out:  
lw   $a0, 0($t0)     
    li   $v0, 1         
    syscall

    la   $a0, space       
    li   $v0, 4           
    syscall

    addi $t0, $t0, 4      
    addi $t1, $t1, -1     
    bgtz $t1, out         
    jr$31              

1 个答案:

答案 0 :(得分:1)

每当您发现自己对某个程序感到困惑时,您就可以使用此策略:

  1. 浏览程序,了解它的作用 只需寻找功能块,例如:" 某处应该有一个循环...... "或" 它在哪里跳跃?"。
    您不必清楚地了解该计划,只需将其划分为主要部分即可 有时你必须猜测。

  2. 从第一部分开始,对每个部分进行评论和反向工程 您可能需要评论单个指令或小指令组 要特别注意寄存器的使用方式,每个寄存器的值。

  3. 使用调试器逐步执行程序 这将帮助您在最困难的情况下以及使用冗长或棘手的程序时。

  4. 在我们的案例中,程序非常简单,我们可以在第2步停止:

    .data
       #Strings
    
       my_string: 
          .asciiz "How many Fibonacci numbers you would like to calculate (3-30): "
       space:
          .asciiz  " "
       head: 
          .asciiz  "The Fibonacci numbers are:\n"
    
       #Array of fibonacci numbers
       fibs: .word   3 : 30       
    
       #Size    
       size: .word  30             
    
    .text
    .globl main
    
    main:
    
       #Print string
       li $v0, 4
       la $a0, my_string
       syscall
    
       #Read integer into v0
       li $v0, 5
       syscall
    
       #Overwrite v0 with t7
       #Faulty code!
       move $v0, $t7
    
       #Load address of fibonacci array into t0
       la   $t0, fibs        # load array
    
       #t0 = Current address into Fibonacci array
    
       #Load size into t5 (MIPS is RISC, no load-from-immediate-address instruction ava)
       la   $t5, size        #Load address of size into t5   
       lw   $t5, 0($t5)      #Load word from t5 
    
       #t5 = Number of numbers to compute
    
       #Load first (and second, they are equal) Fibonacci number into t2
       li   $t2, 1    
    
       #Totally unrelated FB instruction?
       #Remove this!    
       add.d $f0, $f2, $f4
    
       #Store the first and second Fibonacci number into...
       sw   $t2, 0($t0)    #... the first   
       sw   $t2, 4($t0)    #... and second array position (each position is 4 byte)
    
       #Set t1 = t5 - 2 = size = 2
       #t1 is the number of numbers left to compute, we skip the first two we already computed (thus the -2)
       addi $t1, $t5, -2
    
       #t1 = Number of numbers left to do
    
       loop: 
          #t0 points to the second from last number in the array
    
          #Get the second from last number from the array
          lw   $t3, 0($t0)       # get values from array
          #Get the last number from the array
          lw   $t4, 4($t0)      
    
          #Compute the next Fib number into t2
          add  $t2, $t3, $t4    
          #Store it into the array (at fibs[t0+2])
          sw   $t2, 8($t0)  
    
          #Advance t0 to point to the next number
          addi $t0, $t0, 4  
    
          #Decrement the counter (number left to compute)    
          addi $t1, $t1, -1  
    
       #Jump if t1>0 back to the start of the loop   
       bgtz $t1, loop  
    
       #Call print with the array address and number of items
       la   $a0, fibs        
       add  $a1, $zero, $t5  
       jal  print  
    
       #Exit     
       li   $v0, 10         
       syscall   
    
    #print loop numbers
    
    print:
       #Mov arguments to t0 and t1
       add  $t0, $zero, $a0  
       add  $t1, $zero, $a1  
    
       #Print string
       la   $a0, head        
       li   $v0, 4           
       syscall
    
       out:  
          #Load number from array and print it
          lw   $a0, 0($t0)     
          li   $v0, 1         
          syscall
    
          #Print space
          la   $a0, space       
          li   $v0, 4           
          syscall
    
          #Move t0 to the next number (each number occupies 4 bytes)
          addi $t0, $t0, 4    
          #Decrement the number left to do  
          addi $t1, $t1, -1 
    
        #If t1 > 0 jump back to the start of the loop (out)   
        bgtz $t1, out  
    
        #Return       
        jr $31 
    

    不考虑此处和那里的非相关指令,循环开始时的寄存器使用是:

      

    t0 =上次计算的数字的第二个地址
      t0 + 4 =最后一个计算机编号的地址
      t1 =要做的数字
      t5 =要计算的总数

    另外t1 = t5 - 2

    所以应该很容易使这个程序适用于用户的大小。

    只需更改move $v0, $t7(这是错误的,因为将t7移动到v0,覆盖存储用户号码的唯一地方!)

    #Store v0 into size
    la $t5, size
    sw $v0, 0($t5)
    

    你应该注意到这个程序在输入少于1时不会工作。
    您可以将其修复为练习。