Skip to content

Commit 91af20d

Browse files
authored
Document halt bug (#343)
In its two forms, and with a test ROM as citation, too!
1 parent d912688 commit 91af20d

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

src/Interrupts.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ RETI ;Enables interrupts and returns (same as the instruction sequence EI, RET
2222
where \<INT\> means the operation which is automatically executed by the
2323
CPU when it executes an interrupt.
2424

25-
The effect of EI is delayed by one instruction. This means that EI
25+
The effect of `ei` is delayed by one instruction. This means that `ei`
2626
followed immediately by DI does not allow any interrupts between them.
27+
This interacts with the [`halt` bug](<#halt bug>) in an interesting way.
2728

2829
## FFFF - IE - Interrupt Enable (R/W)
2930

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
- [Timer Obscure Behaviour](./Timer_Obscure_Behaviour.md)
3232
- [Interrupts](./Interrupts.md)
3333
- [Interrupt Sources](./Interrupt_Sources.md)
34+
- [HALT](./halt.md)
3435
- [CGB Registers](./CGB_Registers.md)
3536
- [SGB Functions](./SGB_Functions.md)
3637
- [Unlocking and Detecting SGB Functions](./SGB_Unlocking.md)

src/halt.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# `halt`
2+
3+
`halt` is an instruction that pauses the CPU (during which less power is
4+
consumed) when executed. The CPU wakes up as soon as an interrupt is pending,
5+
that is, when the bitwise AND of [`IE`](<#FFFF - IE - Interrupt Enable (R/W)>)
6+
and [`IF`](<#FF0F - IF - Interrupt Flag (R/W)>) is non-zero.
7+
8+
Most commonly, [`IME`](<#IME - Interrupt Master Enable Flag (Write Only)>) is
9+
set. In this case, the CPU simply wakes up, and before executing the instruction
10+
after the `halt`, the [interrupt handler is called](<#Interrupt Handling>)
11+
normally.
12+
13+
If `IME` is *not* set, there are two distinct cases, depending on whether an
14+
interrupt is pending as the `halt` instruction is first executed.
15+
16+
- If no interrupt is pending, `halt` executes as normal, and the CPU resumes
17+
regular execution as soon as an interrupt becomes pending. However, since
18+
`IME`=0, the interrupt is not handled.
19+
- If an interrupt is pending, `halt` immediately exits, as expected, however
20+
the "`halt` bug", explained below, is triggered.
21+
22+
## `halt` bug
23+
24+
Under some circumstances, `pc` fails to be normally incremented.
25+
26+
The most typical trigger, `halt` with `IME`=0 and `[IE] & [IF] != 0`, causes
27+
the byte after the `halt` to be read twice.
28+
29+
The behavior is different when `ei` (whose effect is typically delayed by one
30+
instruction) is followed immediately by a `halt`, and an interrupt is pending
31+
as the `halt` is executed. The interrupt is serviced and the handler called,
32+
but the interrupt returns to the `halt`, which is executed again, and thus
33+
waits for another interrupt.
34+
([Source](https://github.com/LIJI32/SameSuite/blob/master/interrupt/ei_delay_halt.asm))

0 commit comments

Comments
 (0)