前一章叙述了c语言如何转化为汇编程序,如何使用汇编程序。但是,汇编程序具体是如何执行的呢?例如(add %eax %edx)这条指令,我们知道它的功能,处理器是何如执行指令来获得想要的结果?——这是本章的主题。
(一)Y86指令集体系结构
为了简化问题,我们不使用Intel和ATT的指令集体系结构,抽象简化一个Y86。Y86的定义了各种状态元素、指令集及其编码、编程规范、异常事件处理。
(二)存储器和时钟
存储设备都是由同一个时钟控制的。时钟是一个周期性的信号,决定什么时候把新值加载到设备中。
存储设备分两种:
1)时钟寄存器(硬件寄存器),存储单个位或字,时钟信号控制寄存器加载输入值;
2)随机访问存储器(存储器)存储多个字,用地址来选择该读写哪个字,包括:处理器的虚拟存储系统、程序寄存器等。
(硬件和机器级编程,“寄存器”这一概念是有细微差距的。硬件中,寄存器是直接连接到电路中的;而机器级编程中,寄存器是寄存器文件中可寻址的字,地址为寄存器ID。为避免歧义,两类寄存器分别称为:硬件寄存器和程序寄存器。)
(图为时钟寄存器工作方式,Y86中用时钟寄存器保存程序计数器(PC)、条件代码(CC)和程序状态(Stat))
(三)指令执行6大阶段
下面是Y86各个指令对应于6各阶段的分解,可以对照上面的说明仔细对照
(四)SEQ处理器
我们直接实现上述的6大阶段对应的硬件结构,称为SEQ处理器
上面展示了每条指令所对应的分阶段执行情况,现在我们把这些指令汇总,给出每个阶段的指令情况:
(相应的need_regids, need_valC; srcB, dstM; aluB; mem_data, mem_write指令情况见课本)
(五)流水线
SEQ实现的问题是:一个时钟周期内,必须完成6大阶段。故而时钟周期必须非常慢。所以我们使用流水线模型。
流水线的两个重要概念:
throughput(吞吐量):单位时间内服务的顾客总数;
延迟(latency):服务一个用户所需要的时间。
流水线模型需要在各个阶段之间都放上流水线寄存器。
下面是流水线的图例说明:
可以看到流水线的巨大优点,然而流水线就没有一点问题吗?
1. 将系统计算划分为一组具有相同延迟的阶段是很严峻的挑战;
2. 流水线过深的话,收益反而下降。(现在处理器采用很深的(15+阶段)流水线,Y86采用5阶段流水线)
3. 带反馈的流水线。1)data dependency(数据相关):相邻指令之间可能是相关的。流水线模式下,可能下一条指令需要的数据,上一条指令还没产生。2)control dependency(控制相关):下一条指令是否执行依赖的条件,上一条指令还没有计算出来。
当我们实现流水线结构时,我们要解决第三个问题。
(六)Y86的流水线实现——PIPE-
首先对于SEQ,我们将PC的计算挪到取指阶段(在时钟开始是计算,而不是结束时计算),然后再在各个阶段之间加上流水线寄存器:
在PIPE-结构的基础上,根据我们之前的学习,只要再解决几个大问题即可:
1.如何解决数据相关?
2.如何解决控制相关?重点是ret指令和条件跳转指令
3.如何处理异常指令?
解决数据相关:
需要仔细的体会这一过程,尤其是时钟控制下,状态更新如何进行。
解决控制相关:
这一问题分解来看,需要分三个部分:1.如何预测下一个PC值?2.如何处理ret指令?3.如何处理预测错误分支?
处理异常指令:
对于控制相关问题,还需要多做一些说明,如何多个控制问题组合在了一起,我们应该如何处理?这一问题留到最后作为补充、
(七)PIPE处理器实现
根据上面的讨论,我们只要在PIPE-中加入上述问题的解决方案之后,就得到了我们想要的PIPE处理器。
1.实现转发。只需要添加几个电路即可实现。
具体的PIPE的HCL描述,见课本。
2.实现暂停和取消指令
在此新型流水线寄存器的基础上,很容易实现暂停某指令或者取消某指令,由此,我们就可以实现之前问题的解决方案。