mmu.resource and the CPU Support Libraries

Besides mmu.library and memory.library, Thomas Richter's MMULib documents a small stack of processor support components in the NDK 3.2 MuManual/ tree:

  • 680x0.library — the generic CPU dispatcher: identifies CPU, FPU and MMU and loads the processor-specific library.
  • 68040.library / 68060.library — the processor-specific support libraries (MMULib editions): FPU/integer emulation, cache workarounds, exec replacements and MMU setup through mmu.library.
  • fpsp.resource — direct entry points into the Motorola FPSP emulation code, built by the 68040/68060 library.
  • mmu.resource — an optional low-level driver underneath mmu.library, for emulators or unusual MMUs.

All of these are third-party MMULib components, not parts of AmigaOS 3.2. This article covers what their MuManual autodocs, headers and example sources document. The NDK's own SetPatch and CPU release notes describe how AmigaOS 3.2 interacts with them.

How the pieces load

SetPatch
  └─ 680x0.library            (generic dispatcher, stays resident)
       ├─ 68000/68010/68020/68030/68040/68060.library   (CPU specific)
       │    └─ fpsp.resource   (built by the 68040/68060.library)
       └─ mmu.library          (sets up the MMU; uses mmu.resource if present)

From 680x0.doc: "The 680x0.library is usually loaded by 'SetPatch' on startup and remains in the system. It then checks the available hardware and loads the CPU and MMU specific drivers." The 68040 and 68060 autodocs say that MMU setup "is not done by the 68040.library directly but by the mmu.library which is loaded by the 68040.library on startup" (likewise for the 68060).

The AmigaOS SetPatch release notes (ReleaseNotes/SetPatch-RelNotes) record the OS side:

SetPatch Change
45.2 "the code attempts to load a library named 680x0.library upfront. This library is supposed to be the generic CPU dispatcher." Also looks for 68020.library on the 68020
45.3 If 680x0.library is already loaded, SetPatch does not start the CPU-specific libraries
45.10 68060 without 68060.library: SetPatch at least fixes UMult64/SMult64 of utility V40 "such that one can run at least the workbench correctly"
45.11 On a 68040/68060, math libraries older than V45 are removed so they re-probe the FPU when reopened
45.12 If a core math library was removed, the matching trans library is removed too
47.2 AFF_FPGA is honored; "there is currently no CPU support library for this flag"

exec/execbase.h defines AFB_FPGA as bit 10 (AFF_FPGA = 1L<<10) of AttnFlags. The exec.library Reference notes that exec's coldstart only detects a 68060 FPU, so the 68060.library is responsible for FPU handling.

680x0.library

Name MC680X0_NAME = "680x0.library"
Base struct MC680X0Base (only struct Library dllib_Library is public)
Headers libraries/680x0.h, clib/680x0_protos.h, proto/680x0.h, lvo/680x0_lvo.i, BMAPs/680x0_lib.bmap
LVO Function Registers Returns
-30 char CPUType(void) — CPUTYPE_*
-36 char FPUType(void) — FPUTYPE_*
-42 char MMUType(void) — MUTYPE_* (from mmu/mmubase.h)
-48 ULONG SetFPUExceptions(ULONG flags, ULONG mask) d0, d1 previous disable mask

Type codes are characters, not bit masks:

CPU Value FPU Value MMU Value
CPUTYPE_68000 '0' FPUTYPE_NONE 0 MUTYPE_NONE 0
CPUTYPE_68010 '1' FPUTYPE_68881 '1' MUTYPE_68851 '2'
CPUTYPE_68020 '2' FPUTYPE_68882 '2' MUTYPE_68030 '3'
CPUTYPE_68030 '3' FPUTYPE_68040 '4' MUTYPE_68040 '4'
CPUTYPE_68040 '4' FPUTYPE_68060 '6' MUTYPE_68060 '6'
CPUTYPE_68060 '6'

Notes from the autodoc:

  • CPUType() results "are more precise than those that can be found in SysBase->AttnFlags", and "will be correct even for the 68060".
  • FPUType() returns FPUTYPE_68040/FPUTYPE_68060 whenever such an FPU exists, "regardless whether the processor support code has been loaded and the 68881/68882 instructions can be emulated". Check SysBase->AttnFlags if you need to know that emulation is active.
  • MMUType() is routed straight to mmu.library GetMMUType() and returns MUTYPE_NONE if mmu.library is not available. (The autodoc synopsis prints it as GetMMUType(); the prototype and LVO name it MMUType.)
  • SetFPUExceptions() is routed to the CPU-specific library (68020, 68030, 68040 or 68060). It does not touch the FPU. If the driver is missing or cannot change the mask, it does nothing and returns 0.

FPU exception control bits

A set bit in flags disables the exception; mask selects which bits are valid. SetFPUExceptions(0, 0) reads the current setting.

Bit FPUCtrlB_* FPUCtrlF_* Disables
0 FPUCtrlB_BSUN 1L<<0 branch or set on unordered
1 FPUCtrlB_INEX 1L<<1 inexact result
2 FPUCtrlB_DIVZ 1L<<2 divide by zero
3 FPUCtrlB_UNFL 1L<<3 underflow
4 FPUCtrlB_OVFL 1L<<4 overflow
5 FPUCtrlB_SNAN 1L<<5 signalling NaN
6 FPUCtrlB_OPERR 1L<<6 operand error

The same definitions appear in libraries/68040.h and libraries/68060.h.

Example: query CPU/FPU and disable an exception

Adapted from C_Sources/FPU.c, the Shell tool that sets these flags:

#include <exec/types.h>
#include <libraries/680x0.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/680x0.h>

struct MC680X0Base *MC680x0Base;

int main(void)
{
    ULONG flags;

    if (MC680x0Base = (struct MC680X0Base *)OpenLibrary(MC680X0_NAME, 40L)) {
        Printf("CPU 680%lc0, FPU type '%lc'\n",
               (LONG)CPUType(), (LONG)(FPUType() ? FPUType() : '-'));

        /* disable the inexact-result exception, leave the others alone */
        SetFPUExceptions(FPUCtrlF_INEX, FPUCtrlF_INEX);

        flags = SetFPUExceptions(0L, 0L);       /* read back */
        if (flags & FPUCtrlF_INEX)
            Printf("INEX disabled\n");

        CloseLibrary((struct Library *)MC680x0Base);
    } else {
        Printf("680x0.library required.\n");
    }
    return 0;
}

The base variable name must match what proto/680x0.h expects (FPU.c declares MC680x0Base).

68040.library and 68060.library

Each exports one documented function, at an unusual offset: "lots and lots of offsets reserved here.... sigh" says fd/68060_lib.fd, which uses ##bias 222.

Library Name constant Function LVO Registers
68040.library MC68040_NAME ULONG FPUControl(ULONG flags, ULONG mask) -222 d0, d1
68060.library MC68060_NAME ULONG FPUControl(ULONG flags, ULONG mask) -222 d0, d1

FPUControl() takes the FPUCtrl* bits above. It "does not alter the FPU status at all"; it sets control bits in the library base that the library's own FPU exception vectors read, so "this library vector does nothing if someone altered the FPU exception vectors manually". Both autodocs say not to call it directly: "call the same vector of the 680x0.library", i.e. SetFPUExceptions().

What the libraries do, per their --Background-- sections:

Task 68040.library 68060.library
Cache-related fixes and workarounds for programs yes yes
Replacement exec CPU functions yes yes
Load the Motorola FPSP (unimplemented FPU instructions) FPSP68040 FPSP68060
Replace the exec scheduler for FPU support yes
Emulate unimplemented integer instructions yes
MMU setup (delegated to mmu.library) yes yes
Workarounds for 68060 bugs yes

Selected changes from the MMULib ReadMe history:

  • 43.8: the 68040 and 68060.library patch utility.library's division (and on the 68040 also multiplication) routines, "since some kickstart versions apparently do not patch in the optimized versions".
  • 43.11: CPU libraries patch the private exec ExitIntr() to avoid spurious interrupts on fast boards where Paula has not yet cleared the interrupt bits; MMU detection can identify a 68060 that some P5 boards report as a 68010 during bootstrap.
  • 43.11.1: the 68060.library also clears the branch cache in CacheClearU() and CacheClearE().
  • 43.13.2: all CPU libraries install trampolines to p5emu.library if present, for P5 programs that call undocumented LVOs.
  • 43.14: the 68060.library uses an explicit test, rather than the CPU revision, to decide whether to disable the load/store bypass on faulty CPUs.
  • 46.5: CPU libraries bumped to V46.

fpsp.resource

The fpsp.resource is not disk based; the 68040 or 68060.library builds it at startup. Normally every unimplemented FPU instruction goes through exception processing, which "will therefore stop multitasking". Calling the FPSP routines through the resource avoids that overhead. The MMULib FastIEEE tool patches the system IEEE math libraries to use it.

Function Inputs Result
BYTE FPSPMonadic(UWORD opword, IEEEExtended operand) d0 = opword, fp0 = operand d0 = store flag, result in fp0 (and fp1 for FSINCOS)
BYTE FPSPDyadic(UWORD opword, IEEEExtended op1, IEEEExtended op2) d0 = opword, fp0 = source, fp1 = destination d0 = store flag, result in fp0

Rules from fpsp.doc:

  • These are assembly-language stubs, "not designed to be callable from C"; applications should reach them through a link library or the math libraries.
  • They are re-entrant and interrupt-callable, and do not need a6 loaded with the resource base.
  • opword is the second word of the 68881/68882 instruction. Bits 15 and 13 must be 0 (no control instructions), R/M (bit 14) 0, destination (bits 9–7) 0. The source field (bits 12–10) is 0 for monadic and 1 for dyadic. Bits 5–0 hold the opcode; for FSINCOS the FPC field (bits 2–0) must be 001.
  • FPCR and FPSR supply rounding and exception settings. FPSR comes back as a real 68881/68882 would set it.
  • The code never raises an FPU exception itself. A store flag of 0 means a result was produced — possibly NaN or Inf. A non-zero flag means an enabled exception condition was found and fp0 is undefined; the caller must raise the exception if desired.
  • BUGS (dyadic): the encoding implies the source is in fp1, but the function takes it in fp0 and returns the destination in fp0.

C_Sources/FPSPSnoop.c (with FPSPSnoopHandler.asm) shows the other side: it takes over the line-F, FPU exception and unimplemented-instruction vectors in the VBR and prints instructions that would reach the FPSP. It uses mmu.library and disassembler.library V40.

mmu.resource

mmu.resource is "the low-level driver of the mmu.library … just one level above hardware". Application programs never use it: "There is absolutely no need to make use of this resource whatsoever; the calling syntax is wierd and requires assembly language". It exists so mmu.library can run on MMUs it does not natively support — "more advanced processors, external MMUs or even 'software emulated' MMUs for emulators". mmu.library gained support for it in 43.2, so the MC68K MMU could be emulated "on non-native CPUs (i.e. x86) without the need to re-write the entire library".

Contract for implementers

  • Make the resource available with AddResource() at boot, before mmu.library loads. If it is absent, the library uses built-in routines; it never creates one itself.
  • Provide the usual library entries LibOpen(), LibClose(), LibExpunge() and LibExtFunc() (currently unused).
  • Most calls expect a6 = mmu.library base, not the resource base, and some return values in several registers or in the condition codes, mainly for speed.
  • CheckMMUInterface(version, mmubase, mmuresbase) (d0, a0, a6) is the handshake. The lowest API level is 43: "you should currently check for this value and fail if you get anything different". Keep the mmubase it passes; Exception() does not receive it.
  • MMUResType(mmuresbase) (a6) returns the one-byte MMU ID that mmu.library passes on through GetMMUType().
  • Flush and push calls run in supervisor mode and must cover both the user and the supervisor tree.

Function groups

Group Functions (registers)
Handshake / identity CheckMMUInterface (d0, a0, a6), MMUResType (a6)
MMU registers ReadMMUConfig(config) (a0), WriteMMUConfig(config) (a0), BuildMMUConfig(uctx, sctx, defconfig, destconfig) (a0–a3), ParseTT(ctxt, config) (a0, a1), LoadRoot(uroot, sroot) (a0, a1), RootStarter(config, atd, type) (a1, a0, d0)
Context setup DefineMMUContext(config, ctxt) (a0, a5), AdjustMMUContext(depth, destctxt, parent) (d0, a0, a1), AdjustCtxtSettings(ctxt) (a5)
Descriptors ReadDescriptor / ReadFastDescriptor(deptr, atd, type, level, ctxt) (a1, a0, d0, d1, a5), WriteDescriptor(atd, level, ctxt) (a0, d1, a5), FindDescriptor(addr, ctxt) (a0, a5), CmpDescriptor(descr1, descr2, type, delta) (a0, a1, d0, d1; result in CCR), IncrementDescriptor(atd, index) (a0, d0), ReadUMFlags(descr, level, ctxt) (a0, d0, a5)
Page install InstallNewPage / InstallPage(level, tablesize, dest, descr, data, addr, ctxt) (d2, d1, a2, d0, d4, a0, a5), SetIndirect(where, logical, descr) (a0, a1, d0), SetIndirectArray(where, descr, num) (a0, a1, d0)
ATC flush PFlush(addr) (a0), PFlushA(), PFlushTwo(addr1, addr2) (a2, a3)
Cache push PushAll(), PushLine(addr) (a0), PushPage(addr) (a0), PushTwo(addr1, addr2) (a2, a3)
DMA ForbidDMACache(addr, ctxt) (a0, a5), PermitDMACache(addr, ctxt) (a0, a5)
Misc WithoutMMU(userproc) (a5), Exception() (installed directly in the CPU vector table)

a6 = mmu.library base in every call except CheckMMUInterface and MMUResType. The structures involved are struct MMUConfig (mmu/config.h: mcf_UserRootPointer[2], mcf_SupervisorRootPointer[2], mcf_TranslationControl, mcf_DTT0, mcf_DTT1, mcf_ITT0, mcf_ITT1) and struct AbstractDescriptor (mmu/descriptor.h). IMMUContext and struct MMUResBase are internal and not in the MuManual headers. The MuManual provides no LVO or FD file for the resource.

Gotchas from the autodoc:

  • PFlush() flushes the descriptor of one page. Early-termination descriptors cover several pages, so other pages they describe may stay in the ATC.
  • PushPage() pushes the data cache and flushes the instruction cache. 68060 bug: unless the address is page aligned, the instruction cache may not be flushed, and the resource does not work around this — align the address first.
  • Exception() is "the complete access error handler" and "maybe the most trickiest one". Its required steps include: flushing the 68060 branch cache on a branch-prediction error; emulating AbsExecBase reads from a cached copy ("Do NOT attempt to read it from the zero page"); passing physical bus errors and read-modify-write cycles to mulib_OldException; handling MOVE16, predecrement MOVEM, FMOVE.X and FMOVE.D when computing fault addresses; and supporting MAPP_ROM writes and MAPP_REPAIRABLE read-back through trace-mode emulation when there is no pipeline access.

External MMU-Configuration commands

mmuexternals.doc documents the plug-in interface used by tools such as P5Init. mmu.library executes the MMU-Configuration text file at startup. A command that is not built in is looked up in LIBS:mmu, loaded with LoadSeg(), and scanned for a Resident structure with the same name: type NT_UNKNOWN, version at least 40, rt_AutoInit cleared. Its rt_Init is called with:

Register Contents
a0 struct RDArgs *, to pass as the third argument of ReadArgs()
a1 the MMUContext to modify
a2 DOSBase
a6 MMUBase — do not OpenLibrary("mmu.library"); the code runs inside the library's startup in the ramlib process

The command is called twice, once with the default user context and once with the supervisor context, and is unloaded in between. Allocate shared resources only once. Return 0 for success; 5 or more aborts the mmu.library setup. The MMU is not loaded yet when you run. Start the file with moveq #-1,d0 / rts so that running it from the Shell fails harmlessly.

The CPU command (AmigaOS 3.2)

The OS CPU command identifies the same hardware and works alongside these libraries (ReleaseNotes/CPU-RelNotes):

  • 45.1: FASTROM/NOFASTROM/TRAP/NOTRAP became dummies ("did not go through the mmu.library"); 68060 support and CPU errata tests added.
  • 45.5: CHECKINSTALL tests whether a CPU library is present on CPU models that need one.
  • 45.7: CPUTYPE and FPUTYPE switches print minimal output for scripts, alongside an MMU type switch; TO redirects output.
  • 46.1 / 46.2: 68060 F6 bug test; the I4 test no longer changes the installed cache settings.

See Also


Sources: NDK 3.2 R4 MuManual/Autodocs/{680x0,68040,68060,fpsp,mmures,mmuexternals}.doc, MuManual/Include/libraries/{680x0,68040,68060}.h, MuManual/Include/clib/{680x0,68040,68060}_protos.h, MuManual/Include/lvo/{680x0,68040,68060}_lvo.i, MuManual/Include/mmu/{config,descriptor,mmubase}.h, MuManual/fd/68060_lib.fd, MuManual/C_Sources/{FPU,FPSPSnoop}.c, MuManual/ReadMe, ReleaseNotes/SetPatch-RelNotes, ReleaseNotes/CPU-RelNotes, Include_H/exec/execbase.h Updated: 2026-11-13