【问题标题】:I want to calculate the average value of a list on MIPS我想计算 MIPS 上列表的平均值
【发布时间】:2016-12-14 10:18:08
【问题描述】:

我想计算 MIPS 上列表的平均值。我已经尝试过隔离,如果我想打印总和或提示进行测试,它工作得非常好,但是当我把平均计算放回去时,它以某种方式给了我 size * 4 作为答案。我的汇编代码如下:

                .data

size_prompt:    .asciiz "Enter number of elements: "    
element_prompt: .asciiz "Enter an element: "
size:           .word 0 
to_store:       .word 0
sum:            .word 0
avg:            .word 0

                .text
                #Prints prompt
                la $a0, size_prompt
                addi $v0, $0, 4
                syscall

                #Gets input from user
                addi $v0, $0, 5
                syscall
                sw $v0, size

                addi $t0, $0, 0 #Initialise i = 0

                #Creates the list
                lw $s0, size
                addi $t1, $0, 4
                mult $s0, $t1
                mflo $t2
                add $a0, $t1, $t2
                addi $v0, $0, 9
                syscall

stack:          beq $t0, $s0, list_sum
                la $a0, element_prompt
                addi $v0, $0, 4
                syscall

                addi $v0, $0, 5
                syscall
                sw $v0, to_store
                lw $t5, to_store

                addi $sp, $sp, -4
                sw $t5, 0($sp)

                addi $t0, $t0, 1
                j stack

list_sum:       beq $s0, 0, average
                lw $t6, sum
                lw $t7, 0($sp)
                addi $sp, $sp, 4
                add $t6, $t7, $t6
                sw $t6, sum
                addi $s0, $s0, -1
                j list_sum

average:        lw $t0, sum
                div $t0, $s0
                mflo $t0
                sw $t0, avg
                lw $a0, avg
                addi $v0, $0, 1
                syscall

【问题讨论】:

  • 你的切入点是什么?我没有看到main:,而且.text 中的第一位代码根本没有标签。
  • @EOF 我的大学不知何故不需要我们这样做,它工作得很好。
  • @EOF:如果没有_start 标签,GNU 链接器默认将入口点设置为.text 部分的开头。例如在 x86-64 ld: warning: cannot find entry symbol _start; defaulting to 0000000008048060。所以我认为它在 MIPS 上是一样的。尽管如此,金伯利,.globl _start / _start: 将是明确表达这一点的好习惯。
  • 在调试器中单步执行循环时会看到什么?它通过循环的次数是否正确?如果您评论代码以在更高级别解释每个部分中发生的事情,这将是一个更好的问题。 (不过,至少它是可读的缩进并且有有用的标签名称,所以还不错。)添加有关您可以使用调试器找到的信息的信息对于可能会回答这个问题的人来说会缩小很多范围。

标签: assembly mips mars-simulator


【解决方案1】:

好的,你只有一个错误,它是一个单行,所以你做得很好。

但是,代码中没有太多的 cmets,所以在我阅读/分析它的时候,我添加了一些。

我应该提到,当我这样做时,我能够通过目视检查和审查来发现错误。也就是说,我能够找到错误并将其与修复一起注释。

所以,我实际上并不需要使用调试器单步执行代码。应用修复后,它第一次运行正确。

我最近在这里回答了一个非常相似的问题:MIPS questions about writing assembly to call functions on an array 对数组进行求和/乘积

另外,请在此处查看我的回答:MIPS linked list 除其他外,它还提供了根据我自己的个人经验编写干净的 mips/asm 代码的方法。

我创建了您的代码的两个版本。一个更改最少且仅修复错误的一种。而且,另一个,我把它收紧并简化了一点。请原谅无端的风格清理。


这是带有错误/修复注释的代码:

    .data

    # NOTE/BUG: due to alignment issues put the .word directives _before_
    # the [variable length] .asciiz directives
size:       .word       0
to_store:   .word       0
sum:        .word       0
avg:        .word       0

size_prompt:    .asciiz "Enter number of elements: "
element_prompt: .asciiz "Enter an element: "
msg_space:      .asciiz " "

    .text
    .globl  main
main:

    # Prints prompt
    la      $a0,size_prompt
    addi    $v0,$0,4
    syscall

    # Gets input from user
    addi    $v0,$0,5
    syscall
    sw      $v0,size

    addi    $t0,$0,0                # Initialise i = 0

    # Creates the list
    lw      $s0,size                # get array count
    addi    $t1,$0,4                # get 4
    mult    $s0,$t1                 # get count * 4
    mflo    $t2                     # get offset
    add     $a0,$t1,$t2
    addi    $v0,$0,9
    syscall

stack:
    beq     $t0,$s0,list_sum        # done with number input? if yes, fly

    # prompt user for list element
    la      $a0,element_prompt
    addi    $v0,$0,4
    syscall

    # read in element value
    addi    $v0,$0,5
    syscall
    sw      $v0,to_store
    lw      $t5,to_store

    # push element to stack
    addi    $sp,$sp,-4
    sw      $t5,0($sp)

    addi    $t0,$t0,1           # advance array index
    j       stack

    # get sum of array elements
list_sum:
    beq     $s0,0,average       # at end? if yes, fly
    lw      $t6,sum             # get previous sum
    lw      $t7,0($sp)          # get next array element value
    addi    $sp,$sp,4           # advance array pointer
    add     $t6,$t7,$t6         # sum += array[i]
    sw      $t6,sum             # store it
    addi    $s0,$s0,-1          # bump down the _count_
    j       list_sum

    # NOTE/BUG: in the list_sum loop above, s0 is being decremented, so when we
    # get here it is _always_ zero
average:
    lw      $t0,sum             # get the sum

    # print the sum
    li      $v0,1
    move    $a0,$t0
    syscall

    # NOTE/FIX: restore the count value
    lw      $s0,size

    div     $t0,$s0             # divide by count
    mflo    $t0
    sw      $t0,avg             # store average

    li      $v0,4
    la      $a0,msg_space
    syscall

    # print average
    lw      $a0,avg
    addi    $v0,$0,1
    syscall

exit:
    li      $v0,10              # exit program
    syscall

这是我对清理的看法。

mips 有很多个寄存器,所以当它们可以使用时,可以保留中间结果。

例如,请注意,在求和循环中,不同 寄存器用于减量,因此$s0 仍然存在。此外,我能够使用寄存器来保存以前使用内存位置的所有值[堆栈使用情况除外]

    .data

size_prompt:    .asciiz "Enter number of elements: "
element_prompt: .asciiz "Enter an element: "
msg_space:      .asciiz " "

    .text
    .globl  main
main:

    # prompt user for number of elements
    la      $a0,size_prompt
    li      $v0,4
    syscall

    # get array count from user
    li      $v0,5
    syscall
    move    $s0,$v0                 # save array count

    li      $t0,0                   # i = 0

stack:
    beq     $t0,$s0,sumlist         # input done (i.e. i >= count)? if yes, fly

    # prompt user for list element
    la      $a0,element_prompt
    li      $v0,4
    syscall

    # read in element value
    li      $v0,5
    syscall

    # push element to stack
    addi    $sp,$sp,-4
    sw      $v0,0($sp)

    addi    $t0,$t0,1               # i += 1
    j       stack

    # get sum of array elements
    #   t6 -- sum value
sumlist:
    li      $t6,0                   # sum = 0
    move    $t4,$s0                 # get the count

sumlist_loop:
    beqz    $t4,average             # at end? if yes, fly

    # pop element off stack
    lw      $t7,0($sp)              # get next array element value
    addi    $sp,$sp,4               # advance array pointer

    add     $t6,$t6,$t7             # sum += array[i]
    addi    $t4,$t4,-1              # bump down the count
    j       sumlist_loop

    # get average
    #   t6 -- sum value
    #   t5 -- average value
average:
    # print the sum
    li      $v0,1
    move    $a0,$t6             # get the sum
    syscall

    div     $t6,$s0             # compute sum / count
    mflo    $t5                 # retrieve it

    # output a space
    li      $v0,4
    la      $a0,msg_space
    syscall

    # print average
    move    $a0,$t5
    li      $v0,1
    syscall

exit:
    li      $v0,10              # exit program
    syscall

【讨论】:

  • 不错。我什至没有尝试真正遵循 OP 的代码,因为我没有心情从一个很明显甚至没有使用过调试器的人那里调试初学者代码。幸运的是,其他人对他们的时间感到更加慷慨。 :)
  • @PeterCordes 我通过回答关于 SO [利用我在大量其他 asm/arches 方面的经验] 的问题进入(即学习)mips。我有几个自动化这个过程的perl 脚本。例如,我使用的第一个编辑器有一个“asmfix”子命令来重新缩进 (IBM/370) 汇编语言。出于怀旧之情,我创建了一个“asmfix”命令,因此它消除了一些繁琐的工作。 mips 的简洁优雅。虽然我喜欢 x86 [和几乎所有拱门],但 mips 并不复杂。因此,这就像一个假期。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-01
  • 2012-09-17
  • 1970-01-01
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多