Skip to main content

gb_pak/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4//! The Game Pak's own hardware.
5//!
6//! The memory bank controller answers writes to the ROM address range as register
7//! writes, and one 8 KiB window at `0xA000..=0xBFFF` shows whatever those
8//! registers last selected. For example SRAM, where a game saves its data.
9//!
10//! # Sharing the window
11//!
12//! Every peripheral here shares that window, and selecting one deselects the
13//! rest, so they do not nest:
14//!
15//! ```ignore
16//! // Wrong: the second read comes from the rtc.
17//! FILE.open(cs, |f| {
18//!     let a = f.gold.get();
19//!     let t = rtc::time(cs);   // selects rtc registers
20//!     let b = f.gold.get();    // reads the rtc, not the save
21//! });
22//! ```
23//!
24//! An interrupt handler nests the same way without the code showing it, and one
25//! racing a scope for the same bytes would be a data race. [`Sram::open`](sram::Sram::open)
26//! takes a [`CriticalSection`] to rule that out, from `gb::interrupt::free` or
27//! `critical_section::with`. The rest only write registers, and the rule above is
28//! all that keeps a handler off them.
29//!
30//! # What a cartridge has
31//!
32//! `cargo-gb` derives the capabilities below from `cartridge_type` and `ram_size`
33//! in `header.toml`, so a program that reaches for hardware the cartridge lacks
34//! fails to compile rather than writing to a chip that is not there.
35//!
36//! MBC1 spends the same two register bits on ROM banks above 512 KiB and on SRAM
37//! banks, so `wide_banks` and more than one SRAM bank cannot both be set.
38
39#![doc = "| Module | Needs | Present on |"]
40#![doc = "|---|---|---|"]
41#![doc = "| [`sram`](mod@crate::sram) | `ram_size` above zero | MBC1, MBC3, MBC5 |"]
42#![cfg_attr(gb_pak_rtc, doc = "| [`rtc`] | `+TIMER` | MBC3 |")]
43#![cfg_attr(gb_pak_rumble, doc = "| [`rumble`] | `+RUMBLE` | MBC5 |")]
44#![cfg_attr(gb_pak_tilt, doc = "| [`tilt`], [`eeprom`] | MBC7 | MBC7 |")]
45
46/// The shared window. Everything but the motor is read through it.
47pub(crate) const WINDOW: usize = 0xA000;
48pub(crate) const WINDOW_LEN: usize = 0x2000;
49
50pub use critical_section::CriticalSection;
51
52pub(crate) mod reg;
53
54pub mod sram;
55
56pub use gb_pak_macros::sram;
57
58#[cfg(gb_pak_rtc)]
59#[cfg_attr(docsrs, doc(cfg(gb_pak_rtc)))]
60pub mod rtc;
61
62#[cfg(gb_pak_rumble)]
63#[cfg_attr(docsrs, doc(cfg(gb_pak_rumble)))]
64pub mod rumble;
65
66#[cfg(gb_pak_tilt)]
67#[cfg_attr(docsrs, doc(cfg(gb_pak_tilt)))]
68pub mod tilt;
69
70#[cfg(gb_pak_tilt)]
71#[cfg_attr(docsrs, doc(cfg(gb_pak_tilt)))]
72pub mod eeprom;