2

我正在使用 Project Euler 来学习 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!

子例程调用看起来没问题。一些建议:

1)你有一个奇怪的基本操作与伪操作的混合。顶部的ori指令可以使用li(就像底部的系统调用的常量一样)。或者,如果您有意将基本操作用作学习练习,请注意move $a0, $t1可以写成addu $a0, $t1, $0(或or $a0, $1, $0也可以)。

sltu2) 带有和的条件分支beq可以写成bge $t1, $t4, diffsltu这是一个扩展为and的伪操作beq,但很有趣,因为它自动$1用作临时寄存器 - 按照惯例,该寄存器保留用作“汇编程序临时”并命名为$at

3)sll $0, $0, $0确实是一条sllv指令,因为移位量有一个寄存器。规范的 MIPS 无操作是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

(无论如何,Anop往往会脱颖而出,但如果你开始尝试用有用的指令填充它们,如果你不以某种方式标记它们,你很快就会发疯。)

于 2010-07-22T23:18:53.000 回答