1、WFI是什么?
WFI(Wait For Interrupt)指令是ARM中的一个Hint 指令,内核执行hint指令的时候不需要依赖额外的处理操作。
WFI指令可以让CPU进入standby 模式,即低功耗模式,此时内核会暂停其他活动,一直等待中断事件的发生,检测到中断发生后,WFI指令执行完成,CPU退出standby模式。
本文将从ARM hint指令、WFI的用途以及WFI的唤醒事件等三个角度解释WFI指令。
2、ARM Hint 指令
HINT 指令可以合法地被视为 NOP指令,但它们可以具有特定于实现的效果,常见的HINT指令有:
- NOP // No operation,无操作, 不保证CPU会花时间去执行
- YIELD // 提示当前线程正在执行可以换出的任务
- WFE // Wait for Event,进入low power状态,直到等待的事件发生
- WFI // Wait for interrupt,进入low power状态,直到等待的中断或与中断类似的操作发生
- SEV // Send Event,发送事件,与WFE对应
- SEVL // Send Event Local,发送本地事件,与WFE对应
ARM 汇编语言中包含可用于让core进入低功耗状态(low-power state)的指令:WFI或WFE。ARM架构将这些指令定义为hint指令,这意味着core在执行它们时不需要采取任何特定操作。然而,在 Cortex-A 处理器系列中,这些指令的实现方式是关闭几乎所有内核部分的时钟。这意味着内核的功耗显着降低,仅消耗静态漏电流,没有动态功耗。
(这个时钟真的很重要,我得好好看一下这个时钟到底对这个一个硬件意味着什么?)
3、WFI指令的用途
WFI指令的主要目的就是使core进入standby模式,直到中断或者类似中断的事件发送,才退出,core继续工作。
standby 模式- 待机模式
在待机模式下,core保持上电状态,但其大部分时钟停止或者进入时钟门限。这意味着core的绝大部分都处于static state,唯一消耗的功率是用于寻找中断唤醒条件的泄漏电流和少量逻辑时钟。
使用 WFI(等待中断)或 WFE(等待事件)指令可以进入此模式。 ARM 建议在 WFI 或 WFE 之前使用数据同步屏障 (Data Synchronization Barrier ,DSB) 指令,以确保待处理的内存事务在更改状态之前完成。
core进入待机状态后,会停止执行,直到检测到唤醒事件。唤醒条件取决于进入指令。对于 WFI,需要中断事件或外部调试请求来唤醒core。对于 WFE,存在许多指定的事件,包括cluster中执行 SEV 指令的另一个core。
WFI 指令广泛用于电池供电的系统。例如,手机可以每秒多次将core置于待机模式,同时等待用户按下按钮才唤醒core,从而可以节省功耗。
WFE 类似于 WFI。core暂停执行,直到发生事件。这可以是列出的事件条件之一,也可以是cluster中另一个core发出的事件信号。其他core可以通过执行 SEV 指令来发出事件信号。 SEV 向所有core发送一个事件信号。还可以对generic timer通用定时器进行编程,以触发将core从 WFE 唤醒的周期性事件。
总而言之,WFI 指令可以提示hint core在接收到中断或类似的exception之前无需执行任何操作,具体来说有两部分:
- 1、强制暂停core的运行以及所有相关的总线活动。
- 2、暂停处理器执行指令。
4、WFI指令的唤醒事件
WFI可以使core进入待机状态,而将core从待机状态中唤醒,则需要中断事件或者类似中断事件的exception(debug事件):
- 物理的IRQ中断,但是忽略 CPSR寄存器的 I 位.
- 物理的FIQ中断,但是忽略 CPSR寄存器的 F 位.
- 物理的异步abort,但是忽略 CPSR寄存器的 A 位.
- 异步的调试事件(debug event),当启用侵入式调试(invasive debug)并允许调试事件时,比如Trace 32中的 break 操作,也会将core唤醒。
- 包括其他实现定义的硬件机制来生成 WFI 唤醒事件.
5、WFI使用注意事项
- 在WFI指令之前使用 DSB 、DMB等内存屏障指令,使得core在进入待机模式之前,完成内存交互。
- 当硬件检测到WFI唤醒事件后,WFI指令才算执行完成。
- WFI唤醒事件不能被CPSR中的相关掩码(I F A)等bit 位屏蔽,即忽略CPSR中的IFA相关bit 位。
- ARM架构并未定义低功耗状态的确切性质,但 WFI 指令的执行不得导致内存一致性遭受破坏。
- 如果是为了测试中断事件而使用WFI,注意在中断发生和WFI之间不应有耗时事件(如大量的printf打印),否则有可能导致中断丢失,即中断已经处理完成了才执行WFI指令,此时中断已经消失了,但是WFI还在一直等中断。use case如下:
当检测到中断时,WFI指令才算完成,才会唤醒处理器,假设有这样一个use case:
Timer(10); // 假设这是个timer,10秒后将发起中断,中断handler在其他地方定义 WFI(); //如果处理器没有接收到中断,WFI指令将没有完成,一直处于休眠状态,下一条printf也不会被执行 printf("中断发生,WFI检测到中断");
正常情况下是可以看到打印的,但是,在timer和WFI之间加入一个耗时事件:
Timer(10); // 10秒后将发起中断 WasteTime(20); // 执行这个函数需要20秒 WFI(); //从中断发生,到处理完成中断用不了10秒,执行到WFI时,中断已经消失了,所以CPU会一直处于休眠状态,下面的printf也不会被执行 printf("中断发生,WFI检测到中断");
额外的知识关于时钟
在群里请教了前辈们的知识,感觉讲的很清晰。又长知识了,向前辈致敬。
问:不怎么了解硬件,想请教一下前辈们芯片的时钟有多重要。为什么休眠的时候说时钟停了,然后core就休眠了
答:一般的硬件都有个基础的时钟作为所有逻辑部分的"心跳"来源, 通常的做法是: 晶体振荡器稳定在一个固定的频率, 然后由一个压控振荡器以晶振作为参考进行倍频, 然后在经过分频逻辑给到芯片上的各个逻辑部分. 所以各个控制器的时钟都是可控的, 这有利于降低芯片的功耗。
换句话说, 芯片真正费电的部分: 逻辑翻转(受时钟驱动的同步/异步逻辑)和电路之间的漏电流(工艺问题), 现在的工艺牛逼了, 逻辑部分翻转的损耗低, 功耗就低. 而且这里还有个有点: 就是工艺的nm越小, 就翻转的电压越小, 频率响应越高, 频率就可以做的更高. 但是硅这个东西的频率总是有个上限, 就是超10GHz, 全人类感谢你的那个上限. 硅基的芯片貌似上10GHz这辈子不太可能了。core的时钟如果没了, core就不能"动"了。
时钟倍频后靠PLL锁的, PLL就是那个压控的倍频器件, 温度太高的时候, 芯片容易跑飞也大多数是PLL锁不住了, 偏移得太厉害, 就直接飞了