m68k-rs
A safe, pure Rust implementation of the Motorola 68000 family CPU emulator.
One core for transaction-accurate hardware emulation and high-throughput high-level emulation (HLE).
Features
- Complete CPU family support: M68000 through M68060, including EC/LC variants and the SCC68070
- Two explicit execution contracts: transaction-accurate cycle scheduling for hardware emulators, and an instruction-budgeted fast path for HLE
- Bus-visible accuracy: 68000/68010 two-word prefetch, model-specific access ordering, and internal clock synchronization through
AddressBus::sync - Memory-safe core: The interpreter — instruction semantics, decode, exceptions, MMU, FPU — is 100% safe Rust. The optional fast paths (fastmem batch execution and the trace JIT) use a small, contract-documented
unsafeperimeter, fenced by step-vs-batch equivalence tests - FPU emulation: Software 80-bit extended precision, packed decimal, and model-specific 68881/68882/68040/68060 behavior
- MMU emulation: 68030/68040/68060 translation, ATCs, transparent translation,
PTEST, fault frames, and writeback - HLE-ready: Built-in trap interception for High-Level Emulation
- Save-state ready: Optional
serdesupport serializes architectural state while rebuilding runtime caches on load - Extensively tested: Validated against multiple industry-standard test suites
Quick Start
Add to your Cargo.toml:
[]
= "0.3"
The default build has no JIT compiler dependency. Native applications that use
run_batch() can enable Cranelift compilation explicitly:
[]
= { = "0.3", = ["jit"] }
Basic Usage
use ;
// Implement your memory bus
High-Level Emulation (HLE)
Intercept traps for OS emulation or debugger integration with CPU/bus access:
use ;
;
// All methods in HleHandler are optional (default return is false).
// Return `true` to indicate the HLE handled the trap (suppressing the hardware exception).
// Return `false` to let the CPU take the standard hardware exception.
Choosing an Approach
| Method | Budget | Execution contract | Host-visible exit |
|---|---|---|---|
step() |
One instruction | Transaction-accurate AddressBus accesses and cycles |
Surfaces A-line, F-line, TRAP, BKPT, and illegal instructions without taking their exception |
step_with_hle_handler() |
One instruction | Same precise path as step() |
Offers traps to HleHandler; unhandled traps take the hardware exception |
execute() |
CPU cycles | Precise path; whole instructions may overshoot the requested cycles | Takes traps as hardware exceptions and returns consumed cycles |
run_for_cycles() |
CPU cycles | Precise path with actual cycle and instruction totals | Surfaces traps like step() and reports STOP separately |
run_batch() |
Instructions | Throughput path using decoded-op caching, optional direct RAM, and portable or jit-enabled native hot-loop traces |
Surfaces traps, STOP, watched PCs, or budget exhaustion |
Use step() for debugger-style control. Use run_for_cycles() when a
machine scheduler needs to advance the CPU by a clock budget without losing
bus ordering or trap state:
use CycleBatchExit;
let result = cpu.run_for_cycles;
match result.exit
Use step_with_hle_handler() when patching selected guest OS calls while
allowing every unhandled trap to follow hardware behavior. Use
run_batch() for HLE workloads where host-call latency and instruction
throughput matter more than observing the physical prefetch bus.
Supported CPU Types
| CPU | Description |
|---|---|
M68000 |
Original 68000 (24-bit address bus) |
M68010 |
68010 with virtual memory support |
M68EC020 |
68020 embedded controller (no MMU) |
M68020 |
Full 68020 with 32-bit address bus |
M68EC030 |
68030 embedded controller (no MMU) |
M68030 |
Full 68030 with on-chip MMU |
M68EC040 |
68040 embedded controller (no FPU/MMU) |
M68LC040 |
68040 lite (no FPU) |
M68040 |
Full 68040 with FPU and MMU |
M68060 |
Superscalar 68060 with FPU and MMU |
SCC68070 |
Philips SCC68070 variant |
Validation & Testing
This emulator has been rigorously validated against multiple industry-standard test suites to ensure correctness:
SingleStepTests (m68000)
The SingleStepTests project provides exhaustive per-instruction fixtures from MAME's microcoded 68000 core. The suite covers every supplied instruction file and 261,894 cases, including:
- All addressing modes and operand sizes
- Edge cases for condition codes (CCR/SR)
- BCD arithmetic (ABCD, SBCD, NBCD)
- Multiply/divide overflow handling
- Exception frame generation
- Cycle and transaction auditing: all 261,894 cases match their fixture cycle and bus-access totals, with separate ignored audit tools for access sequence and per-access timing analysis
Musashi Reference Implementation
We also run binaries from Musashi, a widely deployed M68000 emulator. The integration tests:
- Execute complete Musashi test binaries
- Verify register state, memory contents, and exception handling
- Cover 68000 through 68040 instruction sets
- Explicitly exclude legacy cases whose undefined BCD flags or illegal 68000 encodings conflict with the hardware-oriented SingleStepTests model
Cross-CPU Verification
Additional test suites verify behavior across CPU generations:
- FPU tests: 80-bit arithmetic, transcendental functions, packed decimal, memory operands, rounding modes, and save/restore
- MMU translation tests: 68030/68040/68060 table walks, ATCs, TTR matching, page crossings, fault frames, and writeback
- Privilege tests: User/supervisor mode transitions, TRAP behavior
- Exception tests: Per-model frames, resumable bus faults, double faults, and address errors
- Execution-path differential tests: Cold/warm cache state, self-modifying code, cycle batches, fast batches, and native traces
Test Coverage
tests/
├── singlestep_m68000_v1_tests.rs # Exhaustive 68000 fixture suite
├── musashi_tests.rs # Musashi integration binaries
├── m68020_tests.rs ... # Generation-specific behavior
├── m68060_tests.rs # 68060 integer, FPU, and MMU behavior
├── fpu_accuracy.rs # Extended-precision differential tests
├── run_for_cycles_tests.rs # Precise cycle-batch boundary contract
├── run_batch_tests.rs # HLE fast-path equivalence and exits
└── fixtures/
├── m68000/ # External SingleStepTests checkout
└── Musashi/ # Musashi reference binaries
Architecture
m68k/
├── core/ # CPU state, interpreter, timing, caches, and trace JIT
├── dasm/ # Disassembler
├── fpu/ # 80-bit FPU, packed decimal, and transcendental operations
└── mmu/ # 68030/68040/68060 translation and ATCs
Key Types
| Type | Description |
|---|---|
CpuCore |
Main CPU state and execution APIs |
CpuType |
CPU model selection enum |
AddressBus |
Extensible memory, device, fetch-cache, timing, and fast-RAM contract |
LinearMemoryBus / FastMem |
Ready-made flat memory and optional direct-RAM window |
HleHandler |
Trap interception callbacks |
StepResult |
Single-instruction result |
CycleBatchResult / CycleBatchExit |
Precise cycle-scheduled execution result |
BatchResult / BatchExit |
High-throughput instruction-batch result |
CpuCore::is_stopped() |
STOP state check |
CpuCore::is_halted() |
Double-fault halt check |
Performance
Accuracy and throughput are separate, deliberate contracts:
- Precise execution —
step,step_with_hle_handler,execute, andrun_for_cyclesuse the interpreter and ordinaryAddressBuscalls. These paths preserve bus-visible prefetch, access ordering, internal-clock synchronization, fault state, and model-specific cycle accounting. - Throughput execution —
run_batchreuses decoded operations and executes eligible hot backward-branch traces through a portable micro-op loop. The opt-injitfeature compiles those traces with Cranelift on native targets. A bus may expose a contiguousFastMemwindow to keep eligible RAM operands inside the trace. Guarded exits and self-modifying-code checks fall back without partially committing an instruction.
The two paths share instruction semantics and are continuously compared in cold-cache, warm-cache, memory, control-flow, and fault tests. This keeps the hardware contract simple for machine emulators while allowing HLE systems to opt into lower dispatch overhead explicitly.
License
MIT License - see LICENSE for details.
Contributing
Contributions are welcome! Please ensure:
- All tests pass:
cargo test - No clippy warnings:
cargo clippy -- -D warnings - Code is formatted:
cargo fmt
Acknowledgments
- Musashi - Reference implementation and test fixtures
- SingleStepTests - Exhaustive instruction test vectors
- The M68000 Programmer's Reference Manual