aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mssola@mssola.com>2026-09-07 16:38:16 +0200
committerMiquel Sabaté Solà <mssola@mssola.com>2026-09-07 16:38:16 +0200
commit44f98890a6d91cd9f0b64dec743a22a6e0013590 (patch)
treec8c7605b3115f1b7da5007bdffc031b637421a7c
parent292f6ba2ed1d0b828ad84d4d4475f8523eef00a0 (diff)
downloadtools.nes-44f98890a6d91cd9f0b64dec743a22a6e0013590.tar.gz
tools.nes-44f98890a6d91cd9f0b64dec743a22a6e0013590.zip
vnf: improve documentation
Provide documentation for the library, and improve the documentation for some of the structs and interfaces. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
-rw-r--r--README.md12
-rw-r--r--lib/vnf/README.md4
-rw-r--r--lib/vnf/src/lib.rs58
3 files changed, 65 insertions, 9 deletions
diff --git a/README.md b/README.md
index 8537eb7..99f10b1 100644
--- a/README.md
+++ b/README.md
@@ -30,10 +30,14 @@ information about it. Read more about it in
`runrom` is an NES/Famicom emulator that doesn't attempt to run a ROM
graphically. Instead, it just runs code and exposes the data on memory,
-registers, etc. for a given run. Thus, `runrom` is a tool to run an NES/Famicom
-programatically, so developers can use it to test their ROM files under certain
-conditions. Read more about it in
-[./crates/runrom/README.md](./crates/runrom/README.md).
+registers, etc. for a given run. This is all done via the [vnf](./lib/vnf)
+library, which allows a developer to programatically run a ROM file from a given
+address, poke memory addresses, submit joypad inputs, etc. For some uses,
+running `runrom` will be fine to get a glimpse of the execution of a piece of
+code, but in some other cases (e.g. unit tests for a specific function on your
+NES game), using `vnf` will be a better fit. In any case, you can read more
+about all of this on [runrom's documentation](./crates/runrom/README.md), and on
+[vnf's documentation](./lib/vnf/README.md).
## License
diff --git a/lib/vnf/README.md b/lib/vnf/README.md
new file mode 100644
index 0000000..8e51163
--- /dev/null
+++ b/lib/vnf/README.md
@@ -0,0 +1,4 @@
+The `vnf` library allows you to programmatically run NES/Famicom ROM files under
+certain conditions. You can look for examples on the
+[../../tests/vnf-tests](../../tests/vnf-tests) binary crate, or check the
+documentation via the usual `cargo doc` commands.
diff --git a/lib/vnf/src/lib.rs b/lib/vnf/src/lib.rs
index 852b6df..dfa2f7f 100644
--- a/lib/vnf/src/lib.rs
+++ b/lib/vnf/src/lib.rs
@@ -1,3 +1,26 @@
+//! # Virtual NES/Famicom
+//!
+//! This library provides all the needed interfaces in order to run an
+//! NES/Famicom ROM programmatically. It allows any developer to pick up a ROM
+//! file, start execution from a given address and stop it at any point. Along
+//! the way, developers can poke for memory accesses, joypad inputs, etc.; and
+//! they can check all the state of the instantiated Virtual Machine to validate
+//! that the code runs as expected. The state also considers chips like the PPU
+//! and the APU, but it does not produce graphics nor sound. This is done in
+//! purpose, as this is all meant to be headless, so it can be run in CI/CD
+//! environments without the hassle of coming up with solutions for
+//! graphics/sound support.
+//!
+//! All in all, the goal of this library is twofold:
+//!
+//! 1. Support [`runrom`](../runrom/index.html) in any way so all the desired
+//! features can be implemented.
+//! 2. Provide a sane API with regards to running and inspecting an
+//! NES/Famicom emulator.
+//!
+//! This way, NES/Famicom developers can write tests for their NES/Famicom
+//! games, checking on specific hot spots for how registers and the memory are
+//! modified.
use header::Header;
use std::assert_matches;
use std::collections::HashMap;
@@ -8,7 +31,9 @@ use std::path::Path;
use xixanta::opcodes::AddressingMode;
use xixanta::opcodes::{Instruction, InstructionIdentifier, OPCODES};
-/// Values on the 'status' register converted to bools for easier use.
+/// The 'status' register from the CPU. All flags are set as booleans for easier
+/// use, and the 'break_mark' byte contains the break mark from the last 'brk'
+/// instruction.
#[derive(Debug)]
pub struct StatusRegister {
pub negative: bool,
@@ -116,7 +141,7 @@ pub struct PPU {
pub oam_dma: u8,
}
-/// A byte from the memory, which other than the actual value, also contains
+/// A byte from memory, which other than the actual value, also contains
/// different stats for it.
#[derive(Clone, Copy, Debug, Default)]
pub struct MemoryCell {
@@ -144,7 +169,10 @@ pub enum MemoryInitialValue {
}
/// Allows users to define a policy for how the memory should be initialized for
-/// the given Machine.
+/// the given Machine. This is one of the parameters to be passed on the
+/// initialization of [`Machine`]. This policy will tell the machine how memory
+/// should be initialized, which sectors are allowed to be read/written, and
+/// what's the lowest point that the stack pointer can reach.
#[derive(Debug)]
pub struct MemoryPolicy {
/// The initial value to be given for each cell.
@@ -462,7 +490,27 @@ impl Machine {
})
}
- /// Push the given 'inputs' to the controller identified by 'id'.
+ /// Push the given 'inputs' to the controller identified by 'id'. In order
+ /// to set the 'inputs' parameter, refer to the constants from
+ /// [`Joypad`]. This way, after initializing a [`Machine`] object, one could
+ /// set the inputs to be considered like so:
+ ///
+ /// ```
+ /// machine.push_inputs_to(
+ /// 0,
+ /// &[
+ /// (Joypad::BUTTON_DOWN | Joypad::BUTTON_B),
+ /// (Joypad::BUTTON_UP | Joypad::BUTTON_A),
+ /// Joypad::BUTTON_A,
+ /// ],
+ /// );
+ /// ```
+ ///
+ /// Then, these values will be the ones being passed whenever the joypad 0
+ /// is read.
+ ///
+ /// Be mindful on the amount of inputs being read by the code, as they will
+ /// be consumed upon use.
///
/// NOTE: for now only standard controllers 0 and 1 are supported.
pub fn push_inputs_to(&mut self, id: usize, inputs: &[u8]) {
@@ -836,7 +884,7 @@ impl Machine {
}
/// Execute the current instruction.
- pub fn execute(&mut self) -> Result<(), String> {
+ fn execute(&mut self) -> Result<(), String> {
self.status_register.overflow = false;
match self.current_instruction.identifier {