Mips读取整数并将它们存储在数组中然后找到最大值

时间:2014-04-20 23:14:03

标签: arrays mips

再次

我正在编写一个MIPS程序,它读取5个整数并将它们存储在数组中。然后它创建一个新数组,其值是初始数组的值乘以其索引。之后我需要找到第二个数组的最大值和最小值。

我是MIPS的新手,这是我写的代码:

.data

Prompt: .asciiz "\n  Enter 5 Integers :" #gets number of integers
op: .asciiz "\n  Enter Option: \n 1-Find the mult \n 2- Find the max \n 3-Find the min  \n 4-Exit" 
invalidm: .asciiz "\n  Bad Input:" 
vec: .space 20
vec2: .space 20

.text 
.globl __start
__start:
la $a0,Prompt
li $v0,4
syscall

#Reading integers and store theme in the array 

options:
la $a0,op
li $v0,4
syscall

li $v0,5
syscall
blt $v0,1,invalid#
bgt $v0,4,invalid#
beq $v0, 1, multp#
beq $v0, 2, max#
beq $v0, 3, min#
beq $v0, 4, exitpro#
j options 


multp:
#multiply every element in the array with its index and store them in the new array vec2

j options

max:
#find the max of the array vec
j options

min:
#find the min of the array vec
j options

invalid:
la $a0,invalidm
li $v0,4
syscall
j options


exitpro:
li $v0,10
syscall

1 个答案:

答案 0 :(得分:2)

我想快速记下编码风格:汇编有点恶魔。很有诱惑力地说“哦,我经常做这5行,我应该jal在这里并重复使用它”。这首先是有道理的,但往往导致令人困惑的意大利面条代码,不能跳过3行而不会跳到某处。因此,我的代码有一些代码重复,但没什么不好。

我稍微改变了你的初始条件,数组的长度是硬编码的,但它使用的是堆栈分配的数组,而不是.data标头初始化时静态分配的数组。而是在data部分中分配数组的长度。这只是个人偏好。它的好处是代码应该适用于任何长度> 0

.data

PromptHead: .asciiz "\n Enter "
PromptTail: .asciiz " integers\n"
Minstr:     .asciiz "Min: "
Maxstr:     .asciiz "Max: "
newline:    .asciiz "\n"

inputs: .word 5

.text

main:
    # Output prompt for input
    ## "\n Enter "
    la $a0, PromptHead
    li $v0, 4
    syscall

    ## "5"
    lw $a0, inputs
    li $v0, 1
    syscall

    ## " integers\n"
    la $a0, PromptTail
    li $v0, 4
    syscall


    # Backup sp value before allocating array
    move $fp, $sp

    # calculate size of vector (numinputs * sizeof(int) = numinputs * 4 = numinputs << 2), store in $s1
    lw   $s0, inputs 
    sll  $s1, $s0, 2

    # dynamically grow stack to include array of ints
    add $sp, $sp, $s1

    # Loop initialization
    # i = 0
    move $s1, $zero
    # while i < numInputs
    ReadInput:
        slt $s2, $s1, $s0
        beq $s2, $zero, ReadInputDone

        # Read integer
        li $v0, 5
        syscall

        # Calculate array offset for this loop
        sll $s2, $s1, 2
        add $s2, $fp, $s2

        # Store array value at calculated address
        sw  $v0, 0($s2)

        # i++
        addi $s1, $s1, 1
        j ReadInput
    ReadInputDone:

    # Scale(array, length)
    move $a0, $fp
    move $a1, $s1
    jal  Scale

    # max = FindMax(array, length)
    jal  FindMax

    # Back up return val, print boilerplate
    move $t0, $v0
    li   $v0, 4
    la   $a0, Maxstr
    syscall

    move $a0, $t0
    li   $v0, 1
    syscall

    la $a0, newline
    li $v0, 4
    syscall


    # min = FindMin(array,length)
    move $a0, $fp
    jal  FindMin

    # Back up return val, print boilerplate
    move $t0, $v0
    li   $v0, 4
    la   $a0, Minstr
    syscall

    move $a0, $t0
    li   $v0, 1
    syscall

    la $a0, newline
    li $v0, 4
    syscall

    # Exit program
    li $v0, 10
    syscall


# Scale(array, length)
# Scales each array element by index+1. This does not alter any s or a registers,
# Alters the array in place.
Scale:
    # Backup return address and fp on stack.
    # Not strictly necessary here, but usually good to do this by habit
    # when you're learning
    sw   $fp, 0($sp)
    sw   $ra, 4($sp)
    addi $fp, $sp, 8
    move $sp, $fp

    # Load arguments into scratch registers
    move $t0, $a0
    move $t1, $a1

    # Loop initialization as above
    # i = 0
    move $t2, $zero
    # while i < 5
    ScaleInput:
        slt $t3, $t2, $t1
        beq $t3, $zero, ScaleInputDone

        # Calculate element offset, store address in $t3
        sll $t3, $t2, 2
        add $t3, $t0, $t3

        # Load array element at $t3, multiply it by current index+1
        # Grab it from the multiplication register (assume no overflow)
        # then store the result back in the array
        lw   $t5, 0($t3)
        addi $t4, $t2, 1
        mult  $t5, $t4
        mflo $t5
        sw   $t5, 0($t3)

        # i++
        addi $t2, $t2, 1
        j ScaleInput
    ScaleInputDone:

    # Unwind stack, restore frame pointer and
    # return address. Again, not necessary here, but good
    # practice
    lw   $ra, -4($fp)
    move $sp, $fp
    lw   $fp, -8($fp)
    jr $ra


# int Max(array, length); result returned in $v0,
# No s or a registers are altered
FindMax:
    # Backup return address and fp on stack.
    sw   $fp, 0($sp)
    sw   $ra, 4($sp)
    addi $fp, $sp, 8
    move $sp, $fp

    # Load arguments into scratch registers
    move $t0, $a0
    move $t1, $a1

    # set currMin = array[0]
    lw $v0, 0($t0)

    # Loop initialization
    # i = 1
    li $t2, 1
    # while i < 5
    MaxLoop:
        slt $t3, $t2, $t1
        beq $t3, $zero, MaxLoopDone

        # Calculate element offset, store address in $t3
        sll $t3, $t2, 2
        add $t3, $t0, $t3

        # Load array element at $t3, check if it's the new max
        lw   $t4, 0($t3)
        sgt  $t5, $t4, $v0
        beq  $t5, $zero, notGreater

        # If so, set return value to it
            move $v0, $t4
        notGreater:

        # i++
        addi $t2, $t2, 1
        j MaxLoop
    MaxLoopDone:

    # Unwind stack
    lw   $ra, -4($fp)
    move $sp, $fp
    lw   $fp, -8($fp)
    jr   $ra


# int Min(array, length); result returned in $v0,
# No s or a registers are altered
FindMin:
    # Backup return address and fp on stack.
    sw   $fp, 0($sp)
    sw   $ra, 4($sp)
    addi $fp, $sp, 8
    move $sp, $fp

    # Load arguments into scratch registers
    move $t0, $a0
    move $t1, $a1

    # set currMin = array[0]
    lw $v0, 0($t0)

    # Loop initialization
    # i = 1
    li $t2, 1
    # while i < 5
    MinLoop:
        slt $t3, $t2, $t1
        beq $t3, $zero, MinLoopDone

        # Calculate element offset, store address in $t3
        sll $t3, $t2, 2
        add $t3, $t0, $t3

        # Load array element at $t3, check if it's the new min
        lw   $t4, 0($t3)
        slt  $t5, $t4, $v0
        beq  $t5, $zero, notLesser

        # If so, set return value to it
            move $v0, $t4
        notLesser:

        # i++
        addi $t2, $t2, 1
        j MinLoop
    MinLoopDone:

    # Unwind stack
    lw   $ra, -4($fp)
    move $sp, $fp
    lw   $fp, -8($fp)
    jr   $ra

正如我在代码中提到的那样,存储$ra$fp时的痴迷有点偏执。如果我真的是偏执狂,我也会存储所有s个寄存器。但是,这通常是一种很好的做法,当您决定在函数中间添加“函数调用”时,可以省去很多麻烦。

这基本上就是汇编的方法,你在头脑中用C编写程序,然后将其翻译成汇编。因此,为什么我将缩放,查找最大值等视为“函数”。

一些成员注释:我反复使用sll $register, $register, 2而不是乘以4(MIPS32上的字大小)。这是因为执行此操作的指令较少,因为无需调用li后跟mult后跟mflo。你可以这样做,而且我曾经这样做过,但是一旦你习惯了sll和其他一些小小的操作,那么使用sll以及更容易阅读就更简洁了。

我确实使用了一些pseudoinstructions,这不是什么大问题,我知道支持它们的大多数现代MIPS汇编器和模拟器(包括SPIM)。我在分支指令之后与线路危险地跳舞(理论上它总是执行而不管分支结果如何),但在这种情况下它通常并不重要,并且大多数模拟器和汇编器通常会在它无论如何时为你注入无操作。

我知道汇编可能有点难以阅读,所以请随时询问您是否有任何问题。