2

私はProjectEulerを使用してMIPSを学習しています。具体的には、問題6を使用してサブルーチンの使用方法を学習しています。残念ながら、私が得ている答えの大きさが大きすぎるため、私は非常に間違ったことをしています。ここでの私の問題は、サブルーチンの使用方法にありますか、それともまったく別のものですか?

## 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
4

1 に答える 1

1

主な問題は、質問6で1から100までの数字を処理するように求められているのに対し、コードは1から999までで動作することだと思います。

サブルーチン呼び出しはOKに見えます。いくつかの提案:

1)基本操作と疑似操作の奇妙な組み合わせがあります。上部のori命令は、を使用して記述できますli(下部のシステムコールの定数と同じように)。または、基本的な操作を学習演習として意図的に使用する場合は、次のmove $a0, $t1ように記述できることに注意してくださいaddu $a0, $t1, $0(またはor $a0, $1, $0機能します)。

2)とを使用した条件付き分岐は。sltubeq書くことができますbge $t1, $t4, diff。これはとに展開される疑似演算ですがsltu、一時レジスタとしてbeq自動的に使用$1されるため興味深いものです。慣例により、このレジスタは「アセンブラ一時」として使用するために予約されており、という名前が付けられて$atいます。

3)シフト量はレジスターがあるので、sll $0, $0, $0実際には命令です。sllv正規のMIPSno-opはsll $0, $0, 0、のオペコードにアセンブルされ0x00000000ます。さらに良いことに、ただ書くだけnopです。

4)明示的な分岐遅延スロットが使用されている場合(一部のアセンブラは命令を自動的に並べ替えてそれらを埋めます-たとえば、指示gasしない限りこれを行い.set reorderます)、目立つように何らかの方法で明確にマークを付けると便利です。便利な規則は、それらに余分なインデントを与えることです。

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

(とにかくAは目立つ傾向がありますが、有用な指示を入力しようとすると、何らかのnop方法でマークを付けないとすぐに怒ります。)

于 2010-07-22T23:18:53.000 に答える