You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: AI/ARCHITECTURE.md
+38Lines changed: 38 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -66,6 +66,32 @@ For an early-stage repo, a simplified equivalent is acceptable as long as these
66
66
- For the PPU, that shared T-cycle timeline is also the dot timeline; dot-by-dot behavior is the intended baseline.
67
67
- Long-running hardware operations triggered by MMIO writes, such as OAM DMA, should become explicit in-flight subsystem state on that shared timeline rather than immediate bulk side effects.
68
68
69
+
## Global scheduler policy
70
+
71
+
- The DMG core must have one global scheduler that advances the whole machine on one deterministic T-cycle timeline.
72
+
- A `GlobalScheduler` plus `step_t_cycle()`-style entry point, or an equally explicit equivalent, is the preferred architectural shape.
73
+
- Do not run PPU, timer, APU, serial, joypad, DMA, or interrupt production as unsynchronized threads or independently clocked loops inside the core.
74
+
- The recommended per-T-cycle phase order is:
75
+
1. external event ingress
76
+
2. master clock / shared system-counter tick
77
+
3. resolution of free-running counter-derived edges
78
+
4. autonomous peripheral ticks
79
+
5. bus arbitration for the current T-cycle
80
+
6. CPU micro-operation
81
+
7. MMIO side-effect commit
82
+
8. interrupt aggregation into `IF`
83
+
9. CPU wake / interrupt-accept evaluation
84
+
- This phase order is an architectural contract for observable behavior, not a claim that Nintendo published one canonical internal scheduler.
85
+
- Another internal decomposition is acceptable only if it preserves the same observable dependencies for PPU mode visibility, DMA blocking, timer overflow delay, serial completion timing, joypad visible-edge timing, MMIO visibility, and CPU interrupt acceptance.
86
+
- Phase `3` is for events derived from the free-running shared clock. Device-local MMIO semantics such as `DIV` reset effects, `FF46` DMA start, `SC.7` transfer start, or `LCDC.7` LCD transitions still belong to the device that owns the register when the access commits in phase `7`.
87
+
- The scheduler should keep one cycle-local context object or equivalent that can carry at least:
88
+
- the global T-cycle index
89
+
- current-cycle external events
90
+
- already-derived counter-edge signals
91
+
- current ownership or arbitration facts
92
+
- queued side effects and interrupt requests
93
+
- The scheduler coordinates ordering and synchronization points; it must not reimplement timer, PPU, DMA, serial, joypad, APU, cartridge, or CPU-local quirks internally.
94
+
69
95
## Console model policy
70
96
71
97
- The core must expose an explicit console model concept.
@@ -125,6 +151,10 @@ to immediately materialize as a separate directory.
125
151
- stable per-T-cycle subsystem stepping order
126
152
- explicit global synchronization points
127
153
- orchestration between CPU, PPU, DMA, timer, APU, and peripherals
154
+
- ingress of timestamped external events such as host input changes or external serial clocks
155
+
- explicit separation between free-running device ticks, bus arbitration, MMIO commit, interrupt aggregation, and CPU wake / accept points
156
+
- cycle-local context and tracing support so phase order remains visible in code and logs
157
+
- subsystem-facing APIs that keep stage boundaries explicit, for example free-running tick, CPU step, MMIO commit, and interrupt-request aggregation steps, even if final names differ
128
158
129
159
### `bus/`
130
160
@@ -134,6 +164,7 @@ to immediately materialize as a separate directory.
134
164
- access arbitration
135
165
- integration of cartridge, VRAM, WRAM, OAM, I/O, HRAM, IE, and boot ROM mapping
136
166
- modeling of access restrictions and conflicts when hardware makes them visible
167
+
- two-layer arbitration made of decode / nominal ownership followed by requester-aware access policy
137
168
- routing of OAM and `FEA0-FEFF` access attempts and CPU-provided address-bearing micro-events into the DMG-family OAM corruption path when applicable
138
169
- MMIO routing to the subsystem-owned register contract for each mapped address
139
170
- one source of truth for MMIO ownership, model availability, access class, and read/write side-effect policy
@@ -154,6 +185,7 @@ to immediately materialize as a separate directory.
154
185
- fixed-priority pending selection
155
186
- MMIO exposure of `FF0F` and `FFFF`
156
187
- separation between controller-owned request state and CPU-owned `IME` / acceptance flow
188
+
- aggregation of source requests into `IF` without collapsing that step into CPU dispatch
157
189
158
190
### `boot/`
159
191
@@ -200,6 +232,7 @@ to immediately materialize as a separate directory.
200
232
- DIV / TIMA / TMA / TAC
201
233
- edge-sensitive timer timing
202
234
- timer interrupt request generation
235
+
- ownership of the timer overflow pipeline, including the delayed `IF` request relative to logical overflow
203
236
204
237
### `joypad/`
205
238
@@ -210,6 +243,7 @@ to immediately materialize as a separate directory.
210
243
- joypad interrupt generation through the shared interrupt-controller path
211
244
- input-driven wake signaling for CPU `STOP` integration
212
245
- separation between frontend input collection and emulated joypad semantics
246
+
- distinction between hardware-facing button changes, visible `JOYP` changes, joypad IRQ requests, and `STOP` wake signaling
213
247
214
248
### `serial/`
215
249
@@ -219,6 +253,7 @@ to immediately materialize as a separate directory.
219
253
- peer or link-endpoint boundary
220
254
- serial interrupt generation through the shared interrupt-controller path
221
255
- separation between emulated serial hardware and any host transport implementation
256
+
- ownership of transfer-complete detection, `SC.7` clear timing, and completion-triggered serial IRQ requests
222
257
223
258
### `cartridge/`
224
259
@@ -287,6 +322,7 @@ to immediately materialize as a separate directory.
287
322
288
323
## Ownership boundary notes
289
324
325
+
- The scheduler owns phase order, cycle context, and subsystem call order; it must not become a second implementation of timer, PPU, DMA, serial, joypad, or CPU rules.
290
326
- The boot subsystem owns firmware assets, model-aware boot configuration, and boot-ROM enable/disable state.
291
327
- The boot subsystem also owns the source-of-truth startup snapshot for direct-boot entry, while the target subsystems still own the live semantics of their registers once execution begins.
292
328
- The DMA subsystem owns transfer state and transfer requests over time.
@@ -298,8 +334,10 @@ to immediately materialize as a separate directory.
298
334
- Frontends, test harnesses, and tooling should provide serial peers, scripted bits, loopback, or external clock pulses through a serial-endpoint boundary rather than by writing received bytes directly into `SB`.
299
335
- The serial subsystem owns the translation from MMIO-visible `SB` / `SC` plus peer-provided bits and clocks into live transfer progress, `SB` intermediate state, and serial interrupt requests.
300
336
- The timer owns the shared divider/system-counter state and visible `DIV`, while the APU owns `DIV-APU`, frame-sequencer state, channel-active state, DAC state, mixer state, and HPF state derived from that shared timing source.
337
+
- The bus owns central decode, requester arbitration, and blocked-access policy; CPU, DMA, and future transfer engines must not bypass that one policy path with caller-specific memory shortcuts.
301
338
- The bus applies boot mapping, DMA contention, and blocked-access semantics using that subsystem state; CPU code should not embed those rules directly.
302
339
- The bus owns address decode and MMIO dispatch, but the device that owns a register must own its read, write, and side-effect semantics.
340
+
- The interrupt controller owns `IF` / `IE` state and fixed-priority pending selection, but it does not decide when the CPU actually accepts an interrupt or wakes from `HALT` / `STOP`.
303
341
- The cartridge owns the meaning of persistent RAM and RTC content, while the save backend owns durable storage mechanics such as file format, paths, versioning, and atomic replacement.
304
342
- Save-state machinery must not be smuggled into the cartridge persistence boundary; CPU, PPU, APU, WRAM, and other console-owned state belong to a different system.
305
343
- MMIO metadata should be centralized enough that readable bits, writable bits, dynamic bits, reserved bits, and model-specific availability are not re-declared ad hoc in several modules.
Copy file name to clipboardExpand all lines: AI/EXECUTION.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,6 +33,14 @@
33
33
- Prefer reproducible validation over intuition.
34
34
- Preserve the project's T-cycle timing foundation; do not introduce M-cycle-first scheduling shortcuts as a local convenience.
35
35
36
+
## When touching the global scheduler or cross-subsystem ordering
37
+
38
+
- Preserve the fixed per-T-cycle phase contract defined by `AI/ARCHITECTURE.md` and `AI/TIMING-AND-ACCURACY.md`.
39
+
- Update the matching hardware docs together when the observable ordering of DMA, PPU mode visibility, MMIO side effects, interrupt visibility, or CPU acceptance changes.
40
+
- Keep requester arbitration, MMIO commit, and interrupt aggregation explicit; do not replace them with ad hoc subsystem-to-subsystem calls just because one local test passes.
41
+
- Add or update focused cross-subsystem tests such as DMA-vs-CPU, delayed timer `IF`, serial completion plus IRQ, joypad visible-edge IRQ, `HALT` / IRQ priority, and `STAT`-versus-bus coherence.
42
+
- Prefer cycle traces over aggregate instruction summaries when validating scheduler work.
43
+
36
44
## Definition of done
37
45
38
46
- Behavior is implemented consistently with hardware semantics and project architecture.
Copy file name to clipboardExpand all lines: AI/ROADMAP.md
+38Lines changed: 38 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -148,6 +148,30 @@ For the authoritative structure and boundaries, see
148
148
149
149
---
150
150
151
+
## Cross-cutting scheduler foundation workstream
152
+
153
+
This workstream spans the early roadmap because the scheduler contract must be
154
+
fixed before later CPU, DMA, PPU, timer, serial, joypad, and APU work can stay
155
+
coherent without refactoring.
156
+
157
+
1.**Explicit scheduler phases** (`Phase 0`)
158
+
Goal: refactor stepping around one visible `step_t_cycle()`-style entry point with fixed per-T-cycle phases.
159
+
Acceptance criteria: the phase order is explicit and stable, there are no hidden cross-calls that bypass it, the scheduler owns ordering rather than reimplementing subsystem rules, and one `CycleContext`-style object or equivalent carries current-cycle events, derived signals, ownership facts, and queued side effects or IRQ requests.
160
+
2.**Central arbitration** (`Phase 1`)
161
+
Goal: unify decode, ownership, and access policy behind one requester-aware bus path.
162
+
Acceptance criteria: CPU and DMA use the same arbitration route, decode/ownership and access-policy layers stay distinct, and DMG OAM DMA correctly leaves CPU with HRAM only.
163
+
3.**IRQ aggregation layer** (`Phase 2`)
164
+
Goal: separate source request, `IF` visibility, and CPU acceptance.
165
+
Acceptance criteria: PPU, timer, serial, and joypad only request; the CPU accepts by `IME/IE/IF` and fixed priority; timer keeps its delayed one-M-cycle request timing.
166
+
4.**Cycle logging** (`Phase 0`, expanded later)
167
+
Goal: make the actual ordering visible per T-cycle.
168
+
Acceptance criteria: traces can expose phase, bus owner, CPU micro-op, PPU mode, DMA activity, timer or serial events, and `IF/IE/IME`.
Goal: lock down the scheduler invariants at cross-subsystem boundaries.
171
+
Acceptance criteria: focused tests cover DMA versus CPU, delayed timer `IF`, serial completion plus IRQ, joypad visible `High -> Low` plus IRQ, `HALT` / IRQ priority, and `STAT`-versus-bus coherence.
172
+
173
+
---
174
+
151
175
## Recommended implementation order
152
176
153
177
### Phase 0 — Verification, debugging, and base architecture infrastructure
@@ -200,8 +224,10 @@ This phase must define:
200
224
201
225
- base hardware types in `model/`
202
226
- T-cycle scheduler skeleton
227
+
- explicit per-T-cycle phase order with one `step_t_cycle()`-style top-level entry point
203
228
- definition of responsibilities by module
204
229
- initial interfaces between CPU, bus, PPU, DMA, timer, cartridge, and debugger
230
+
- a cycle-local context shape carrying external events, derived signals, ownership facts, and queued side effects or IRQ requests
205
231
- conventions to avoid mixing frontend logic with core logic
206
232
207
233
#### Done criteria
@@ -210,7 +236,9 @@ This phase must define:
210
236
- the project can run base tests against `gb-core`
211
237
- there is a reusable minimum tracing infrastructure
212
238
- the scheduler has a defined notion of T-cycle advancement
239
+
- the scheduler phase order is explicit in code and docs rather than implicit in subsystem call chains
213
240
- the responsibility split between modules is fixed
241
+
- cycle traces can expose enough per-T-cycle state to debug scheduler ordering issues
214
242
- the core does not depend on `gb-cli`, `gb-desktop`, or `gb-web` to function
215
243
- the architecture is prepared to incorporate CGB without contaminating DMG behavior yet
216
244
@@ -253,6 +281,7 @@ Build the real foundation of the emulated system on top of which CPU, timer, DMA
253
281
- global stepping by T-cycle
254
282
- explicit notion of dot compatible with the PPU
255
283
- stable stepping order for subsystems inside the scheduler
284
+
- explicit ordering between external-event ingress, shared-counter advance, derived edges, free-running peripherals, bus arbitration, CPU micro-ops, MMIO commit, IRQ aggregation, and CPU wake / accept
256
285
257
286
##### Bus and memory map
258
287
@@ -261,6 +290,7 @@ Build the real foundation of the emulated system on top of which CPU, timer, DMA
261
290
- modeling of echo RAM and unusable areas
262
291
- access arbitration infrastructure
263
292
- one central decode path across `0x0000-0xFFFF` with explicit owner and access policy per region
293
+
- distinct decode / ownership and access-policy layers in that arbitration path
264
294
- centralized MMIO register routing instead of a generic RAM-like `FF00-FF7F` block
265
295
266
296
##### Base cartridge
@@ -293,9 +323,11 @@ Build the real foundation of the emulated system on top of which CPU, timer, DMA
293
323
#### Done criteria
294
324
295
325
- the system can advance by T-cycles consistently
326
+
- the scheduler phase order is stable, explicit, and shared across subsystems instead of encoded through call-site accidents
296
327
- all memory accesses go through `bus/`
297
328
- the memory map is modeled completely for DMG
298
329
- every DMG address region has an explicit owner, read behavior, write behavior, and blocked-access policy where applicable
330
+
- bus arbitration resolves decode/ownership before applying requester-specific restrictions, and DMA-versus-CPU precedence is centralized instead of duplicated
299
331
- every MMIO address in `0xFF00-0xFF7F` and `0xFFFF` has an explicit routed owner and contract rather than accidental default byte-storage behavior
300
332
- mixed MMIO registers are represented as per-field contracts rather than as plain read/write bytes plus a coarse mask
301
333
- the cartridge subsystem parses `0x0100-0x014F` into a typed header structure and preserves CGB/SGB compatibility flags for later work
@@ -423,6 +455,7 @@ Build a truly temporal CPU core, where observable behavior emerges from internal
423
455
- real temporal effect of EI and DI
424
456
- interrupt priority
425
457
- interrupt acceptance timing
458
+
- explicit separation between source request, `IF` aggregation, CPU wake, and CPU interrupt acceptance
426
459
- HALT
427
460
- STOP
428
461
- HALT bug
@@ -433,6 +466,7 @@ Build a truly temporal CPU core, where observable behavior emerges from internal
433
466
- instructions generate their real bus accesses
434
467
- the timer advances with the global scheduler
435
468
- interrupts and HALT are integrated into the real execution flow
469
+
- source requests become visible in `IF` before the CPU accepts them, and timer keeps its delayed request timing instead of being flattened into same-cycle overflow service
436
470
- direct-boot timer state does not fake `DIV` or related registers through disconnected visible-only initialization
437
471
- real boot executes through the same CPU fetch/decode/execute engine used for the rest of the machine
438
472
- real boot reaches cartridge code only through an executed `FF50` write and next-fetch handoff
@@ -470,11 +504,13 @@ Integrate OAM DMA as a real transfer mechanism inside the system architecture, c
470
504
- real temporal copy progression
471
505
- integration with bus arbitration
472
506
- observability of DMA start, progress, and completion
507
+
- scheduler-visible DMA state that bus arbitration can use on the same T-cycle
473
508
474
509
#### Done criteria
475
510
476
511
- the transfer is not implemented as an instantaneous memory copy
477
512
- arbitration correctly reflects DMA effects on concurrent accesses
513
+
- CPU-versus-DMA precedence is decided centrally through bus arbitration instead of CPU-local blocking logic
478
514
- the system can trace DMA over time
479
515
480
516
#### Risks if delayed too much
@@ -697,6 +733,7 @@ Complete basic system peripherals on top of an already consolidated bus, schedul
697
733
- serial interrupt generation driven by real transfer completion rather than by transfer start
698
734
- serial port functional at the emulated hardware level
699
735
- trace tools to observe both peripherals
736
+
- scheduler-visible regression coverage for their IRQ timing and CPU wake interactions
700
737
701
738
#### Done criteria
702
739
@@ -716,6 +753,7 @@ Complete basic system peripherals on top of an already consolidated bus, schedul
716
753
- serial interrupt requests occur only at transfer completion, when the eighth shift clears `SC.7`
717
754
- both are integrated through the bus and scheduler
718
755
- their interrupts and states are observable and testable
756
+
- their event timing does not depend on frame callbacks or host timers bypassing the T-cycle scheduler
Copy file name to clipboardExpand all lines: AI/TIMING-AND-ACCURACY.md
+21Lines changed: 21 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -52,6 +52,25 @@ When implementing timing:
52
52
- When external documentation expresses a timing rule in M-cycles or microseconds, restate the corresponding T-cycle value in project docs and code whenever that rule becomes behaviorally relevant or is recorded as deferred validation work.
53
53
- Keep the timing model clean enough that future CGB double-speed behavior can be expressed as an extension of the same temporal foundation rather than a separate clocking design.
54
54
55
+
## Global scheduler rule
56
+
57
+
- The core should advance through one fixed per-T-cycle scheduler contract, not through ad hoc call chains between subsystems.
58
+
- The recommended ordering is:
59
+
1. external event ingress
60
+
2. master clock / shared system-counter tick
61
+
3. free-running counter-derived edge resolution
62
+
4. autonomous peripheral ticks
63
+
5. bus arbitration
64
+
6. CPU micro-operation
65
+
7. MMIO side-effect commit
66
+
8. interrupt aggregation into `IF`
67
+
9. CPU wake / interrupt-accept evaluation
68
+
- This is a project-level deterministic ordering rule chosen to preserve documented dependencies; it is not presented as the one true internal Nintendo implementation.
69
+
- Free-running divider-derived events such as timer input edges and `DIV-APU` edge detection belong to step `3`, after the shared counter advances and before autonomous peripherals consume those edges.
70
+
- Immediate MMIO effects produced by a write on the access T-cycle, such as `DIV` reset behavior, `FF46` DMA start, `SC.7` transfer start, or `LCDC.7` LCD transitions, still belong to the owning device when the access commits in step `7`.
71
+
-`IF` updates from hardware sources belong to step `8`; CPU acceptance is a later CPU-owned decision and must not be collapsed into the producer path.
72
+
- Another internal implementation shape is acceptable only if these same observable dependencies remain true.
73
+
55
74
## Practical timing rule
56
75
57
76
- CPU, PPU, timer, APU, DMA, and bus-visible effects should be expressible on a shared T-cycle timeline.
@@ -80,3 +99,5 @@ When implementing timing:
80
99
- Slow APU control clocks such as length, envelope, and CH1 sweep must remain distinct from each channel's own fast waveform timer and from the host sample or resampler cadence.
81
100
- Host-rate sample production should observe already-stepped hardware state; it must not become the clock that drives the APU core.
82
101
- When cartridge hardware uses wall-clock-like progression outside powered-on execution, such as battery-backed `MBC3` RTC advance between sessions, model that through an explicit elapsed-time source at the persistence boundary and restate any powered-on bus-visible timing rule in T-cycles when it becomes behaviorally relevant.
102
+
- Timer, joypad, serial, and the APU frame sequencer must not be tied to video-frame or VBlank callbacks; they live on the shared machine timeline even when their visible effects are unrelated to the LCD.
103
+
- Bus restrictions and MMIO-visible state must tell one coherent story on that timeline. For example, `STAT.mode`, VRAM/OAM accessibility, DMA blocking, `SC.7`, `TIMA/TMA/IF`, and visible `JOYP` state must align with the same current-cycle machine state the scheduler uses internally.
0 commit comments