假设有一个外部中断请求发送到8086。处理器将在完成当前正在执行的指令(如果有)后处理中断。在处理中断之前,程序的状态也将通过将数据压入堆栈段来保存(PSW标志、寄存器等)。
现在,大多数教程/文档都描述了指令指针也被推到堆栈段上,这是可以的,因为它指向代码段中指令的下一个字节(就在发出中断请求之前)。
但是指令队列会发生什么呢?当处理中断请求时,它也会被推到堆栈段上吗?或者它的内容会被清除为零吗?在这种情况下,指令指针是否应该递减,以便可以使它指向代码段中的前一条指令(在中断被处理后)?
这里,中断请求之后***实际上是指***中断请求被处理之后。此图显示的是,在中断请求到来之前,指令被缓存,IP指向CS内存段中下一个字节指令的地址。要处理中断请求,寄存器的内容(* 包括IP和标志 )被推送到堆栈段上。处理请求后,以前的内容被加载回-IP仍指向第7个字节的位置(指令),队列(缓存)为空。这就是我的疑问。 IP是否递减以指向回i1*?其次,我们是否需要手动处理IP(例如,在中断时将其推到堆栈上)或中断服务例程是否为我们处理此问题?请提供帮助,谢谢!
备注:指令队列-8086体系结构有一个6字节预取指令管道。当执行单元执行当前指令时,总线接口单元会提前从内存中读取多达6字节的操作码。
3条答案
按热度按时间7xzttuei1#
你不太清楚你所说的“指令队列”是什么意思。
一个含义可能是“预取指令”。实际上,处理器从最后一个 * 完成 * 指令的点开始在指令流中推测性地预读,基于各种类型的分支预测算法来决定是否跟随分支。由于这些是 * 读取 ,因此如果处理器决定放弃当前指令“流”以用于另一指令“流(例如中断例程),则它简单地忽略其预读。
另一个意思可能是“部分执行的指令(in flight/in the 'pipeline')",这在超标量CPU中经常发生。在异步中断的情况下,处理器必须完成影响系统可见状态的中断(例如,已提交对寄存器或存储器的写入),并且根据特定处理器的设计者的突发奇想可以完成或不完成其它指令。在同步陷阱的情况下,处理器必须完成影响状态的指令,而是简单地放弃其余的(OP的短语是“将队列置零”,其概念是正确的,但措辞错误)。
[应OP的要求添加我的评论]:你说8086有一个6字节的预取“指令流水线”(恕我直言)。可能有一个具有该属性,但这是实现的细节,没有很好的理由相信这是所有8086的属性。对于现代CPU,实现指令预取的方式简单地取决于设计者的聪明程度。您可以合理预测的是,将存在某种预取方案,并且除了对性能的影响和关于自修改代码的有趣规则外,您将很难在应用程序中检测到它的存在。
[回答OP的第二个问题]: 第二,我们是否需要手动处理IP(例如,在中断时将其推送到堆栈上),或者中断服务例程是否为我们处理此问题?*
对于任何类型的陷阱或中断,存储体系结构定义的状态就足够了(“寄存器”、PC等)。对于许多处理器,硬件存储体系结构状态的关键子集就足够了,并让中断例程存储(并最终恢复)其余的状态。因此,存储整个状态的责任由硬件和软件分担(以保存硬件中的实现工作)。
对于x86系列,指令指针通常(IP)和旗标寄存器由硬件推入到当前堆栈上,控制转移到中断,且中断例行程序具有通常以通常称为“上下文块”的操作系统定义的数据结构存储其余寄存器的指令。中断例行程序完成其工作,或者通过重新加载寄存器,然后通过使用特殊的IRET指令重新加载IP和标志,将控制返回给应用程序,或者将控制转移给OS调度程序,该调度程序选择运行某些其它活动,最终使用保存的上下文块内容来重新启动应用程序。
一个 * 真正 * 快速的中断例程可能只保存足够的寄存器来完成它的关键工作,然后在返回被中断者之前恢复这些寄存器。
x9ybnkn62#
8086处理器有一个6字节的指令预取队列。为了回答这个问题,当中断发生时,程序计数器(指令指针)被压入堆栈并丢弃队列。棘手的部分是内部程序计数器指向要预取的下一个字节,其与要执行的下一字节不同。解决方案是通过减去队列大小来校正程序计数器值,使用一个小常数表和寻址加法器。同样的校正发生在子程序调用和相对跳转,因为它们也需要真实的的PC值。
引用8086 patent第8列第27行:
PC不是一个真实的的程序计数器,因为它和CPU内的任何其它寄存器在任何时候都不保持实际的执行点。PC实际上指向要输入队列的下一个字节。每当需要相对转移或调用时,通过从PC中减去队列中尚未使用的已访问指令数,按指令计算真正的程序计数器。
ftf50wuq3#