gb/mmio.rs
1//! Memory Map IO address for the GameBoy components.
2//!
3//! Documents are provided by [GB Pan Docs](https://gbdev.io/pandocs/Memory_Map.html)
4
5use voladdress::{Safe, Unsafe, VolAddress, VolBlock};
6
7/// [Joypad](https://gbdev.io/pandocs/Joypad_Input.html#ff00--p1joyp-joypad)
8///
9/// The eight GameBoy action/direction buttons are arranged as a 2x4 matrix.
10/// Select either action or direction buttons by writing to this register, then read out the bits
11/// 0-3.
12///
13/// <table class="bit-descrs"><thead><tr><th></th><th>7</th><th>6</th><th>5</th><th>4</th><th>3</th><th>2</th><th>1</th><th>0</th></tr></thead><tbody><tr><td><strong>P1</strong></td><td colspan="2" class="unused-field"></td><td colspan="1">Select buttons</td><td colspan="1">Select d-pad</td><td colspan="1">Start / Down</td><td colspan="1">Select / Up</td><td colspan="1">B / Left</td><td colspan="1">A / Right</td></tr></tbody></table>
14///
15/// * **Select buttons**: If this bit is `0`, then buttons (SsBA) can be read from the lower
16/// nibble.
17/// * **Select d-pad** : If this bit is `0`, then directional keys can be read from the lower
18/// nibble.
19/// * The lower nibble is *Read-only*. Note that, rather unconventionally for GameBoy, a button
20/// being pressed is seen as the corresponding bit being `0`, not `1`.
21///
22/// If neigher buttons nor d-pad is selected (`$30` was written), then the low nibble reads `$F`
23/// (all buttons released).
24///
25/// If both buttons and d-pad is selected, then the low nibble reads d-pad *or* button is pressed.
26///
27/// # Safety
28/// After writing to [`JOYP`], if [`JOYP`] is read in the following instruction, the
29/// unexpected value will be read. Therefore, if you want it to work as intended, you have
30/// to give a brief delay.
31pub const JOYP: VolAddress<u8, Safe, Unsafe> =
32 unsafe { VolAddress::new(0xFF00) };
33
34/// [Serial transfer data](https://gbdev.io/pandocs/Serial_Data_Transfer_(Link_Cable).html#ff01--sb-serial-transfer-data)
35pub const SB: VolAddress<u8, Safe, Safe> =
36 unsafe { VolAddress::new(0xFF01) };
37
38/// [Serial transfer control](https://gbdev.io/pandocs/Serial_Data_Transfer_(Link_Cable).html#ff02--sc-serial-transfer-control)
39pub const SC: VolAddress<u8, Safe, Safe> =
40 unsafe { VolAddress::new(0xFF02) };
41
42/// [Divider](https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff04--div-divider-register)
43///
44/// This register is incremented at a rate of 16384Hz (~16779Hz on SGB). Writing any value to this
45/// register resets it to `$00`. Additionally, this register is reset when executing the `stop`
46/// instruction, and only begins ticking again once `stop` mode ends. This also occurs during a
47/// [speed switch](https://gbdev.io/pandocs/CGB_Registers.html#ff4d--key1-cgb-mode-only-prepare-speed-switch).
48///
49/// Note: This divider is affected by CGB double speed mode, and will increment at 32768Hz in
50/// double speed.
51pub const DIV: VolAddress<u8, Safe, Safe> =
52 unsafe { VolAddress::new(0xFF04) };
53
54/// [Timer counter](https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff05--tima-timer-counter)
55///
56/// This timer is incremented at the clock frequency specified by the [`TAC`] register.
57/// When the value overflows, it is reset to the value specified in [`TMA`] and an interrupt is
58/// requested.
59pub const TIMA: VolAddress<u8, Safe, Safe> =
60 unsafe { VolAddress::new(0xFF05) };
61
62/// [Timer modulo](https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff06--tma-timer-modulo)
63///
64/// When TIMA overflows, it is reset to the value in this register and Timer interrupt is
65/// requested. Example of use: if TMA is set to $FF, an interrupt is requested at the clock
66/// frequency selected in [`TAC`] (because every increment is an overflow). However, if TMA is set
67/// to $FE, an interrupt is only requested every two increments, which effectively divides the
68/// selected clock by two. Setting TMA to $FD would divide the clock by three, and so on.
69///
70/// If a TMA write is executed on the same M-cycle as the content of [`TMA`] is transferred to
71/// [`TIMA`] due to a timer overflow, the old value is transferred to [`TIMA`]
72pub const TMA: VolAddress<u8, Safe, Safe> =
73 unsafe { VolAddress::new(0xFF06) };
74
75/// [Timer control](https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff07--tac-timer-control)
76///
77/// <table class="bit-descrs"><thead><tr><th></th><th>7</th><th>6</th><th>5</th><th>4</th><th>3</th><th>2</th><th>1</th><th>0</th></tr></thead><tbody><tr><td><strong>TAC</strong></td><td colspan="5" class="unused-field"></td><td colspan="1">Enable</td><td colspan="2">Clock select</td></tr></tbody></table>
78///
79/// - **Enable**: Controls whether `TIMA` is incremented.
80/// Note that `DIV` is **always** counting, regardless of this bit.
81/// - **Clock select**: Controls the frequency at which `TIMA` is incremented, as follows:
82///
83/// <div class="table-wrapper"><table>
84/// <thead>
85/// <tr><th rowspan=2>Clock select</th><th rowspan=2>Increment every</th><th colspan=3>Frequency (Hz)</th></tr>
86/// <tr><th>DMG, SGB2, CGB in single-speed mode</th><th>SGB1</th><th>CGB in double-speed mode</th></tr>
87/// </thead><tbody>
88/// <tr><td>00</td><td>256 M-cycles </td><td> 4096</td><td> ~4194</td><td> 8192</td></tr>
89/// <tr><td>01</td><td>4 M-cycles </td><td>262144</td><td>~268400</td><td>524288</td></tr>
90/// <tr><td>10</td><td>16 M-cycles </td><td> 65536</td><td> ~67110</td><td>131072</td></tr>
91/// <tr><td>11</td><td>64 M-cycles </td><td> 16384</td><td> ~16780</td><td> 32768</td></tr>
92/// </tbody>
93/// </table></div>
94///
95/// Note that writing to this register may increase [`TIMA`] once!
96/// For more information, please refer [GB Pan Docs](https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff07--tac-timer-control)
97pub const TAC: VolAddress<u8, Safe, Safe> =
98 unsafe { VolAddress::new(0xFF07) };
99
100/// [Interrupt flag](https://gbdev.io/pandocs/Interrupts.html#ff0f--if-interrupt-flag)
101///
102/// <table class="bit-descrs"><thead><tr><th></th><th>7</th><th>6</th><th>5</th><th>4</th><th>3</th><th>2</th><th>1</th><th>0</th></tr></thead><tbody><tr><td><strong>IF</strong></td><td colspan="3" class="unused-field"></td><td colspan="1">Joypad</td><td colspan="1">Serial</td><td colspan="1">Timer</td><td colspan="1">LCD</td><td colspan="1">VBlank</td></tr></tbody></table>
103///
104/// * **VBlank** (Read/Write): Controls whether the VBlank interrupt handler is being requested.
105/// * **LCD** (Read/Write) : Controls whether the LCD interrupt handler is being requested.
106/// * **Timer** (Read/Write) : Controls whether the Timer interrupt handler is being requested.
107/// * **Serial** (Read/Write) : Controls whether the Serial interrupt handler is being requested.
108/// * **Joypad** (Read/Write) : Controls whether the Joypad interrupt handler is being requested.
109///
110///
111/// When an interrupt request signal (some internal wire going from the PPU/APU/... to the CPU)
112/// changes from low to high, the corresponding bit in the [`IF`] register becomes set. For
113/// example, bit 0 becomes set when the PPU enters the VBlank period.
114///
115/// Any set bits in the [`IF`] register are only **requesting** an interrupt. The actual
116/// **execution** of the interrupt handler happnes only if both the `IME` flag and the
117/// corresponding bit in the [`IE`] register are set; otherwise the interrupt "waits" until
118/// **both** `IME` and [`IE`] allow it to be serviced.
119///
120/// Since the CPU automatically sets and clears the bits in the [`IF`] register, it is usually not
121/// necessary to write to the [`IF`] register. However, the user still do that in order to manually
122/// request (or discard) interrupts. Just like real interrupts, a manually requeseted interrupt
123/// isn't serviced unless/until `IME` and [`IE`] allow it.
124pub const IF: VolAddress<u8, Safe, Safe> =
125 unsafe { VolAddress::new(0xFF0F) };
126
127/// [Sound channel 1 sweep](https://gbdev.io/pandocs/Audio_Registers.html#ff10--nr10-channel-1-sweep)
128pub const NR10: VolAddress<u8, Safe, Safe> =
129 unsafe { VolAddress::new(0xFF10) };
130
131/// [Sound channel 1 length timer & duty cycle](https://gbdev.io/pandocs/Audio_Registers.html#ff11--nr11-channel-1-length-timer--duty-cycle)
132pub const NR11: VolAddress<u8, Unsafe, Safe> =
133 unsafe { VolAddress::new(0xFF11) };
134
135/// [Sound channel 1 volume & envelope](https://gbdev.io/pandocs/Audio_Registers.html#ff12--nr12-channel-1-volume--envelope)
136pub const NR12: VolAddress<u8, Safe, Safe> =
137 unsafe { VolAddress::new(0xFF12) };
138
139/// [Sound channel 1 period low](https://gbdev.io/pandocs/Audio_Registers.html#ff13--nr13-channel-1-period-low-write-only)
140pub const NR13: VolAddress<u8, (), Safe> =
141 unsafe { VolAddress::new(0xFF13) };
142
143/// [Sound channel 1 period high & control](https://gbdev.io/pandocs/Audio_Registers.html#ff14--nr14-channel-1-period-high--control)
144pub const NR14: VolAddress<u8, Unsafe, Safe> =
145 unsafe { VolAddress::new(0xFF14) };
146
147/// [Sound channel 2 length timer & duty cycle](https://gbdev.io/pandocs/Audio_Registers.html#sound-channel-2--pulse)
148pub const NR21: VolAddress<u8, Unsafe, Safe> =
149 unsafe { VolAddress::new(0xFF16) };
150
151/// [Sound channel 2 volume & envelope](https://gbdev.io/pandocs/Audio_Registers.html#sound-channel-2--pulse)
152pub const NR22: VolAddress<u8, Safe, Safe> =
153 unsafe { VolAddress::new(0xFF17) };
154
155/// [Sound channel 2 period low](https://gbdev.io/pandocs/Audio_Registers.html#sound-channel-2--pulse)
156pub const NR23: VolAddress<u8, (), Safe> =
157 unsafe { VolAddress::new(0xFF18) };
158
159/// [Sound channel 2 period high & control](https://gbdev.io/pandocs/Audio_Registers.html#sound-channel-2--pulse)
160pub const NR24: VolAddress<u8, Unsafe, Safe> =
161 unsafe { VolAddress::new(0xFF19) };
162
163/// [Sound channel 3 DAC enable](https://gbdev.io/pandocs/Audio_Registers.html#ff1a--nr30-channel-3-dac-enable)
164pub const NR30: VolAddress<u8, Safe, Safe> =
165 unsafe { VolAddress::new(0xFF1A) };
166
167/// [Sound channel 3 length timer](https://gbdev.io/pandocs/Audio_Registers.html#ff1b--nr31-channel-3-length-timer-write-only)
168pub const NR31: VolAddress<u8, (), Safe> =
169 unsafe { VolAddress::new(0xFF1B) };
170
171/// [Sound channel 3 output level](https://gbdev.io/pandocs/Audio_Registers.html#ff1c--nr32-channel-3-output-level)
172pub const NR32: VolAddress<u8, Safe, Safe> =
173 unsafe { VolAddress::new(0xFF1C) };
174
175/// [Sound channel 3 period low](https://gbdev.io/pandocs/Audio_Registers.html#ff1d--nr33-channel-3-period-low-write-only)
176pub const NR33: VolAddress<u8, (), Safe> =
177 unsafe { VolAddress::new(0xFF1D) };
178
179/// [Sound channel 3 period high & control](https://gbdev.io/pandocs/Audio_Registers.html#ff1e--nr34-channel-3-period-high--control)
180pub const NR34: VolAddress<u8, Unsafe, Safe> =
181 unsafe { VolAddress::new(0xFF1E) };
182
183/// [Sound channel 4 length timer](https://gbdev.io/pandocs/Audio_Registers.html#ff20--nr41-channel-4-length-timer-write-only)
184pub const NR41: VolAddress<u8, (), Safe> =
185 unsafe { VolAddress::new(0xFF20) };
186
187/// [Master volume & VIN panning](https://gbdev.io/pandocs/Audio_Registers.html#ff24--nr50-master-volume--vin-panning)
188pub const NR50: VolAddress<u8, Safe, Safe> =
189 unsafe { VolAddress::new(0xFF24) };
190
191/// [Sound panning](https://gbdev.io/pandocs/Audio_Registers.html#ff25--nr51-sound-panning)
192pub const NR51: VolAddress<u8, Safe, Safe> =
193 unsafe { VolAddress::new(0xFF25) };
194
195/// [Sound on/off](https://gbdev.io/pandocs/Audio_Registers.html#ff26--nr52-audio-master-control)
196pub const NR52: VolAddress<u8, Safe, Safe> =
197 unsafe { VolAddress::new(0xFF26) };
198
199/// [Storage for one of the sound channel's waveform](https://gbdev.io/pandocs/Audio_Registers.html#ff30ff3f--wave-pattern-ram)
200///
201/// Wave RAM is 16 bytes long; each byte holds two "samples", each 4 bits.
202///
203/// As CH3 plays, it reads wave RAM left to right, upper nibble first. That is, `$FF30`'s upper
204/// nibble, `$FF30`'s lower nibble, `$FF31`'s upper nibble, and so on.
205///
206/// # Warning
207/// When CH3 is started, the first sample read is the one at index 1, i.e. the lower nibble of the
208/// first byte, NOT the upper nibble.
209///
210/// # Safety
211/// Accessing wave RAM while CH3 is **active** (i.e. playing) causes accesses to misbehave:
212/// * On AGB, reads return `$FF`, and writes are ignored.
213/// * On monochrome consoles, wave RAM can only be accessed on the same cycle that CH3 does.
214/// Otherwise, reads return `$FF`, and writes are ignored.
215/// * On other consoles, the byte accessed will be the on CH3 is currently reading; that is, if Ch3
216/// is currently reading one of the first two samples, the CPU will really access `$FF30`,
217/// regardless of the address being used.
218///
219/// Wave RAM can be accessed normally even if the DAC is on, as long as the channel is not active.
220/// This is especially relevant on GBA whose mixer behaves as if DACs are always enabled.
221///
222/// The way it works is that wave RAM is a 16-byte memory buffer, and whie it's playing, CH3 has
223/// priority over the CPU when choosing which of those 16 bytes is accessed. So, from the CPU's
224/// point of view, wave RAM reads out the same byte, reagardless of the address.
225pub const WAVE_RAM: VolBlock<u8, Unsafe, Unsafe, 16> =
226 unsafe { VolBlock::new(0xFF30) };
227
228/// [LCD control](https://gbdev.io/pandocs/LCDC.html#ff40--lcdc-lcd-control)
229pub const LCDC: VolAddress<u8, Safe, Unsafe> =
230 unsafe { VolAddress::new(0xFF40) };
231
232/// [LCD status](https://gbdev.io/pandocs/STAT.html#ff41--stat-lcd-status)
233pub const STAT: VolAddress<u8, Safe, Unsafe> =
234 unsafe { VolAddress::new(0xFF41) };
235
236/// [Viewport Y position](https://gbdev.io/pandocs/Scrolling.html#ff42ff43--scy-scx-background-viewport-y-position-x-position)
237pub const SCY: VolAddress<u8, Safe, Safe> =
238 unsafe { VolAddress::new(0xFF42) };
239
240/// [Viewport X position](https://gbdev.io/pandocs/Scrolling.html#ff42ff43--scy-scx-background-viewport-y-position-x-position)
241pub const SCX: VolAddress<u8, Safe, Safe> =
242 unsafe { VolAddress::new(0xFF43) };
243
244/// [LCD Y coordinate](https://gbdev.io/pandocs/STAT.html#ff44--ly-lcd-y-coordinate-read-only)
245pub const LY: VolAddress<u8, Safe, ()> =
246 unsafe { VolAddress::new(0xFF44) };
247
248/// [LY compare](https://gbdev.io/pandocs/STAT.html#ff45--lyc-ly-compare)
249pub const LYC: VolAddress<u8, Safe, Safe> =
250 unsafe { VolAddress::new(0xFF45) };
251
252/// [OAM DMA source address & start](https://gbdev.io/pandocs/OAM_DMA_Transfer.html#ff46--dma-oam-dma-source-address--start)
253pub const DMA: VolAddress<u8, Safe, Safe> =
254 unsafe { VolAddress::new(0xFF46) };
255
256/// [BG palette data](https://gbdev.io/pandocs/Palettes.html#ff47--bgp-non-cgb-mode-only-bg-palette-data)
257pub const BGP: VolAddress<u8, Safe, Safe> =
258 unsafe { VolAddress::new(0xFF47) };
259
260/// [OBJ palette 0 data](https://gbdev.io/pandocs/Palettes.html#ff48ff49--obp0-obp1-non-cgb-mode-only-obj-palette-0-1-data)
261pub const OBP0: VolAddress<u8, Safe, Safe> =
262 unsafe { VolAddress::new(0xFF48) };
263
264/// [OBJ palette 1 data](https://gbdev.io/pandocs/Palettes.html#ff48ff49--obp0-obp1-non-cgb-mode-only-obj-palette-0-1-data)
265pub const OBP1: VolAddress<u8, Safe, Safe> =
266 unsafe { VolAddress::new(0xFF49) };
267
268/// [Window Y position](https://gbdev.io/pandocs/Scrolling.html#ff4aff4b--wy-wx-window-y-position-x-position-plus-7)
269pub const WY: VolAddress<u8, Safe, Unsafe> =
270 unsafe { VolAddress::new(0xFF4A) };
271
272/// [Window X position plus 7](https://gbdev.io/pandocs/Scrolling.html#ff4aff4b--wy-wx-window-y-position-x-position-plus-7)
273pub const WX: VolAddress<u8, Safe, Unsafe> =
274 unsafe { VolAddress::new(0xFF4B) };
275
276/// [Prepare speed switch](https://gbdev.io/pandocs/CGB_Registers.html#ff4d--key1-cgb-mode-only-prepare-speed-switch)
277#[cfg(any(feature="color", doc))]
278#[doc(cfg(feature="color"))]
279pub const KEY1: VolAddress<u8, Safe, Unsafe> =
280 unsafe { VolAddress::new(0xFF4D) };
281
282/// [VRAM bank](https://gbdev.io/pandocs/CGB_Registers.html#ff4f--vbk-cgb-mode-only-vram-bank)
283///
284/// This register can be written to change VRAM banks. Only bit 0 matters, all other bits are
285/// ignored.
286#[cfg(any(feature="color", doc))]
287#[doc(cfg(feature="color"))]
288pub const VBK: VolAddress<u8, Safe, Safe> =
289 unsafe { VolAddress::new(0xFF4F) };
290
291/// [VRAM DMA source high](https://gbdev.io/pandocs/CGB_Registers.html#ff51ff52--hdma1-hdma2-cgb-mode-only-vram-dma-source-high-low-write-only)
292#[cfg(any(feature="color", doc))]
293#[doc(cfg(feature="color"))]
294pub const HDMA1: VolAddress<u8, (), Safe> =
295 unsafe { VolAddress::new(0xFF51) };
296
297/// [VRAM DMA source low](https://gbdev.io/pandocs/CGB_Registers.html#ff51ff52--hdma1-hdma2-cgb-mode-only-vram-dma-source-high-low-write-only)
298#[cfg(any(feature="color", doc))]
299#[doc(cfg(feature="color"))]
300pub const HDMA2: VolAddress<u8, (), Safe> =
301 unsafe { VolAddress::new(0xFF52) };
302
303/// [VRAM DMA destination high](https://gbdev.io/pandocs/CGB_Registers.html#ff53ff54--hdma3-hdma4-cgb-mode-only-vram-dma-destination-high-low-write-only)
304#[cfg(any(feature="color", doc))]
305#[doc(cfg(feature="color"))]
306pub const HDMA3: VolAddress<u8, (), Safe> =
307 unsafe { VolAddress::new(0xFF53) };
308
309/// [VRAM DMA destination low](https://gbdev.io/pandocs/CGB_Registers.html#ff53ff54--hdma3-hdma4-cgb-mode-only-vram-dma-destination-high-low-write-only)
310#[cfg(any(feature="color", doc))]
311#[doc(cfg(feature="color"))]
312pub const HDMA4: VolAddress<u8, (), Safe> =
313 unsafe { VolAddress::new(0xFF54) };
314
315/// [VRAM DMA length/mode/start](https://gbdev.io/pandocs/CGB_Registers.html#ff55--hdma5-cgb-mode-only-vram-dma-lengthmodestart)
316#[cfg(any(feature="color", doc))]
317#[doc(cfg(feature="color"))]
318pub const HDMA5: VolAddress<u8, Safe, Unsafe> =
319 unsafe { VolAddress::new(0xFF55) };
320
321/// [Infrared communications port](https://gbdev.io/pandocs/CGB_Registers.html#ff56--rp-cgb-mode-only-infrared-communications-port)
322#[cfg(any(feature="color", doc))]
323#[doc(cfg(feature="color"))]
324pub const RP: VolAddress<u8, Safe, Unsafe> =
325 unsafe { VolAddress::new(0xFF56) };
326
327/// [Background color palette specification](https://gbdev.io/pandocs/Palettes.html#ff68--bcpsbgpi-cgb-mode-only-background-color-palette-specification--background-palette-index)
328#[cfg(any(feature="color", doc))]
329#[doc(cfg(feature="color"))]
330pub const BCPS: VolAddress<u8, Safe, Safe> =
331 unsafe { VolAddress::new(0xFF68) };
332
333/// [Background color palette data](https://gbdev.io/pandocs/Palettes.html#ff69--bcpdbgpd-cgb-mode-only-background-color-palette-data--background-palette-data)
334#[cfg(any(feature="color", doc))]
335#[doc(cfg(feature="color"))]
336pub const BCPD: VolAddress<u8, Unsafe, Unsafe> =
337 unsafe { VolAddress::new(0xFF69) };
338
339/// [OBJ color palette specification](https://gbdev.io/pandocs/Palettes.html#ff6aff6b--ocpsobpi-ocpdobpd-cgb-mode-only-obj-color-palette-specification--obj-palette-index-obj-color-palette-data--obj-palette-data)
340#[cfg(any(feature="color", doc))]
341#[doc(cfg(feature="color"))]
342pub const OCPS: VolAddress<u8, Unsafe, Unsafe> =
343 unsafe { VolAddress::new(0xFF6A) };
344
345/// [OBJ color palette data](https://gbdev.io/pandocs/Palettes.html#ff6aff6b--ocpsobpi-ocpdobpd-cgb-mode-only-obj-color-palette-specification--obj-palette-index-obj-color-palette-data--obj-palette-data)
346#[cfg(any(feature="color", doc))]
347#[doc(cfg(feature="color"))]
348pub const OCPD: VolAddress<u8, Unsafe, Unsafe> =
349 unsafe { VolAddress::new(0xFF6B) };
350
351/// [Object priority mode](https://gbdev.io/pandocs/CGB_Registers.html#ff6c--opri-cgb-mode-only-object-priority-mode)
352#[cfg(any(feature="color", doc))]
353#[doc(cfg(feature="color"))]
354pub const OPRI: VolAddress<u8, Unsafe, Unsafe> =
355 unsafe { VolAddress::new(0xFF6C) };
356
357/// [WRAM bank](https://gbdev.io/pandocs/CGB_Registers.html#ff70--svbk-cgb-mode-only-wram-bank)
358#[cfg(any(feature="color", doc))]
359#[doc(cfg(feature="color"))]
360pub const SVBK: VolAddress<u8, Safe, Safe> =
361 unsafe { VolAddress::new(0xFF70) };
362
363/// [Audio digital outputs 1 & 2](https://gbdev.io/pandocs/Audio_details.html#ff76--pcm12-cgb-mode-only-digital-outputs-1--2-read-only)
364///
365/// The low nibble is a copy of a sound channel 1's digital output, the high nibble is a copy of
366/// sound channel 2's
367#[cfg(any(feature="color", doc))]
368#[doc(cfg(feature="color"))]
369pub const PCM12: VolAddress<u8, Safe, ()> =
370 unsafe { VolAddress::new(0xFF76) };
371
372/// [Audio digital outputs 3 & 4](https://gbdev.io/pandocs/Audio_details.html#ff77--pcm34-cgb-mode-only-digital-outputs-3--4-read-only)
373///
374/// Same with [`PCM12`], but with channels 3 and 4.
375#[cfg(any(feature="color", doc))]
376#[doc(cfg(feature="color"))]
377pub const PCM34: VolAddress<u8, Safe, ()> =
378 unsafe { VolAddress::new(0xFF77) };
379
380/// [Interrupt enable](https://gbdev.io/pandocs/Interrupts.html#ffff--ie-interrupt-enable)
381///
382/// <table class="bit-descrs"><thead><tr><th></th><th>7</th><th>6</th><th>5</th><th>4</th><th>3</th><th>2</th><th>1</th><th>0</th></tr></thead><tbody><tr><td><strong>IE</strong></td><td colspan="3" class="unused-field"></td><td colspan="1">Joypad</td><td colspan="1">Serial</td><td colspan="1">Timer</td><td colspan="1">LCD</td><td colspan="1">VBlank</td></tr></tbody></table>
383///
384/// * **VBlank** (Read/Write) : Controls whether the VBlank interrupt handler may be called (see
385/// [`IF`]).
386/// * **LCD** (Read/Write) : Controls whether the LCD interrupt handler may be called (see [`IF`])
387/// * **Timer** (Read/Write) : Controls whether the Timer interrupt handler may be calle (see
388/// [`IF`])
389/// * **Serial** (Read/Write) : Controls whether the Serial interrupt handler may be called (see
390/// [`IF`])
391/// * **Joypad** (Read/Write) : Controls whether the Joypad interrupt handler may be called (see
392/// [`IF`])
393pub const IE: VolAddress<u8, Safe, Safe> =
394 unsafe { VolAddress::new(0xFFFF) };