libretroadmin a502ceafc4 ppu: precomputed pair LUT for the per-tile palette gather
The pputile.h `if (X1 >= 2)` block does the 8-pixel per-tile pen
expansion via eight serial nibble loads:

    P[0] = PALRAM[pixdata & 0xF]; pixdata >>= 4;
    P[1] = PALRAM[pixdata & 0xF]; pixdata >>= 4;
    ... [8 iterations]

gcc -O3 already does an impressive job: it unrolls the eight shifts
into independent loads from the L1-resident 16-byte PALRAM, then
folds the eight bytes into a single 64-bit register via a
shift-OR-accumulate chain and emits one movq to P.  Even so, the
per-tile gather shows up as the dominant (a)-case missed-vec site
in -fopt-info-vec-missed for RefreshLine (10 hits at ppu.c:367 and
4-hit clusters at every pputile.h include site), "control flow in
loop" being the headline reason.

Replacing it with a precomputed 256-entry pair LUT halves the load
count: each 8-bit slice of pixdata indexes pair_lut[256] returning
a 16-bit value with two expanded pens, so four 16-bit loads and a
shift-OR-accumulate of four halves produce the same 64-bit tile
word that one movq writes to P.  The LUT is rebuilt at the start of
every RefreshLine call (~768 ops per rebuild, ~240 rebuilds/frame
plus the occasional mid-scanline FCEUPPU_LineUpdate call), so
mid-frame raster effects writing to $3F00-$3F0F are reflected on
the very next scanline.

A subtlety found while implementing: the natural

    uint64_t packed = ...; memcpy(P, &packed, 8);

(or a packed-struct equivalent) routes the store through a stack
scratch -- gcc spills `packed` to %rsp, then "copies" 8 bytes back
out via a memcpy lowering that re-reads the same stack slot.  Result
is *slower* than the original eight-load scalar.  Using a
`uint64_t __attribute__((may_alias, aligned(1)))` typedef sidesteps
that path entirely; gcc emits a direct `movq %reg, -8(%r13)` and
the optimisation lands.

Codegen verified: 12 distinct pputile.h expansion sites in the .s
each emit four `movzwl 0(%rbx,...,2)` LUT loads + a shift-OR
accumulate + one `movq %X, -8(%r13)` to P, with no %rsp traffic
in the inner loops.  gcc hoists the LUT base into %rbx once at
function entry and reuses it across all 12 sites.

Microbench (32 tiles x 240 scanlines x 1000 frames; PALRAM and
pixdata refreshed each iter to defeat caching games, LUT rebuild
charged on every iteration to the new path):
  -O3:  22.4 ms -> 9.9 ms   (2.25x)   2730 -> 6200 Mpix/s
  -O2:  27.1 ms -> 12.3 ms  (2.21x)   2267 -> 5005 Mpix/s
Bit-exact across 2000 random PALRAM+pixdata permutations.
2026-06-14 15:39:45 +02:00
2024-09-23 05:55:21 -07:00
2023-01-02 19:47:36 +01:00
2026-04-02 10:14:04 +01:00
Fix
2017-12-21 20:40:28 +09:00
2014-12-23 09:50:29 +01:00
2015-08-06 13:28:43 +02:00
2025-09-03 16:20:50 +02:00
2019-06-28 23:44:06 +02:00

Build Status Build status

FCE Ultra mappers modified

FCEU "mappers modified" is an unofficial build of FCEU Ultra by CaH4e3, which supports a lot of new mappers including some obscure mappers such as one for unlicensed NES ROM's.

Sequential targets Light Guns support added

Support for Sequential targets Light Guns has been added. "Gun Aux A" serves as light sensor logic input.

Description
Pinned internal source mirror of libretro/libretro-fceumm for Supergame releases
Readme 4.3 MiB
Languages
C 97.7%
Python 2%
C++ 0.2%