Copper68k 1.5.0

dotnet add package Copper68k --version 1.5.0
                    
NuGet\Install-Package Copper68k -Version 1.5.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.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Copper68k" Version="1.5.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.5.0
                    
#r "nuget: Copper68k, 1.5.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.5.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.5.0
                    
Install as a Cake Addin
#tool nuget:?package=Copper68k&version=1.5.0
                    
Install as a Cake Tool

Copper68k

Mainline release 1.5.0

1.5.0 brings the preceding OCS CPU development series into main and the normal NuGet release line. The old ocs020 prerelease suffix described the original OCS/68020 integration effort; this release also includes experimental 030/040 support and a distinct diagnostic MC68060 core. A normal package version does not remove the advanced CPU limitations documented below.

The release includes the 1.4.2-ocs020.56 correction to instruction fetching in the OCS 040 interpreter. Aligned longword reads start at the eight-byte half-line base, including when execution starts in the second longword. The holding register retains loops in the first six bytes even with CACR.IE clear. Integer fallback execution now uses the same frontend rather than a separate 68000 prefetch queue. Reset, instruction-cache maintenance, privilege/translation changes and host mapping generations prevent reuse of stale context. Guest data writes alone do not invalidate held instructions. JIT max-speed fetching is unchanged.

This is a demand-driven approximation, not a complete 040 pipeline: consuming the fourth word retires the half-line; speculative next-half-line transfers, deferred prefetch faults, pipeline overlap and accurate instruction costs remain unimplemented. These limits are not a Lotus-specific delay or compatibility rule. The architectural fetch/retention expectations come from MC68040UM section 4.2 and the paragraph after table 7-3. Timings in chapter 10 require a separate BCLK pipeline model; the current fixed one-native-cycle policy does not implement it.

The preceding 1.4.2-ocs020.55 work supplies experimental OCS 030/040 integration and a distinct, integer-focused MC68060 diagnostic core. The 060 has its own PCR identity, single supervisor stack with software M bit, removed-control-register exceptions, vector-61 removed-integer traps, aligned CAS boundary, and eight-native- clock approximate fixed timing policy. It is not a complete 68060 implementation: FPU arithmetic, enabled MMU/transparent translation, BUSCR operation, full indexed addressing and full exception/trace conformance remain unavailable or incomplete. FPU control-register transfers and NULL/IDLE 12-byte state frames are implemented; unsupported FPU forms stop explicitly. No JIT is provided for the 060.

The 040 now uses its documented CACR enable bits (15/31), with CINV/CPUSH line/page/all maintenance and privilege/encoding checks. Chip RAM permits instruction caching on 030/040 as well as 020. Cache capacity/associativity, copyback data, physical cache-fill timing and superscalar dispatch remain bounded policies, not hardware certification. The 000/020 execution profiles are preserved.

Native Kickstart 1.3 cannot boot this 060 profile. Its initial task FPU frame is four bytes; MC68060UM requires twelve even for NULL. The correctly sized restore consumes the following saved context and sends the task to address zero. A newer OS and 060-aware task/FPU support are required before desktop availability. The 030 and 040 native paths are validated separately by the CopperScreen consumer. Native boot and Lotus III replay evidence is maintained in the CopperScreen consumer. That evidence covers boot, demo and menu progress with retained inputs; it does not certify complete gameplay or physical accelerator timing.

Architectural sources: MC68060UM sections 3.2.2, 8.2.4, 11.1.2, C.2 and appendix D; MC68040UM section 2.2.2.5; M68000PRM CINV/CPUSH. Remaining features must be implemented from these contracts, without substituting 040 FPU frames or 68881 NULL frames to make old software boot.

Preceding prerelease 1.4.2-ocs020.54

Prerelease 1.4.2-ocs020.54 fixes indexed JSR and 13 further operand forms reached by Kickstart 1.3 CopperHDF startup and native Fast RAM allocation/file I/O. The added forms cover JMP, MOVE, MOVEA, ADD, ADDA, SUBA, ANDI, NOT, CMPI and MOVEM. Focused cases check signed/scaled indexes, extension-word PC bases (including MOVEM's preceding register mask), stack aliasing/alignment, widths, flags and preserved surrounding memory. The shared 030 executor receives these forms; 040 retains its fallback. Full index extensions remain explicitly unsupported on these paths. The operand-shape timing policy remains approximate. This prerelease is approved for publication; no additional host CPU is enabled.

The suite passes 3,395 cases, including 189 new HDF/indexed-control cases. Against the preceding .53 binary, 162 of those new cases reproduce the missing forms; 27 fallback/full-extension controls pass. Six optional external conformance cases are unavailable. Architectural expectations follow the instruction and effective-address definitions in M68000PRM.

The preceding 1.4.2-ocs020.53 adds PC-relative brief-indexed LEA for the 020/EC020 Autoconfig boot path. The shared 030 executor receives the same operand form; this does not enable another host CPU. Signed indexes, scale, PC base, register aliasing and unchanged flags have focused coverage. Full index extensions on this path remain unsupported; 040 keeps its existing fallback. Instruction timing uses the existing bounded indexed-LEA policy.

Copper68k is a reusable C# Motorola 68000-family CPU emulation core extracted from CopperScreen and CopperMod. It provides interpreter backends for MC68000, MC68010, 68EC020, 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.

Development version 1.4.2-ocs020.52

The advanced interpreter now distinguishes absolute and PC-relative memory sources from immediate values for MOVE.L <ea>,(An). The old decoder mask could copy an address as instruction bytes, corrupting later execution. Its 30-case regression includes 24 memory-source failures under the old mask and six passing immediate controls. Additional memory moves, arithmetic, logical/bit operations, shifts and PC-relative jumps cover the newly reached Lotus III continuation path. Tests check width, flags, signed/scaled addresses and ordered side effects when source and destination address registers alias.

The 020 profiles now permit Chip RAM instruction caching. A Chip RAM code write retains the cached instruction until guest invalidation, as documented by Commodore's CacheClearE autodoc. Custom/CIA instruction fetches remain uncached; 030/040 profile policies are unchanged. Four enabled/disabled-cache regression cases cover both 020 variants. A standalone Chip RAM self-modification ROM agrees with WinUAE's stale-code/flush behavior. Cache-line fetch timing remains approximate and is not certified here.

This candidate extends the shared advanced interpreter for experimental OCS 68EC020/68020 integration. EC020 now advertises host code reads only when the underlying bus supplies that optional capability. Added operand forms cover MOVE, arithmetic/logical, condition-code, bit, MOVEM and rotate-through-extend operations exercised by Kickstart 1.3 and Lotus III startup. Regression cases cover operand width, flags, signed/scaled addressing, register aliasing, stack updates and optional code-reader behavior.

The 68000 implementation is unchanged; new advanced forms retain the 68040's existing fallback. The 68030 shares advanced execution code, but this work does not establish native 68030 host support. Missing advanced forms still fail explicitly. Operand-shape timing remains a bounded execution policy; it does not certify a particular accelerator card or the sequence-dependent timings in MC68020UM section 8. This is an unpublished development version, not a stable release. Native Kickstart boot and bounded Lotus III driving-demo/menu progression are covered; complete game compatibility, player-controlled racing, FPU/MMU behavior and physical timing conformance remain outside this slice.

The candidate passes 3,107 regular CPU tests, including 1,419 continuation cases across 020, EC020 and the shared 030 executor. The earlier 184 expansion cases and Chip RAM cache checks remain included. Six optional external conformance tests were unavailable and skipped.

Stable version 1.4.1

Copper68k 1.4.1 is the stable NuGet release. It retains the 68000 trace-exception correction and prefetch-locality improvements from the 1.4.1-locality.1 development build. It further reduces interpreter stack initialization in cached fixed-batch execution and avoids deferred interrupt-sample resolution when no deferred-timing provider is present. The public API and emulated bus ordering are unchanged.

The combined candidate passed all 1,499 regular Copper68k tests and all three retained CopperScreen performance workloads on the recorded Ryzen 5 5600X host. The one-sided 95% upper regression bound is below 1% for each workload; native Lemmings gains 2.76% paired FPS. Six optional external conformance suites were not run because their external datasets or generators are opt-in. See the complete benchmark and validation record for exact binaries, confidence bounds and coverage details.

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 HasHostGateway(uint address) => false;

    public bool TryInvokeHostGateway(uint instructionProgramCounter, uint token, 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.
  • M68010: 68010-style core with VBR and a 24-bit external address bus.
  • M68020: 68020-style core with VBR, format-zero exception frames, and native-cycle timing state.
  • M68EC020: 68020-style core with a 24-bit external address bus and full 32-bit registers.
  • 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.

HasHostGateway and TryInvokeHostGateway are optional host integration hooks. The private gateway instruction is FF00 followed by a big-endian 32-bit opaque token. Return false from both if your emulator does not use CopperMod host gateways.

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.

MC68000 fast-path coverage

The MC68000 interpreter retires instructions through one of several paths: a cycle-accurate scalar decoder, a planned dispatch that skips decoding, and cached fixed-plan runs that hoist the prefetch and bus-timing machinery out of hot loops entirely. All paths are held to byte-identical retired cycle counts by a differential test harness.

Register-direct forms of the following are admitted to the cached fixed-plan-run path, so loops built from them stay on the fastest tier: NOP, MOVEQ, short unconditional branches, ADDQ/SUBQ, long register OR/AND/EOR/ADD, CLR/NEG/NEGX/NOT/TST, and shifts and rotates with an immediate count. Shifts with a register-sourced count stay on the planned dispatch because their cycle cost depends on register state.

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.

NuGet packages (3)

Showing the top 3 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.

CopperMod.Amiga.Lightweight

Independent single-clock PAL OCS A500 engine with reusable framebuffer and 48 kHz stereo audio output.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.0 0 9/27/2026
1.4.2-ocs020.54 0 9/27/2026
1.4.2-ocs020.52 34 9/26/2026
1.4.1 69 9/24/2026
1.4.1-boundary.1 78 9/16/2026
1.4.0 350 8/26/2026
1.3.0 485 7/31/2026
1.2.0 123 7/12/2026
1.1.1 114 7/4/2026
1.1.0 134 6/22/2026
1.0.0 145 6/20/2026

Mainline release of the OCS 020/030/040 interpreter improvements and diagnostic integer-focused MC68060 core. Includes expanded indexed/operand forms, Chip RAM instruction caching, 040 cache maintenance and corrected demand-driven uncached instruction fetching with a shared holding register for integer fallback execution. Advanced CPU profiles remain experimental: speculative prefetch, pipeline overlap, cache geometry and instruction timing are approximate; the diagnostic 060 is incomplete and cannot boot native Kickstart 1.3. See the README for scope and validation.