在此 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查看单独的指令。
该程序旨在允许用户使用破折号(“-”和“|”)形成框,连接 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查看单独的指令。