2010-07-22 10 views
2

J'utilise Project Euler pour apprendre MIPS, en particulier en utilisant le problème 6 pour apprendre à utiliser un sous-programme. Malheureusement, je fais quelque chose de très mal parce que la réponse que je reçois est beaucoup trop grande. Est-ce que mon problème ici est comment j'utilise le sous-programme, ou est-ce autre chose entièrement?Sous-routines dans MIPS et autres bêtises de débutant

## p6.asm 
## 
## Andrew Levenson, 2010 
## Project Euler, Problem 6 
## 
## Calculate the difference 
## between the sum of the squares 
## and the square of the sum 
## of all natural numbers n 
## such that n < 1000 
     .text 
     .globl main 

main: 
init: 
    ## Registers 
     ori  $t0, $0, 0x0  # $t0 will be used for scratch 
     ori  $t1, $0, 0x0  # $t1 is the loop counter and n 
     ori  $t2, $0, 0x0  # $t2 will be the sum of the squares 
     ori  $t3, $0, 0x0  # $t3 will be the square of the sum 
     ori  $t4, $0, 0x3E8  # $t4 = 1000, the limit 

loop: 
    ## Main loop 
     addiu $t1, $t1, 0x1  # Increment n 

     sltu $t0, $t1, $t4  # Is n less than 1000? 
     beq  $t0, $0, diff  # if $t0 == 0 then jump to diff 
     sll  $0, $0, $0   # no op 

     addu $t3, $t3, $t1  # sum = sum + n 

     move $a0, $t1   # put n in $a0 
     jal  square    # jump to square and save position to $ra 
     sll  $0, $0, $0   # no op 

     addu $t2, $t2, $a0  # The sum of the squares = 
            # sum + n **2 

     j  loop    # jump to loop 
     sll  $0, $0, $0   # no op 




square: 
    ## Subroutine that squares a given number 
     mul  $a0, $a0, $a0  # Argument = Argument ** 2 
     jr  $ra     # jump to $ra 
            # $ra = instruction where jal was called 
     sll  $0, $0, $0   # no op 


diff: 
    ## Finds the difference of $t2 and $t3 
    ## But first, we have to square $t3 
     move $a0, $t3   # puts $t3 in $a0 
     jal  square    # jump to square and save position to $ra 
     sll  $0, $0, $0   # no op 

     move $t3, $a0   # $t3 = $a0 = $t3 ** 2 

     subu $t0, $t2, $t3  # $t0 = $t2 - $t3 


print: 
     li  $v0, 0x1   # system call #1 - print int 
     move $a0, $t0 
     syscall      # execute 

     li  $v0, 0xA   # system call #10 - exit 
     syscall 

## End of Program 

Répondre

1

Je pense que le principal problème est que question 6 vous demande de travailler avec les chiffres de 1 à 100, alors que votre code fonctionne avec 1 à 999!

L'appel du sous-programme semble OK. Quelques suggestions:

1) Vous avez un mélange étrange d'opérations de base et de pseudo-opérations. Les instructions ori en haut peuvent être écrites en utilisant li (tout comme les constantes pour les appels système en bas). Alternativement, si vous souhaitez délibérément utiliser les opérations de base comme un exercice d'apprentissage, notez que move $a0, $t1 peut être écrit comme addu $a0, $t1, $0 (ou or $a0, $1, $0 fonctionne également). 2) La branche conditionnelle avec sltu et beq peut s'écrire bge $t1, $t4, diff. Ceci est un pseudo-op qui s'étend à sltu et beq, mais est intéressant car il utilise automatiquement $1 comme un registre temporaire - par convention, ce registre est réservé pour être utilisé comme "assembleur temporaire" et nommé $at.

3) sll $0, $0, $0 est vraiment une instruction sllv, comme la quantité de décalage il y a un registre. Le non-op canonique MIPS est sll $0, $0, 0 qui s'assemble à un opcode de 0x00000000. Mieux encore, il suffit d'écrire nop. 4) Où les slots à retard de branche explicites sont utilisés (notez que certains assembleurs réorganiseront automatiquement les instructions pour les remplir - par exemple gas le fait à moins que vous ne le disiez avec .set reorder), il est utile de les marquer clairement d'une manière ou d'une autre afin qu'ils se distinguent. Une convention utile est de leur donner un peu plus d'indentation:

move $a0, $t1   # put n in $a0 
jal  square    # jump to square and save position to $ra 
nop      # no-op 

(A nop tend à se démarquer de toute façon, mais si vous commencez à essayer de les remplir avec des instructions utiles, vous allez rapidement devenir fou si vous n » t marquez-les en façon.)

+0

Merci pour la réponse en profondeur! Malheureusement, le programme donne toujours une réponse incorrecte. Voyez-vous quelque chose que je puisse mal faire algorithmiquement? – Andy

+0

Peu importe, je l'ai juste compris! J'utilisais les chiffres 1..99, au lieu de 1..100. Changer '$ t4' en' 0x65' l'a corrigé. Merci encore! – Andy