Hyper Sports 1

The four gymnastics and diving events of Hyper Sports in a 16 KB cartridge: trampoline, long horse, horizontal bar and diving, for two players taking turns, all driven by the per-frame interrupt.

Konami · © Konami 1984 · An RC-715 16 KB cartridge · MSX1 · page 1 · Dump 440dae57…

There is not one illustration or capture here. The graphics are drawn from the bytes of the ROM, by running in Python the same run-length decompressor the Z80 runs. The listing and the numbers come from the binary and are reproducible with make.

The cartridge in numbers

100%of the binary explained
387routines identified
4events
5,953bytes of code
10,431bytes of data
0bytes unidentified

What turned up when we took it apart

The athlete does not pick its drawings: it rewrites them every frame

The pattern number of each of the athlete's sprites is in no pose table at all. 0x618E nails it down once, when the event is set up, with an ld (hl),a / add a,004h that leaves 0x00, 0x04, 0x08… across the seven sprites. Sprite 1 draws pattern 0x04, and it always will.

What changes every frame are the patterns. 0x65AD pulls the pose's script out of the table at 0x65F6; that script is triplets of (dy, dx, colour) which 0x65BE writes into the sprite entries at 0xE0D0, closed by a 0x8N byte whose low nibble says how many blocks of drawings follow. 0x65D9 points the VDP at VRAM 0x1800 —the sprite pattern table— and 0x65E5 uploads them with the decompressor at 0x69F9.

That is where the clothing comes from. Sprite 1 is always pattern 0x04, but in some poses that pattern holds a pair of white shoes and in others it holds nothing. And since the lowest-numbered sprite wins on the MSX1, the order of the triplets inside the script is what decides which piece covers which.

The order of the events is in the table, not in the texts

The four labels sit back to back in the ROM from 0x6F08 in the order DIVING, TRAMPOLINE, LONG HORSE, HORIZONTAL BAR. That is not the order they are played in. What picks is the four-pointer table at 0x6F00, which 0x6E38 indexes with 0xE052 and 3, and that table reorders them: 0 DIVING, 1 LONG HORSE, 2 TRAMPOLINE, 3 HORIZONTAL BAR. Reading the texts instead of the table swaps the second and the third — exactly what this site said until it was checked in the emulator, reading the name table as text while the attract mode plays all four.

0xE052 is not reset between rounds: it keeps climbing, and the event comes from its two low bits, so the fifth is DIVING again with the STAGE gone up.

The scoreboard font is not in the cartridge

The scoreboard writes letters and digits as tile numbers in plain ASCII, and the cartridge does not draw those tiles: 0x43BF takes the CGTBL pointer at 0x0004 —the character table of the MSX ROM—, skips 0x180 bytes to start at '0' and uploads 48 characters to VRAM. The cartridge supplies only six of its own, through two compressed scripts: tiles 0x3A and 0x3B (where the dash in 1P-000000 comes from) and 0x5C to 0x5F. Checked: the BIOS font plus those touch-ups gives the 384 bytes in VRAM across all three thirds, without a single difference.

The crowd claps with two scripts, and one is the tail of the other

The stands are animated by alternating two consecutive cartridge scripts, 0x4976 and 0x498E, over VRAM 0x2158. The first is not a separate block: it is the tail of the common stream that 0x4891 decompresses when setting up any event, and which is also dumped on its own to animate. 431 dumps in the first 60 seconds, measured with a breakpoint at 0x440D.

One dead loop, and the whole machine in the interrupt

INIT hooks the interrupt to 0x402C and falls into a jr to itself. From there the main program does nothing: each frame the interrupt reads 0xE000 (the state), jumps through the handler table at 0x40C2, and inside each handler the byte 0xE001 splits the sub-states. Bit 6 of 0xE002 marks the demo.

Two different drawing interpreters

The cartridge stores no screens: it stores scripts. One, at 0x405E, copies byte by byte into the name table with destination jumps (0xFE) and an end (0xFF); the other, at 0x440D, decompresses by runs with a count byte whose top bit tells a literal copy from a fill. This site's figures come from running that second one in Python.

The sound is the house's three-channel player

The engine at 0x7C3D walks three eleven-byte records (0xE010), reads the melodies with its command interpreter and writes the PSG through the BIOS. It is the same player framework Konami spread across its MSX cartridges, with its tone table and its effects.

Two players sharing one state block by turns

The event state lives at 0xE050 for player 1 and at 0xE080 for player 2. On a change of turn, 0x413E swaps the two whole blocks with a single 32-byte routine, so the rest of the code always works on the same place without knowing whose turn it is.

It does not carry Konami's hidden mark

Many of the house's cartridges hide their catalogue number and the title in katakana at the end of the ROM; Manuel Pazos (@ManuelPazosMSX) found it. Here it is absent: the last bytes are sound-player data, with no 0xAA to close the mark. RC-715 comes from the catalogue, not the binary.

What the cartridge draws

Under the picture is where it comes from and what is on it.

<b>DIVING</b>, the first event. The screen is stored nowhere in the cartridge: the drawings —patterns and colours— are decompressed here from the ROM with the same format the Z80 uses, and the tile map and the sprites come from the MSX's VRAM, because the event's engine composes them as it runs. The 7,680 drawing bytes coming out of the ROM match that VRAM <b>byte for byte</b>
DIVING, the first event. The screen is stored nowhere in the cartridge: the drawings —patterns and colours— are decompressed here from the ROM with the same format the Z80 uses, and the tile map and the sprites come from the MSX's VRAM, because the event's engine composes them as it runs. The 7,680 drawing bytes coming out of the ROM match that VRAM byte for byte
The same dive a second later: the splash of the entry. The five judges at the white table score the attempt, and their marks appear right there
The same dive a second later: the splash of the entry. The five judges at the white table score the attempt, and their marks appear right there
<b>LONG HORSE</b>, the second. The athlete runs down the track towards the springboard and the horse. In this scene the crowd is on its <b>second clapping frame</b>, the one the cartridge keeps at 0x498E
LONG HORSE, the second. The athlete runs down the track towards the springboard and the horse. In this scene the crowd is on its second clapping frame, the one the cartridge keeps at 0x498E
<b>TRAMPOLINE</b>, the third, and the only one with a <code>TIME</code> readout: its label script (0x4560) is the only one that writes that word, and it is dumped for this event alone
TRAMPOLINE, the third, and the only one with a TIME readout: its label script (0x4560) is the only one that writes that word, and it is dumped for this event alone
<b>HORIZONTAL BAR</b>, the fourth, with the gymnast mid-swing. It is the event with the most frames of its own: seven of the 52 strips in the pose block are used by no other
HORIZONTAL BAR, the fourth, with the gymnast mid-swing. It is the event with the most frames of its own: seven of the 52 strips in the pose block are used by no other
The athlete's 45 poses, built the way the cartridge builds them: 0x65AD indexes the script table at 0x65F6, and each script lays out the sprite entries <b>and uploads that pose's patterns to VRAM</b>. Look at the footwear: in some poses the white entry draws a pair of shoes and in others it draws nothing at all, yet it is always <b>the same sprite with the same pattern number</b>. What changes is the drawing underneath
The athlete's 45 poses, built the way the cartridge builds them: 0x65AD indexes the script table at 0x65F6, and each script lays out the sprite entries and uploads that pose's patterns to VRAM. Look at the footwear: in some poses the white entry draws a pair of shoes and in others it draws nothing at all, yet it is always the same sprite with the same pattern number. What changes is the drawing underneath
The athlete is <b>four 16x16 sprites stacked</b>, each one a single colour: the four apart and, on the right, assembled. The colour is not in the pattern —it is in byte 3 of each entry, the only thing the script writes besides the position— and that is why <b>what changes the athlete's clothing is the ORDER of the colours</b>. There are <b>three compositions</b>, one per row: with the red on the topmost sprite the shirt shows; drop it to last and the two yellows cover it
The athlete is four 16x16 sprites stacked, each one a single colour: the four apart and, on the right, assembled. The colour is not in the pattern —it is in byte 3 of each entry, the only thing the script writes besides the position— and that is why what changes the athlete's clothing is the ORDER of the colours. There are three compositions, one per row: with the red on the topmost sprite the shirt shows; drop it to last and the two yellows cover it
One event's tiles, with their colour, drawn from the ROM by <code>tools/graficos.py</code> by decompressing its runs with the same format the Z80 uses. These are the SETTING's pieces: the athlete is not here, because its drawings do not live in this table —each pose's script rewrites the sprite pattern table every frame
One event's tiles, with their colour, drawn from the ROM by tools/graficos.py by decompressing its runs with the same format the Z80 uses. These are the SETTING's pieces: the athlete is not here, because its drawings do not live in this table —each pose's script rewrites the sprite pattern table every frame