Question: can Cable be brought from Marvel vs. Capcom 2 into MvC1 on CPS-2 arcade hardware?
Answer: the art is nearly free. The character is not.
Art: 14,095 distinct tiles, 1,804,160 B — converted, measured, lossless. 6.56 MB free in the target region; he needs 1.72 MB. Frame data: 34,958 bytes, 3.4% of the 1 MB program window at $500000.
Blocker: MvC2 ran on NAOMI — SH-4. There has never been a 68000 implementation of Cable. ~52 populated move slots have no donor code.
Identification: Cable is PL17. Capcom left their developer roster in plaintext at 1ST_READ.BIN + 0x128DFC — and his sprites are now decoded and visually confirmed (below).
Update (same day): the full decode pipeline shipped. All 4,031 of Cable's sprites decode with zero failures, and the CPS-2 tile conversion is complete and lossless: 14,095 distinct tiles, 1,804,160 bytes — 99.84% of the estimate. One earlier claim is retracted below.
I have imported two characters into Marvel vs. Capcom before — Shuma-Gorath and Dark Sakura, both out of Marvel Super Heroes vs. Street Fighter. Those worked, and the reason they worked is the whole subject of this post.
MSHvSF is CPS-2. Same 68000, same engine family, same data formats. So "importing" a character there means: find the routine in the donor ROM, copy its code into free space in the target, remap the player-struct field offsets, fix what breaks. Every hard bug I hit was a relocation bug — data islands inside a code span being disassembled and rewritten, a past-end animation subtable, an orphaned detector chain. Painful, but all of it mechanical.
Cable is a different animal, and I want to be precise about why before showing any numbers.
First, a premise I got wrong
I opened the MvC2 disc, found a 3.6 MB file called 2_DP.BIN starting with 09 00 09 00 09 00 — SH-4 NOP — and called it the game executable.
It is not. It is DreamPassport, the Dreamcast's web browser.
2_DP.BIN: "DreamPassport" x2 "Mozilla" x2
"CAPCOM" x0 "MARVEL" x0 "NAOMI" x0 "CABLE" x0Every SH-4 binary starts with those NOPs. I pattern-matched on a signature that identifies the architecture, not the program, and let it stand as an identification. The actual game is 1ST_READ.BIN, 1,809,817 bytes — the standard Dreamcast boot binary, which I should have looked for by name in the first place.
Worth recording because it is a specific failure mode: a signature that every member of a class shares cannot pick one member out of the class.
Cable is PL17, and Capcom labelled it themselves
Inside 1ST_READ.BIN, at 0x128DFC, there is a run of 59 NUL-terminated strings that label their own hex index:
0x128DFC "00 RYU"
0x128E04 "01 ZANGIEF"
0x128E10 "02 GUILE"
0x128E1C "03 MORRIGAN"
0x128E28 "04 ANAKARIS"
0x128E34 "05 STRIDER HIRYU"
...
0x128F50 "17 CABLE" <- the target
0x128F5C "18 LAST BOSS 1"
0x128F6C "19 LAST BOSS 2"
0x128F7C "1A LAST BOSS 3"
...
0x129120 "3A KOBUN"Exactly 59 entries spanning 0x00..0x3A — exactly the 59 PLxx file indices on the disc. The literal string CABLE occurs three times in the entire 1.8 MB binary: once here, twice in the shipped on-screen name tables.
The control that could have failed
A self-labelling table is nice, but it proves the table is consistent, not that the table describes the files. So here is a test with a real chance of coming out wrong.
Only 56 of the 59 indices have a PLxx_WIN.BIN — a win-pose file. If the index space is genuinely shared between the debug roster and the files on disc, the three missing ones should be characters that have no win pose. Enumerated blind:
indices with no win pose: 18, 19, 1A
18 -> "18 LAST BOSS 1"
19 -> "19 LAST BOSS 2"
1A -> "1A LAST BOSS 3"Bosses do not have win poses. Under a random index→name mapping, landing exactly on those three is 1 in C(59,3) ≈ 3.1 × 10⁻⁵.
I originally flagged one honest limit here: no content check constrained index 0x17 itself — proven by table, not by eye. That limit is now closed. Decoding PL17_DAT.BIN's sprite section produces this:

White hair, grizzled face, silver cybernetic left arm, gold X-harness with red X buckles, the rifle stored as separate rotated sprites. All 4,031 blobs in his sprite section decode with zero failures, and the imagery is consistently one character plus his effects — muzzle flashes, plasma bursts, beam streaks bracketing the section.
The art path, and the false negative I have now hit twice
This is the part I find genuinely interesting, because the first answer was wrong for a reason this project has been burned by before.
Earlier the same week, auditing the Dreamcast MvC1 disc, I ran a structural sweep for box-shape tables across every file and reported them absent, with what I described as a positive control. Both the sweep and the control were broken:
- The sweep did
read_bytes()[:400000]— every file truncated to 400 KB. The table lives 2.78 MB into the binary. I never looked at it. - The search only tried big-endian. The Dreamcast stores those tables little-endian.
- My "control" proved my extractor worked. It could never have detected a byte-swapped copy, because it never exercised a byte swap.
An insufficient control is worse than no control, because it manufactures confidence. The rule I keep writing down and keep having to re-learn: the control must exercise the same transform the real search needs.
So for MvC2 I forced the question in the other direction: prove the matcher can find a true match before believing any negative.
The retraction
The first pass reported that MvC2's decoded pixels were byte-identical to CPS-2 tiles for shared characters, and I published that. It is false, and the way it fell apart is the whole lesson of this post repeated at a higher level.
The "identity" signal came from an arcade pixel recipe that mis-interleaved columns 8–15 of each tile — its best match was 6.5% in a scrambled-texture band, which is collision noise. The re-run built the comparison properly: the exact same search code was fed known-present arcade fragments as a positive control and scored 3491/3491 = 100% — proof it would find matches if they existed. Against MvC2 it found 0/60 tiles, 0/400 row fragments, and 1–2 of 8,000 8-pixel windows — exactly the shuffled-null floor. MvC2's Dreamcast art is a reprocessed derivative of the arcade art (extra shading bands, consistent with a rescale/anti-alias/requantise pass in the NAOMI conversion), not a copy.
So tile-lifting is dead. What survives is better-grounded: the decoder is proven (all 1,533 Ryu blobs and all 4,031 Cable blobs decode with exact stream consumption; Ryu renders as recognisable Ryu), and conversion means re-encoding those pixels into fresh CPS-2 tiles — which is exactly what happened next.

The container, for the record:
PL17_DAT.BIN
S0 @0x000040 964,736 B sprite bitmaps (4,031 blobs, LZSS + PowerVR twiddle)
S1 @0x0EB8C0 65,856 B sprite lists (681 lists, 7,718 parts)
S2 @0x0FBA00 1,824 B palettes (57 x 16 x ARGB4444)
S3 @0x0FC120 65,536 B collision (64 pages x 1,024 B, 8-byte records)
S5 @0x10C120 24,288 B animation / frames
S8 @0x112F40 3,584 B move properties (52 of 128 slots used)S3, S7 and S8 are identically sized across all 59 characters. The whole roster shares one fixed action-id namespace.
Cable's own pixels are MvC2-original — he never existed on CPS-2. But they arrive through a conversion path that is provably lossless and mechanical, because it can be validated end-to-end against a character who exists in both games. That is the difference between "we think we can convert this" and "we can check our converter against ground truth."
The numbers
- Cable's art as CPS-2 tiles1,807,104bytes
14,118 tiles x 128 B
- GFX headroom already built33,554,432bytes
the 32 MB -> 64 MB core expansion
Every asset number came in comfortable. The art is 5.4% of headroom I built for an unrelated reason. The frame data is 3.4% of a megabyte window I opened last week. If this project were about space, it would already be done.
The bill
It is not about space.
| Shuma / Dark Sakura | Cable | |
|---|---|---|
| behaviour code | copy + field-remap | author from scratch |
| animation tree | relocate | author (data exists, format differs) |
| sprite art | seat zero-remap | convert (mechanical, checkable) |
| boxes | relocate box-sets | convert |
| frame data | relocate | convert |
Every row except the first got easier than I expected. The first row did not get harder — it became categorically different work.
MvC2 ran on NAOMI: SH-4, little-endian, a different CPU and a different fighting-engine codebase. There has never been a 68000 implementation of Cable. There is no donor span to copy, no homolog to locate, no field shift to measure. The tooling I built for the last two imports — find_homolog.py, field_map.py, port_handler.py — has no input for this. Cable's specials, his hyper combos, his air-dash, the AHVB loop that defines him competitively: all of that is behaviour that has to be written, in 68000, against MvC1's engine idioms.
I am deliberately not putting an hour estimate on that. I have watched this project's estimates fail in both directions, and "port a character" and "implement a character" are not the same unit.
Update, same day: he renders in the game — and the first shot was not fit to publish
Cable's 14,095 tiles are seated in the expanded graphics region (contiguous words $C400..$FB0E, zero core changes — the existing sprite-bank window turned out to span all 65,536 word values, proven from the emulator core source line by line), and a diagnostic build got his tiles drawing through the game's own renderer in a live match. That proved the two things the gate existed to prove: the routing inference holds (tile words far beyond anything previously used pass through the sprite hardware unmasked), and the assembly law is right.
An earlier version of this section showed that screenshot. It was removed, because the render it showed was wrong in two ways the gate had accepted as engineering shortcuts and I then wrongly presented as a milestone: the frame borrowed Dark Sakura's sprite-list geometry, so the parts of Cable that fall outside her body footprint — head top, right flank, feet — were simply missing; and the palette write path was still hers, so he rendered in her golds instead of his blues. A partial, discolored character is a debugging artifact, not a result. The fix — sprite lists authored for his geometry (the position-block format is fully decoded now) with his palette installed across all select variants — is in the pipeline that is converting his walk, jump and attack animations; the shot that belongs here is the one where he is whole and the right colors, and this section will carry it when it exists and not before.
Two findings from the seating work worth more than any screenshot: the shipped graphics chips carry 6 MB of art no manifest tracks (legacy core-seated content a naive rebuild would silently destroy — now documented and preserved by overlay), and the sprite position-block format is now fully decoded, validated by reproducing Sakura's idle stance pixel-perfect from pure data.
Still true, and unchanged by any of this: he is a statue borrowing another character's slot. The moveset bill from the verdict above stands.
Where the path stands now
The first two gates I set are passed: identification is visual, and the art conversion is complete and lossless — cable_tiles_decoded.bin, 14,095 tiles in arcade byte order, verified by reassembling every sprite through the project's reference decoder.
What remains, in order:
- Seat and render one frame in MvC1. The tiles need word-slot assignment in the expanded GFX region (6.56 MB free; Cable needs 1.72 MB) and a mapper window — Cable has no arcade code words to preserve, so unlike the zero-remap imports every sprite code is a fresh assignment. Then one standing pose on screen in the real game.
- Decode MvC2's animation and collision sections (
S5,S3, and the sprite-list placement convention inS1). His frame data exists on disc; its formats are MvC2's own and still undecoded. This is what converts "we have his pixels" into "we can assemble his frames." - The behaviour bill, unchanged. Nothing above touches it: his state machine, normals, specials, throws, and sound wiring must be authored in 68000 against MvC1's engine. The Shuma record is the honest reference for what that costs — months of handler work, and art was never the hard part there either.
The GFX headroom this leans on is the 64 MB core expansion; the program window is the $500000 mapping. The transplant tooling that does not apply here is what built the Dark Sakura native port.