Expand description
§r68k - Motorola 68000 CPU Emulator
A cycle-accurate Motorola 68000 CPU emulator, ported from Karl Stenerud’s battle-tested Musashi emulator which has been successfully running in the MAME project for years.
§Features
- Complete MC68000 instruction set implementation
- Cycle-accurate emulation verified against Musashi via property-based testing
- All addressing modes supported (Dn, An, (An), (An)+, -(An), (d,An), (d,An,Xn), etc.)
- Full exception handling (Address Error, Illegal Instruction, Traps, Interrupts)
- Supervisor/User mode with separate stack pointers
- Customizable memory interface via the
AddressBustrait - Customizable interrupt handling via the
InterruptControllertrait - Zero production dependencies
§Quick Start
use r68k::cpu::ConfiguredCore;
use r68k::ram::PagedMem;
use r68k::interrupts::AutoInterruptController;
// Create memory with 0x00 as the uninitialized byte pattern
let mut memory = PagedMem::new(0x00000000);
// Write reset vectors: SSP at 0x00, PC at 0x04
// Initial stack pointer
memory.write_u8(0x00, 0x00);
memory.write_u8(0x01, 0x01);
memory.write_u8(0x02, 0x00);
memory.write_u8(0x03, 0x00); // SSP = 0x00010000
// Initial program counter
memory.write_u8(0x04, 0x00);
memory.write_u8(0x05, 0x00);
memory.write_u8(0x06, 0x10);
memory.write_u8(0x07, 0x00); // PC = 0x00001000
// Write a NOP instruction at 0x1000
memory.write_u8(0x1000, 0x4E);
memory.write_u8(0x1001, 0x71); // NOP = 0x4E71
// Create CPU with autovectored interrupt controller
let mut cpu = ConfiguredCore::new_with(
0,
AutoInterruptController::new(),
memory
);
// Reset the CPU (loads SSP and PC from vectors)
cpu.reset();
// Execute instructions for up to 1000 cycles
let cycles_used = cpu.execute(1000);§Custom Memory Implementation
Implement AddressBus to provide your own memory system:
use r68k::ram::{AddressBus, AddressSpace};
struct MyMemory {
rom: Vec<u8>,
ram: Vec<u8>,
}
impl AddressBus for MyMemory {
fn copy_from(&mut self, other: &Self) {
self.ram.copy_from_slice(&other.ram);
}
fn read_byte(&self, _space: AddressSpace, address: u32) -> u32 {
let addr = address as usize & 0xFFFFFF; // 24-bit address bus
if addr < 0x8000 {
self.rom.get(addr).copied().unwrap_or(0) as u32
} else {
self.ram.get(addr - 0x8000).copied().unwrap_or(0) as u32
}
}
fn read_word(&self, space: AddressSpace, address: u32) -> u32 {
(self.read_byte(space, address) << 8)
| self.read_byte(space, address.wrapping_add(1))
}
fn read_long(&self, space: AddressSpace, address: u32) -> u32 {
(self.read_word(space, address) << 16)
| self.read_word(space, address.wrapping_add(2))
}
fn write_byte(&mut self, _space: AddressSpace, address: u32, value: u32) {
let addr = (address as usize & 0xFFFFFF).saturating_sub(0x8000);
if let Some(byte) = self.ram.get_mut(addr) {
*byte = value as u8;
}
}
fn write_word(&mut self, space: AddressSpace, address: u32, value: u32) {
self.write_byte(space, address, value >> 8);
self.write_byte(space, address.wrapping_add(1), value);
}
fn write_long(&mut self, space: AddressSpace, address: u32, value: u32) {
self.write_word(space, address, value >> 16);
self.write_word(space, address.wrapping_add(2), value);
}
}§Exception Handling
Use Callbacks to intercept exceptions:
use r68k::cpu::{Callbacks, Core, Cycles, Exception, Result};
struct MyCallbacks;
impl Callbacks for MyCallbacks {
fn exception_callback(&mut self, core: &mut impl Core, ex: Exception) -> Result<Cycles> {
match ex {
Exception::Trap(num, _) => {
println!("TRAP #{} called", num - 32);
// Return cycles consumed, or Err(ex) to let CPU handle it
Ok(Cycles(40))
}
_ => Err(ex), // Let CPU handle other exceptions normally
}
}
}§Architecture
cpu- CPU emulation core withConfiguredCoreandCoretraitram- Memory interface withAddressBustrait andPagedMemimplementationinterrupts- Interrupt handling withInterruptControllertraitcommon- Shared constants and opcode definitions
Re-exports§
pub use cpu::Cpu;pub use cpu::ConfiguredCore;pub use cpu::Core;pub use cpu::Cycles;pub use cpu::Callbacks;pub use cpu::Exception;pub use cpu::ProcessingState;pub use cpu::Result;pub use ram::AddressBus;pub use ram::AddressSpace;pub use ram::PagedMem;pub use ram::SUPERVISOR_DATA;pub use ram::SUPERVISOR_PROGRAM;pub use ram::USER_DATA;pub use ram::USER_PROGRAM;pub use interrupts::InterruptController;pub use interrupts::AutoInterruptController;
Modules§
- common
- cpu
- CPU emulation core for the Motorola 68000.
- interrupts
- Interrupt handling for the 68000 CPU.
- ram
- Memory interface for the 68000 CPU.