Findings

The eighteen holes are one single map

The eighteen screens are not eighteen separate backdrops. They are windows onto one course of 20 × 415 cells, stacked with hole 1 at the southern end and hole 18 at the northern one, and two consecutive holes share one row: the top row of hole n is the bottom row of hole n+1.

This was spotted by theNestruo, in issue #1. It is measured here, and the measurement is what tests/test_campo_continuo.py guards:

compared rowscells equal, of 20
the shared row (top of n / bottom of n+1)70.9 %
two adjacent rows within one hole — the baseline41.6 %
two rows of one hole that do not touch21.0 %
stacked the other way round — what this site published first35.9 %

The baseline that matters is the middle one. A shared row has to look more alike than any two rows that merely sit next to each other, and it does, in all seventeen joins taken one by one. Stacking the other way does not just score lower: it scores below rows picked at random from the same hole.

The overlap is exactly one row. Trying overlaps of one to six rows, one wins in all seventeen pairs.

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

A note on how this went wrong the first time. The original answer to that issue reported 7.2 cells matching out of 20 and called the premise unfounded. That number was right and the reading was backwards: it compared the bottom of hole n against the top of hole n+1, which is the stack upside down. The issue had said "bottom to top" plainly enough.

CALL GOLF loads a course that is not in the ROM

The AB header at 0x8000 declares INIT at 0x8028 and STATEMENT at 0x8010, and theNestruo explained in issue #2 what the second one is for: boot with a key held so the game does not start, BLOAD"CAS:" a different course into RAM, and CALL GOLF to play that one instead of the cartridge's. He is right, and the listing says exactly why.

init (0x8028) does three things in order: it reads keyboard row 7 through SNSMAT and ret z if bit 2 is down; it writes 0x9C33 into (0xE000) — the eighteen-hole pointer table in ROM — and 0x99DD into (0xE002); and only then does it set up the machine from 0x8041.

statement (0x8010) compares the unrecognised BASIC statement against the four bytes "GOLF" at 0x8024. On a match it does jr $+33, which lands on 0x8041 — past the key check and past both pointer writes. And hoyo_normal (0x9871) reads the hole table from (0xE000), never from 0x9C33 directly. So whatever address is in (0xE000) when CALL GOLF runs is the course that gets played.

Nothing in init's setup touches it: it clears 0xE005–0xE01E and puts the stack at 0xF300, so 0xE000–0xE004 survive.

Proven by writing a course and playing it

tools/campo.py writes eighteen holes in the cartridge's own format — a straight sand fairway, a lake that swaps sides, and a bar of water on row 1 that is exactly as many cells long as the hole number, so it cannot be mistaken for the ROM course. tools/omsx_call_golf.tcl then does the whole sequence in openMSX: boot with row 7 bit 2 held, drop the 1,229 bytes at 0xC000 (which is what the BLOAD would do), point (0xE000) there, and type CALL GOLF.

(0xE000) after booting with the key held0xFFFF — the cartridge never ran
(0xE000) after CALL GOLF0xC000 — the pointer survived
screen against the generated holes480 / 480 cells, holes 1, 2, 3 and 4
the same screen against the ROM course261 / 480 at best (that is the grass)

The scoreboard reads them too: the attract mode shows HOLE 2, PAR 4, 302 m, which are the par and the length written into the generated hole 2 and are not the ROM's 168 m par 3.

The format

table       eighteen 2-byte pointers, in playing order
each hole   three header bytes, the script, a 0x21, three ASCII digits

The three header bytes are the hole's materials. In the script a 0x3n, 0x4n or 0x5n byte repeats the first, second or third of them n+1 times; any other byte is a literal cell — which is why a literal cell can never be in 0x30..0x5F. Three literals mark places: 0xE9 is the flag, and 0xD9, 0xDD and 0xE3 are the tee, which also state the par. 480 cells, twenty per row.

The generated course is re-read with the same interpreter that reads the ROM's, and all eighteen come back with their 480 cells intact — which is the check that the format is understood rather than merely described.

The tape: three more courses, and HAL's own instructions

Hole In One Extension Course (HAL Laboratory, 1985) is a two-sided tape that holds three more eighteen-hole courses for this cartridge. It is what the second half of issue #2 asked about, and it turns the CALL GOLF mechanism from a deduction into something written down by the people who made it.

Each side carries seven files:

filetypeloads at
CONSTbinary0x8000–0xAFFF, runs at 0x8000
SOUTH / WEST / NORTHASCII BASICthree lines each
SDATA / WDATA / NDATAbinary0xC050–0xD6FF, runs at 0xC050

And the BASIC programs are the whole procedure, in HAL's own words:

10 'SOUTH
20 BLOAD"CAS:SDATA",R
30 CALL GOLF

The ,R runs the code the course file starts with, at 0xC050, and that code does exactly what init does in the ROM — only pointing at RAM:

push af / push hl
ld hl,0c066h / ld (0e000h),hl     the eighteen-hole table
ld hl,0c08ah / ld (0e002h),hl     the greens table
ld a,001h    / ld (0e004h),a
pop hl / pop af / ret

Then CALL GOLF enters at 0x8041, past the two writes that would have pointed 0xE000 back at the ROM. That is the mechanism, and the tape is the manual.

The three courses

They are read with the same interpreter that reads the cartridge's, and the same tiles draw them — because it is the same format, byte for byte:

courseparlength
SOUTH726,147 m
WEST736,540 m
NORTH726,428 m

WEST is a par 73, which the ROM course never is.

And all three are one continuous strip too

The stacking theNestruo found in the cartridge's course is not a one-off: it is how this studio built all four of them. Measured the same way, with the same control:

courseshared rowadjacent rows within a holejoins above baseline
ROM cartridge70.9 %41.6 %17 of 17
SOUTH72.6 %38.9 %17 of 17
WEST70.0 %37.8 %17 of 17
NORTH73.5 %38.6 %17 of 17

Four courses, four continuous maps, hole 1 south and hole 18 north in every one.

The three courses stacked into the strips they form, hole 1 at the bottom: SOUTH · WEST · NORTH

The two sides, and how each one is loaded

The six course files are identical between side A and side B, byte for byte. Only CONST differs, and only in two bytes of padding after its last ret (0xAFD0–0xAFD1: 0xFF on side A, 0x00 on side B). What changes is the order: side A puts CONST first, for BLOAD"CAS:",R; side B puts the BASIC programs first, for RUN"CAS:".

That order is the difference in use, because side B needs BASIC and side A does not:

The ESC trick is not an MSX convention: the cartridge itself does it, in the first three instructions of init.

ld a,007h        ; 8028   row 7 of the keyboard matrix
call 00141h      ; 802a   BIOS SNSMAT
and 004h         ; 802d   bit 2 of that row is ESC
ret z            ; 802f   held down: returns without setting anything up

With ESC held the cartridge sets up neither the screen nor the interrupt hook: it hands control back to the BIOS and the machine finishes booting into BASIC, with CALL GOLF already registered. Which is exactly what the tape's three BASIC programs ask for.

CONST is the course editor

CONST is not a course, and it is not — as this page used to say — the game's engine for a machine with no cartridge: that reading collapses once you know both sides are loaded with the cartridge in. What it actually is can be read off the strings inside it:

SETCHR   SET=UP   MOVE   SWAP   CLEAR   SCROLL: OFF/ON
SAVE1    SAVE18   LOAD   FILES  DEVICE  DEV:
NAME:    SAVING   LOADING   SURE>>   OK =Y=
GREEN OR TEE NOT FOUND>
Directory of Drive     Too Many Disks !!!     Verify Error !?

An editor: you place tees and greens (and it complains if one is missing), move and clear, give the thing a name and save it — one hole or all eighteen — to tape or disk. What it produces is a course file in the SDATA/WDATA/NDATA format, which is why the tape's three courses read back with the cartridge's own interpreter.

It shares 2,803 bytes with the 1984 ROM in eleven runs, the longest being 2,123 bytes (the pattern table at 0xB324, relocated). And it shares another 3,050 bytes in 24 runs with Hole in One Professional (HAL, 1986), including the club table and the sprite sheet: the 1986 cartridge ships a GAME >>CONSTRUCTION mode and a COURSE >>USER slot, which is this tape's editor built in.

A hole's header is its palette

Every map starts with three bytes the cartridge copies to 0xE451. In the script, a 0x3n, 0x4n or 0x5n byte repeats one of those three n+1 times.

What links the two is an offset of three: the index comes from the opcode's high nibble, and the table it reads from starts at 0xE44E, three bytes before the header. So 3, 4 and 5 land right on it. There is no palette table anywhere; there is an offset that makes the hole's header be the palette.

Par and length live inside the map

There is no hole card either. The par is told by the tile that draws the tee: 0xD9 is a par 3, 0xDD a par 4 and 0xE3 a par 5, and the interpreter takes the chance to note where it falls and put the ball there. The length is three ASCII digits stuck behind the 0x21 that closes the map, and the scoreboard writes them out as they are with an 'm' beside them.

Add the eighteen up and you get par 72 and 6,430 metres.

One pattern table for all three thirds

The MSX's SCREEN 2 is three independent thirds: 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. The game's entire pattern table is 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 A comes out non-zero, the Z flag goes clear, and the six calls that follow load the long tables: the course.

But 0x8829 does not call 0x9505, it calls 0x9506, the second byte of that same instruction. And 0xAF on its own is xor a. So entering there runs the operand as an instruction, zeroes A and sets the Z flag, and the six calls load two short tables instead.

One two-byte instruction that is two different instructions depending on where you come in, and each entry picks a set of tables. The short ones write 112 bytes - fourteen tiles, 0x10 to 0x1D - on top of what was already there: they are the letters of HOLE IN ONE.

The wordmark's two tables overrun by eight bytes

They fall short: they give 104 of the 112 bytes that have to be written. Since the decompressor stops on the VRAM pointer and not on the source, it keeps reading whatever comes next. The last eight bytes of tile 0x1D come from the colour table's header, 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. And it never shows, because nothing names tile 0x1D: the wordmark's two halves stop at 0x1C.

The greens use exactly the tiles the wordmark overwrites

The three putting greens are drawn with tiles 0x10 to 0x1F - the fourteen the wordmark overwrites, plus two. The eighteen holes, on the other hand, do not name a single one of that range.

That is why the cartridge can leave the wordmark in place for the whole round without reloading anything - checked: the pattern and colour tables come out identical to the title's across six dumps with the game running - and only has to bring the long tables back when it is time to putt.

Ten columns for the scoreboard, twenty for the course

0x9571 writes ten cells per row and skips twenty-two, twenty-four times over: the panel fills columns 1 to 10. 0x9A66 dumps the hole's 480 cells as twenty columns by twenty-four rows from 0x180B, which is column 11. Neither half is drawn centred, so they never collide.