Assembly 此组件MIPS中的Nop和管道危险

Assembly 此组件MIPS中的Nop和管道危险,assembly,mips,Assembly,Mips,通过交叉编译器将C编译成程序集MIPS后,我有: main: .frame $fp,32,$31 # vars= 16, regs= 1/0, args= 0, gp= 8 addiu $sp,$sp,-32 sw $fp,24($sp) move $fp,$sp li $2,5 # 0x5 sw $2,8($fp) lw $2,8($fp) nop sw $2,16($fp) li $2,5 # 0x5 lw $3,16($fp) nop beq $3,$2,$L4 nop li $2,1

通过交叉编译器将C编译成程序集MIPS后,我有:

main:
.frame $fp,32,$31 # vars= 16, regs= 1/0, args= 0, gp= 8

addiu $sp,$sp,-32
sw $fp,24($sp)
move $fp,$sp
li $2,5 # 0x5
sw $2,8($fp)
lw $2,8($fp)
nop
sw $2,16($fp)
li $2,5 # 0x5
lw $3,16($fp)
nop
beq $3,$2,$L4
nop

li $2,10 # 0xa
lw $3,16($fp)
nop
beq $3,$2,$L5
nop

li $2,1 # 0x1
lw $3,16($fp)
nop
beq $3,$2,$L3
nop

b $L7
nop

$L3:
lw $2,8($fp)
nop
addiu $2,$2,3
sw $2,8($fp)
b $L7
nop

$L4:
lw $2,8($fp)
nop
sll $2,$2,3
sw $2,8($fp)
b $L7
nop

$L5:
lw $2,8($fp)
nop
srl $2,$2,2
sw $2,8($fp)
$L7:
move $sp,$fp
lw $fp,24($sp)
addiu $sp,$sp,32
j $31
nop

.end main

我不明白为什么有很多
nop
代码行,这段代码中
nop
的含义是什么?它对管道危险有帮助吗?如果我删除所有的NOP怎么办

由于管道危险,插入了NOP

回想一下,MIPS管道由5个阶段组成:获取、解码、执行、存储和写回

让我们看一些
NOP
s。第一个是:

lw $2,8($fp)
nop
sw $2,16($fp)
此代码假定没有内存转发。为什么?因为如果您绘制时间线管道图,您将看到
NOP
正在强制
sw
的内存阶段在
lw
上的写回阶段之后正好一个周期发生。因此,代码假定处理器具有内存->ALU转发,或写回->内存转发。如果我们没有在两者之间使用
NOP
sw
的内存阶段将从
$2
中读取一些垃圾值(来自解码阶段的任何内容),并且行为将是未定义的

第二个
nop

lw $3,16($fp)
nop
beq $3,$2,$L4
这里,
$3
仅在
lw
的内存阶段完成后可用。如果我们没有
NOP
,那么
beq
执行阶段将与
lw
的内存阶段在同一个周期内发生,这是不可能的,即使使用内存->ALU转发。因此,我们必须将beq延迟一个周期,这就是NOP所做的。使用此
NOP
beq
的执行阶段将在
lw
的内存后一个周期发生。这是可行的,假设存在内存->ALU转发


类似的原因也适用于其他情况,我建议您自己尝试解决。

NOP
s是由于管道危险而插入的

回想一下,MIPS管道由5个阶段组成:获取、解码、执行、存储和写回

让我们看一些
NOP
s。第一个是:

lw $2,8($fp)
nop
sw $2,16($fp)
此代码假定没有内存转发。为什么?因为如果您绘制时间线管道图,您将看到
NOP
正在强制
sw
的内存阶段在
lw
上的写回阶段之后正好一个周期发生。因此,代码假定处理器具有内存->ALU转发,或写回->内存转发。如果我们没有在两者之间使用
NOP
sw
的内存阶段将从
$2
中读取一些垃圾值(来自解码阶段的任何内容),并且行为将是未定义的

第二个
nop

lw $3,16($fp)
nop
beq $3,$2,$L4
这里,
$3
仅在
lw
的内存阶段完成后可用。如果我们没有
NOP
,那么
beq
执行阶段将与
lw
的内存阶段在同一个周期内发生,这是不可能的,即使使用内存->ALU转发。因此,我们必须将beq延迟一个周期,这就是NOP所做的。使用此
NOP
beq
的执行阶段将在
lw
的内存后一个周期发生。这是可行的,假设存在内存->ALU转发


类似的原因也适用于其他情况,我建议您自己尝试解决这些问题。

根据您的代码,添加了所有“nop”指令以修复以下错误

1) 分支延迟

2) 负载延迟


由于这些nop是由编译器添加的,所以您可以通过“set noreorder”显式地为编译器提供一个选项,使其不添加这些nop指令。更好的是,我应该为您提供阅读参考。“见Mips运行第二版”第288页。根据本书,我不认为“nop”是危险屏障装置。

根据您的代码,添加了所有“nop”说明以修复以下错误

1) 分支延迟

2) 负载延迟


由于这些nop是由编译器添加的,所以您可以通过“set noreorder”显式地为编译器提供一个选项,使其不添加这些nop指令。更好的是,我应该为您提供阅读参考。“见Mips运行第二版”第288页。根据这本书,我不认为nop是危险屏障。

我认为第一个(
lw…nop…sw
)确实有内存转发,如果没有,将有2条nop线(…nop…nop…)来避免危险。@VAK有内存->ALU转发或写回->内存转发,但没有内存->内存。如果有内存->内存,我们就不需要NOP。有了这个NOP,我们将
sw
的解码与
lw
的内存放在同一个周期上(因此,可能有来自内存的转发->ALU,丢弃从解码读取的垃圾);它还将
sw
的内存放在与
lw
的写回相同的周期中,因此我们也可以进行写回->内存转发。但是我们肯定没有内存->内存,或者如果我们有,编译器也不会意识到。我认为第一个(
lw…nop…sw
)确实有内存转发,如果没有,将有两条nop行(…nop…nop…)来避免危险。@VAK有内存->ALU转发或写回->内存转发,但没有内存->内存。如果有内存->内存,我们就不需要NOP。有了这个NOP,我们将
sw
的解码与
lw
的内存放在同一个周期上(因此,可能有来自内存的转发->ALU,丢弃从解码读取的垃圾);它还将
sw
的内存放在与
lw
的写回相同的周期中,因此我们也可以进行写回->内存转发。但是我们肯定没有内存->内存,或者如果我们有,编译器也不知道。