Skip to content

BillyRuffian/6502

Repository files navigation

MOS6502 Workbench

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.

Features

  • 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, and Device primitives 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

Installation

From RubyGems:

gem install mos6502-workbench

For local development:

bundle install

Usage

The 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)

Building A Machine

The gem now exposes a small machine-building surface:

  • MOS6502::Bus for 16-bit address decoding
  • MOS6502::Device as the peripheral/storage base class
  • MOS6502::RAM and MOS6502::ROM as ready-made devices
  • MOS6502::Machine as 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) # => 0x42

Custom devices should subclass MOS6502::Device and implement read_byte and write_byte. If they need timed behaviour, they can also override tick(cycles).

Tracing And Timing

The emulator now exposes a few hooks intended for downstream machine projects:

  • cpu.cycle_count and cpu.last_cycles track coarse base-cycle timing
  • cpu.subscribe_steps { |event| ... } receives instruction-level trace events
  • bus.subscribe_accesses { |event| ... } receives memory read/write events
  • machine.step, machine.run, machine.irq, and machine.nmi tick 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.

Command-Line Tools

The gem ships with these executables:

  • assemble
  • disassemble
  • run_assembled_program
  • run_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.asm

The TUI supports:

  • space to run or pause
  • n to single-step
  • r to reset
  • [ and ] to change autoplay speed
  • h and l to move the watch-memory window
  • q to quit

Assembler Support

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.rb
  • examples/traced_machine.rb

Development

Run the test suite:

bundle exec rspec

Run RuboCop:

bundle exec rubocop --cache false

Build the gem locally:

gem build mos6502-workbench.gemspec

Run the opt-in Klaus functional ROM test:

RUN_ROM_TESTS=1 bundle exec rspec spec/rom_spec.rb

Project Layout

  • lib/mos6502/workbench.rb is the canonical gem entrypoint
  • lib/mos6502/workbench/ contains the emulator, bus/device/machine primitives, assembler, disassembler, Intel HEX loader, TUI, and version support
  • bin/ contains executable helpers
  • examples/ contains sample assembly programs
  • spec/ contains the automated test suite and ROM harness

License

MIT. See LICENSE.txt.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages