views:

85

answers:

1

I'm using Project Euler to learn MIPS, specifically using Problem 6 to learn how to use a subroutine. Unfortunately, I am doing something very wrong because my answer that I'm getting is far too large in magnitude. Is my problem here with how I am using the subroutine, or is it something else entirely?

## 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
+1  A: 

I think the main problem is that question 6 asks you to work with the numbers from 1 to 100, whereas your code works with 1 to 999!

The subroutine call looks OK. Some suggestions:

1) You have a strange mixture of basic ops vs. pseudo-ops. The ori instructions at the top can be written using li (just as the constants for the syscalls at the bottom are). Alternatively, if you deliberately want to use basic ops as a learning exercise, note that move $a0, $t1 can be written as addu $a0, $t1, $0 (or or $a0, $1, $0 also works).

2) The conditional branch with sltu and beq can be written as bge $t1, $t4, diff. This is a pseudo-op which expands to sltu and beq, but is interesting because it automatically uses $1 as a temporary register - by convention this register is reserved for use as the "assembler temporary" and named $at.

3) sll $0, $0, $0 is really a sllv instruction, as the shift amount there is a register. The canonical MIPS no-op is sll $0, $0, 0 which assembles to an opcode of 0x00000000. Better still, just write nop.

4) Where explicit branch delay slots are being used (note that some assemblers will reorder instructions automatically to fill them - e.g. gas does this unless you tell it not to with .set reorder), it's helpful to clearly mark them in some way so that they stand out. A useful convention is to give them an extra bit of indentation:

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

(A nop tends to stand out anyway, but if you start trying to fill them with useful instructions, you will quickly go mad if you don't mark them in some way.)

Matthew Slattery
Thanks for the in depth response! Unfortunately, the program still yields an incorrect answer. Do you see anything I could be doing wrong algorithmically?
Andrew
Nevermind, I actually just figured it out! I was using the numbers 1..99, instead of 1..100. Changing `$t4` to `0x65` fixed it. Thank you again!
Andrew