我正在使用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
答案 0 :(得分:1)
我认为主要问题是question 6要求您使用1到100之间的数字,而您的代码使用1到999!
子程序调用看起来没问题。一些建议:
1)你有一个奇怪的混合基本操作与伪操作。顶部的ori
指令可以使用li
编写(正如底部系统调用的常量一样)。或者,如果您故意将基本操作用作学习练习,请注意move $a0, $t1
可以写为addu $a0, $t1, $0
(或or $a0, $1, $0
也可以。)
2)sltu
和beq
的条件分支可以写为bge $t1, $t4, diff
。这是一个伪操作,扩展为sltu
和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
(A nop
往往会脱颖而出,但是如果你开始尝试用有用的说明填写它们,如果你不用某些方式标记它们,你会很快发疯。)