I am very new to bare metal programming and have never delt with interrupts before, but I've been learning on a RISC-V FE310-G002 SOC powered dev board.
I've been reading about the RISC-V WFI (Wait for interrupt) instruction and from the manuals, it doesn't sound like you can rely on it to actually sleep the core. Instead, it only suggests that execution can be halted to the system and that the instruction should be treated more like a NOP. However, this seems rather useless to me. Consider the following ASM program snippet:
wfi_loop:
WFI
J wfi_loop
This would have to be done since WFI can not be depended on. However, upon MRET from the interrupt handler, you would still be caught in the loop. So you would have to make it conditional against a global variable whose value is updated in the interrupt handler. This seems very messy.
Also, if your implementation does in fact honor the WFI instruction and the interrupt is triggered just prior to the execution of the WFI instruction, the entire core will stall until some other interrupt is triggered since it will return prior to the WFI instruction.
It seems that the only correct usage of the instruction would be inside of a kernel scheduler when there is no work to be done. But even then, I don't think you would ever want to return from the interrupt handler into such code, but rather restart the scheduler algorithm from the start. But that would be a problem too since you would somehow have to roll back the stack, etc....
I keep going round and round with this in my head and I can't seem to figure out a safe use. Maybe, if you atomically, enable interrupts in with CSRRS and then immediately call WFI like this:
CSRRSI zero, mie, 0x80
wfi_loop:
WFI
J wfi_loop
NOP
NOP
Then make sure to increment the mepc register by 8 bytes before calling MRET from the interrupt handler. The interrupt would also have to be disabled again in the mie register inside of the interrupt handler before returning. This solution would only be safe if WFI, J, and NOP are all encoded as 4 byte instructions, regardless of whether compressed instructions are used. It also depends on the program counter reaching the WFI instruction before it is possible for the interrupt to be triggered, after being enabled by the CSRRSI instruction. This would then allow the interrupt to be triggered in a safe place in code and to return in such a way that it breaks out of the loop that was waiting for it.
I guess I am just trying to understand what behavior I can expect from the hardware and, therefore, how to correctly call and return from interrupts and use the WFI instruction?
hlt
. Which "halts" until the next hardware interrupt request (IRQ) occurs. It is often misinterpreted as "halting" the machine forever though. Sowfi
is a better mnemonic choice. – Disfiguresti
\hlt
as the last attempt to idle the machine. It is called here when waiting for key input, after having detected none available yet. We do not care which interrupt request occurs, the only need is that it will resume if a key is pressed (IRQ 1). It is essentially polling with sleep while waiting. (86-DOS applications assume that they are the sole foreground task.) – Disfigurehlt
can be short (especially if running in a virtual machine or such), but what is short to us is already very long for the machine to burn if busy-looping. Idling properly allows the CPU to underclock and sleep for easily >95% of the time. I imaginewfi
is the same ashlt
for these purposes. – Disfigure