circuit delays in units of picoseconds (abbreviated “ps”), or 10−12 seconds.
throughput in units of giga-instructions per second (abbreviated GIPS), or billions of instructions per second.
sequential dependencies occurs due to the instruction control flow.
条件测试的结果决定了接下来要执行的指令是irmovq指令(第4行)还是halt指令(第7行)。
b, the result of I1 becomes an input to I2
d, the result of I1 becomes an input to I4.
a) PC计算发生在时钟周期结束时,根据当前时钟周期内计算得到的信号值,计算PC寄存器的新值。
b) 创建状态寄存器来保存在指令执行期间计算得到的信号。然后,当新的时钟周期开始时,这些值通过完全相同的逻辑传播,以计算当前指令的PC。
从SEQ移动到SEQ+的转换是一种被称为电路重定时的通用转换。
重定时改变了系统的状态表示,而不改变其逻辑行为。它通常用于平衡流水线系统不同阶段之间的延迟。
电路重定时是一种优化技术,旨在通过重新安排寄存器的位置来改进电路的性能。通过重新定时电路,可以改善电路的时序性能,减少时序违规和提高时序裕度,从而提高电路的工作频率和性能。这种优化技术通常用于数字电路设计中,特别是在集成电路设计和高性能计算系统中。
在SEQ+的各个阶段之间插入了流水线寄存器,并稍微重新排列了信号,得到了PIPE−处理器,其中名称中的“−”表示该处理器的性能略低于我们的最终处理器设计。PIPE−的结构如图所示。在这个图中,流水线寄存器显示为蓝色方框,每个方框包含不同的字段,这些字段显示为白色方框。如白色方框所示,由于包含多个字段,每个流水线寄存器包含多个字节和字。与顺序处理器的硬件结构中显示的圆角方框中的标签不同,这些白色方框代表实际的硬件组件。
PIPE−使用了几乎与我们的顺序设计SEQ相同的硬件单元,但是流水线寄存器分隔了各个阶段。
PIPE-, 信号在流水线中通过执行和内存阶段传递,并在它们到达写回阶段后才被指向寄存器文件。
SEQ+, 可以直接将这些信号连接到寄存器文件写入端口的地址输入。
在PIPE-中的一个块,在SEQ+中以完全相同的形式不存在,这个块被标记为“Select A”,位于解码阶段。我们可以看到,这个块通过选择来自流水线寄存器D的valP或者来自寄存器文件A端口的值来生成流水线寄存器E的valA。这个块的作用是减少必须传递到流水线寄存器E和M的状态量。在所有不同的指令中,只有call指令需要在memory stage使用valP。只有jump指令需要在execute stage使用valP的值(如果跳转没有发生)。这些指令中没有一个需要从寄存器文件中读取的值。因此,我们可以通过合并这两个信号并将它们作为单个信号valA在流水线中传递来减少流水线寄存器状态的数量。这消除了SEQ和SEQ+中标记为“Data”的模块的需要。在硬件设计中,通常会仔细确定信号的使用方式,然后通过合并这些信号来减少寄存器状态和布线的数量。
pc是在fetch阶段更新的,一般作为ret时候的地址。
也有其他的情况会需要在内存阶段获取地址。
在流水线设计中的目标是在每个时钟周期发出一个新指令,这意味着在每个时钟周期,一个新指令进入执行阶段,并最终完成。
为了做到这一点,必须确定在获取当前指令后的下一条指令的位置。所以需要预测PC。
3个nop指令会创建一个延迟。
2个nop指令的情况:
第二个irmovq指令处于写回阶段,因此对程序寄存器%rax的写入只会发生在时钟上升时的第7个周期开始。所以存在hazard。
1个nop指令的情况:
对寄存器%rdx的待定写入仍处于写回阶段,对寄存器%rax的待定写入仍处于内存阶段。valA和valB两个操作数都获得了不正确的值。
没有nop 指令的情况:
addq指令从寄存器文件中读取其源操作数。对寄存器%rdx的待定写入仍在内存阶段,而寄存器%rax的新值正在执行阶段计算中。valA和valB两个操作数都获得了不正确的值。
处理器可以通过在解码阶段暂停一个指令,直到其他指令通过写回阶段,从而避免数据冲突。
stalling技术和直接使用nop之间的区别在于它们处理数据冲突的方式。停顿技术会在发现数据冲突时暂停执行,等待相关的数据可用后再继续执行。这意味着处理器在等待期间不会浪费任何周期。而直接使用nop指令则是在发现数据冲突时在流水线中插入一个空操作指令,以消耗一个周期的时间,而不会等待相关数据就绪。因此,停顿技术能够更有效地利用处理器的资源,而直接使用nop则可能会导致一些浪费。
第六个周期时, irmovq指令处于写回阶段,因此对程序寄存器%rax的写入只会发生在时钟上升时的第7个周期开始。存在data hazard, stall control logic 插入了一个bubble 在execute 阶段和重复decoding 在cycle 7,相当于插入了一个一个nop 指令。
插入了3个 bubble。
在decode stage, 暂停addq指令时,我们还必须暂停在fetch stage阶段的halt指令。可以通过保持程序计数器的固定值来实现这一点,这样就会重复获取halt指令,直到stall完成。
In these figures the arrow between the box labeled “D” for the addq instruction and the box labeled “E” for one of the pipeline bubbles indicates that a bubble was injected into the execute stage in place of the addq instruction.
教科书表示这个技术不是很好。
Writes and reads of the data memory both occur in the memory stage. By the time an instruction reading memory reaches this stage, any preceding instructions writing memory will have already done so. 所以一般对memory 的读写不会出现hazard.
On the other hand, there can be interference between instructions writing data in the memory stage and the reading of instructions in the fetch stage, since the instruction and data memories reference a single address space. 另一方面,memory阶段中的指令写入数据和fetch阶段中的指令读取之间可能会发生干扰,因为指令存储器和数据存储器引用同一地址空间。暂时不考虑这个问题。
Rather than stalling until the write has completed, it can simply pass the value that is about to be written to pipeline register E as the
source operand.
2个nop的情况:
使用W_ValE 而不是 R[%rax]
1个nop的情况:
使用W_valE 和 M_valE 而非 R[%rdx] 和 R[%rax]
没有nop的情况:
使用M_valE 和 e_valE
Note that using the ALU output does not introduce any timing problems.
增加了Sel+FwdA 和 FwdB
block labeled “Sel+FwdA” combines the role of the block labeled “SelectA” in PIPE− with the forwarding logic.
block labeled “Fwd B” implements the forwarding logic for source operand valB.
call 指令只使用srcB, 所以使用valA存储valP。
jmp指令不使用srcB和srcA, 所以也可以使用valA存储valP。
4.53 这个例子,需要到memory stage 才能获取到%rax 的值。
instruction (the mrmovq at address 0x028) reads a value from memory
所以4.53 这个例子是存在data hazard.
采用stalling 和 forwarding 结合方式。
This use of a stall to handle a load/use hazard is called a load interlock.
Control hazards arise when the processor cannot reliably determine the address of the next instruction based on the current instruction in the fetch stage. control hazards can only occur in our pipelined processor for ret and jump instructions.
mispredicted branch:
jump 指令:
对应的流水线图:
流水线预测分支将被采取,因此开始在跳转目标处获取指令。在误判在第4个周期被检测到之前,已经获取了两条指令,当跳转指令通过执行阶段时。在第5个周期,流水线通过向解码和执行阶段注入气泡来取消这两个目标指令,并且还获取了跳转后的指令。
the pipeline control logic must disable any updating of the condition code register or the data memory when an instruction in the memory or write-back stages has caused an exception.
to include a status code stat in each of our pipeline registers
call 指令只使用srcB, 所以使用valA存储valP。
jmp指令不使用srcB和srcA, 所以也可以使用valA存储valP。
ret需要从内存获取valp存储的内容,作为新的pc。
select pc 模块对应hcl代码:
predict pc 模块对应hcl代码:
#设置从寄存器文件中读取的源
word d_srcA = [
D_icode in {IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ} : D_rA; #这些指令需要从寄存器rA中读取数据
D_icode in {IPOPQ, IRET} : RRSP; #需要设置栈顶指针,所以需要读取栈值
1 : RNONE;
];
word d_srcB = [
D_icode in {IOPQ, IRMMOVQ, IMRMOVQ} : D_rB; #从内存中读取时需要从寄存器中读取偏移量
D_icode in {IPUSHQ, IPOPQ, ICALL, IRET} : RRSP;
1 : RNONE;
];
#设置写入寄存器文件的目的
#注意:在译码阶段并不会进行写入,只是先计算出当前指令需要的目的寄存器地址,保存到流水线寄存器中,而后在写回阶段才使用
word d_dstE = [
D_icode in {IRRMOVQ, IIRMOVQ, IOPQ} : D_rB;
D_icode in {IPUSHQ, IPOPQ, ICALL, IRET} : RRSP;
1 : RNONE;
];
word d_dstM = [
D_icode in {IMRMOVQ, IPOPQ} : D_rA;
1 : RNONE;
];
#通过合并信息和转发机制设置valA的值
word d_valA = [
#合并信息
D_icode in {ICALL, IJXX} : D_valP;
#按照转发源的优先级设置转发源
d_srcA == e_dstE : e_valE;
d_srcA == M_dstM : m_valM;
d_srcA == M_dstE : M_valE;
d_srcA == W_dstM : W_valM;
d_srcA == W_dstE : W_valE;
#默认都是从寄存器文件中读取的
1 : d_rvalA;
];
#通过转发机制设置valB的值
word d_valB = [
d_srcB == e_dstE : e_valE;
d_srcB == M_dstM : m_valM;
d_srcB == M_dstE : M_valE;
d_srcB == W_dstM : W_valM;
d_srcB == W_dstE : W_valE;
1 : d_rvalB;
];
流水线实现应该总是优先考虑最早的流水线阶段中的转发源,因为它保存了程序序列中设置寄存器的最新指令。例如e 早于 m, 早于 w。
updating of the condition codes should be suppressed
bool set_cc = E_icode == IOPQ && #首先要保证当前指令是算数指令,才会设置CC
!m_stat in {SADR, SINS, SHLT} && #保证上一条处在访存阶段的指令没有出现异常
!W_stat in {SADR, SINS, SHLT}; #保证上两条指令没有出现异常
这部分代码seq和hcl相似
#设置内存地址
word mem_addr = [
M_icode in {IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ} : M_valE;
M_icode in {IPOPQ, IRET} : M_valA;
];
#设置读写的控制信号
bool mem_read = M_icode in {IMRMOVQ, IPOPQ, IRET};
bool mem_write = M_icode in {IRMMOVQ, IPUSHQ, ICALL};
#由于当前阶段可能出现内存地址错误,所以还需要设置状态
word m_stat = [
dmem_error :SADR;
1 : M_stat;
];
#将其他需要的值传递下去
word w_dstE = W_dstE;
word w_valE = W_valE;
word w_dstM = W_dstM;
word w_valM = W_valM;
当涉及到秒(s)、纳秒(ns)、毫秒(ms)、微秒(μs)和皮秒(ps)等时间单位的转换时,以下是一些常见的转换关系:
1秒(s)= 1,000毫秒(ms)
1毫秒(ms)= 1,000微秒(μs)
1微秒(μs)= 1,000纳秒(ns)
1纳秒(ns)= 1,000皮秒(ps)
因此,可以使用这些转换关系将秒、毫秒、微秒、纳秒和皮秒之间进行转换。
https://zhuanlan.zhihu.com/p/107760564