1
0
mirror of https://github.com/mre/mos6502.git synced 2024-12-11 15:49:34 +00:00
MOS 6502 emulator written in Rust
Go to file
Matthias 2c65fe7e1b Fix SBC implementation and improve overflow detection
- Correct decimal mode subtraction in SBC operation
- Implement accurate overflow detection for non-decimal mode
- Fix carry flag calculation as inverse of borrow
- Add comments explaining complex bit manipulation for overflow detection
- Update tests to verify correct behavior in both decimal and non-decimal modes

This commit addresses issues with the Subtract with Carry (SBC) operation,
ensuring correct behavior in both decimal and non-decimal modes, and
improves code readability with added comments.
2024-10-18 21:01:06 +02:00
.github Add CI pipeline (#71) 2023-04-20 17:42:18 +02:00
assets
examples Starting on implementing different variants (#88) 2023-10-31 16:45:15 +01:00
notes
src Fix SBC implementation and improve overflow detection 2024-10-18 21:01:06 +02:00
.gitattributes
.gitignore Code Cleanup (#97) 2024-04-27 19:51:39 +01:00
AUTHORS.txt
Cargo.toml bump version 2024-09-26 09:04:18 +02:00
COPYRIGHT
LICENSE
README.md Starting on implementing different variants (#88) 2023-10-31 16:45:15 +01:00

mos6502

MOS6502

docs.rs

An emulator for the MOS 6502 CPU written in Rust.
Tested and validated by solid65.
It builds on stable Rust and supports #[no_std] targets.

What is the MOS 6502?

The MOS Technology 6502 (typically pronounced "sixty-five-oh-two" or "six-five-oh-two") is an 8-bit microprocessor that was designed by a small team led by Chuck Peddle for MOS Technology. [...]

When it was introduced in 1975, the 6502 was the least expensive microprocessor on the market by a considerable margin. It initially sold for less than one-sixth the cost of competing designs from larger companies, such as the 6800 or Intel 8080. Its introduction caused rapid decreases in pricing across the entire processor market. Along with the Zilog Z80, it sparked a series of projects that resulted in the home computer revolution of the early 1980s.

Source: Wikipedia

How to use this library

use mos6502::memory::Bus;
use mos6502::memory::Memory;
use mos6502::instruction::Nmos6502;
use mos6502::cpu;

fn main() {
    // Calculate the greatest common divisor of 56 and 49
    // using Euclid's algorithm.
    let zero_page_data = [56, 49];

    let program = [
        // (F)irst | (S)econd
        // .algo
        0xa5, 0x00,       // Load from F to A
        // .algo_
        0x38,             // Set carry flag
        0xe5, 0x01,       // Substract S from number in A (from F)
        0xf0, 0x07,       // Jump to .end if diff is zero
        0x30, 0x08,       // Jump to .swap if diff is negative
        0x85, 0x00,       // Load A to F
        0x4c, 0x12, 0x00, // Jump to .algo_
        // .end
        0xa5, 0x00,       // Load from S to A
        0xff,
        // .swap
        0xa6, 0x00,       // load F to X
        0xa4, 0x01,       // load S to Y
        0x86, 0x01,       // Store X to F
        0x84, 0x00,       // Store Y to S
        0x4c, 0x10, 0x00, // Jump to .algo
    ];

    let mut cpu = cpu::CPU::new(Memory::new(), Nmos6502);

    cpu.memory.set_bytes(0x00, &zero_page_data);
    cpu.memory.set_bytes(0x10, &program);
    cpu.registers.program_counter = 0x10;

    cpu.run();

    // The expected GCD is 7
    assert_eq!(7, cpu.registers.accumulator);
}

The same can be achieved, by compiling the euclid example yourself.

First install a 6502 assembler and linker, e.g. cc65.

brew install cc65

Then compile and link the assembly file:

cd examples/asm/euclid
ca65 euclid.a65
ld65 -C ../linker.cfg -o euclid.bin euclid.o

This will create a binary file euclid.bin that you can load into the emulator:

use mos6502::memory::Bus;
use mos6502::memory::Memory;
use mos6502::instruction::Nmos6502;
use mos6502::cpu;
use std::fs::read;

fn main() {
    // Calculate the greatest common divisor of 56 and 49
    // using Euclid's algorithm.
    let zero_page_data = [56, 49];

    // Load the binary file from disk
    let program = match read("examples/asm/euclid/euclid.bin") {
        Ok(data) => data,
        Err(err) => {
            println!("Error reading euclid.bin: {}", err);
            return;
        }
    };

    let mut cpu = cpu::CPU::new(Memory::new(), Nmos6502);

    cpu.memory.set_bytes(0x00, &zero_page_data);
    cpu.memory.set_bytes(0x10, &program);
    cpu.registers.program_counter = 0x10;

    cpu.run();

    // The expected GCD is 7
    assert_eq!(7, cpu.registers.accumulator);
}

Credits

This started off as a fork of amw-zero/6502-rs, which seems to be unmaintained at this point.