Copper68k 1.2.0

dotnet add package Copper68k --version 1.2.0
                    
NuGet\Install-Package Copper68k -Version 1.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Copper68k" Version="1.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Copper68k" Version="1.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Copper68k" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Copper68k --version 1.2.0
                    
#r "nuget: Copper68k, 1.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Copper68k@1.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Copper68k&version=1.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Copper68k&version=1.2.0
                    
Install as a Cake Tool

Copper68k

Copper68k is a reusable C# Motorola 68000-family CPU emulation core extracted from CopperScreen and CopperMod. It provides interpreter backends for MC68000, MC68020, MC68030, and MC68040-style execution behind a small bus/core API, plus an opt-in MC68040 JIT backend for hosts that expose stable code snapshots and write invalidation.

The package is intended for emulator projects that want to supply their own memory map, devices, interrupt sources, and host integration.

Install

dotnet add package Copper68k

Copper68k currently targets .NET 10.

Quick Start

Implement IM68kBus, create a core through M68kCoreFactory, reset it with an initial PC and stack pointer, then execute instructions.

using Copper68k;

var bus = new RamBus(64 * 1024);
bus.WriteWord(0x1000, 0x7042); // MOVEQ #$42,D0

using var cpu = M68kCoreFactory.Default.Create(M68kCpuModel.M68000, bus);
cpu.Reset(programCounter: 0x1000, stackPointer: 0x2000);
cpu.ExecuteInstruction();

Console.WriteLine(cpu.State.D[0]); // 66

sealed class RamBus : IM68kBus
{
    private readonly byte[] memory;

    public RamBus(int size) => memory = new byte[size];

    public byte ReadByte(uint address, ref long cycle, M68kBusAccessKind accessKind)
        => memory[address % memory.Length];

    public ushort ReadWord(uint address, ref long cycle, M68kBusAccessKind accessKind)
        => (ushort)((ReadByte(address, ref cycle, accessKind) << 8) |
            ReadByte(address + 1, ref cycle, accessKind));

    public uint ReadLong(uint address, ref long cycle, M68kBusAccessKind accessKind)
        => ((uint)ReadWord(address, ref cycle, accessKind) << 16) |
            ReadWord(address + 2, ref cycle, accessKind);

    public void WriteByte(uint address, byte value, ref long cycle, M68kBusAccessKind accessKind)
        => memory[address % memory.Length] = value;

    public void WriteWord(uint address, ushort value)
    {
        long cycle = 0;
        WriteWord(address, value, ref cycle, M68kBusAccessKind.CpuDataWrite);
    }

    public void WriteWord(uint address, ushort value, ref long cycle, M68kBusAccessKind accessKind)
    {
        WriteByte(address, (byte)(value >> 8), ref cycle, accessKind);
        WriteByte(address + 1, (byte)value, ref cycle, accessKind);
    }

    public void WriteLong(uint address, uint value, ref long cycle, M68kBusAccessKind accessKind)
    {
        WriteWord(address, (ushort)(value >> 16), ref cycle, accessKind);
        WriteWord(address + 2, (ushort)value, ref cycle, accessKind);
    }

    public bool HasHostTrapStub(uint address) => false;

    public bool TryInvokeHostTrap(uint instructionProgramCounter, ushort trapId, M68kCpuState state)
        => false;

    public void ResetExternalDevices(long cycle)
    {
    }
}

CPU Models

Use M68kCpuModel to select the default interpreter backend:

  • M68000: base 68000 interpreter with 68000-style exception frames.
  • M68020: 68020-style core with VBR, format-zero exception frames, and native-cycle timing state.
  • M68030: 68030-oriented interpreter profile.
  • M68040: 68040-oriented interpreter with the current integer/FPU/MMU support used by CopperScreen.

M68kCoreFactory.Create(model, bus) always creates the interpreter path. Use the options overload only when you want a non-default execution mode.

MC68040 JIT

The MC68040 JIT is included in the package as an opt-in backend. The concrete implementation remains internal; package consumers select it through M68kCoreOptions.

using var cpu = M68kCoreFactory.Default.Create(
    M68kCpuModel.M68040,
    bus,
    new M68kCoreOptions { ExecutionMode = M68kExecutionMode.Jit });

JIT mode is supported only for M68kCpuModel.M68040. Requesting it for another model throws M68kEmulationException.

The bus must implement IM68kJitBus. That capability tells Copper68k which physical code ranges are eligible for compilation, lets the JIT capture immutable code snapshots for background compilation, and raises invalidation events when writable code changes.

Hosts may also implement IM68kJitFastMemoryBus and IM68kJitTimedMemoryBus to expose direct fast-memory paths or host-specific timed device shortcuts. If those optional interfaces are absent, compiled traces fall back to normal IM68kBus memory access.

Bus Contract

IM68kBus receives every CPU byte, word, and long access with an address, a mutable cycle counter, and an access kind. Implementations may advance the cycle counter to model memory wait states.

M68kBusAccessKind distinguishes instruction fetches, data reads, and data writes. This matters for bus errors, address errors, MMU translation, and device side effects.

HasHostTrapStub and TryInvokeHostTrap are optional host integration hooks. Return false from both if your emulator does not use CopperMod host traps.

Reset and Interrupts

Reset(programCounter, stackPointer) clears the general registers, sets the PC and supervisor stack pointer, and initializes SR to 0x2700 (Supervisor | IPL 7), matching 68k reset behavior.

RequestInterrupt(level, vectorAddress) ignores levels that are masked by SR. Pass a vector-table byte offset such as 24u * 4 for level 6 autovector, or a device-specific vector offset. On 68020+ cores the offset is relative to the current vector base register.

State

M68kCpuState exposes data registers D[0..7], address registers A[0..7], the program counter, status register, stack pointers, cycle counters, STOP/HALT state, and 68020+ control registers. Setting StatusRegister also updates the active stack pointer when supervisor/user or master/interrupt stack mode changes.

Status

Copper68k 1.1 is an accuracy-oriented emulator core with a stable, intentionally small public API. Applications should create cores through M68kCoreFactory and depend on IM68kBus, IM68kCore, M68kCpuModel, M68kCpuState, and the optional JIT capability interfaces rather than implementation-specific interpreter or JIT classes.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Copper68k:

Package Downloads
CopperMod.Amiga

Internal Amiga hardware emulation core layered on Copper68k for CUST playback and emulator hosts.

CopperMod.Amiga.Emulator

Full Amiga emulator host services, boot helpers, and disk media adapters layered on CopperMod.Amiga.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.0 100 7/12/2026
1.1.1 99 7/4/2026
1.1.0 118 6/22/2026
1.0.0 127 6/20/2026

Adds public MC68010 support and refined MC68020, MC68030, and MC68040 interpreter backends. Improves MC68000 interpreter and JIT timing, two-word prefetch behavior, exception handling, self-modifying-code invalidation, and hot-path performance; improves MC68040 JIT memory-loop performance and removes steady-state allocations. Expands conformance coverage with SingleStepTests, Musashi, m68k-rs, and WinUAE CPU tests.