A simple NMOS 6502 emulator.
Go to file
2024-04-01 23:40:38 -05:00
.idea Add maintenance badge 2024-04-01 23:31:50 -05:00
src Format 2024-04-01 23:32:56 -05:00
tests Format 2024-04-01 23:32:56 -05:00
.gitignore Initial commit 2024-04-01 23:22:35 -05:00
Cargo.toml Fix incorrect link 2024-04-01 23:38:12 -05:00
LICENSE-APACHE Initial commit 2024-04-01 23:22:35 -05:00
LICENSE-MIT Initial commit 2024-04-01 23:22:35 -05:00
README.md Fix incorrect link 2024-04-01 23:40:38 -05:00

GitHub Actions Workflow Status Documentation MSRV Repository Latest version License unsafe forbidden Maintenance

r6502

Yet another NMOS 6502 emulator.


Designed to support no-std and not require an allocator nor any unsafe code, and be reasonably fast.

The API of this crate shies away from implementing interrupt handling,
instead having you step the emulator one opcode at a time and handle them yourself.

Feature Flags

The following feature flags exist:

Name Description
bcd Enable binary-coded decimal arithmetic.
Enabled by default. Disable if you're writing a NES emulator.
Note that invalid BCD is left untested and will not function faithfully to the NMOS 6502.
bytemuck Enables bytemuck support.
arbitrary Enables arbitrary support. This will pull in std.
serde Enables serde support.
hashbrown Enables hashbrown support.

Example

extern crate std;

use std::eprintln;

use r6502::{Emulator, FunctionReadCallback, FunctionWriteCallback};

fn main() {
    let mut emu = Emulator::default()
        .with_read_callback(FunctionReadCallback(|state: &mut State, addr| {
            // Log reads  
            eprintln!("Read from #${addr:04x}");
            state.memory[addr as usize]
        }))
        .with_write_callback(FunctionWriteCallback(|state: &mut State, addr, byte|
            // Don't write to ROM 
            if addr < 0xFF00 {
                state.memory[addr as usize] = byte
            })
        )
        .with_rom(include_bytes!("rom.bin"))
        .with_program_counter(0x200);

    loop {
        let interrupt_requested = emu.step()
            .expect("found an invalid opcode (only NMOS 6502 opcodes are supported)");
        if interrupt_requested { // Go to IRQ interrupt vector 
            let vector = u16::from_le_bytes([
                emu.read(0xFFFE),
                emu.read(0xFFFF)
            ]);
            emu.state.program_counter = vector;
        }
    }
}

Licensing

This may be licensed under either the MIT or Apache-2.0 license, at your option.