Skip to main content

Crate hram

Crate hram 

Source
Expand description

Typed handles to the Game Boy’s High RAM (HRAM, 0xFF80..=0xFFFE).

HRAM is a 127-byte region the CPU can still reach while an OAM DMA holds the bus, and the ldh instructions address it in a single byte. Cells declared with the hram! macro are read and written with the immediate ldh (n) form (2 bytes / 3 cycles): the linker assigns each cell a fixed HRAM address and the low byte is baked into the instruction. That is faster and smaller than the 3-byte / 4-cycle absolute ld (nn) used for WRAM.

§Which kind to declare

An access one byte wide is a single instruction, and the CPU takes interrupts only between instructions, so it cannot be observed half done. A wider access is several instructions and an interrupt landing in the middle leaves the reader with a value that never existed. The three kinds differ in what they do about that.

KindWidthAccess
HramAtomicCell<T>one byteget() / set()
HramCell<T>up to MAX_BYTESget(cs) / set(cs, v)
HramArea<N>anyraw pointers

HramCell takes a CriticalSection because nothing else can make a multi-instruction access indivisible on this CPU. Obtaining the token is the caller’s business; a cell reached only from the main loop, never from an interrupt handler, still needs one.

Both cells hold a CellValue, which under the bank-safe feature also has to survive a bank switch.

§Examples

#![feature(asm_experimental_arch)]
use gb_hram::hram;

hram! {
    /// Frames elapsed, bumped by the VBlank handler.
    pub static FRAME: HramAtomicCell<u8>;
    static SCROLL: HramCell<ScrollState>;
    static OAM_DMA: HramArea<13>;
}

fn tick() {
    FRAME.set(FRAME.get().wrapping_add(1));   // ldh a,(n) / ldh (n),a
}

Write static NAME as "symbol": ...; to export the storage under a fixed symbol, to share a cell with C or assembly. The symbol is emitted with the target’s usual prefix.

The accessors emit ldh inline asm in the calling crate, so that crate needs #![feature(asm_experimental_arch)].

§Zero initialisation

HRAM is NOLOAD, so nothing is loaded from ROM, and a conforming runtime is required to clear 0xFF80..=0xFFFE before main. A cell whose type has a valid all-zero bit pattern therefore starts at 0 and may be read before it is first written; any other type must be written first.

§Feature flags

  • bank-safe — Require every cell value to be BankSafe, so a pointer to banked code cannot be parked in HRAM and outlive its bank.

Modules§

prelude
Common imports for HRAM access (use gb_hram::prelude::*).

Macros§

hram
Declare static HRAM cells and areas, each at a linker-assigned High RAM address.

Structs§

CriticalSection
Critical section token.
HramArea
A raw, fixed-size region of High RAM, addressed through pointers.
HramAtomicCell
Storage for a one-byte cell, accessed without a CriticalSection.
HramCell
Storage for a cell read and written under a CriticalSection.

Constants§

MAX_BYTES
The widest HramCell value an access unrolls into straight-line ldhs. HRAM is only 127 bytes, so cells are small; a wider type is a compile error.

Traits§

CellValuebank-safe
What an HRAM cell may hold.
HramAccess
Read and write an HRAM cell under a CriticalSection.
HramAtomicAccess
Read and write a one-byte HRAM cell without a CriticalSection.