Skip to content

Releases: thekoalakoa/paprium-pocket

0.2.6 — CPU MATE, the menu options, and the cartridge's own sprite rules

Choose a tag to compare

@thekoalakoa thekoalakoa released this 12 Oct 21:44

The game's CPU MATE partner on the Pocket, a menu of cheats, arcade and console options, and the
end-credits and Solarium bugs fixed by doing what the original cartridge does.

Install with Pupdate or unzip onto the card. Your ROM and
paprium.pcm in Assets/paprium/common/ are untouched by an upgrade. Copy the whole
Cores/Koala_Koa.Paprium/ folder, not just the bitstream: the new menu lives in interact.json.
Everything new is off by default. With the defaults, the one menu-level difference from 0.2.5 is
that the game no longer shows a MegaWire as connected, which is what a real cartridge does with nothing
plugged in.

New

CPU MATE. With a Mega CD unit chosen in the core menu, Paprium offers its computer-controlled
partner, as it does on a real Mega Drive with a Mega CD:

  1. Core menu: Mega CD = any unit except None or Unknown CD, then Soft Reset (mini game).
  2. In the game's Options, switch CPU MATE on.
  3. At character select, bring the partner in:
    • Played handheld: turn 6-Button on in the core menu. Hold Select to add the partner;
      still holding it, move the partner's cursor with the D-pad and press Start to pick its
      character. Release Select to pick your own. No second controller needed: it is the game's own
      six-button control with a Mega CD (Paprium FAQ).
    • With a second controller on the Dock: press Start on controller 2, and again to pick its
      character.

On the real thing the partner's AI runs on the Mega CD's sub-CPU. Here it is the game's own AI program,
re-implemented and translated to run on the cartridge MCU, behind a Mega CD link that hands the game the
partner's moves at the moment the real sub-CPU would. The game's code is not patched. The brain is built
into this release's bitstream; nothing extra to download to play.

Scum!, new switches in the core menu:

Entry What it does
Little-Man Cheats: infinite Health (players take no damage, specials cost none; enemies unaffected), Pills (Blu pills are not spent) and Lives, in any combination. Applies at once
Arcade Stage Select / 2 The game's hidden ARCADE PAPRIUM mode (credits, friendly fire), started on any of 25 stages. Select inserts a coin. Needs a Soft Reset
6-Button X, Y, Z and Mode reach the game, on L, X, R and Select. Applies at once

Nothing touches your ROM file: while a switch is on, the cartridge serves a few replacement words in
place of the game's own, like a Game Genie in the FPGA.

The machine the game sees, also new in the core menu, each read at boot (change, then Soft Reset):

Entry Choices
Console Mega Drive (default), Genesis, Mega Drive 2, Genesis Model 2, Genesis 3, Nomad, Mega Jet, Unknown. Sets the region and the console picture in the Boom Box; the TMSS models boot with no licence screen
Mega CD None (default), Mega-CD / Sega CD, Mega-CD 2 / Sega CD 2, Wondermega, Wondermega M2 / X'Eye, LaserActive, Aiwa CSD-GM1, CDX, Unknown CD. Each with its splash and region
32X Mode The game believes a 32X is attached; some throwables become 32X boxes
MegaWire Off by default, which is what a real cartridge reports with nothing plugged in: MODEM : NONE, no MegaWire icon. Every earlier release showed a MegaWire as connected; on brings that back

Fixed

Enemies that could not be killed, and Pang's KTV Member Card going missing. When enemies dropped in from above, an enemy could turn invisible and unkillable and stop the screen scrolling, so the section could not be finished; pausing did not help. In Original mode, beating Pang at Golden Of Seas earns his KTV Member Card, the pass the bouncer at Digniti KTV asks for. Without it the run ends at Digniti KTV with "THE END?", before The Vault, Sanophix Labs, The Solarium and the ending, as it does on a real cartridge. Here, Pang still handed the card over on screen, but nearly half the time it was not kept in the save. The core's cartridge memory stored single-byte writes from the console, which a real cartridge does not, so the game's own check of the cartridge concluded it was not genuine and, until the game was reset or switched off, did both. The cartridge memory now ignores single-byte writes, and the check passes as it does on a real cartridge, so the card is now kept every time. A save that lost the card under an earlier release does not get it back by itself: clear Golden Of Seas once more in Original mode. Every earlier release had this.

The end credits. Sparkles were drawn as squares of background art, and the credits pictures had
damaged tiles. The firmware's sprite cache put the sparkle's art into memory that the credits background
lives in. The cache now works the way the original cartridge's does (slots age into free, idle and
recently used; a missing block takes the lowest free slot first; a piece that cannot load is dropped on
its own), and the sparkle lands clear of the background every time.

The Solarium float. At the end of the game, characters froze in mid-walk and floated across the
camera pan. With the HUD hidden, the previous frame's sprites stayed linked and kept drawing. The sprite
table is now closed the cartridge's way, with an end mark (the MiSTer Paprium team's patch).

Freezes in busy fights. A character could freeze in a pose for up to half a second when its new
pose's art was refused a slot. With the new cache, a recorded fight that refused 1,038 loads refuses
none, and the DMA budget and pose hold now follow the cartridge too: a pose that does not fit is held
whole or pre-loaded over a few frames, never drawn in part.

Animation, the cartridge's way. 0.2.6 replaces 0.2.5's props-versus-actors rule, and the three
animation rules before it, with the cartridge's own: when it takes a queued animation, it writes it back
into the game's object record, which is what the game checks next time. With that one write, a dropped
weapon settles and a character walking in keeps walking, with no heuristic. The four old rules are
compiled out.

The Boom Box bars run at the measured tempo instead of about 20% fast.

Under the hood

  • A clock-crossing race on the MCU's stream pointer, fixed at its root; constraint exceptions for the
    real crossings; FX68K's own multicycle constraint for its worst (false) path.
  • The sound-effect echo line and the album's stream buffer moved into the Pocket's cellular RAM, freeing
    block RAM; the Pocket's SRAM opened to the MCU for the CPU MATE.
  • A stale one-clock reply on APF file commands fixed.
  • The release firmware compiles all debug output out.
  • Fit: seed 3, 18,079 ALM (98%), 253 M10K, worst setup −1.026 ns, worst hold +0.085 ns.

Tested on a real Pocket before release: default boot, all 8 consoles and every Mega CD unit (picture,
splash, region), the TMSS consoles, MegaWire off, 32X Mode, and the regression list (select screen,
Original to Arcade, The Solarium, credits, elevator, dropped weapons, attract demo, CPU MATE, busy
fights, sound effects and echo). The final build, with the cartridge-memory fix, was checked again: five
cold boots; Soft Resets across switches between Arcade and Original modes, Console, Mega CD and
MegaWire; enemies dropping in on MTS and Roof-Top after a food pickup; the Arcade coin, which credits
and plays the coin sound; CPU MATE joining and playing well; and a long play including the elevator and
The Solarium.

How each fix was made, what was measured, and what did not work (our own float fix, a cache flush at
the credits, the two-load DMA floor, the four animation heuristics, five earlier CPU MATE partners, a
hooked translation, storing single-byte writes as whole words, a first build of that fix which passed
the timing check but did not boot, and more): the README's
0.2.6: what worked, and what did not
and docs/SCUM.md.

Known issues

Four. The two audio ones are unchanged: the music is the released soundtrack rather than the
cartridge's own live synthesiser, and the "VM DAC" option does nothing when enabled. Two are new with
the menu options:

  • Hall of Fame name entry, with Arcade Stage Select or 6-Button on: the blinking bar on the entry
    row shows garbage, worst at the left edge where the initials go. The code those switches add sits in
    ROM space that turned out to be the bar's own tile data, which the game copies with a DMA. Little-Man
    alone does not do it. (The hex-looking scores and birthdays in the Hall of Fame are the game's own
    style, on a real cartridge too.)
  • Rarely, a Soft Reset after changing Console or Mega CD needs a second Soft Reset: that boot may
    show the wrong console picture or stay on a black screen. Change the setting first, then Soft Reset;
    if it looks wrong, Soft Reset again.

Details: README, Known issues.

Building it yourself: the CPU MATE brain download

Players do not need this; the brain is already in the bitstream above.

The partner's brain is made from the game's own code, so it is not in the repository. It is the second
asset of this release, cpu-mate-brain_0.2.6.zip: three files and a short README.

file md5
brain.bin 1b64e14d710e8768d3385d1421162bc7
cf.bin a5fa37b435f26f9fc2c8fd62d218d7ef
rodata.bin 5b1d74f454b578196ed1e82548f01b99

Unzip it in the top folder of your clone. It makes cpu-mate-brain/, which the repository ignores (any
other folder works too, with --brain <folder>). Then build:

./scripts/build_mcu.sh --brain cpu-mate-brain    # checks the md5s; installs the shipped...
Read more

0.2.5 — knocked-down drops settle, and new platform art

Choose a tag to compare

@thekoalakoa thekoalakoa released this 11 Sep 13:14

The other half of the dropped-weapon fix, and new platform artwork.

Install with Pupdate or unzip onto the card. Your ROM and
paprium.pcm in Assets/paprium/common/ are untouched by an upgrade.

Fixed

Weapons dropped when the player is knocked down kept spinning.

0.2.4 settled the weapons an enemy drops. It turned out that is one of two drop paths, and the other
one — your own weapon, knocked out of your hands — still tumbled forever. Knives, chains, pipes and
neon sticks, all of it.

The game hands a dropped item over and walks away: it arms the ground animation as a queued
follow-up
and then never writes the animation itself again, for hundreds of frames. Only the
cartridge can make that switch. The rule that decides whether to make it is the same rule that stops
a character sliding across the screen in their standing pose when walking into a new room, and that
is what has made this bug so stubborn — three separate readings of when the game arms the queue
each settled the weapons and each brought the sliding back:

the rule dropped weapons character walk-in
take the queue at any animation end all settle slides
take it only when the queue was armed at that end (0.2.4) enemy drops only walks
take it when armed with the animation, or left standing ~1s settle, late slides

Every attempt, the weapons wanted the wide rule and the characters refused it. So the answer is not
when the queue was armed at all — the game uses exactly the same idiom for a player's looping idle
stance as for a dropped knife. It is what the object is.

And the cartridge firmware already knows: it keeps a per-object animation count, which splits the
two populations with a gap and nothing in between.

animation counts
props — items, pickups, scenery 2 to 29. Every weapon is exactly 10
actors — playable characters and enemies 39 to 220. All three characters are 157

A prop now takes its queued animation at any animation end, which is the behaviour hardware confirms
settles every weapon. An actor keeps the 0.2.4 rule, unchanged — verified by replaying the firmware's
own decision against five recorded play sessions and diffing: every chain on an object that is not
a prop is identical to 0.2.4.

This is a containment boundary, not a discovery. The real cartridge is certainly not counting
animations, and if its actual rule is ever found this gets replaced. What it buys is that a
regression which came back twice, from two different readings of the same measurements, cannot come
back a third time out of a rule nobody can see into.

Also in this release

New platform artwork by LemonGrwab — the banner on the Pocket's system list. The artwork is
theirs; this core just ships it.

Known issues

Two, both on the audio side, unchanged: the music is the released soundtrack rather than the
cartridge's own live synthesiser, and the "VM DAC" option does nothing when enabled. Both are
documented in the README.

Build

Bitstream 61b8d42f, firmware c62e2175, fit at seed 5: ALM 16,410 / M10K 279 / setup −1.469 /
hold +0.052 / TNS −50.528 — identical to 0.2.4, as a firmware-only change should be. Tested on
hardware before release: knocked-down drops settle, enemy drops unchanged, walk-ins keep walking.

0.2.4 — dropped weapons settle

Choose a tag to compare

@thekoalakoa thekoalakoa released this 11 Sep 01:39

One fix, and the reason it took three attempts to find.

Install with Pupdate or unzip onto the card. Your ROM and
paprium.pcm in Assets/paprium/common/ are untouched by an upgrade.

Fixed

Dropped weapons kept spinning instead of settling on the ground.

An enemy drops a knife, a pipe or an electric stick. Each has a short falling animation that cycles
and a long ground animation that is mostly still and stirs every few seconds. The item spun where it
should have settled.

The game hands the item over and walks away. When it lands, the game arms the ground animation as a
queued follow-up and then never writes the animation itself — 458 frames in one capture. Only the
cartridge can make that switch. This port refused it, and the rule that refused it is the same one
that stops a character sliding across the screen in its standing pose when entering a new room.
Switching that rule off lands the items and brings the sliding back. Both confirmed on hardware, in
both directions, which is what made this stubborn: the two cases are identical in every field the
firmware reads.

What separates them is when the game arms the queue. An animation that loops has ends at
predictable frames, and:

animation ends at frame queue armed at on an end
weapon fall 25 frames, loops 49, 73, 97 49 11 of 11
character walk-in 49 frames, loops 49, 97, 145 5, 17, 18, 19, 80, 116 0 of 31

The game arms the queue on the exact frame the animation finishes when it means "switch now", and
mid-cycle when it is only a standing fallback it intends to resolve itself later. It is a
handshake, and both this port and the reference emulator were throwing the timing away — which is
why the emulator shows the sliding too.

So a queued animation is now taken at a looping end only if the queue was armed at that end.

How it was checked

The emulator cannot test this rule, which is worth saying plainly. It decides at the moment it
draws an animation's last frame; this firmware keeps the frame just drawn and decides on the next
call. The weapon's queue appears in the one-frame gap between those two points, so the two
implementations give opposite answers on the only case that matters.

Instead the firmware's own routine was replayed against four recorded captures of the game — 5,558
object lifetimes — where it fires 11 of 11 weapon switches and 0 on the character walk-in,
identically for every timing window from 0 to 4 frames. Then on hardware: items settle and stir,
walk-ins keep walking.

Also

The game's animation protocol is now documented rather than guessed: bit 14 of its setAnim argument
queues an animation, a plain value switches immediately, bit 15 forces a restart.

Four other explanations were measured and refuted before this one, and all four are written up in
patches/README.md so nobody repeats them. The most seductive was a set of unexplained per-frame
flag bits that neither implementation reads and that differ between weapons and characters — they
turn out to be a graphics streaming hint, counting how many tiles a pose adds, matching 99.5% of
24,893 cases. Weapons carried small values because a weapon is a one-tile sprite.

The shipped rule this replaces also turned out not to be the narrow refinement it read as: across 12
minutes of play it took 0 of 821 queued animations. In practice it was "never".

Known issues

Two, both on the audio side: the music is the released soundtrack rather than the cartridge's live
synthesiser, and the "VM DAC" option does nothing. Both in the README.

Bitstream c072bab0, firmware 7e4b51c1, as tested on hardware.

0.2.3

Choose a tag to compare

@thekoalakoa thekoalakoa released this 10 Sep 22:23

Three fixes, and one bug run down far enough to be worth writing up even though it is still open.

Install with Pupdate or unzip onto the card. Your ROM and
paprium.pcm in Assets/paprium/common/ are untouched by an upgrade.

Fixed

The Boom Box's bar graph was lit permanently instead of following the music.

Cartridge RAM 0x1B98–0x1BFF is a per-voice level feed — 26 voices of left and right, ending
exactly on 0x1C00 — that the cartridge's music engine rewrites every row, and the Boom Box draws
its 26 bars straight from it. This port substitutes the released soundtrack for the synthesiser and
never sequences the modules, so nothing wrote that window at all and the game was drawing its
bars out of uninitialised memory. The neighbouring buffer fill stops short of it, which is why it
had never been noticed.

Rather than smear one playback level across 26 identical columns, the bars are now driven from the
sequence module the firmware already decompresses on every music command and then throws away — so
they show the real per-voice arrangement, for no extra work. Their tempo comes from the module
header, which turns out to hold frames per row rather than a fixed rate. Verified against
hardware: Stage Clear is 105 rows at 20 rows a second, 5.250 seconds predicted, and a capture of the
Boom Box measures 5.25.

Twenty clock-domain-crossing synchronisers were living in block RAM.

Two project settings were letting the fitter infer synch_3's flop chains into shift-register
memory. That costs a memory block each, and worse, it throws away the whole point of a synchroniser:
metastability figures are published for flip-flops and do not transfer to RAM cells. The 40-bit
instance asked for 160 flops and had five.

Reverting the settings only reached the narrow instances — the fitter still judged the wide ones
worth inferring. Fixed on the entity instead, with an attribute on the module itself, which reaches
every instance regardless of width and travels with the source. All twenty now report zero block
RAM
, and 7 memory blocks came back (286 → 279).

A field the firmware was corrupting.

The object record at +0x0A is the game's one-shot restart flag: it writes 1 to ask for an
animation to replay from its first frame, and expects that to be acknowledged. This firmware treated
it as a private frame counter and incremented it every drawn frame, in memory the 68000 owns — a
hardware capture read values of 93, 137, 233, 440, 659 and 900, where three emulator captures across
147,283 records show only ever 0 or 1.

Known issue: dropped weapons keep spinning

Enemies drop a knife, a pipe or an electric stick. Each has a short falling animation that cycles,
and a long ground animation that is mostly still and stirs every few seconds. The item asks for the
ground animation and this port refuses the switch, so it spins where it should settle.

The rule that refuses it is the same one that stops a character sliding in its standing pose when
entering a new screen, added in 0.2.1. Switching it off fixes the weapons and brings the sliding
back — both confirmed on hardware, in both directions. The two cases are identical in every field
the firmware reads
: same animation shape, same flags, same queued follow-up. Telling them apart
needs something the firmware currently discards. The reference emulator discards it too, which is
why that emulator shows the sliding as well.

It is cosmetic, and only on dropped items. The full write-up, including the object identities and
where to look next, is in docs/PORT_PLAN.md.

Also

A worked method for identifying objects: the graphics block bank, the sprite record layout and the
tile order are all documented in docs/PORT_PLAN.md now. Rendering an object takes minutes.
Inferring one from its animation structure cost most of a day and was wrong three times.

scripts/dump_music.py could not run at all — a raw NUL byte where an escape belonged, committed
that way. Fixed.

Bitstream 986ccfee, firmware 28a937c8, as tested on hardware.

0.2.2 — FX68K becomes the shipping CPU

Choose a tag to compare

@thekoalakoa thekoalakoa released this 09 Sep 19:54

Unzip onto your SD card. Installation: docs/INSTALL.md.

For a player, nothing should look or sound different from 0.2.1. This release changes the 68000 and nothing else.

What changed

The core now runs FX68K (Jorge Cwik, GPL-3, vendored in rtl/fx68k/) in place of the gate-level 68000 netlist. The point is area: the fit drops from 98% to 88% ALM, and that headroom is what the live cartridge synthesiser under Known issues needs. M10K 93%, setup −1.021 ns, hold +0.041 ns.

Getting there needed one fix in the CPU wrapper worth writing down, because it is the kind of fault that hides for a long time. The wrapper released the 68000's function-code pins as soon as the address strobe went inactive, but the board registers that strobe a cycle later. So for one cycle the console's arbiter saw the pin pattern that means interrupt acknowledge while the strobe still read active, and the video chip discarded whichever raster interrupt it happened to be holding — roughly eleven thousand false acknowledgements a frame. Because the game's raster-interrupt chain reloads itself from each handler, a single lost interrupt threw every later split on that frame onto the wrong line, which shows up as a whole plane in the wrong place. Holding the function code one cycle longer fixes it.

Verified on hardware

This zip contains the exact bitstream that was tested, not a rebuild.

paprium.rbf_r MD5 991C395424F46CC7A6EA2AFBF0D953FF

Boot and SEGA screen, character-select load, elevator, ship bar in menu and in levels, and the Tug room all clean on an Analogue Pocket.

Known issues

Unchanged, both on the audio side: the music is the released soundtrack rather than the cartridge's live synthesiser, and the "VM DAC" option does nothing when enabled. See the README.

We cannot help you obtain the ROM or the soundtrack.

0.2.1 — character animation fixed

Choose a tag to compare

@thekoalakoa thekoalakoa released this 06 Sep 16:15

Character animation fixed. Two separate firmware faults, both confirmed on hardware:

  • Attacks losing frames. When a block for a new animation could not be loaded in time, the firmware rewound the object to its previous frame and overwrote the game's one-shot "restart animation" request, so the object carried on in its old cycle until the game asked for a different animation. The request is now kept pending and retried on the next draw, and the tiles shown meanwhile are protected from eviction within the same frame.
  • Walking into a new screen in the standing pose. At a screen transition the game queues idle as the walk's follow-up and then scripts the character across. Stock firmware (and the reference emulator) took a queued follow-up as soon as the current cycle ended; the real cartridge keeps walking. A looping animation now keeps looping, and a queued follow-up applies only when an animation actually ends.

Also in this release:

  • info.txt on the Pocket now matches the README (the music blob is built from your own rip with the scripts; the ROM is the 8 MiB dump).
  • A small floor on the sprite loader's share of the frame's DMA budget, measured harmless.

Install: unzip openfpga-Paprium_0.2.1.zip onto the SD card, or let Pupdate pick it up. Assets go in /Assets/paprium/common/ as before (Paprium.md, and paprium.pcm if you built one).

Bitstream md5 c2bf6e66, firmware fd872d74. Fit on the shipping placement: 18,194 / 18,480 ALM, setup −2.549 / hold +0.264.

0.2.0 — elevator fixed

Pre-release

Choose a tag to compare

@thekoalakoa thekoalakoa released this 06 Sep 01:33

Second beta. The elevator-shaft corruption is fixed, and the intro no longer pauses.

Beta. Two issues stay open and characterised (characters animating on the spot,
a cosmetic intro flicker), which is what the 0.x and the pre-release flag are
saying. The minor version moved because the known-issues list shrank.

You supply your own cartridge dump and your own copy of the soundtrack; nothing
game-derived is distributed here. See docs/INSTALL.md.

Fixed in this release

Elevator level: bands of wrong tiles scrolling up the shaft, and the corrupted
Intercom Complete screen after it
(open as #8 on the MiSTer port). The game
parks a decompressed level payload in cartridge RAM at 0x9000 and reads rows of
it back through the cartridge window for thousands of frames while the shaft
scrolls. The replacement firmware unpacks every newly loaded sprite block into its
scratch area at the same address, so those rows came back as whatever sprite art
had been unpacked since: 16-tile bands under correct name tables, accumulating
with the scroll. The scratch now lives at 0x1E0000, above anything the game
addresses. Stock mega-ppm has the same scratch at 0x9000, so every setup
running it shares the fault. An earlier note in the README blamed a DMA ceiling;
that reading was wrong.

Blank or shifted background rows in the same shaft, visible once the bands were
gone. The game asks for one row per frame and tests the cartridge's busy flag once,
right after asking; the replacement firmware could answer late, so the row was read
before the read pointer had moved. Busy is now held set at rest and dropped only
once the pointer is in place. The first attempt at this held busy through the
response and made one boot-time reader run a 0.56 s timeout after every scene load
(the pause some test builds had after "presented by"); the released form releases
busy through the response and re-raises it on the game's next request.

Full list, with what each was: README.

Known issues

See README.

0.1.0 — first public beta

Pre-release

Choose a tag to compare

@thekoalakoa thekoalakoa released this 03 Sep 00:23

First public build of the Paprium openFPGA core for the Analogue Pocket.

Beta. The game is playable end to end and the major sprite bugs are fixed,
but several issues remain open and characterised rather than solved — which is
what the 0.x and the pre-release flag are saying. Each verified fix from here
takes a patch bump; the minor version moves when the known-issues list actually
shrinks.

You supply your own cartridge dump and your own copy of the soundtrack; nothing
game-derived is distributed here. See docs/INSTALL.md.

Fixed in this release

Sprites drawn behind the scenery, or vanishing entirely — the rooftop boss
fight, the elevator shaft and the subway station. One cause behind all three:
sprites were composed in the wrong place in the frame. The reference
implementation composes each sprite as its draw command arrives; the stock
replacement firmware queued them all and rendered the batch at frame end. The
game interleaves — draw some sprites, write its sprite masks, draw more — and a
mask hides every sprite later in the link chain on its scanlines. Batching put
every cartridge sprite after the masks. On the rooftop they sat at sprite-table
entries 14–19 instead of 31–36 and hid nine sprites including the whole player;
composing inline puts them at 34–39 and hides three. Verified against a Genesis
Plus GX savestate of the same scene, entry by entry.

Characters sliding without their walk cycle — much improved by the same
change. Batching sampled every object's state at frame end, so an object slot
reused twice within one frame lost its first pose.

Destructibles keeping their intact artwork after being smashed — a regression
from the fix above, found and fixed in the same session.

Plus the audio and palette work from earlier: echo, stereo imaging, the large-enemy
death sound, one-shot cues, the punk-TV and ambience channels, the Block 888
doorway palette, and the 0x81 decoder that corrupted the subway.

Full list, with what each was: README.

Known issues

  • Elevator scrolling tile squares. Open. The level's depth problems are fixed;
    the squares are separate. Derived as a per-frame DMA limit, and an elevator-only
    run measures the sprite block loader at 3.3% refusals — the same as the rest of
    the game — so the loader is not the ceiling. The background streaming path is
    unmeasured
  • Residual animation skipping under heavy enemy counts
  • Full-health stage clear plays the ordinary cue; occasional single-pixel intro
    flicker

Notes

  • Boots straight into the game — fixed filenames for the dump and the save
  • Region fixed to Japan; the cartridge runs in both, so this is one less menu item
  • No 6-button option: Paprium's own controller read is 3-button
  • Fits a Cyclone V at 98% ALM / 95% M10K. Timing does not fully close on this
    device, inherited from the base core, which runs correctly on hardware regardless

Firmware changes rebuild from a clean krikzz/mega-ppm
clone via patches/.