Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ Desktop.ini
# Gradle wrapper (gradlew[.bat] + gradle-wrapper.jar) and keystore.properties.example
# are intentionally tracked.
android/**/build/
android/.gradle/
**/.gradle/
android/local.properties
android/keystore.properties
*.jks
Expand Down
50 changes: 30 additions & 20 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,61 @@

## Project Structure & Module Organization

This is a Rust 2021 workspace pinned to Rust 1.86 in `rust-toolchain.toml`.
This is a Rust 2024 workspace pinned to Rust 1.96 in `rust-toolchain.toml`.
Workspace crates live under `crates/`: `rustynes-core` contains the emulator facade,
scheduler, save states, and shared integration logic; `rustynes-cpu`, `rustynes-ppu`,
`rustynes-apu`, and `rustynes-mappers` model the hardware subsystems; `rustynes-frontend`
contains the `rustynes` desktop binary; `rustynes-test-harness` runs ROM-based
regression tests. Project documentation is in `docs/`, planning tickets are in
`to-dos/`, benchmark targets sit beside crate code in `benches/`, and licensed
test ROM fixtures are under `tests/roms/`.
test ROM fixtures are under `tests/roms/`. `ref-docs/` contains immutable hardware and emulation reference; updates go in dated supplemental files. ADRs go in `docs/adr/` (Michael Nygard format).

## Build, Test, and Development Commands

- `cargo build --workspace`: build all crates.
- `cargo run --release -p rustynes-frontend -- path/to/rom.nes`: run the emulator
frontend against a local ROM.
- `cargo run --release -p rustynes-frontend -- path/to/rom.nes`: run the emulator frontend against a local ROM.
- `cargo test --workspace`: run unit and integration tests.
- `cargo test --workspace --features test-roms`: include ROM harness tests.
- `cargo test --workspace --features test-roms,commercial-roms`: include 60-ROM commercial oracle (needs local dumps).
- `cargo clippy --workspace --all-targets -- -D warnings`: run the CI lint gate.
- `cargo fmt --all --check`: verify Rust formatting; use `cargo fmt --all` to
apply it.
- `cargo fmt --all --check`: verify Rust formatting; use `cargo fmt --all` to apply it.
- `cargo bench --workspace`: run Criterion benchmarks.
- `cargo build -p rustynes-core --target thumbv7em-none-eabihf --no-default-features`: cross-compile to no_std.

## Coding Style & Naming Conventions

Use rustfmt defaults with crate-level import grouping from `rustfmt.toml`.
`.editorconfig` requires UTF-8, LF endings, final newlines, and spaces: four for
Rust, two for Markdown/TOML/YAML. Public APIs should have rustdoc comments.
Workspace lints warn on `unsafe_code` and `missing_docs`, with Clippy
`pedantic` and `nursery` enabled; justify local `#[allow]` uses. Prefer
allocation-light code in CPU, PPU, APU, mapper, and scheduler hot paths.
`.editorconfig` requires UTF-8, LF endings, final newlines, and spaces: four for Rust, two for Markdown/TOML/YAML.
Public APIs should have rustdoc comments. Workspace lints warn on `missing_docs`, with Clippy `pedantic` and `nursery` enabled; justify local `#[allow]` uses.

**CRITICAL DOCUMENTATION RULE:** Always craft extensive, robust, and technically detailed Rust preambles (`//!`) at the top of crates/modules and inline source code comments (`///` and `//`). Documentation must match the quantity, quality, length, and technical depth seen in existing `rustynes-*` crates, comprehensively explaining the *why* alongside architectural details, memory safety guarantees, and lockstep timing considerations.

`unsafe` blocks require a `// SAFETY:` comment explaining the invariant. The chip stack is `#![no_std]` + `extern crate alloc;`.
No emojis in code, comments, or commits (project policy).
Hot paths (`Cpu::tick`, `Ppu::tick`, mapper register access) MUST avoid allocations, prefer fixed arrays, and be highly optimized. Target <= 2 ms/frame headless.

## Testing Guidelines

Place crate-specific integration tests in `crates/<crate>/tests/`. ROM-driven
coverage belongs in `crates/rustynes-test-harness/tests/` with fixtures documented in
`tests/roms/README.md` and `tests/roms/LICENSES.md`. Never commit commercial
ROMs; use `tests/roms/external/` for local-only material. Add focused tests for
mapper, timing, save-state, and audio changes, and run the `test-roms` feature
when touching harness code or fixtures.
ROMs; use `tests/roms/external/` for local-only material.
For accuracy work: pin the failing test ROM expectation first, then implement until it passes. The blargg / kevtris / mmc3_test_2 / AccuracyCoin suites are the closed-form definition of "cycle-accurate."

## Commit & Pull Request Guidelines

Use Conventional Commits, matching the existing history:
`fix(ppu): handle OAMDATA writes during rendering` or
`docs(changelog): record release notes`. Keep subjects imperative, under 72
characters, and without trailing periods. Before opening a PR, run fmt, clippy,
and tests; link the relevant ticket from `to-dos/`; update `CHANGELOG.md` for
user-visible behavior; and update `docs/` when architecture, mapper support, or
frontend behavior changes.
`fix(ppu): handle OAMDATA writes during rendering` or `docs(changelog): record release notes`.
Keep subjects imperative, under 72 characters, and without trailing periods.
Branch names should follow `<type>/<short-desc>`.

**CRITICAL COMMIT RULE:** Commit message bodies should ALWAYS be robust, comprehensive, and technically detailed. Go beyond a summary to explain architectural impacts, mathematical implementations, memory constraints, and deep technical specifics.

Before opening a PR, run fmt, clippy, and tests; link the relevant ticket from `to-dos/`; update `CHANGELOG.md` under `[Unreleased]` for user-visible behavior; and update `docs/` when architecture, mapper support, or frontend behavior changes. A chip-behavior change MUST touch both the chip code and the chip's `docs/<subsystem>.md` to prevent drift.

## Documentation & Markdown Guidelines

- `docs/STATUS.md` is the authoritative single source of truth for per-suite pass counts, the mapper matrix, and version policy.
- Markdownlint is a CI gate (pre-commit, pinned `markdownlint-cli v0.39.0`). Verify with `pre-commit run markdownlint --all-files`.
- `.markdownlint.json` keeps `MD013`/`MD033`/`MD041` disabled by design.
- `rustynes-core` re-exports public types from the chip crates; downstream consumers should depend on `rustynes-core` rather than the chip crates directly.
148 changes: 146 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ members = [
"crates/rustynes-gfx-shaders",
"crates/rustynes-hdpack",
"crates/rustynes-ra",
"crates/rustynes-monetization",
"crates/rustynes-monetization", "crates/rustynes-libretro",
]

[workspace.package]
Expand Down
30 changes: 30 additions & 0 deletions crates/rustynes-core/src/nes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,36 @@ pub struct Nes {
}

impl Nes {
/// Returns a reference to the internal WRAM.
pub fn wram(&self) -> &[u8] {
self.bus.ram.as_ref()
}

/// Returns a mutable reference to the internal WRAM.
pub fn wram_mut(&mut self) -> &mut [u8] {
self.bus.ram.as_mut()
}

/// Returns a reference to the cartridge SRAM (if any).
pub fn sram(&self) -> &[u8] {
self.bus.mapper.sram()
}

/// Returns a mutable reference to the cartridge SRAM (if any).
pub fn sram_mut(&mut self) -> &mut [u8] {
self.bus.mapper.sram_mut()
}

/// Returns a reference to the internal VRAM (nametables).
pub fn vram(&self) -> &[u8] {
self.bus.ppu.vram_ref()
}

/// Returns a mutable reference to the internal VRAM (nametables).
pub fn vram_mut(&mut self) -> &mut [u8] {
self.bus.ppu.vram_mut()
}

/// Build a new emulator from raw ROM bytes (iNES 1.0 or NES 2.0).
///
/// # Errors
Expand Down
25 changes: 25 additions & 0 deletions crates/rustynes-libretro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "rustynes-libretro"
description = "Cycle-accurate NES emulator libretro core wrapper"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
authors.workspace = true
repository.workspace = true
keywords = ["nes", "emulator", "famicom", "libretro", "retroarch"]
categories = ["emulators"]

[lib]
crate-type = ["cdylib"]

[lints]
workspace = true

[dependencies]
libc = "0.2.186"
rust-libretro = "0.3.2"

Comment thread
doublegate marked this conversation as resolved.
[dependencies.rustynes-core]
path = "../rustynes-core"
default-features = false
Loading