Loading

CSAPP 家庭作业4.57

A

对于没有加载转发的情况下,加载/使用冒险的条件为:

E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB };

根据题干,我们可以得到加载转发的使用条件和效果:

  1. 当前指令从内存中读取一个值到寄存器,将该寄存器作为源操作数
  2. 下一条指令不会在执行阶段使用源操作数,会在访存阶段将源操作数写入内存,例如指令:rmmov, push
  3. 添加一条旁路,将内存输出信号(m_valM)转发到流水线寄存器M中的valA字段(转发到e_valA)。

加载转发是在加载/使用冒险的组合中一种特殊的情况,可以不必使用暂停从而规避冒险。

那么能够使用加载转发的条件是什么?

  1. 当前指令会从内存中取值放入寄存器rX(处于访存阶段),例如指令mrmovpop
  2. 下一条指令会将rX作为源操作数(处于执行阶段),写入内存:
    • 写入内存的指令:rmmov, push(没有call指令,因为call 不需要rX作为操作数)
    • 将操作数写入内存:类似mrmovq xxx,rX;pushq rX的形式,即E_srcA == M_dstM

最终得到加载转发的条件:

E_icode in { IMRMOVQ, IPOPQ } && E_srcA == M_dstM

在出现加载转发之前,加载/使用冒险的条件是

E_icode in { IMRMOVQ, IPOPQ } && E_dstM in { d_srcA, d_srcB };

我们需要对E_dstM in { d_srcA, d_srcB }进行进一步的讨论:

  • E_dstM == d_srcA代表着当前指令写入的寄存器,是下一条指令中的源操作数。如果下一条指令是mrmovpush,这样就满足了加载转发的情况,从而规避了加载/使用冒险,所以冒险发生的情况应该是:

    E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ });
    
  • E_dstM == d_srcB代表当前指令写入的目标寄存器,在下一条指令中不会被用作源操作数,显然这不满足加载转发,所以当前情况下一定会发生冒险

  • 综上所述,在存在加载转发的情况下,加载/使用冒险发生的条件是:

    E_icode in { IMRMOVQ, IPOPQ } &&
    (
      E_dstM == d_srcB || 
      (
        E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })
      )
    );
    

B

改动1

由于有了加载转发,所以满足条件时,可以转发给下一条指令的源操作数。此时当前指令在访存阶段,下一条指令在执行阶段,所以时e_valA接受m_valM

word e_valA = [
  E_icode in { IRMMOVQ, IPUSHQ } && E_srcA == M_dstM: m_valM;
	1 : E_valA;  # Use valA from stage pipe register
];

改动2

加载/使用冒险条件的改变,流水线寄存器的暂停条件也发生变化。

bool F_stall =
	# Conditions for a load/use hazard
	## Set this to the new load/use condition
	(E_icode in { IMRMOVQ, IPUSHQ } && 
    (
      E_dstM == d_srcB ||
      (
        E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })
      )
    )
  ) ||
	# Stalling at fetch while ret passes through pipeline
	IRET in { D_icode, E_icode, M_icode };

# Should I stall or inject a bubble into Pipeline Register D?
# At most one of these can be true.
bool D_stall = 
	# Conditions for a load/use hazard
	## Set this to the new load/use condition
	(
    E_icode in { IMRMOVQ, IPUSHQ } &&
    (
      E_dstM == d_srcB || 
      (
        E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })
      )
    )
  ); 

bool D_bubble =
	# Mispredicted branch
	(E_icode == IJXX && !e_Cnd) ||
	# Stalling at fetch while ret passes through pipeline
	# but not condition for a load/use hazard
	!(E_icode in { IMRMOVQ, IPOPQ } && (E_dstM == d_srcB || (E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })))) &&
	  IRET in { D_icode, E_icode, M_icode };

bool E_bubble =
	# Mispredicted branch
	(E_icode == IJXX && !e_Cnd) ||
	# Conditions for a load/use hazard
	## Set this to the new load/use condition
	(
    E_icode in { IMRMOVQ, IPUSHQ } &&
    (
      E_dstM == d_srcB || 
      (
        E_dstM == d_srcA && !(D_icode in { IMRMOVQ, IPUSHQ })
      )
    )
  );
posted @ 2022-07-12 00:31  Frank_Ou  阅读(260)  评论(0编辑  收藏  举报