// JoeyLib platform, CPU, endian, and capability defines.
//
// Exactly one JOEYLIB_PLATFORM_* must be defined per build. The build
// system normally sets this via -D; if absent, the header attempts to
// auto-detect from compiler-predefined macros.

#ifndef JOEYLIB_PLATFORM_H
#define JOEYLIB_PLATFORM_H

// ----- Auto-detect platform from compiler macros if not preset -----

#if !defined(JOEYLIB_PLATFORM_IIGS) && \
    !defined(JOEYLIB_PLATFORM_AMIGA) && \
    !defined(JOEYLIB_PLATFORM_ATARIST) && \
    !defined(JOEYLIB_PLATFORM_DOS) && \
    !defined(JOEYLIB_PLATFORM_X68000) && \
    !defined(JOEYLIB_PLATFORM_BLANK)

  #if defined(__DJGPP__) || defined(__MSDOS__)
    #define JOEYLIB_PLATFORM_DOS
  #elif defined(__amigaos__) || defined(AMIGA) || defined(__amigaos4__)
    #define JOEYLIB_PLATFORM_AMIGA
  #elif defined(__atarist__) || defined(__MINT__) || defined(__TOS__)
    #define JOEYLIB_PLATFORM_ATARIST
  #elif defined(__APPLE2GS__) || defined(__GNO__)
    #define JOEYLIB_PLATFORM_IIGS
  #elif defined(__x68k__) || defined(__X68000__) || defined(__HUMAN68K__)
    #define JOEYLIB_PLATFORM_X68000
  #else
    #error "JoeyLib: unknown platform; define JOEYLIB_PLATFORM_<TARGET> explicitly via -D"
  #endif

#endif

// JOEYLIB_PLATFORM_BLANK is the copy-to-start template for a new port (see
// src/blank/blank.c). It has no auto-detect macro -- bring it up by building
// with -DJOEYLIB_PLATFORM_BLANK.

// ----- Validate exactly one platform is defined -----

#if (defined(JOEYLIB_PLATFORM_IIGS) + \
     defined(JOEYLIB_PLATFORM_AMIGA) + \
     defined(JOEYLIB_PLATFORM_ATARIST) + \
     defined(JOEYLIB_PLATFORM_DOS) + \
     defined(JOEYLIB_PLATFORM_X68000) + \
     defined(JOEYLIB_PLATFORM_BLANK)) != 1
  #error "JoeyLib: exactly one JOEYLIB_PLATFORM_* must be defined"
#endif

// ----- Derived CPU markers -----

#if defined(JOEYLIB_PLATFORM_IIGS)
  #define JOEYLIB_CPU_65816
  #define JOEYLIB_ENDIAN_LITTLE
  #define JOEYLIB_NATIVE_CHUNKY
  #define JOEYLIB_PLATFORM_NAME "Apple IIgs"
#elif defined(JOEYLIB_PLATFORM_AMIGA)
  #define JOEYLIB_CPU_68000
  #define JOEYLIB_ENDIAN_BIG
  #define JOEYLIB_NATIVE_PLANAR
  #define JOEYLIB_HAS_BLITTER
  #define JOEYLIB_HAS_COPPER
  #define JOEYLIB_PLATFORM_NAME "Commodore Amiga"
#elif defined(JOEYLIB_PLATFORM_ATARIST)
  #define JOEYLIB_CPU_68000
  #define JOEYLIB_ENDIAN_BIG
  #define JOEYLIB_NATIVE_PLANAR
  #define JOEYLIB_PLATFORM_NAME "Atari ST"
#elif defined(JOEYLIB_PLATFORM_DOS)
  #define JOEYLIB_CPU_X86
  #define JOEYLIB_ENDIAN_LITTLE
  #define JOEYLIB_NATIVE_CHUNKY
  #define JOEYLIB_PLATFORM_NAME "MS-DOS"
#elif defined(JOEYLIB_PLATFORM_X68000)
  // BRING-UP STATE: chunky stage in main RAM, expanded to GVRAM by jlpPresent.
  // This is deliberately the slow-but-correct path -- it makes every one of the
  // 772 lines of src/generic work unmodified, so the port renders correctly
  // before a single native primitive exists.
  //
  // The native storage model is NOT yet decided. The two candidates are GVRAM
  // (2 bytes/pixel, trivial primitives) and the text plane at $E00000 (four
  // 1bpp planes 128 KB apart -- byte-for-byte the Amiga layout with stride 40
  // replaced by 128, so src/amiga adapts by changing one constant). Measured
  // under MAME with the wait-state patch: TVRAM costs 1.92 cycles/access
  // against GVRAM's 1.03, but needs only 0.25 word-writes per 16-colour pixel
  // against GVRAM's 1.0 -- so the text plane still wins ~2x. See
  // docs/x68000_mame_crtc_timing.md. Do not switch to JOEYLIB_NATIVE_PLANAR
  // until that is settled and measured.
  #define JOEYLIB_CPU_68000
  #define JOEYLIB_ENDIAN_BIG
  #define JOEYLIB_NATIVE_PLANAR
  #define JOEYLIB_PLATFORM_NAME "Sharp X68000"
#elif defined(JOEYLIB_PLATFORM_BLANK)
  // Chunky little-endian is the simplest baseline for a new port: the generic
  // backend gives you fully-working software rendering out of the box. Adjust
  // these (or switch to JOEYLIB_NATIVE_PLANAR) once you know your hardware.
  #define JOEYLIB_ENDIAN_LITTLE
  #define JOEYLIB_NATIVE_CHUNKY
  #define JOEYLIB_PLATFORM_NAME "Blank Template"
#endif

// ----- Per-machine op override registry (JL_HAS_<OP>) -----
//
// A machine #define-s JL_HAS_<OP> for each overridable platform op it replaces
// with its own (asm / native) implementation in src/<machine>/. Ops a machine
// does NOT claim fall back to the portable-C default in src/generic/, selected
// at compile time (no runtime dispatch). The jlp<Op> macros/prototypes in
// src/core/port.h read this table. This is the new lib's equivalent of the
// original joeylib's joey.h JL_HAS_* table.

#if defined(JOEYLIB_PLATFORM_IIGS)
  #define JL_HAS_SURFACE_CLEAR    // iigsSurfaceClearFastInner (stage), macro
  #define JL_HAS_DRAW_PIXEL       // iigsDrawPixelInner, macro
  #define JL_HAS_DRAW_LINE        // iigsDrawLineInner, macro
  #define JL_HAS_DRAW_CIRCLE      // iigsDrawCircleInner, macro
  #define JL_HAS_FILL_CIRCLE      // iigsFillCircleInner (stage), macro -- returns bool
  #define JL_HAS_FILL_RECT        // iigsFillRectMark (stage, fused mark), macro -> generic else
  #define JL_HAS_TILE_FILL        // iigsTileFillInner, macro
  #define JL_HAS_TILE_COPY        // iigsTileCopyInner, macro
  #define JL_HAS_TILE_COPY_MASKED // iigsTileCopyMaskedInner, macro
  #define JL_HAS_TILE_PASTE       // iigsTilePasteInner, macro
  #define JL_HAS_TILE_PASTE_MONO  // iigsTilePasteMonoInner (stage), macro -> generic else
  #define JL_HAS_TILE_SNAP        // iigsTileSnapInner, macro
  #define JL_HAS_SURFACE_COPY_RECT // jlpSurfaceCopyRect: inline word copy for
                                   // short spans (llvm-mos memcpy is a slow far
                                   // byte-loop, finding #79), function
  #define JL_HAS_SPRITE_DRAW      // chunky -> codegen; planes mirror is noop macro
  #define JL_HAS_SPRITE_SAVE      // noop macro (codegen path saves)
  #define JL_HAS_SPRITE_RESTORE   // noop macro
  #define JL_HAS_FLOOD_WALK_AND_SCANS // iigsFloodWalkAndScansInner (all-in-one), macro
  #define JL_HAS_BIG_ALLOC            // Memory Manager NewHandle/DisposeHandle, function
  #define JL_HAS_STAGE_ALLOC_PIXELS   // pinned $01:2000 display memory, function
  #define JL_HAS_STAGE_FREE_PIXELS    // no-op (pinned), function
  #define JL_HAS_FRAME_HZ             // runtime 50/60 from battery RAM, function
  // (frameCount: port.h #defines jlpFrameCount straight to iigsGetTickWord,
  //  the GetTick asm wrapper -- no function override to register here.)
  #define JL_HAS_WAIT_VBL             // $C019 VBL poll, function
  // audio: every real port implements the full engine
  #define JL_HAS_AUDIO_INIT
  #define JL_HAS_AUDIO_SHUTDOWN
  #define JL_HAS_AUDIO_PLAY_MOD
  #define JL_HAS_AUDIO_STOP_MOD
  #define JL_HAS_AUDIO_IS_PLAYING_MOD
  #define JL_HAS_AUDIO_PLAY_SFX
  #define JL_HAS_AUDIO_PLAY_SFX_STREAM
  #define JL_HAS_AUDIO_STOP_SFX
  #define JL_HAS_AUDIO_TONE
  #define JL_HAS_AUDIO_VOICE
  #define JL_HAS_AUDIO_NOISE
  #define JL_HAS_AUDIO_TICK_REGISTER
  #define JL_HAS_AUDIO_CRITICAL_ENTER
  #define JL_HAS_AUDIO_CRITICAL_EXIT
  #define JL_HAS_AUDIO_FRAME_TICK
  // lifecycle / present / input (every real port implements)
  #define JL_HAS_INIT
  #define JL_HAS_SHUTDOWN
  #define JL_HAS_PRESENT
  #define JL_HAS_INPUT_INIT
  #define JL_HAS_INPUT_SHUTDOWN
  #define JL_HAS_INPUT_POLL
  #define JL_HAS_JOYSTICK_RESET
  // serial add-on (optional; SCC modem/printer + 6551 Super Serial Card)
  #define JL_HAS_SERIAL_OPEN
  #define JL_HAS_SERIAL_CLOSE
  #define JL_HAS_SERIAL_POLL
  #define JL_HAS_SERIAL_READ
  #define JL_HAS_SERIAL_WRITE
  #define JL_HAS_SERIAL_AVAILABLE
  #define JL_HAS_SERIAL_FLUSH
  // save files + disk space: delete (GS/OS Destroy), dir-ensure (GS/OS Create
  // $2001, storageType 13), disk-free (GS/OS Volume $2008 via prefix 0).
  #define JL_HAS_SAVE_DIR_ENSURE
  #define JL_HAS_SAVE_DELETE
  #define JL_HAS_DISK_FREE
  // millisElapsed: generic frameCount*1000/frameHz (no override)
#elif defined(JOEYLIB_PLATFORM_AMIGA)
  #define JL_HAS_SURFACE_CLEAR    // planar clear, function
  #define JL_HAS_DRAW_PIXEL       // amigaPlanarSetPixel, function
  #define JL_HAS_DRAW_LINE        // amigaPlanarLine, function
  #define JL_HAS_DRAW_CIRCLE      // amiga planar circle, function
  #define JL_HAS_FILL_CIRCLE      // amiga planar fill circle, function -- returns bool
  #define JL_HAS_FILL_RECT        // amiga planar fill rect, function
  #define JL_HAS_TILE_FILL        // amiga planar tile fill, inline (amigaTile.h)
  #define JL_HAS_TILE_COPY        // amiga planar tile copy, inline (amigaTile.h)
  #define JL_HAS_TILE_COPY_MASKED // amiga planar masked copy, inline (amigaTile.h)
  #define JL_HAS_TILE_PASTE       // amiga planar tile paste, inline (amigaTile.h)
  #define JL_HAS_TILE_SNAP        // amiga planar tile snap, inline (amigaTile.h)
  #define JL_HAS_TILE_PASTE_MONO  // amiga planar mono colorize+paste, inline (amigaTile.h)
  #define JL_HAS_SPRITE_DRAW      // amiga planar sprite draw, function
  #define JL_HAS_SPRITE_SAVE      // amiga planar sprite save, function
  #define JL_HAS_SPRITE_RESTORE   // amiga planar sprite restore, function
  #define JL_HAS_FLOOD_WALK_PLANES     // amiga planar flood walk-out, function
  #define JL_HAS_FLOOD_SCAN_ROW_PLANES // amiga planar flood scan-row, function
  #define JL_HAS_SURFACE_COPY_PLANES   // amiga blitter plane copy, function
  #define JL_HAS_SURFACE_COPY_RECT     // amiga per-plane rect row copy, function
  #define JL_HAS_SAMPLE_PIXEL          // amiga planar nibble decode, function
  #define JL_HAS_SURFACE_HASH          // amiga planar hash, function
  #define JL_HAS_SURFACE_LOAD_FILE     // amiga planar load, function
  #define JL_HAS_SURFACE_SAVE_FILE     // amiga planar save, function
  #define JL_HAS_STAGE_ALLOC_PIXELS    // amiga: NULL (no chunky stage shadow), function
  #define JL_HAS_SURFACE_ALLOC_PIXELS  // amiga: NULL (planar storage), function
  #define JL_HAS_SURFACE_ALLOC_PORT_DATA // amiga AmigaPlanarT + chip planes, function
  #define JL_HAS_SURFACE_FREE_PORT_DATA  // amiga FreeMem planes, function
  #define JL_HAS_FRAME_HZ              // PAL 50, function
  #define JL_HAS_FRAME_COUNT           // VBL-server counter, function
  #define JL_HAS_WAIT_VBL              // WaitTOF, function
  // audio: every real port implements the full engine
  #define JL_HAS_AUDIO_INIT
  #define JL_HAS_AUDIO_SHUTDOWN
  #define JL_HAS_AUDIO_PLAY_MOD
  #define JL_HAS_AUDIO_STOP_MOD
  #define JL_HAS_AUDIO_IS_PLAYING_MOD
  #define JL_HAS_AUDIO_PLAY_SFX
  #define JL_HAS_AUDIO_PLAY_SFX_STREAM
  #define JL_HAS_AUDIO_STOP_SFX
  #define JL_HAS_AUDIO_TONE
  #define JL_HAS_AUDIO_VOICE
  #define JL_HAS_AUDIO_NOISE
  #define JL_HAS_AUDIO_TICK_REGISTER
  #define JL_HAS_AUDIO_CRITICAL_ENTER
  #define JL_HAS_AUDIO_CRITICAL_EXIT
  #define JL_HAS_AUDIO_FRAME_TICK
  // lifecycle / present / input (every real port implements)
  #define JL_HAS_INIT
  #define JL_HAS_SHUTDOWN
  #define JL_HAS_PRESENT
  #define JL_HAS_INPUT_INIT
  #define JL_HAS_INPUT_SHUTDOWN
  #define JL_HAS_INPUT_POLL
  #define JL_HAS_JOYSTICK_RESET
  // serial add-on (optional; serial.device)
  #define JL_HAS_SERIAL_OPEN
  #define JL_HAS_SERIAL_CLOSE
  #define JL_HAS_SERIAL_POLL
  #define JL_HAS_SERIAL_READ
  #define JL_HAS_SERIAL_WRITE
  #define JL_HAS_SERIAL_AVAILABLE
  #define JL_HAS_SERIAL_FLUSH
  // save files + disk space (CreateDir/DeleteFile/Info via dos.library)
  #define JL_HAS_SAVE_DIR_ENSURE
  #define JL_HAS_SAVE_DELETE
  #define JL_HAS_DISK_FREE
  // millisElapsed: generic frameCount*1000/frameHz (no override)
#elif defined(JOEYLIB_PLATFORM_ATARIST)
  #define JL_HAS_SURFACE_CLEAR    // planar clear, function
  #define JL_HAS_DRAW_PIXEL       // stPlanarSetPixel, function
  #define JL_HAS_DRAW_LINE        // stPlanarLine, function
  #define JL_HAS_DRAW_CIRCLE      // st planar circle, function
  #define JL_HAS_FILL_CIRCLE      // st planar fill circle, function -- returns bool
  #define JL_HAS_FILL_RECT        // st planar fill rect, function
  #define JL_HAS_TILE_FILL        // st planar tile fill, inline (stTile.h)
  #define JL_HAS_TILE_COPY        // st planar tile copy, inline (stTile.h)
  #define JL_HAS_TILE_COPY_MASKED // st planar masked copy, inline (stTile.h)
  #define JL_HAS_TILE_PASTE       // st planar tile paste, inline (stTile.h)
  #define JL_HAS_TILE_SNAP        // st planar tile snap, inline (stTile.h)
  #define JL_HAS_TILE_PASTE_MONO  // st planar mono colorize+paste, inline (stTile.h)
  #define JL_HAS_SPRITE_DRAW      // st planar sprite draw, function
  #define JL_HAS_SPRITE_SAVE      // st planar sprite save, function
  #define JL_HAS_SPRITE_RESTORE   // st planar sprite restore, function
  #define JL_HAS_FLOOD_WALK_PLANES     // st planar flood walk-out, function
  #define JL_HAS_FLOOD_SCAN_ROW_PLANES // st planar flood scan-row, function
  #define JL_HAS_SURFACE_COPY_PLANES // st planar buffer memcpy, function
  #define JL_HAS_SURFACE_COPY_RECT   // st interleaved rect row memcpy, function
  #define JL_HAS_SAMPLE_PIXEL        // st planar nibble decode, function
  #define JL_HAS_SURFACE_HASH        // st planar hash, function
  #define JL_HAS_SURFACE_LOAD_FILE   // st planar load, function
  #define JL_HAS_SURFACE_SAVE_FILE   // st planar save, function
  #define JL_HAS_STAGE_ALLOC_PIXELS    // st: NULL (no chunky stage shadow), function
  #define JL_HAS_SURFACE_ALLOC_PIXELS  // st: NULL (planar storage), function
  #define JL_HAS_SURFACE_ALLOC_PORT_DATA // st StPlanarT + interleaved buffer, function
  #define JL_HAS_SURFACE_FREE_PORT_DATA  // st free buffer, function
  #define JL_HAS_FRAME_HZ            // PAL 50, function
  #define JL_HAS_FRAME_COUNT         // VBL-ISR counter, function
  #define JL_HAS_WAIT_VBL            // frame-counter wait, function
  #define JL_HAS_MILLIS_ELAPSED      // Supexec 200 Hz tick, function
  // audio: every real port implements the full engine
  #define JL_HAS_AUDIO_INIT
  #define JL_HAS_AUDIO_SHUTDOWN
  #define JL_HAS_AUDIO_PLAY_MOD
  #define JL_HAS_AUDIO_STOP_MOD
  #define JL_HAS_AUDIO_IS_PLAYING_MOD
  #define JL_HAS_AUDIO_PLAY_SFX
  #define JL_HAS_AUDIO_PLAY_SFX_STREAM
  #define JL_HAS_AUDIO_STOP_SFX
  #define JL_HAS_AUDIO_TONE
  #define JL_HAS_AUDIO_VOICE
  #define JL_HAS_AUDIO_NOISE
  #define JL_HAS_AUDIO_TICK_REGISTER
  #define JL_HAS_AUDIO_CRITICAL_ENTER
  #define JL_HAS_AUDIO_CRITICAL_EXIT
  #define JL_HAS_AUDIO_FRAME_TICK
  // lifecycle / present / input (every real port implements)
  #define JL_HAS_INIT
  #define JL_HAS_SHUTDOWN
  #define JL_HAS_PRESENT
  #define JL_HAS_INPUT_INIT
  #define JL_HAS_INPUT_SHUTDOWN
  #define JL_HAS_INPUT_POLL
  #define JL_HAS_JOYSTICK_RESET
  // serial add-on (optional; BIOS Aux / XBIOS Rsconf on the Modem port)
  #define JL_HAS_SERIAL_OPEN
  #define JL_HAS_SERIAL_CLOSE
  #define JL_HAS_SERIAL_POLL
  #define JL_HAS_SERIAL_READ
  #define JL_HAS_SERIAL_WRITE
  #define JL_HAS_SERIAL_AVAILABLE
  #define JL_HAS_SERIAL_FLUSH
  // save files + disk space (POSIX mkdir/remove + GEMDOS Dfree)
  #define JL_HAS_SAVE_DIR_ENSURE
  #define JL_HAS_SAVE_DELETE
  #define JL_HAS_DISK_FREE
#elif defined(JOEYLIB_PLATFORM_DOS)
  // chunky generics: surface clear, draw pixel/line/circle, fill circle/rect,
  // tiles, surface readers, allocation -- DOS overrides the timing services
  // plus the whole-map tile walker (src/dos/dosTile.h, dispatched via the
  // jlpTileMapPaste alias from tile.c's shared whole-map arm like the ST
  // engine; not a jlp op, so no JL_HAS flag).
  // (The planar dual-write hooks are not linked to generics: every chunky port
  //  elides them to ((void)0) in port.h's shared chunky block, PERF-AUDIT #42.)
  #define JL_HAS_FRAME_HZ            // VGA ~70, function
  #define JL_HAS_FRAME_COUNT         // $3DA retrace edge counter, function
  #define JL_HAS_WAIT_VBL            // $3DA retrace poll, function
  #define JL_HAS_MILLIS_ELAPSED      // uclock / audio-ISR tick, function
  // audio: every real port implements the full engine
  #define JL_HAS_AUDIO_INIT
  #define JL_HAS_AUDIO_SHUTDOWN
  #define JL_HAS_AUDIO_PLAY_MOD
  #define JL_HAS_AUDIO_STOP_MOD
  #define JL_HAS_AUDIO_IS_PLAYING_MOD
  #define JL_HAS_AUDIO_PLAY_SFX
  #define JL_HAS_AUDIO_PLAY_SFX_STREAM
  #define JL_HAS_AUDIO_STOP_SFX
  #define JL_HAS_AUDIO_TONE
  #define JL_HAS_AUDIO_VOICE
  #define JL_HAS_AUDIO_NOISE
  #define JL_HAS_AUDIO_TICK_REGISTER
  #define JL_HAS_AUDIO_CRITICAL_ENTER
  #define JL_HAS_AUDIO_CRITICAL_EXIT
  #define JL_HAS_AUDIO_FRAME_TICK
  // lifecycle / present / input (every real port implements)
  #define JL_HAS_INIT
  #define JL_HAS_SHUTDOWN
  #define JL_HAS_PRESENT
  #define JL_HAS_INPUT_INIT
  #define JL_HAS_INPUT_SHUTDOWN
  #define JL_HAS_INPUT_POLL
  #define JL_HAS_JOYSTICK_RESET
  // serial add-on (optional; 8250/16550 UART on a COM port, IRQ RX ring)
  #define JL_HAS_SERIAL_OPEN
  #define JL_HAS_SERIAL_CLOSE
  #define JL_HAS_SERIAL_POLL
  #define JL_HAS_SERIAL_READ
  #define JL_HAS_SERIAL_WRITE
  #define JL_HAS_SERIAL_AVAILABLE
  #define JL_HAS_SERIAL_FLUSH
  // save files + disk space (POSIX mkdir/remove + int21h/36h disk-free)
  #define JL_HAS_SAVE_DIR_ENSURE
  #define JL_HAS_SAVE_DELETE
  #define JL_HAS_DISK_FREE
#elif defined(JOEYLIB_PLATFORM_X68000)
  // Bring-up: platform SERVICES only (src/x68000/hal.c), plus the serial
  // add-on (src/x68000/serial.c). Everything graphical comes from the portable
  // generics, so the port renders correctly before any native primitive
  // exists. Native ops arrive with the storage-model decision.
  // Planar graphics, adapted from the Amiga (identical surface layout).
  #define JL_HAS_SURFACE_CLEAR
  #define JL_HAS_DRAW_PIXEL
  #define JL_HAS_DRAW_LINE
  #define JL_HAS_DRAW_CIRCLE
  #define JL_HAS_FILL_CIRCLE
  #define JL_HAS_FILL_RECT
  #define JL_HAS_TILE_FILL
  #define JL_HAS_TILE_COPY
  #define JL_HAS_TILE_COPY_MASKED
  #define JL_HAS_TILE_PASTE
  #define JL_HAS_TILE_SNAP
  #define JL_HAS_TILE_PASTE_MONO
  #define JL_HAS_SPRITE_DRAW
  #define JL_HAS_SPRITE_SAVE
  #define JL_HAS_SPRITE_RESTORE
  #define JL_HAS_FLOOD_WALK_PLANES
  #define JL_HAS_FLOOD_SCAN_ROW_PLANES
  #define JL_HAS_SURFACE_COPY_PLANES
  #define JL_HAS_SURFACE_COPY_RECT
  #define JL_HAS_SAMPLE_PIXEL
  #define JL_HAS_SURFACE_HASH
  #define JL_HAS_SURFACE_LOAD_FILE
  #define JL_HAS_SURFACE_SAVE_FILE
  #define JL_HAS_STAGE_ALLOC_PIXELS
  #define JL_HAS_SURFACE_ALLOC_PIXELS
  #define JL_HAS_SURFACE_ALLOC_PORT_DATA
  #define JL_HAS_SURFACE_FREE_PORT_DATA
  #define JL_HAS_INIT            // _iocs_crtmod display bring-up
  #define JL_HAS_SHUTDOWN        // restore the previous CRT mode
  #define JL_HAS_PRESENT         // expand the chunky stage into GVRAM
  #define JL_HAS_INPUT_INIT
  #define JL_HAS_INPUT_SHUTDOWN
  #define JL_HAS_INPUT_POLL      // _iocs_bitsns key bitmaps -> gKeyState[]
  #define JL_HAS_JOYSTICK_RESET
  #define JL_HAS_WAIT_VBL        // _iocs_vsync
  #define JL_HAS_FRAME_COUNT
  #define JL_HAS_FRAME_HZ        // ~55 Hz in the 31 kHz modes
  // Chains Human68k's MFP Timer C (~100 Hz). Without this the port fell back to
  // the generic clock, which derives ms from the POLLED frame counter and
  // undercounts exactly in proportion to how slow the op is.
  #define JL_HAS_MILLIS_ELAPSED
  // Save add-on: Human68k _dos_dskfre / _dos_mkdir, structurally the ST HAL.
  #define JL_HAS_DISK_FREE
  #define JL_HAS_SAVE_DELETE
  #define JL_HAS_SAVE_DIR_ENSURE
  // Serial add-on: IOCS polled RS-232C, structurally the ST HAL.
  #define JL_HAS_SERIAL_OPEN
  #define JL_HAS_SERIAL_CLOSE
  #define JL_HAS_SERIAL_POLL
  #define JL_HAS_SERIAL_AVAILABLE
  #define JL_HAS_SERIAL_READ
  #define JL_HAS_SERIAL_WRITE
  #define JL_HAS_SERIAL_FLUSH
  // Audio. CHIP side on the YM2151 (OPM): tone voices + noise, which is what
  // the portable JYM1 tracker rides, with no CPU mixing.
  #define JL_HAS_AUDIO_INIT
  #define JL_HAS_AUDIO_SHUTDOWN
  #define JL_HAS_AUDIO_TONE
  #define JL_HAS_AUDIO_VOICE
  #define JL_HAS_AUDIO_NOISE
  #define JL_HAS_AUDIO_CRITICAL_ENTER
  #define JL_HAS_AUDIO_CRITICAL_EXIT
  #define JL_HAS_AUDIO_FRAME_TICK
  // SAMPLE side (src/x68000/audioPcm.c): libxmp-lite + the shared 5-slot SFX
  // overlay, encoded to MSM6258 ADPCM and played via _iocs_adpcmlot. Separate
  // device from the OPM, so chip music and digital audio do not contend.
  #define JL_HAS_AUDIO_PLAY_MOD
  #define JL_HAS_AUDIO_STOP_MOD
  #define JL_HAS_AUDIO_IS_PLAYING_MOD
  #define JL_HAS_AUDIO_PLAY_SFX
  #define JL_HAS_AUDIO_PLAY_SFX_STREAM
  #define JL_HAS_AUDIO_STOP_SFX
#elif defined(JOEYLIB_PLATFORM_BLANK)
  // Copy-to-start template. It overrides ONLY the platform SERVICES (TODO
  // stubs in src/blank/blank.c). Everything graphical -- draw / tile / sprite
  // primitives, surface readers, allocation, bigAlloc, millisElapsed -- comes
  // from the portable-C generics for free, so a chunky port renders correctly
  // before you write a line of graphics code. Add a JL_HAS_<OP> here + an
  // override in blank.c only when you want to accelerate a specific op.
  #define JL_HAS_INIT            // bring up your display mode
  #define JL_HAS_SHUTDOWN        // restore it
  #define JL_HAS_PRESENT         // blit the chunky stage to your framebuffer
  #define JL_HAS_INPUT_INIT
  #define JL_HAS_INPUT_SHUTDOWN
  #define JL_HAS_INPUT_POLL      // read your keyboard into gKeyState[]
  #define JL_HAS_JOYSTICK_RESET
  #define JL_HAS_WAIT_VBL        // pace to the display
  #define JL_HAS_FRAME_COUNT     // a monotonic frame/refresh counter
  #define JL_HAS_FRAME_HZ        // your refresh rate in Hz
  // audio: left to the no-op generics (your port links + runs silent). Add
  //   JL_HAS_AUDIO_* + overrides in blank.c when you wire up sound.
#endif

// ----- Library version -----

#define JOEYLIB_VERSION_MAJOR 1
#define JOEYLIB_VERSION_MINOR 0
#define JOEYLIB_VERSION_PATCH 0
#define JOEYLIB_VERSION_STRING "1.0.0"

#endif
