Подпрограммы в MIPS и другие начинающие глупости - PullRequest
2 голосов
/ 23 июля 2010

Я использую 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

1 Ответ

1 голос
/ 23 июля 2010

Я думаю, что основная проблема в том, что вопрос 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 no-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 имеет тенденцию выделяться в любом случае, но если вы начнете пытаться заполнить их полезными инструкциями, вы быстро сойдете с умаесли вы не пометите их каким-то образом.)

...