考虑一个问题宽度等于N的 VLIW 处理器:这意味着它能够同时启动N个操作,因此每条非常长的指令最多可以包含N个操作。
假设 VLIW 处理器加载一个很长的指令,该指令由具有不同延迟的操作组成:属于同一很长指令的操作可能在不同的时间结束。如果一个操作在属于同一条很长指令的其他操作之前完成它的执行会发生什么?后续操作(即属于下一条超长指令的操作)能否在当前超长指令的剩余操作执行之前开始执行?还是一条很长的指令等待属于当前很长指令的所有操作完成?
考虑一个问题宽度等于N的 VLIW 处理器:这意味着它能够同时启动N个操作,因此每条非常长的指令最多可以包含N个操作。
假设 VLIW 处理器加载一个很长的指令,该指令由具有不同延迟的操作组成:属于同一很长指令的操作可能在不同的时间结束。如果一个操作在属于同一条很长指令的其他操作之前完成它的执行会发生什么?后续操作(即属于下一条超长指令的操作)能否在当前超长指令的剩余操作执行之前开始执行?还是一条很长的指令等待属于当前很长指令的所有操作完成?
我见过的大多数 VLIW 处理器都支持具有不同延迟的操作。
由编译器来安排这些指令,并确保操作数在操作执行之前可用。VLIW 处理器是愚蠢的,不会检查操作之间的任何依赖关系。当执行长指令字时,字中的每个操作只是从寄存器文件中读取其输入数据,并在同一周期结束时将其结果写回,或者如果操作需要两个或三个周期,则稍后再写回结果。
这仅在指令是确定性的并且总是采用相同数量的周期时才有效。我见过的所有 VLIW 架构都有需要固定周期数的操作,不多也不少。如果它们确实需要更长的时间,例如外部内存提取,整个机器就会停止。
现在有一个关键因素限制了具有不同延迟的指令的调度:寄存器文件的端口数量。端口是寄存器文件和操作执行单元之间的连接。在 VLIW 处理器中,每个操作都在一个发布槽中执行,并且每个发布槽都有自己的寄存器文件端口。端口在硬件方面很昂贵。端口越多,实现寄存器文件所需的芯片就越多。
现在考虑以下情况,其中一个两周期操作想要将其结果写入寄存器文件,同时又是一个安排在其后的单周期操作。现在发生了冲突,因为两个操作都想通过同一个端口写入同一个寄存器文件。同样,编译器的任务是确保不会发生这种情况。在许多 VLIW 架构中,在同一问题槽中执行的操作数都具有相同的延迟。这避免了这种冲突。
现在回答你的问题:
你说:“如果一个操作在属于同一条很长指令的其他操作之前完成执行,会发生什么?”
没有什么特别的事情发生。处理器只是继续执行下一个很长的指令字。
您说:“后续操作(即属于下一条超长指令的操作)是否可以在当前超长指令的剩余操作执行之前开始执行?”
是的,但这可能会在以后出现注册端口冲突。由编译器来防止这种情况。
你说:“或者一个很长的指令是否等待属于当前很长指令的所有操作完成?”
不。每个周期的处理器只是转到下一个很长的指令字。有一个例外,那就是当一个操作比正常时间花费更长的时间时,例如因为缓存未命中,然后管道停止,机器不会处理下一个长指令字。
VLIW 背后的想法是编译器计算出许多事情供处理器并行执行,并将它们打包成称为“超长指令字”的包。
Amhdahl 定律告诉我们并行程序的加速(例如,VLIW 指令的并行部分)受到最慢部分(例如,最长持续时间的子指令)的约束。
VLIW 和“长延迟”的简单答案是“不要混合具有不同延迟的子指令”。实际的答案是 VLIW 机器尽量不要有不同延迟的子指令;理想情况下,您需要“一个时钟”子指令。通常,即使内存提取也只需要一个时钟,因为它被划分为“内存提取开始(这里是要提取的地址)”,唯一的可变延迟子指令是“等待前一次提取到达”,其想法是编译器生成为尽可能多的其他计算,以便内存获取延迟由其他指令来解决。