【问题标题】:Understanding a MIPS algorithm了解 MIPS 算法
【发布时间】:2017-06-05 16:40:36
【问题描述】:

我对编码非常陌生,我们从 MIPS 开始。我们有点“被扔进了冷水里”,不得不实现一种算法来检查数组的元素是否按升序排序。如果已排序,则将 1 存储在 $v0 中,否则将存储 0。 给我们的解决方案:

.data
A: .word 1, 2, 3, 4, 5
l: .word 5

.text
main:
la $s0, A #address of A
lw $s1, l
add $t0, $0, $0 #counter for loop
addi $v0, $0, 1
sub $s1, $s1, $v0
for:
beq $t0, $s1, done
sll $t1, $t0, 2 #byte offset
add $t1, $t1, $s0
lw $t1, 0($t1) #$t1 = A[j]
addi $t2, $t0, 1
sll $t2, $t2, 2
add $t2, $t2, $s0
lw $t2, 0($t2) #$t2 = A[j + 1]
sub $t3, $t2, $t1 #$s3 = A[j+1] - A[j]?
slt $t4, $t3, $0
addi $t3, $0, 1
beq $t3, $t4 unsort #A isn’t sorted if A[j+1] - A[j] has a negative value
addi $t0, $t0, 1 #$t0 = $t0 + 1
j for

unsort:
add $v0, $0, $0 #set $v0 if array isn’t sorted

done:

我无法理解此代码/算法。首先什么是数组,为什么我们特别需要其中的 5 个? 但对我来说更重要的是理解这个代码/算法。所以我需要一个足够友善的人,用简单的话一步一步地向我解释:D,这段代码是如何工作的。

将非常有帮助,并提前感谢。

【问题讨论】:

    标签: mips mips32


    【解决方案1】:

    简答

    基本上,这个程序在带有循环计数器的循环中迭代数组A,比如i。索引i 初始化为0,并且在每次循环迭代中递增1,直到达到l-1,其中l 是数组A 的大小/长度。在每次迭代中,算法都会检查 A[i] < A[i + 1] 是否(即 A 中的第 i 个和第 (i+1) 个元素是否按升序排列并因此排序)。如果是,则继续执行,$v0 保持 1。否则,它将 $v0 设置为 0 并终止。


    长答案

    数组和内存

    数组基本上是一个有序的数据列表——在这种情况下,它是一个有序的单词列表(MIPS 中的一个单词意味着:32 位值,它由 4 个字节组成,每个字节其中有8位信息)。所以在这种情况下,每个单词都代表一个 32 位整数。
    如果我们有一个长度为l 的数组A,则元素的索引从0l-1。数组A(符号:A[0])中的第一个元素保存在内存中的某个地址,我们称之为addr。然后将A (A[i]) 中的第 i 个元素保存在内存地址addr + 4*i 中。这是因为 MIPS 中的内存是字节可寻址的,即每个字节都有自己的地址,并且因为一个字由 4 个字节组成,字地址偏移 4(见下文)。


    .数据部分

    A: .word 1, 2, 3, 4, 5
    l: .word 5
    

    你会意识到你没有 5 个数组,只有一个(称为A),它包含值 1、2、3、4 和 5。因此,长度为 5,并且它被指定在l这个词中。您可以向数组添加更多值,但随后您必须调整长度,否则会发生奇怪的事情(或者至少结果将是随机的)。您的数据在此 .data 部分中指定,因此存储在程序内存空间中的某个位置。


    MIPS 程序集

    为了理解 .text 部分中的代码,您必须了解 MIPS 汇编。如果我写的是寄存器,只需将其视为 32 位值的占位符。例如,$0 是零寄存器,它总是存储一个 32 位的 0。其他寄存器用于临时存储程序中使用的值。您使用的说明是:

    • la rd, label(“加载地址”)
      (rd = label的地址;将“label”指定的字的地址存储在目标寄存器rd中)
    • lw rd,标签(“加载词”)

      lw rd, offset(rs)
      (将label指定的数据,或者地址rs+offset的数据加载到目的寄存器rd中)
    • 添加 rd, rs, rt
      (rd = rs + rt; 添加源寄存器 rs 和 rt 并将结果存储到目标寄存器 rd)
    • addi rd, rs, imm ("立即添加")
      (rd = rs + imm; 将源寄存器 rs 和立即数(16 位常数)值相加,并将结果存储到目标寄存器 rd)
    • sub rd, rs, rt ("减")
      (rd = rs - rt; 从源寄存器 rs 中减去源寄存器 rt 并将结果存储到目标寄存器 rd)
    • beq rs, rt, label ("如果相等则分支")
      (如果 rs 中的值等于 rt 中的值,则跳转到标签)
    • sll rd, rs, shamt(“逻辑左移”)
      (rd = rs
    • slt rd, rs, rt ("设置小于")
      (rd = (rs
    • j 标签(“跳跃”)
      (跳转到标签)

    .文本部分

    main:
    la $s0, A
    lw $s1, l
    add $t0, $0, $0
    addi $v0, $0, 1
    sub $s1, $s1, $v0
    
    for:
    beq $t0, $s1, done
    sll $t1, $t0, 2 #byte offset
    add $t1, $t1, $s0
    lw $t1, 0($t1) #$t1 = A[j]
    addi $t2, $t0, 1
    sll $t2, $t2, 2
    add $t2, $t2, $s0
    lw $t2, 0($t2) #$t2 = A[j + 1]
    sub $t3, $t2, $t1 #$s3 = A[j+1] - A[j]?
    slt $t4, $t3, $0
    addi $t3, $0, 1
    beq $t3, $t4 unsort #A isn’t sorted if A[j+1] - A[j] has a negative value
    addi $t0, $t0, 1 #$t0 = $t0 + 1
    j for
    
    unsort:
    add $v0, $0, $0 #set $v0 if array isn’t sorted
    
    done:
    

    这个汇编代码相当于伪代码(如果你不习惯伪代码或while循环,请在网上查一下):

    s0 <- address of first element in A
    s1 <- l
    t0 <- 0
    v0 <- 1
    s1 <- s1-1
    
    while (t0 != s1) do
        t1 <- 4 * t0
        t1 <- t1 + s0
        t1 <- word at address t1
        t2 <- t0 + 1
        t2 <- 4 * t2
        t2 <- t2 + s0
        t2 <- word at address t2
        t3 <- t2 - t1
        if (t3 < 0) then t4 <- 1
        else t4 <- 0
        t3 <- 1
        if (t3 == t4) then
            v0 <- 0
            return
        else t0 <- t0 + 1
    

    希望,这有帮助。如果您以前没有编码,我认为从汇编代码开始是非常雄心勃勃的。祝你好运!

    【讨论】:

    • 非常感谢。这很有帮助。您能否具体评论每一行并说出他们的工作。我仍然不知道代码如何对数组的元素进行排序,什么是循环计数器?
    • 天啊。我不能为你评论每一行,我也有其他的爱好。只要问你不明白的行。该算法对数组进行排序,它只是确定数组是否按升序排序。循环计数器是在每个循环周期中递增的变量。因此,如果您有一个长度为n 的数组A,并且您想查看每个数组元素,则使用循环计数器i,将其初始化为0 并重复循环n 次(直到i等于n-1),然后在每次迭代中,您可以查看第 i 个元素,即A[i]
    • 如果对您有帮助,请标记为正确答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    • 2015-03-22
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多