diff --git a/09_intuition/README.md b/09_intuition/README.md index a84f9af..ac4d314 100644 --- a/09_intuition/README.md +++ b/09_intuition/README.md @@ -2,6 +2,8 @@ # Intuition — GUI Subsystem Overview +Intuition is the AmigaOS windowing system and user interface manager. It sits between applications and the low-level graphics/input hardware, providing screens, windows, gadgets, menus, and an event-driven message passing system. Unlike modern desktop GUIs, Intuition operates with **zero memory protection** and **cooperative multitasking** — every application directly shares hardware resources. + ## Section Index | File | Description | @@ -15,3 +17,346 @@ | [idcmp.md](idcmp.md) | IDCMP message classes and IntuiMessage | | [boopsi.md](boopsi.md) | BOOPSI object-oriented gadget system | | [input_events.md](input_events.md) | InputEvent, input.device, commodities | + +--- + +## System Architecture — Where Intuition Fits + +```mermaid +graph TB + subgraph "User Applications" + APP1["Application 1"] + APP2["Application 2"] + WB["Workbench"] + end + + subgraph "GUI Layer" + INT["intuition.library
Screens, Windows, IDCMP"] + GT["gadtools.library
Standard Gadgets"] + ASL["asl.library
File/Font Requesters"] + BOOPSI["BOOPSI Framework
OOP Gadgets"] + end + + subgraph "Graphics Layer" + GFX["graphics.library
RastPort, BitMap, Draw"] + LAY["layers.library
Clipping, Damage Repair"] + COP["Copper
Display List DMA"] + BLT["Blitter
Area Fill, Scroll"] + end + + subgraph "Input Layer" + INP["input.device
Raw Input Stream"] + KBD["keyboard.device"] + GP["gameport.device
Mouse / Joystick"] + CON["console.device
Text I/O"] + end + + subgraph "Hardware" + CUSTOM["Custom Chips
Denise/Lisa · Paula"] + CIA_["CIA-A / CIA-B
Keyboard, Timers"] + end + + APP1 & APP2 & WB --> INT + INT --> GT & ASL & BOOPSI + INT --> GFX + GFX --> LAY + GFX --> COP & BLT + INT --> INP + INP --> KBD & GP + INP --> CON + KBD --> CIA_ + GP & COP & BLT --> CUSTOM +``` + +--- + +## Data Flow — From Keypress to Application + +```mermaid +sequenceDiagram + participant HW as CIA-A / Keyboard + participant KBD as keyboard.device + participant INP as input.device + participant INT as Intuition + participant WIN as Active Window + participant APP as Application + + HW->>KBD: IRQ (key scancode) + KBD->>INP: InputEvent (IECLASS_RAWKEY) + INP->>INT: Input handler chain + Note over INT: Intuition checks:
Menu shortcut?
System key?
Gadget activation? + INT->>WIN: Route to active window + WIN->>APP: IDCMP IntuiMessage
(via MsgPort) + APP->>APP: ReplyMsg() when done +``` + +--- + +## Screen / Window / Gadget Hierarchy + +```mermaid +graph TB + subgraph "Display Hardware" + VP["ViewPort
(Copper-driven display)"] + end + + subgraph "Screen Layer" + SCR["Screen
sc_ViewPort, sc_RastPort
sc_BitMap, sc_Flags"] + end + + subgraph "Window Layer" + W1["Window A
IDCMP flags, RastPort"] + W2["Window B
IDCMP flags, RastPort"] + end + + subgraph "Gadget Layer" + G1["System Gadgets
Close, Depth, Size, Drag"] + G2["GadTools Gadgets
Button, Slider, ListView"] + G3["BOOPSI Objects
Custom gadgets via OOP"] + end + + subgraph "Menu Layer" + M1["MenuStrip
Menu → MenuItem → SubItem"] + end + + VP --> SCR + SCR --> W1 & W2 + W1 --> G1 & G2 & G3 + W1 --> M1 + W2 --> G1 +``` + +### Ownership Rules + +| Object | Owned By | Lifetime | +|---|---|---| +| **Screen** | Creator task (or Workbench) | Until `CloseScreen()` — all windows must close first | +| **Window** | Creator task | Until `CloseWindow()` — must drain IDCMP port first | +| **Gadget** | Window | Attached via `AddGList()`, removed before window close | +| **Menu** | Window | Attached via `SetMenuStrip()`, cleared via `ClearMenuStrip()` | +| **RastPort** | Window/Screen | Borrowed reference — never free directly | + +--- + +## IDCMP — The Event System + +**Intuition Direct Communication Message Port** is the core event mechanism. Each window has a `UserPort` (MsgPort) that receives `IntuiMessage` structs: + +```mermaid +graph LR + subgraph "Input Sources" + MOUSE["Mouse Move/Click"] + KEY["Keyboard"] + TIMER["Timer Tick"] + RESIZE["Window Resize"] + end + + subgraph "Intuition Dispatch" + INT["Intuition
Event Router"] + end + + subgraph "Window IDCMP Port" + PORT["Window.UserPort
(MsgPort)"] + MSG1["IntuiMessage
Class: MOUSEBUTTONS"] + MSG2["IntuiMessage
Class: VANILLAKEY"] + MSG3["IntuiMessage
Class: NEWSIZE"] + end + + subgraph "Application" + WAIT["Wait(sigmask)"] + LOOP["GetMsg() loop"] + REPLY["ReplyMsg()"] + end + + MOUSE & KEY & TIMER & RESIZE --> INT + INT --> PORT + PORT --> MSG1 & MSG2 & MSG3 + WAIT --> LOOP + LOOP --> REPLY +``` + +### Critical IDCMP Classes + +| Class | Hex | Meaning | +|---|---|---| +| `CLOSEWINDOW` | `$0200` | User clicked close gadget | +| `MOUSEBUTTONS` | `$0008` | Mouse button press/release | +| `MOUSEMOVE` | `$0010` | Mouse moved (requires `REPORTMOUSE`) | +| `GADGETUP` | `$0040` | Gadget released (RELVERIFY) | +| `GADGETDOWN` | `$0020` | Gadget pressed | +| `MENUPICK` | `$0100` | Menu item selected | +| `VANILLAKEY` | `$00200000` | Cooked keystroke (ASCII) | +| `RAWKEY` | `$0400` | Raw keyboard scancode | +| `NEWSIZE` | `$0002` | Window resized | +| `REFRESHWINDOW` | `$0004` | Damage — app must redraw | +| `INTUITICKS` | `$00400000` | ~10Hz timer for UI updates | + +--- + +## Library Interactions — Who Calls Whom + +```mermaid +graph LR + subgraph "Application Code" + APP["Your Program"] + end + + subgraph "intuition.library" + OS["OpenScreen()"] + OW["OpenWindow()"] + GT_["GadTools Layout"] + SM["SetMenuStrip()"] + IDCMP["IDCMP Dispatch"] + end + + subgraph "graphics.library" + RP["RastPort Operations
Move, Draw, Text, RectFill"] + BM["BitMap Allocation"] + VIEW["MakeVPort / LoadView"] + end + + subgraph "layers.library" + LY["Layer Clipping
CreateUpfrontLayer"] + DMG["Damage List
BeginRefresh / EndRefresh"] + end + + subgraph "exec.library" + MP["MsgPort
CreateMsgPort"] + SIG["Signals
AllocSignal, Wait"] + MEM["Memory
AllocMem, FreeMem"] + end + + APP --> OS & OW & GT_ & SM + APP --> RP + APP --> MP & SIG + + OW --> LY + OS --> VIEW & BM + IDCMP --> MP & SIG + RP --> LY + LY --> DMG + VIEW --> |"Copper list"| COP["Copper DMA"] +``` + +--- + +## Screen Types and Display Pipeline + +```mermaid +graph TB + subgraph "Screens (front to back)" + S1["Screen 1: Custom (640×256 4-colour)
sc_ViewPort → Copper List 1"] + S2["Screen 2: Workbench (640×256 8-colour)
sc_ViewPort → Copper List 2"] + S3["Screen 3: Game (320×256 32-colour)
sc_ViewPort → Copper List 3"] + end + + subgraph "Copper" + COP["Copper DMA
Interleaves ViewPorts
Sets palette per screen"] + end + + subgraph "Denise/Lisa" + OUT["Video Output
Composited scanlines"] + end + + S1 & S2 & S3 --> COP + COP --> OUT +``` + +The Copper hardware makes Amiga's multi-screen system possible — each screen gets its own palette, resolution, and scroll position, all managed by a single Copper list that switches parameters mid-frame at the correct scanline. + +--- + +## GadTools vs BOOPSI — Gadget Frameworks + +| Aspect | GadTools (OS 2.0+) | BOOPSI (OS 2.0+) | +|---|---|---| +| **Philosophy** | Wrapper functions around Intuition gadgets | True OOP with classes, methods, inheritance | +| **Creation** | `CreateGadget(kind, prev, newgad, tags)` | `NewObject(class, NULL, tags)` | +| **Layout** | Manual X/Y positioning with font scaling | Manual or custom layout classes | +| **Event model** | IDCMP `GADGETUP` + `GT_GetIMsg()` | `OM_NOTIFY` → target chain | +| **Extensibility** | Fixed set: BUTTON, STRING, SLIDER, etc. | Unlimited custom classes | +| **Typical use** | Preferences panels, simple tools | MUI internals, complex UIs | +| **Complexity** | Low — 5 functions to learn | High — requires understanding class dispatch | + +--- + +## Refresh Modes — How Windows Repaint + +| Mode | Flag | Description | Trade-off | +|---|---|---|---| +| **Simple Refresh** | `WFLG_SIMPLE_REFRESH` | App must redraw on `REFRESHWINDOW` IDCMP | Minimum memory, maximum app work | +| **Smart Refresh** | `WFLG_SMART_REFRESH` | Layers saves/restores obscured regions | Uses RAM for damage bitmaps, less app work | +| **Super Bitmap** | `WFLG_SUPER_BITMAP` | Full off-screen bitmap, auto-restored | Highest RAM use, zero redraw work | +| **Backdrop** | `WFLG_BACKDROP` | Window behind all others, fills screen | Used by Workbench | + +```mermaid +graph LR + subgraph "Simple Refresh" + A1["Window obscured"] --> A2["REFRESHWINDOW IDCMP"] + A2 --> A3["App: BeginRefresh()"] + A3 --> A4["App: Redraw damaged areas"] + A4 --> A5["App: EndRefresh()"] + end +``` + +--- + +## Common Patterns + +### Minimal Window Event Loop + +```c +struct Window *win = OpenWindowTags(NULL, + WA_Title, "My Window", + WA_Width, 320, WA_Height, 200, + WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY, + WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE, + TAG_DONE); + +BOOL running = TRUE; +while (running) { + Wait(1L << win->UserPort->mp_SigBit); + struct IntuiMessage *msg; + while ((msg = GT_GetIMsg(win->UserPort))) { + switch (msg->Class) { + case IDCMP_CLOSEWINDOW: + running = FALSE; + break; + case IDCMP_VANILLAKEY: + /* msg->Code = ASCII key */ + break; + } + GT_ReplyIMsg(msg); + } +} +CloseWindow(win); +``` + +### Shared IDCMP Port (Multiple Windows) + +```c +/* Create one port, share across windows */ +struct MsgPort *sharedPort = CreateMsgPort(); + +win1 = OpenWindowTags(NULL, ..., WA_IDCMP, 0, TAG_DONE); +win1->UserPort = sharedPort; +ModifyIDCMP(win1, IDCMP_CLOSEWINDOW); + +win2 = OpenWindowTags(NULL, ..., WA_IDCMP, 0, TAG_DONE); +win2->UserPort = sharedPort; +ModifyIDCMP(win2, IDCMP_CLOSEWINDOW); + +/* Single Wait() handles both windows */ +/* Check msg->IDCMPWindow to identify source */ +``` + + +--- + +## References + +- RKRM: *Libraries Manual* — Intuition chapter +- RKRM: *Libraries Manual* — GadTools chapter +- RKRM: *Libraries Manual* — BOOPSI chapter +- NDK39: `intuition/intuition.h`, `intuition/screens.h`, `intuition/gadgetclass.h` +- ADCD 2.1: Intuition Autodocs — `OpenWindow`, `OpenScreen`, `ModifyIDCMP` diff --git a/11_libraries/mathffp.md b/11_libraries/mathffp.md index 5742ba6..9015533 100644 --- a/11_libraries/mathffp.md +++ b/11_libraries/mathffp.md @@ -1,69 +1,468 @@ [← Home](../README.md) · [Libraries](README.md) -# Math Libraries — Floating Point +# Math Libraries — Floating Point Architecture ## Overview -AmigaOS provides multiple math libraries for floating-point operations. The 68000 has no FPU, so all math is done in software unless a 68881/68882/68040/68060 FPU is present. +AmigaOS provides a layered floating-point system designed to work transparently across the entire 68k family — from a bare 68000 with no FPU to a 68060 with integrated hardware floating point. The same application binary runs unchanged on all hardware; the libraries detect the CPU/FPU at open time and dispatch to the optimal implementation. + +This is one of Amiga's most elegant architectural decisions: **the library JMP table is the abstraction layer**. --- -## Library Stack +## The Three Numeric Formats -| Library | Format | Description | +```mermaid +graph TB + subgraph "Motorola FFP (Legacy)" + FFP["32-bit FFP
24-bit mantissa · 7-bit exp (excess-64) · 1-bit sign
Range: ±9.2×10¹⁸ · Precision: ~6.9 digits"] + end + + subgraph "IEEE 754 Single" + SP["32-bit float
23-bit mantissa · 8-bit exp (bias 127) · 1-bit sign
Range: ±3.4×10³⁸ · Precision: ~7.2 digits"] + end + + subgraph "IEEE 754 Double" + DP["64-bit double
52-bit mantissa · 11-bit exp (bias 1023) · 1-bit sign
Range: ±1.8×10³⁰⁸ · Precision: ~15.9 digits"] + end + + FFP -->|"SPTieee()"| SP + SP -->|"IEEEDPFieee()"| DP + SP -->|"SPFieee()"| FFP + DP -->|"IEEEDPTieee()"| SP +``` + +### Bit Layout Comparison + +``` +FFP (32-bit): MMMMMMMM MMMMMMMM MMMMMMMM ESSSSSSS + ╰── 24-bit mantissa ──╯╰exp╯╰sign╯ + +IEEE SP (32-bit): SEEEEEEE EMMMMMMM MMMMMMMM MMMMMMMM + ╰s╯╰─ 8-bit exp ─╯╰── 23-bit mantissa ──╯ + +IEEE DP (64-bit): SEEEEEEE EEEEMMMM MMMMMMMM MMMMMMMM + MMMMMMMM MMMMMMMM MMMMMMMM MMMMMMMM + ╰s╯╰─ 11-bit exp ──╯╰──── 52-bit mantissa ────╯ +``` + +> **FFP is NOT IEEE 754.** It predates the standard. The sign bit is at bit 0, the exponent uses excess-64 encoding, and the mantissa occupies the upper 24 bits. Mixing FFP and IEEE values without conversion causes silent data corruption. + +--- + +## Library Matrix — Six Libraries, Three Formats + +| Library | Format | Functions | In ROM? | Base Variable | +|---|---|---|---|---| +| `mathffp.library` | FFP | Basic: add, sub, mul, div, fix, flt | Yes | `MathBase` | +| `mathtrans.library` | FFP | Transcendental: sin, cos, tan, sqrt, exp, log | No (disk) | `MathTransBase` | +| `mathieeesingbas.library` | IEEE SP | Basic arithmetic (V36+) | Yes | `MathIeeeSingBasBase` | +| `mathieeesingtrans.library` | IEEE SP | Transcendentals (V36+) | No (disk) | `MathIeeeSingTransBase` | +| `mathieeedoubbas.library` | IEEE DP | Basic arithmetic | No (disk) | `MathIeeeDoubBasBase` | +| `mathieeedoubtrans.library` | IEEE DP | Transcendentals | No (disk) | `MathIeeeDoubTransBase` | + +### Dependency Chain + +```mermaid +graph LR + mathtrans["mathtrans.library
(FFP trig)"] -->|"auto-opens"| mathffp["mathffp.library
(FFP basic)"] + singtrans["mathieeesingtrans.library
(SP trig)"] -->|"auto-opens"| singbas["mathieeesingbas.library
(SP basic)"] + doubtrans["mathieeedoubtrans.library
(DP trig)"] -->|"auto-opens"| doubbas["mathieeedoubbas.library
(DP basic)"] +``` + +> **Important:** The transcendental library auto-opens the corresponding basic library. But if you need both, you must explicitly open the basic library yourself to get `MathBase` / `MathIeeeSingBasBase` / `MathIeeeDoubBasBase`. + +--- + +## How to Choose — Developer Decision Guide + +```mermaid +flowchart TD + START["Need floating point?"] --> Q1{"Targeting 68000 only?
(A500/A600/A1000)"} + Q1 -->|"Yes"| FFP_CHOICE["Use FFP libraries
mathffp.library + mathtrans.library"] + Q1 -->|"No, 68020+ ok"| Q2{"Need > 7 digits precision?"} + Q2 -->|"No, 7 digits fine"| SP_CHOICE["Use IEEE Single
mathieeesingbas.library"] + Q2 -->|"Yes, need ~16 digits"| DP_CHOICE["Use IEEE Double
mathieeedoubbas.library"] + Q1 -->|"Using a compiler"| Q3{"Does compiler handle it?"} + Q3 -->|"SAS/C: -ff or -fi"| COMPILER["Compiler links math
libs automatically"] + Q3 -->|"GCC: default IEEE"| GCC["GCC uses IEEE SP/DP
via libm or inline FPU"] + + FFP_CHOICE --> NOTE1["⚠ Legacy — avoid for new code"] + SP_CHOICE --> NOTE2["✓ Best balance for most apps"] + DP_CHOICE --> NOTE3["✓ Scientific / financial"] + + style FFP_CHOICE fill:#fff3cd,stroke:#d4a017,color:#333 + style SP_CHOICE fill:#d4edda,stroke:#28a745,color:#333 + style DP_CHOICE fill:#cce5ff,stroke:#007bff,color:#333 +``` + +### Quick Recommendation + +| Scenario | Library | Why | |---|---|---| -| `mathffp.library` | FFP (Motorola Fast Floating Point) | Original Amiga format (32-bit) | -| `mathieeesingbas.library` | IEEE 754 single (32-bit) | IEEE single precision | -| `mathieeedoubbas.library` | IEEE 754 double (64-bit) | IEEE double precision | -| `mathtrans.library` | FFP | Transcendental functions (sin, cos, sqrt) | -| `mathieeesingtrans.library` | IEEE single | IEEE single transcendentals | -| `mathieeedoubtrans.library` | IEEE double | IEEE double transcendentals | +| **New code, any CPU** | IEEE Single (`mathieeesingbas`) | Industry standard, auto-uses FPU when present | +| **Scientific / financial** | IEEE Double (`mathieeedoubbas`) | 15+ digits, no precision loss on long chains | +| **Legacy A500 compatibility** | FFP (`mathffp`) | Only choice for pure 68000 before V36 | +| **Game math (3D, physics)** | IEEE Single or direct FPU asm | Speed-critical — consider inline 68881 code | +| **GCC cross-compiler** | GCC built-in `float`/`double` | GCC generates FPU instructions or links soft-float | --- -## FFP Format +## FPU Detection and Transparent Acceleration -Motorola FFP is NOT IEEE 754: -``` -Bits 31–8: 24-bit mantissa (normalised, implicit 1.xxx) -Bits 7–1: 7-bit exponent (excess-64) -Bit 0: sign (0=positive, 1=negative) -``` - ---- - -## Using IEEE Math +When an FPU is present, the IEEE math libraries **automatically replace their JMP table entries** with native FPU instructions. The application sees no API change: ```c -struct Library *MathIeeeSingBasBase = - OpenLibrary("mathieeesingbas.library", 0); +#include -float a = 3.14f; -float b = 2.0f; -float c = IEEESPMul(a, b); /* 6.28 */ -float d = IEEESPAdd(a, b); /* 5.14 */ -float e = IEEESPDiv(a, b); /* 1.57 */ +/* Check FPU type */ +if (SysBase->AttnFlags & AFF_68881) /* 68881 or 68882 coprocessor */ +if (SysBase->AttnFlags & AFF_68882) /* specifically 68882 */ +if (SysBase->AttnFlags & AFF_FPU40) /* 68040 integrated FPU */ +if (SysBase->AttnFlags & AFF_68060) /* 68060 (check for LC variant!) */ +``` -CloseLibrary(MathIeeeSingBasBase); +### What Happens Under the Hood + +```mermaid +sequenceDiagram + participant APP as Application + participant LIB as mathieeedoubbas.library + participant EXEC as Exec + + APP->>LIB: OpenLibrary("mathieeedoubbas.library", 0) + LIB->>EXEC: Check AttnFlags + alt No FPU (68000/68020) + LIB->>LIB: JMP table → software emulation routines + else 68881/68882 Coprocessor + LIB->>LIB: JMP table → FPU instruction wrappers + else 68040/68060 Internal FPU + LIB->>LIB: JMP table → inline FMUL.D/FADD.D sequences + end + LIB-->>APP: Library base (same API regardless) + APP->>LIB: IEEEDPMul(a, b) + Note over LIB: Dispatches through JMP table
to hardware or software path + LIB-->>APP: Result in D0/D1 ``` --- -## 68881/68882 FPU +## 68040.library / 68060.library — The CPU Support Layer -When an FPU is present, the math libraries are replaced with ROM patches that use native FPU instructions. The application code is identical — the library transparently switches to hardware. +The math libraries are only half the story. The 68040 and 68060 **removed hardware microcode** for many FPU instructions that the 68881/68882 coprocessor supported natively. When the math libraries (or user code) execute these instructions on a 040/060, the CPU raises a **Line-F exception**. The CPU support libraries trap this exception and emulate the missing instruction in software. -```c -if (SysBase->AttnFlags & AFF_68881) { - /* 68881/68882 FPU present */ -} -if (SysBase->AttnFlags & AFF_FPU40) { - /* 68040 internal FPU */ -} +> **Without `68040.library` or `68060.library`, any transcendental FPU instruction (`FSIN`, `FCOS`, `FLOG`, etc.) causes an immediate Guru Meditation on 040/060 hardware.** + +See [68040_68060_libraries.md](../15_cpu_and_mmu/68040_68060_libraries.md) for the full instruction list and internals. + +### The Complete Math Execution Stack + +```mermaid +graph TB + subgraph "Application" + APP["IEEEDPSin(angle)"] + end + + subgraph "Math Library Layer" + MATHLIB["mathieeedoubtrans.library
JMP table dispatch"] + end + + subgraph "FPU Instruction Layer" + FPU_BASIC["Basic FPU ops
FADD, FMUL, FDIV, FSQRT
(implemented in 040/060 silicon)"] + FPU_TRANS["Transcendental FPU ops
FSIN, FCOS, FLOG, FATAN
(removed from 040/060)"] + end + + subgraph "CPU Support Layer" + CPULIB["68040.library / 68060.library
Line-F exception handler
FPSP (FP Support Package)"] + end + + subgraph "Emulation" + SOFT["Software emulation
Polynomial approximation
using basic FADD/FMUL"] + end + + APP --> MATHLIB + MATHLIB -->|"FPU present"| FPU_BASIC + MATHLIB -->|"FPU present"| FPU_TRANS + FPU_TRANS -->|"Line-F trap"| CPULIB + CPULIB --> SOFT + SOFT -->|"Uses"| FPU_BASIC + MATHLIB -->|"No FPU"| SOFT_DIRECT["Pure software path
(integer arithmetic)"] + + style FPU_TRANS fill:#fff3cd,stroke:#d4a017,color:#333 + style CPULIB fill:#cce5ff,stroke:#007bff,color:#333 ``` +### Library Variants and Sources + +| Library | Version | Source | Notes | +|---|---|---|---| +| `68040.library` 37.4 | OS 3.0 | Commodore | Original distribution | +| `68040.library` 40.1 | OS 3.1 | Commodore | Improved precision | +| `68060.library` 40.1 | — | Phase5 | For Blizzard/CyberStorm accelerators | +| `68060.library` 46.x | — | Motorola FPSP reference | Best precision and compatibility | +| `Mu68040.library` | — | Thomas Richter (MMULib) | Enhanced, with MMU support | +| `Mu68060.library` | — | Thomas Richter (MMULib) | Enhanced, with MMU + optimisations | + +### Three CPU Flavours + +| CPU | FPU | Math Behaviour | +|---|---|---| +| **68040** (full) | ✅ Built-in | Basic FPU ops in hardware. Transcendentals trapped → 68040.library | +| **68LC040** | ❌ No FPU | ALL FPU ops trap → needs 68040.library + SoftIEEE or full emulation | +| **68060** (full) | ✅ Built-in | Same as 040 but different removed set. Uses 68060.library | +| **68LC060** | ❌ No FPU | ALL FPU ops trap → needs 68060.library + SoftIEEE | +| **68EC040** | ❌ No FPU/MMU | Same as LC040 but also no MMU | + +> **LC = Low Cost** — these were cheaper variants that physically removed the FPU (and sometimes MMU) from the die. Many accelerator cards used LC variants to reduce cost. Applications must handle this gracefully. + +### Performance Impact + +Software emulation of transcendental FPU instructions through the Line-F trap is **10–100× slower** than the 68881/68882 hardware microcode: + +| Operation | 68882 (hardware) | 68040 + 68040.library | Ratio | +|---|---|---|---| +| FSIN | ~200 cycles | ~4000 cycles | ~20× | +| FCOS | ~200 cycles | ~4000 cycles | ~20× | +| FATAN | ~300 cycles | ~6000 cycles | ~20× | +| FLOG | ~400 cycles | ~8000 cycles | ~20× | + +Performance-critical code should use lookup tables, CORDIC algorithms, or polynomial approximations instead of relying on FSIN/FCOS in tight loops. + +--- + +## Third-Party Replacement Libraries + +The Amiga's library system allows **drop-in replacements** — you simply copy an optimised `.library` to `LIBS:` and it supersedes the ROM version. Several third-party packages exploit this for dramatic speedups. + +### HSMathLibs (Matthias Henze) + +The most comprehensive third-party math library replacement. Written entirely in hand-tuned assembler for specific CPU targets, achieving significant speedups over Commodore's original code. + +| Package | Target CPU | Aminet | +|---|---|---| +| `HSMathLibs_040` | MC68040 | `util/libs/HSMathLibs_040.lha` | +| `HSMathLibs_060` | MC68060 | `util/libs/HSMathLibs_060.lha` | + +**Replaces:** +- `mathieeedoubbas.library` — full replacement +- `mathieeedoubtrans.library` — full replacement +- `mathieeesingtrans.library` — full replacement +- `mathtrans.library` — full replacement +- `mathffp.library` — patched (via `mathffp-Patch` command) +- `mathieeesingbas.library` — patched (via `mathieeesingbas-Patch` command) + +**Key Properties:** +- Precision equal to or better than Commodore originals +- CPU-specific instruction scheduling (040 vs 060 pipelines differ significantly) +- Includes installer and uninstaller scripts +- Active development through v46.00 (2011) + +> **Install the correct version for your CPU.** The 040 and 060 have different pipeline architectures; using the wrong version may be slower than the originals or cause incorrect results. + +### Mu680x0Libs / MMULib (Thomas Richter) + +Part of the MMULib package, these provide optimised CPU-specific libraries including math support: + +| Package | Aminet | +|---|---| +| `Mu680x0Libs` | `util/sys/Mu680x0Libs.lha` | + +**Scope:** Primarily CPU support libraries (`68040.library`, `68060.library`) that include proper FPSP (Floating Point Support Package) for unimplemented FPU instructions. While not direct math library replacements, they ensure the hardware FPU is fully operational, which the standard math libraries then leverage. + +### SoftIEEE — Virtual FPU for LC/EC Variants + +For **68LC040** and **68LC060** processors (cost-reduced variants with no FPU silicon), `SoftIEEE` provides a complete FPU emulator: + +| Package | Aminet | +|---|---| +| `SoftIEEE` | `util/libs/SoftIEEE.lha` | + +Without SoftIEEE (or equivalent), any code that executes an FPU instruction on an LC variant causes an immediate **Line-F exception** → Guru Meditation. SoftIEEE traps these exceptions and emulates the FPU in software. + +### MuRedox — JIT FPU Acceleration + +For systems using FPU emulation (LC/EC processors), `MuRedox` provides a JIT (Just-In-Time) compilation approach: + +| Package | Aminet | +|---|---| +| `MuRedox` | `util/boot/MuRedox.lha` | + +Instead of trapping every FPU instruction via the exception handler, MuRedox patches the calling code in-place on first execution, replacing the FPU instruction with an equivalent software sequence. Subsequent calls skip the exception overhead entirely. + +### Replacement Architecture + +```mermaid +graph TB + subgraph "Application" + APP["IEEEDPMul(a, b)"] + end + + subgraph "Library Resolution" + LIBS["LIBS: directory
(disk-resident)"] + ROM["ROM resident
(Kickstart)"] + end + + subgraph "Possible Implementations" + STD["Commodore Original
(software / auto-FPU)"] + HS["HSMathLibs
(hand-tuned asm)"] + MU["Mu680x0Libs
(FPSP + MMU)"] + end + + APP --> LIBS + LIBS -->|"LIBS: copy wins"| HS + LIBS -->|"No LIBS: copy"| ROM + ROM --> STD + HS -->|"040 version"| OPT040["68040-optimised code"] + HS -->|"060 version"| OPT060["68060-optimised code"] + MU --> FPSP["FPSP: handles
unimplemented FPU ops"] +``` + +--- + +## Register Conventions (Assembly Interface) + +All math library functions follow the AmigaOS register calling convention: + +### Single Precision / FFP (32-bit) + +```asm +; Input: D0 = argument 1 (IEEE SP or FFP) +; D1 = argument 2 (for binary ops) +; Output: D0 = result +; Base: A6 = library base + + MOVEA.L _MathIeeeSingBasBase, A6 + MOVE.L arg1, D0 + MOVE.L arg2, D1 + JSR _LVOIEEESPMul(A6) ; D0 = arg1 * arg2 +``` + +### Double Precision (64-bit) + +```asm +; Input: D0/D1 = argument 1 (high/low longwords) +; D2/D3 = argument 2 +; Output: D0/D1 = result +; Base: A6 = library base + + MOVEA.L _MathIeeeDoubBasBase, A6 + MOVEM.L arg1, D0-D1 ; 64-bit value in D0:D1 + MOVEM.L arg2, D2-D3 + JSR _LVOIEEEDPMul(A6) ; D0:D1 = arg1 * arg2 +``` + +--- + +## Complete Function Reference + +### Basic Functions (all three formats) + +| Function | FFP (`SP*`) | IEEE SP (`IEEESP*`) | IEEE DP (`IEEEDP*`) | +|---|---|---|---| +| Fix to int | `SPFix` | `IEEESPFix` | `IEEEDPFix` | +| Int to float | `SPFlt` | `IEEESPFlt` | `IEEEDPFlt` | +| Compare | `SPCmp` | `IEEESPCmp` | `IEEEDPCmp` | +| Test sign | `SPTst` | `IEEESPTst` | `IEEEDPTst` | +| Absolute | `SPAbs` | `IEEESPAbs` | `IEEEDPAbs` | +| Negate | `SPNeg` | `IEEESPNeg` | `IEEEDPNeg` | +| Add | `SPAdd` | `IEEESPAdd` | `IEEEDPAdd` | +| Subtract | `SPSub` | `IEEESPSub` | `IEEEDPSub` | +| Multiply | `SPMul` | `IEEESPMul` | `IEEEDPMul` | +| Divide | `SPDiv` | `IEEESPDiv` | `IEEEDPDiv` | +| Ceiling | `SPCeil` | `IEEESPCeil` | `IEEEDPCeil` | +| Floor | `SPFloor` | `IEEESPFloor` | `IEEEDPFloor` | + +### Transcendental Functions + +| Function | FFP (`SP*`) | IEEE SP (`IEEESP*`) | IEEE DP (`IEEEDP*`) | +|---|---|---|---| +| Sine | `SPSin` | `IEEESPSin` | `IEEEDPSin` | +| Cosine | `SPCos` | `IEEESPCos` | `IEEEDPCos` | +| Tangent | `SPTan` | `IEEESPTan` | `IEEEDPTan` | +| Sin+Cos | `SPSincos` | `IEEESPSincos` | `IEEEDPSincos` | +| Arcsine | `SPAsin` | `IEEESPAsin` | `IEEEDPAsin` | +| Arccosine | `SPAcos` | `IEEESPAcos` | `IEEEDPAcos` | +| Arctangent | `SPAtan` | `IEEESPAtan` | `IEEEDPAtan` | +| Sinh | `SPSinh` | `IEEESPSinh` | `IEEEDPSinh` | +| Cosh | `SPCosh` | `IEEESPCosh` | `IEEEDPCosh` | +| Tanh | `SPTanh` | `IEEESPTanh` | `IEEEDPTanh` | +| Exponential | `SPExp` | `IEEESPExp` | `IEEEDPExp` | +| Nat. log | `SPLog` | `IEEESPLog` | `IEEEDPLog` | +| Log base 10 | `SPLog10` | `IEEESPLog10` | `IEEEDPLog10` | +| Power | `SPPow` | `IEEESPPow` | `IEEEDPPow` | +| Square root | `SPSqrt` | `IEEESPSqrt` | `IEEEDPSqrt` | + +### Conversion Functions (FFP ↔ IEEE) + +| Function | Direction | +|---|---| +| `SPTieee(ffp)` | FFP → IEEE single | +| `SPFieee(ieee)` | IEEE single → FFP | +| `IEEEDPTieee(dp)` | IEEE double → IEEE single | +| `IEEEDPFieee(sp)` | IEEE single → IEEE double | + +### String Conversion (FFP only, in `amiga.lib`) + +| Function | Purpose | +|---|---| +| `afp(string)` | ASCII → FFP | +| `fpa(ffp, buf)` | FFP → ASCII | +| `arnd(places, exp, buf)` | ASCII rounding | +| `dbf(exp, mantissa)` | Decimal base → FFP | + +--- + +## Compiler Integration + +### SAS/C + +``` +sc MATH=IEEE ; use IEEE single (default: FFP) +sc MATH=IEEEDP ; use IEEE double +sc MATH=FFP ; use FFP (default) +sc MATH=68881 ; direct 68881 code generation (not portable) +``` + +SAS/C automatically links the correct math library and generates the appropriate `JSR LVO(A6)` calls. + +### GCC (vbcc / m68k-amigaos-gcc) + +```bash +m68k-amigaos-gcc -m68020 -m68881 prog.c -lm # hardware FPU +m68k-amigaos-gcc -msoft-float prog.c -lm # software float +``` + +GCC uses IEEE format natively. With `-m68881`, it generates inline FPU instructions. Without it, it links a soft-float library. + +### vbcc + +```bash +vc +aos68k -fpu=68881 prog.c -lmieee # FPU code +vc +aos68k prog.c -lmieee # software IEEE +``` + +--- + +## Common Pitfalls + +1. **Mixing FFP and IEEE** — FFP and IEEE SP are both 32-bit but have incompatible layouts. Passing an FFP value to an IEEE function (or vice versa) produces garbage. Always convert with `SPTieee()` / `SPFieee()`. + +2. **Not opening basic + trans** — If you open `mathtrans.library`, it auto-opens `mathffp.library` internally. But `MathBase` won't be set in your code. If you need both basic and transcendental functions, open both explicitly. + +3. **Sharing base pointers between tasks** — Each task must call `OpenLibrary()` independently. The library base may contain per-opener state. Do not share `MathIeeeDoubBasBase` across tasks. + +4. **68LC040/060 crashes** — Code that works on full 68040 Gurus on LC variants. Install `SoftIEEE` or equivalent FPSP to trap Line-F exceptions from unimplemented FPU instructions. + +5. **HSMathLibs CPU mismatch** — Installing the 040-optimised libraries on a 060 (or vice versa) can cause incorrect results or reduced performance. The pipeline timings are architecturally different. + --- ## References -- NDK39: `libraries/mathffp.h`, `libraries/mathieeesp.h` +- RKRM: *Libraries Manual* — Math Libraries chapter +- [AmigaOS Wiki: Math Libraries](https://wiki.amigaos.net/wiki/Math_Libraries) +- NDK39: `libraries/mathffp.h`, `libraries/mathieeesp.h`, `libraries/mathieeedp.h` +- HSMathLibs: Aminet `util/libs/HSMathLibs_040.lha`, `util/libs/HSMathLibs_060.lha` +- Mu680x0Libs: Aminet `util/sys/Mu680x0Libs.lha` +- SoftIEEE: Aminet `util/libs/SoftIEEE.lha` +- MuRedox: Aminet `util/boot/MuRedox.lha`