在此 MIPS 汇编程序中传递到标签是如何工作的?

How does passing into label in this MIPS Assembly program work?

该程序旨在允许用户使用破折号(“-”和“|”)形成框,连接 3x3 网格的顶点。我想知道这个程序是如何在游戏板上标记动作的。在 markMove 部分,这个代码块到底发生了什么:

lb $t0, offset($a0) #Pass $a0 which is integer move 0-9 into offset, then load that data into $t0

#Actually mark now; transfer marker to board through $t1
lb $t1, marker($a0) #Load marker into $t1 after finding corresponding marker
sb $t1, board($t0) #Place the marker at spot in board by storing from $t1

当 $a0 和 $t0 被传递到上面相应的数据类型时,实际上发生了什么?感谢您的帮助。

以下为完整节目供参考。在 MARS 4.5

上使用 MIPS 汇编
    .data #Data declaration segment
board: .ascii   "\n\n   . . .          . 0 . 1 ."
       .ascii     "\n                  2   3   4"
       .ascii     "\n   . . .          . 5 . 6 ."
       .ascii     "\n                  7   8   9"
       .asciiz    "\n   . . .          . a . b .\n"
offset: .byte     6,   8,  33,  35,  37,  62,  64,  89,  91,  93,  118, 120
marker: .byte    '-', '-', '|', '|', '|', '-', '-', '|', '|', '|', '-', '-'

    .text #Text declaration statement

main:
    li $t0, 6 #Number of loops/moves to make; For counting loop. Whatever this is set to will determine number of moves to make
    jal loop1
    
    #Print game board
    li $v0, 4
    la $a0, board
    syscall
    
    #Exit Program
    li $v0, 10
    syscall
    
loop1:
    #Load return address to main onto stack pointer
    subu $sp, $sp, 4 
    sw $ra, ($sp) #Store $ra into $sp

#Inner loop for loop1 is necessary or else return address to main will be infinitely stored.
inner_loop:
    #Read integer for marking excluding a and b
    li $v0, 5
    syscall
    
    move $a0, $v0 #Set $v0 to $a0
    jal markMove #Jump to markMove; return address is set in $ra
    sub $t0, $t0, 1 #Decrement counter by 1
    bnez $t0, inner_loop #Return to L1 if counter not 0
    
    ##Cut off point for loop
    
    #Once counter is 0, pop return address off stack pointer
    lw $ra, ($sp)
    addu $sp, $sp, 4
    
    jr $ra
    
#Mark a move on the game board
#Input : $a0 (Integer move 0-9)
markMove:
    ##Prepare to pass necessary variables ($v0, $ra) into function.
    

    subu $sp, $sp, 4 #First must subtract 4 to make space on stack pointer. This must always be done before storing
    sw $ra, ($sp) #Store $ra into $sp

    subu $sp, $sp, 4 #First must subtract 4 to make space on stack pointer. This must always be done before storing
    sw $t0, ($sp) #Store $t0 into $sp
    
    lb $t0, offset($a0) #Pass $a0 which is integer move 0-9 into offset, then load that data into $t0
    
    ##Must now check if move has been done already
    jal checkMove
    beq $v0, 0, loop2 #Pass $v0 into loop2... after loop2, if $v0 = 1 (valid); else $v0 = 0 (invalid)
    
    #Actually mark now; transfer marker to board through $t1
    lb $t1, marker($a0) #Load marker into $t1 after finding corresponding marker
    sb $t1, board($t0) #Place the marker at spot in board by storing from $t1

#Clear stack pointer ($sp) and return to $ra; $t0 is popped off of $sp; necessary to see if $t0 = 1 or 0 depending on checkMove result
loop2:
    ##Prepare to take the variables ($t0, $ra) from above.
    lw $t0, ($sp) #Pop $t0 off of stack pointer
    addu $sp, $sp, 4 #First must add 4 to make space on stack pointer. This must always be done before loading
    lw $ra, ($sp) #Pop $ra off of stack pointer
    addu $sp, $sp, 4 #First must add 4 to make space on stack pointer. This must always be done before loading
    
    jr $ra #Return to return address; jump register

#Check if a move is valid or not depending on if it has already been done
checkMove:
    jr $ra

你问的三个指令都是MIPS伪指令。

它们的目的是访问用标签声明的全局数组。它们通过命名寄存器中的值对这些全局数组进行索引。例如,

lb $t0, offset($a0)

表示,给定全局标签offset,通过寄存器$a0中的值进行索引,然后执行lb操作——加载字节。获取的字节(符号扩展为 32 位并)存储在 $t0 中。变址是运行次相加,所以offset的地址与寄存器$a0保存的值相加,形成lb内存加载操作的有效地址。因此,如果 $a0 保持值 5,则内存位置 offset+5 的字节将被加载到 $t0,这将加载 62 假设内存保持初始化状态。

在类似硬件的描述语言中,这些lb正在做的是:

ea <- offset + $a0              # compute intermediate result
$t0 <- SignExtend8To32(Mem[ea]) # where Mem[ea] fetches a byte from memory at addr ea

您引用的其他指令工作相同,另一个 lb 使用不同的标签和相同的寄存器(尽管可能具有不同的实际值 - 您必须 运行程序查看当时 $a0 中的内容)。

并且 sb,存储字节,指令将字节值存储到索引地址处的内存中,索引的计算方式相同。

ea <- offset + $a0  # compute intermediate result
Mem[ea] <- $t0[0:7] # where Mem[ea] is a byte store to memory at address ea

注意:虽然 lb 符号扩展了从内存中获取的字节值(此处为 $t0),但 sb 仅存储 [=16] 的低 8 位=] 注册到内存中。


这种形式的指令称为伪指令。 MIPS 处理器实际上并没有把它作为一条指令——汇编程序将它扩展为两条指令的序列。你可以在模拟器中看到两条指令,组装代码后,如果你检查出来。实际操作是使用两条MIPS指令对标号的32位地址进行编码,并在一次内存索引操作中将其添加到寄存器中。两条指令用于组成 32 位地址——一条用于加载标签的完整 32 位地址的高 16 位和低 16 位。

除此之外,如果您想了解更多细节,请查看模拟器对这些指令的扩展,并查看MIPS green sheet查看单独的指令。