mos6502-workbench is a Ruby MOS 6502 toolkit for building, running, and
debugging 6502 programs. It packages a tested NMOS 6502 CPU emulator together
with an assembler, disassembler, Intel HEX support, a pluggable memory bus for
machine builders, runnable examples, and an optional Ratatui-powered terminal
UI.
- NMOS 6502 CPU emulator with IRQ, NMI, BRK, RTI, decimal mode, and stack support
- Two-pass assembler with labels, expressions,
.org,.byte, and.word - Disassembler that derives its decode table from the emulator opcode map
- Intel HEX import and export
- Pluggable
Bus,Machine,RAM,ROM, andDeviceprimitives for custom computers - CPU step tracing, bus access tracing, and coarse cycle counting for external debuggers and devices
- Example programs and helper scripts
- Optional TUI for stepping through execution, inspecting registers, memory, and stack state
- RSpec suite with coverage gating plus an opt-in Klaus Dormann functional ROM harness
From RubyGems:
gem install mos6502-workbenchFor local development:
bundle installThe canonical require path is:
require 'mos6502/workbench'The main namespace remains MOS6502, so existing code written against the
emulator classes can stay the same:
require 'mos6502/workbench'
cpu = MOS6502::CPU.new
cpu.load([0xA9, 0x42, 0x85, 0x10, 0x00], start_address: 0x8000)
cpu.reset
cpu.run(max_instructions: 2)
puts cpu.read_byte(0x0010)The gem now exposes a small machine-building surface:
MOS6502::Busfor 16-bit address decodingMOS6502::Deviceas the peripheral/storage base classMOS6502::RAMandMOS6502::ROMas ready-made devicesMOS6502::Machineas a composition root around a CPU plus mapped devices
Example:
require 'mos6502/workbench'
machine = MOS6502::Machine.new
machine.map_ram(start_address: 0x0000, end_address: 0x7fff)
rom = Array.new(0x8000, 0xea)
rom[0x0000] = 0xa9 # LDA #$42
rom[0x0001] = 0x42
rom[0x0002] = 0x8d # STA $2000
rom[0x0003] = 0x00
rom[0x0004] = 0x20
rom[0x7ffc] = 0x00 # reset vector -> $8000
rom[0x7ffd] = 0x80
machine.map_rom(rom, start_address: 0x8000)
machine.power_on
machine.run(max_instructions: 2)
puts machine.cpu.read_byte(0x2000) # => 0x42Custom devices should subclass MOS6502::Device and implement read_byte and
write_byte. If they need timed behaviour, they can also override tick(cycles).
The emulator now exposes a few hooks intended for downstream machine projects:
cpu.cycle_countandcpu.last_cyclestrack coarse base-cycle timingcpu.subscribe_steps { |event| ... }receives instruction-level trace eventsbus.subscribe_accesses { |event| ... }receives memory read/write eventsmachine.step,machine.run,machine.irq, andmachine.nmitick mapped devices using the CPU's base cycle counts
The current cycle counts are base timings only. They intentionally do not yet model page-crossing penalties, taken-branch penalties, or a full cycle-accurate bus.
The gem ships with these executables:
assembledisassemblerun_assembled_programrun_klaus_functional_test
Examples:
assemble examples/countdown.asm
assemble --write tmp/countdown.bin examples/countdown.asm
assemble --format intel_hex --write tmp/countdown.hex examples/countdown.asm
disassemble --start '$8000' tmp/countdown.bin
run_assembled_program examples/countdown.asm 20
run_assembled_program --tui examples/countdown.asmThe TUI supports:
spaceto run or pausento single-steprto reset[and]to change autoplay speedhandlto move the watch-memory windowqto quit
The assembler currently supports:
- labels written as
name: - directives:
.org,.byte,.word - hex (
$8000), binary (%1010), decimal (42), and character ('A') literals - expressions using labels,
+,-,<,>, and*for the current address - the official opcode/addressing-mode set implemented by the emulator
See examples/README.md for sample programs and workflows. For machine-building examples, see:
examples/simple_machine.rbexamples/traced_machine.rb
Run the test suite:
bundle exec rspecRun RuboCop:
bundle exec rubocop --cache falseBuild the gem locally:
gem build mos6502-workbench.gemspecRun the opt-in Klaus functional ROM test:
RUN_ROM_TESTS=1 bundle exec rspec spec/rom_spec.rblib/mos6502/workbench.rbis the canonical gem entrypointlib/mos6502/workbench/contains the emulator, bus/device/machine primitives, assembler, disassembler, Intel HEX loader, TUI, and version supportbin/contains executable helpersexamples/contains sample assembly programsspec/contains the automated test suite and ROM harness
MIT. See LICENSE.txt.