Hole in One

An eighteen-hole course, par 72 and 6,430 metres, inside 16 KB: each hole fits in some three hundred bytes because it declares three materials in its header and then paints with them, the pattern table is stored once and serves all three thirds of the screen, and the title's wordmark sneaks in as fourteen tiles loaded on top.

HAL Laboratory · © HAL 1984 · A 16 KB cartridge · MSX1 · page 2 · Dump 14311cc2…

There is not one illustration here. The wordmark, the scoreboard and all eighteen holes are drawn from the bytes of the ROM, by running in Python the same decompressors and the same script interpreter the Z80 runs, and checked against the emulator's VRAM: 13,655 of 13,664 bytes identical — the nine that differ are the scoreboard digits, which the game writes as it plays — and all 480 cells of every hole exact across six in-game dumps. The one screen capture on this page is the CALL GOLF one, because what it shows is precisely the cartridge running. The listing and the numbers come from the binary and are reproducible with make.

The cartridge in numbers

100%of the binary explained
358routines identified
18holes, par 72, 6,430 m
6,065bytes of code
10,319bytes of data
0bytes unidentified

What turned up when we took it apart

The eighteen holes are one single map, stacked bottom to top

The eighteen screens are not eighteen separate backdrops: they are windows onto one course of 20 × 415 cells. Hole 1 is the southern end, hole 18 the northern one, and two consecutive holes share one row: the top row of hole n is the bottom row of hole n+1. That is why the lake hole 1 ends in sits at the foot of hole 2, and the sea crowning hole 2 is the one washing hole 3.

theNestruo spotted this. Here it is measured: the shared row matches on 70.9 % of its twenty cells, against 41.6 % for any two adjacent rows within a single hole — the baseline it has to beat — and 21.0 % for two rows that do not touch. All seventeen joins beat it, one by one. And the overlap is exactly one row: trying one through six, one wins in all seventeen pairs.

Stacked the other way round — hole 2 below hole 1, which is how this site had it first — gives 35.9 %: below the baseline. What was wrong was the measurement, not the map.

There is not a single coordinate in a hole's script: the continuity is drawn, not computed. And the game itself gives the direction, because all eighteen tees sit in the top rows and all eighteen flags in the bottom ones: every hole is played north to south, and the course is walked south to north.

Every hole declares its three materials and then paints with them

A whole hole takes some three hundred bytes, and the trick is in the first three. The cartridge copies them to 0xE451 and there they stay: they are the hole's palette. Then, in the script, a 0x3n, 0x4n or 0x5n byte repeats the first, second or third of those materials n+1 times.

What links the two is a subtraction of three. The palette index is the opcode's high nibble, and the table starts at 0xE44E — three bytes before the header — exactly so that 3, 4 and 5 land on it. So there is no palette table: there is an offset that makes the hole's header be the palette.

The screen's three thirds come from a single table

The MSX's SCREEN 2 is three independent thirds, and for all three to hold the same thing you have to write it three times. 0x9505 makes the six calls — three of patterns and three of colour — but 0x9834 sets DE=0xB324 again on every one, so all three decompress the same source.

That is 2 KB of cartridge for 6 KB of table, and the same for the colour. The game's entire pattern table fits in 1,613 compressed bytes.

The wordmark is loaded by entering halfway into an instruction

0x9505 is an or 0AFh, that is, the two bytes F6 AF: call there and the Z flag goes clear, and the six calls behind it load the long tables. But 0x8829 calls 0x9506, the second byte of that same instruction, and 0xAF on its own is xor a: entering there runs the operand, zeroes A and sets Z, and then the six load two short tables that only touch tiles 0x10 to 0x1D of each third.

Those fourteen tiles are the letters of HOLE IN ONE. The rest of the screen — the striped background, the credits — is built with the same 20×24 grid the course uses.

The wordmark's two tables run eight bytes short, and it does not matter

Both decompressors stop when the VRAM pointer reaches its limit, not when the source runs out. And the wordmark's two tables fall short: they give 104 of the 112 bytes that have to be written.

So they keep reading. The last eight bytes of tile 0x1D come from the header of the colour table that follows, and the colour table's own come from the start of the code at 0xBE0D. All sixteen bytes sit like that in the emulator's VRAM. It is free because nothing names tile 0x1D: the wordmark's two halves only reach 0x1C.

Par and length are hidden inside the map

There is no table with the holes' details. The par is told by the very tile that draws the tee: 0xD9 is a par 3, 0xDD a par 4 and 0xE3 a par 5, and on the way past the interpreter notes where it is so it can place the ball. The length is three ASCII digits stuck right behind the 0x21 that closes the map, and the scoreboard writes them out as they are with an 'm' beside them.

Added up, the eighteen give a course of par 72 and 6,430 metres, with four par 3s, ten par 4s and four par 5s. A championship layout, and not one byte spent saying so.

The scoreboard fits in ten columns, and the course starts at the eleventh

0x9571 writes ten cells per row and skips twenty-two to land on the next, twenty-four times over: that leaves the TOP, SHOTS, HOLE, PAR, POWER, CURVE and CLUB panel filling columns 1 to 10 of the screen.

The course comes in right behind it. 0x9A66 dumps the hole's 480 cells as twenty columns by twenty-four rows from 0x180B, which is column 11. The two halves never collide because neither is drawn centred: each one knows its own width.

What the cartridge draws

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

<b>The whole course</b>: the eighteen holes stacked into the 20 × 415 cell strip they really form, hole 1 at the very bottom and hole 18 at the top. It is cut into six columns of three holes because in one piece it is one cell wide for every twenty tall; each column continues above the one to its right, and the row each starts on is the row the previous one ended on. The numbers are the hole numbers, written in the cartridge's own font. River, sea and desert cross the joins uncut: the course is <b>an island</b>
The whole course: the eighteen holes stacked into the 20 × 415 cell strip they really form, hole 1 at the very bottom and hole 18 at the top. It is cut into six columns of three holes because in one piece it is one cell wide for every twenty tall; each column continues above the one to its right, and the row each starts on is the row the previous one ended on. The numbers are the hole numbers, written in the cartridge's own font. River, sea and desert cross the joins uncut: the course is an island
Four joins up close — holes 1/2, 6/7, 11/12 and 17/18 — five rows either side of the row they share. Lake, sand and shoreline carry from one hole to the next without a jump. The join between holes 6 and 7 is the weakest of the seventeen and the desert still crosses it whole
Four joins up close — holes 1/2, 6/7, 11/12 and 17/18 — five rows either side of the row they share. Lake, sand and shoreline carry from one hole to the next without a jump. The join between holes 6 and 7 is the weakest of the seventeen and the desert still crosses it whole
<b>SOUTH</b>, the first of the three courses on the <i>Hole In One Extension Course</i> tape (HAL, 1985). Par 72 and 6,147 metres, eighteen holes that are <b>not in the cartridge</b>: they load into RAM from tape and are played with <code>CALL GOLF</code>. Drawn with the same interpreter and the same tiles as the cartridge's, because it is the same format
SOUTH, the first of the three courses on the Hole In One Extension Course tape (HAL, 1985). Par 72 and 6,147 metres, eighteen holes that are not in the cartridge: they load into RAM from tape and are played with CALL GOLF. Drawn with the same interpreter and the same tiles as the cartridge's, because it is the same format
And SOUTH is <b>one single strip</b> too, stacked south to north just like the cartridge's: the coastline and the desert cross the joins uncut. Its shared row matches on <b>72.6 %</b> against 38.9 % for two adjacent rows within one hole, and all seventeen joins beat that baseline. It is an archipelago
And SOUTH is one single strip too, stacked south to north just like the cartridge's: the coastline and the desert cross the joins uncut. Its shared row matches on 72.6 % against 38.9 % for two adjacent rows within one hole, and all seventeen joins beat that baseline. It is an archipelago
<b>WEST</b>, the second on the tape and the only <b>par 73</b> of the four courses: 6,540 metres, the longest. Cactus deserts, black cliffs and a closing hole with a grandstand
WEST, the second on the tape and the only par 73 of the four courses: 6,540 metres, the longest. Cactus deserts, black cliffs and a closing hole with a grandstand
<b>NORTH</b>, the third: par 72 and 6,428 metres, almost exactly the cartridge course's 6,430 and yet eighteen different holes. Its joins fit the best of the four, at <b>73.5 %</b>
NORTH, the third: par 72 and 6,428 metres, almost exactly the cartridge course's 6,430 and yet eighteen different holes. Its joins fit the best of the four, at 73.5 %
<b>A course that is not in the ROM.</b> Eighteen holes written by <code>tools/campo.py</code> in the cartridge's own format: a sand fairway, a lake that swaps sides, and a bar of water at the top as many cells long as the hole number. They are drawn with the <b>same</b> interpreter that draws the ROM's — if the format were misunderstood, this would come out as noise
A course that is not in the ROM. Eighteen holes written by tools/campo.py in the cartridge's own format: a sand fairway, a lake that swaps sides, and a bar of water at the top as many cells long as the hole number. They are drawn with the same interpreter that draws the ROM's — if the format were misunderstood, this would come out as noise
And the cartridge plays it. Booted with the key held, the course dropped at 0xC000 and <code>CALL GOLF</code> typed at the BASIC prompt: the attract mode draws the <b>generated</b> hole 2 — 480 of 480 cells — and the scoreboard reads its <b>PAR 4</b> and <b>302 m</b>, which are not the ROM's 168 m par 3. Captured from openMSX by <code>tools/omsx_call_golf.tcl</code>
And the cartridge plays it. Booted with the key held, the course dropped at 0xC000 and CALL GOLF typed at the BASIC prompt: the attract mode draws the generated hole 2 — 480 of 480 cells — and the scoreboard reads its PAR 4 and 302 m, which are not the ROM's 168 m par 3. Captured from openMSX by tools/omsx_call_golf.tcl
<b>The course's eighteen holes</b>, drawn one by one with the same script interpreter the Z80 runs, following the pointers at 0x9C33. That they are right is not an impression: all 480 cells of each were compared against openMSX dumps taken with the game running, with <b>zero differences</b>
The course's eighteen holes, drawn one by one with the same script interpreter the Z80 runs, following the pointers at 0x9C33. That they are right is not an impression: all 480 cells of each were compared against openMSX dumps taken with the game running, with zero differences
The title screen, built with the cartridge's own steps: the grid from 0x8864 with its striped background, the wordmark's two halves and the credits handed to it by 0x8954
The title screen, built with the cartridge's own steps: the grid from 0x8864 with its striped background, the wordmark's two halves and the credits handed to it by 0x8954
Hole 1 in full, with the scoreboard panel on the left exactly as 0x9571 writes it. Par 4 and 331 metres: the fairway climbs between trees to a green with the lake behind it
Hole 1 in full, with the scoreboard panel on the left exactly as 0x9571 writes it. Par 4 and 331 metres: the fairway climbs between trees to a green with the lake behind it
Hole 4, the course's longest par 5 at 556 metres. The black patch is not a drawing error: it is tile 0x00, which this hole declares as one of its three materials, and the game paints it just the same
Hole 4, the course's longest par 5 at 556 metres. The black patch is not a drawing error: it is tile 0x00, which this hole declares as one of its three materials, and the game paints it just the same
Hole 2, the shortest par 3: 168 metres from tee to green, with water across nearly all of it
Hole 2, the shortest par 3: 168 metres from tee to green, with water across nearly all of it
The same screen with the other text. The builder at 0x8864 takes an address and pulls the three bottom lines from it: 0x8954 gives the credits, 0x8975 the number of players
The same screen with the other text. The builder at 0x8864 takes an address and pulls the three bottom lines from it: 0x8954 gives the credits, 0x8975 the number of players
The wordmark up close. These are the fourteen tiles loaded by the two short tables at 0xBDAB and 0xBDDB, laid out in two blocks of five rows by fourteen columns
The wordmark up close. These are the fourteen tiles loaded by the two short tables at 0xBDAB and 0xBDDB, laid out in two blocks of five rows by fourteen columns
The three greens. They are the alternative mode at 0xB1CB, and carry the same script format as the holes — 480 cells and a 0x21 at the end — but without the three length digits behind, because in that mode the interpreter never reads them. At 109, 112 and 115 bytes each they are the tightest thing in the cartridge
The three greens. They are the alternative mode at 0xB1CB, and carry the same script format as the holes — 480 cells and a 0x21 at the end — but without the three length digits behind, because in that mode the interpreter never reads them. At 109, 112 and 115 bytes each they are the tightest thing in the cartridge
The 256 tiles with their colour, as they sit in VRAM once 0xB324 and 0xB971 have been decompressed. The whole course is in there: grass, water, sand, trees, the tee, the flag and the clubhouse
The 256 tiles with their colour, as they sit in VRAM once 0xB324 and 0xB971 have been decompressed. The whole course is in there: grass, water, sand, trees, the tee, the flag and the clubhouse
The nineteen 16×16 sprites that 0xBE0D decompresses into the sprite pattern table: the golfer, the ball and the meter's arrows
The nineteen 16×16 sprites that 0xBE0D decompresses into the sprite pattern table: the golfer, the ball and the meter's arrows
The font everything is written with, from 0x20 to 0x5F. Plain ASCII, with the 'm' for metres and the © slotted in where they fit
The font everything is written with, from 0x20 to 0x5F. Plain ASCII, with the 'm' for metres and the © slotted in where they fit