{
  "chunk": "game_setup_0200_0200",
  "unit": "game/setup_0200",
  "routines": [
    {
      "addr": "0300",
      "name": "initGameSystems",
      "summary": "One-shot start-up routine that lives inside the block loaded from track 18 sectors 15-16. Called exactly once, from mainStart at $0A87 immediately after loadSetupBlock ($10BB). It calls resetGameVariables ($0C1C), resetSpritesAndVicBank ($035E), invertTextFonts ($031B), seeds the 24-bit game RNG with $49/$19/$02, calls buildMapRowAddressTable ($0339) and finally JMPs to initBitmapScreen ($2D41), which sets up the hires bitmap display and returns to mainStart.",
      "inputs": "none (runs with $01=$35, ROMs out, I/O in)",
      "outputs": "zero page and $9008-$92FF cleared by resetGameVariables; zp_57/58/59 = $49/$19/$02 (RNG seed); all sprite registers and $9022 cleared; VIC bank 2 selected; fonts at $98BE-$9C6D inverted; map row tables at $BFB0/$BFD8 built; bitmap screen initialised; zp_48-zp_4B and zp_4E/4F clobbered",
      "confidence": "high"
    },
    {
      "addr": "031B",
      "name": "invertTextFonts",
      "summary": "Inverts (EOR #$FF) the 944 bytes at $98BE-$9C6D in place, walking the source pointer with advanceFillPointer ($C3F9) using zp_48/49 = $98BE and the limit zp_4A/4B = $9C6D. That range is exactly the two 59-glyph 8x8 character sets used by the $C000 overlay's text plotter: $98BE (multicolour / double-width glyphs) and $9A96 = $98BE+$1D8 (hires glyphs), selected at $C20B by bit 4 of the $D016 shadow $9001. The glyphs are stored positive on disk (1 bits = strokes) and are negatives after this call, so the plotter's ORA/EOR/CMP draw modes (set via setBitmapDrawMode, which patches $C22B) operate on inverted art.",
      "inputs": "none; hardcoded range $98BE..$9C6D",
      "outputs": "$98BE-$9C6D EORed with $FF; zp_48/49 left at $9C6E, zp_4A/4B = $9C6D, zp_4E/4F incremented 944 times (never read)",
      "confidence": "high"
    },
    {
      "addr": "0339",
      "name": "buildMapRowAddressTable",
      "summary": "Builds the 40-entry row address table of the 40x40 battlefield map: for row 0..39 it stores the high byte of $F000+40*row at $BFD8+row and the low byte at $BFB0+row. These tables are what readMapCell ($25FA) and every other map accessor use to turn (column,row) into a pointer, so this must run before any map access. Uses zp_48/zp_49 as the running address.",
      "inputs": "none; base address $F000 and stride $28 are hardcoded",
      "outputs": "$BFB0-$BFD7 = row address low bytes, $BFD8-$BFFF = high bytes; zp_48/zp_49 left at $F640 (one row past the map)",
      "confidence": "high"
    },
    {
      "addr": "035E",
      "name": "resetSpritesAndVicBank",
      "summary": "Clears all sprite state and picks the VIC bank. Zeroes $D000-$D010 (all eight sprite X/Y pairs plus the X-MSB register), $D015 (sprite enable) and its shadow $9022, $D017 (Y expand) and $D01A-$D01F (raster IRQ mask, sprite priority, sprite multicolour, X expand and the two collision latches, which the write clears). Then makes CIA2 port A bits 0-1 outputs and writes $05: VIC bank 2 ($8000-$BFFF, matching bitmap $A000 / screen $8C00) with the user-port RS-232 TXD latch left high. Ends with JMP clearAllSpriteData ($2FA5), which zeroes the sprite shape area $8A00-$8BFF.",
      "inputs": "none",
      "outputs": "$D000-$D010, $D015, $D017, $D01A-$D01F = 0; $9022 = 0; CIA2_DDRA |= $03; CIA2_PRA = $05 (VIC bank 2); $8A00-$8BFF cleared; A = 0",
      "confidence": "high"
    }
  ],
  "variables": [
    {"addr": "48", "scope": "zp", "name": "fillPointer", "meaning": "16-bit source/destination pointer (with $49) driven by advanceFillPointer ($C3F9); used here as the font pointer in invertTextFonts and as the running map row address in buildMapRowAddressTable", "confidence": "high"},
    {"addr": "49", "scope": "zp", "name": "fillPointerHi", "meaning": "high byte of fillPointer", "confidence": "high"},
    {"addr": "4A", "scope": "zp", "name": "fillLimit", "meaning": "16-bit last address compared by advanceFillPointer (with $4B); set to $9C6D by invertTextFonts", "confidence": "high"},
    {"addr": "4B", "scope": "zp", "name": "fillLimitHi", "meaning": "high byte of fillLimit", "confidence": "high"},
    {"addr": "4E", "scope": "zp", "name": "fillCounter", "meaning": "16-bit counter (with $4F) that advanceFillPointer increments as a side effect; not initialised or read by this chunk", "confidence": "medium"},
    {"addr": "57", "scope": "zp", "name": "gameRngState0", "meaning": "byte 0 of the 24-bit game RNG state stepped by nextGameRandom ($FD5D); seeded with $49 at $030B", "confidence": "high"},
    {"addr": "58", "scope": "zp", "name": "gameRngState1", "meaning": "byte 1 of the game RNG state; seeded with $19 at $030F", "confidence": "high"},
    {"addr": "59", "scope": "zp", "name": "gameRngState2", "meaning": "byte 2 of the game RNG state; seeded with $02 at $0313", "confidence": "high"},
    {"addr": "02A2", "scope": "abs", "name": "bamDiskIdLo", "meaning": "second use of this page: when checkDiskId ($0FB1) reads the BAM (track 18 sector 0) into $0200 this byte is BAM offset $A2, the first disk-id character ('O' for the game disk, 'E' for a data disk). It is contourRuleTable index $A2 the rest of the time", "confidence": "high"},
    {"addr": "02A3", "scope": "abs", "name": "bamDiskIdHi", "meaning": "BAM offset $A3, the second disk-id character ('Z' / 'A'), compared by checkDiskId at $0FE0", "confidence": "high"},
    {"addr": "02AB", "scope": "abs", "name": "bamDiskSerial", "meaning": "BAM offset $AB, 10 bytes copied to $FFDE-$FFE7 at $0FF3 for the game disk in modem mode; used by the link protocol as the disk serial", "confidence": "high"},
    {"addr": "9022", "scope": "abs", "name": "spriteEnableShadow", "meaning": "software shadow of VIC $D015; cleared here together with the register", "confidence": "high"},
    {"addr": "BFB0", "scope": "abs", "name": "mapRowAddrLo", "meaning": "40 low bytes of the $F000 map row addresses, built at $034A and read by readMapCell at $25FC", "confidence": "high"},
    {"addr": "BFD8", "scope": "abs", "name": "mapRowAddrHi", "meaning": "40 high bytes of the map row addresses, built at $0345 and read at $2603; the pair occupies $BFB0-$BFFF, the tail of the VIC bank above the bitmap ($A000-$BF3F)", "confidence": "high"},
    {"addr": "98BE", "scope": "abs", "name": "fontMulticolour", "meaning": "59 x 8 bytes ($1D8) of multicolour / double-width glyphs for the $C000 overlay text plotter (base used when $9001 bit 4 = multicolour); inverted in place by invertTextFonts", "confidence": "high"},
    {"addr": "9A96", "scope": "abs", "name": "fontHires", "meaning": "59 x 8 bytes ($1D8) of hires glyphs, the same character set as fontMulticolour at single width; base used when $9001 bit 4 is clear (plotter adds $01D8 at $C215/$C21B); inverted in place by invertTextFonts", "confidence": "high"},
    {"addr": "9001", "scope": "abs", "name": "vicCtrl2Shadow", "meaning": "shadow of VIC $D016; bit 4 (multicolour) selects which of the two fonts inverted by this chunk the $C000 plotter uses", "confidence": "high"}
  ],
  "dataBlocks": [
    {
      "addr": "0200",
      "length": 256,
      "type": "byteTable",
      "name": "contourRuleTable",
      "description": "Terrain-contour rule table of the random map generator (overlay A, read at $7484 as contourRuleTable,Y). Y is an 8-bit mask of which of the eight neighbours of the current cell are higher terrain; the bit order is verified from the edge-clamp masks at $7463-$7481 ($D6 at column 0, $6B at column 39, $F8 at row 0, $1F at row 39): bit0=NW, bit1=N, bit2=NE, bit3=W, bit4=E, bit5=SW, bit6=S, bit7=SE. Entry semantics, confirmed against the actual bytes: $00 (index 0 only) = do nothing; $41-$51 = contour tile code to place (the generator subtracts contourTileOffset $0324, 0 for the summit ring, $20 for the lower-hill ring) - $51 north edge, $4D south edge, $4B west edge, $49 east edge, $45 N+W corner, $46 N+E, $47 W+S, $48 E+S, $44/$43/$42/$41 the isolated NW/NE/SW/SE diagonals; $80+n (105 entries, n = neighbour bit index) = randomly erase neighbour n instead; $91/$95/$97 (indexes $05 NW+NE, $A0 SW+SE, $84 NE+SE) = erase that neighbour or else fill; $FF (93 entries, including index $FF) = fill the cell with the interior tile. Loaded from track 18 sector 15 by loadSetupBlock/loadMapAndSetup; never written back to disk."
    },
    {
      "addr": "0389",
      "length": 119,
      "type": "unknown",
      "name": "setupBlockPadding",
      "description": "$0389-$03FF, all zero on disk. Tail of track 18 sector 16 after the start-up code; not referenced as code or data by anything. At run time the page is later reused for other things (film directory, sprite shape buffer, map-generator variables)."
    }
  ],
  "misclassified": [],
  "insights": [
    "The block at $0200-$03FF is not really a 'saved setup block': $0200-$02FF is the map generator's 256-entry contour rule table and $0300-$0388 is a one-shot start-up routine, both read from track 18 sectors 15-16 and never written back. writeSectors ($0843) has exactly two callers, $7E85 (film directory -> track 18 s2-3) and $8194 (film pages), so nothing in the game rewrites T18 s15-16.",
    "The $0200-$03FF page is time-multiplexed between at least five owners: (1) contourRuleTable + this start-up code, reloaded by loadSetupBlock ($10BB, once at boot) and loadMapAndSetup_10AB ($10AB, from $0B35 before every game session); (2) BAM buffer for checkDiskId ($0FB1, uses $02A2/$02A3/$02AB); (3) the RLE sprite-shape buffer written by unpackRleTo0200 and read at $CD15 / by loadDirectionShapeSprite; (4) overlay A's map-generator scratch variables at $0300-$032E (hillSiteCount, riverCol, mapStyleFlags, ...), which overwrite the start-up code; (5) the film directory $0300-$04FF (track 18 s2-3) and, at game start, the unit-deployment tables that sub_EC91 (called from $7AE9) loads from track 29 sectors 6-8 into $0200-$04FF. The contour table is therefore only valid between $0B35 and $7AE9.",
    "Neighbour-mask bit order for the whole map generator, derived from the edge clamps at $7463-$7481: bit0=NW, bit1=N, bit2=NE, bit3=W, bit4=E, bit5=SW, bit6=S, bit7=SE (reading order, centre skipped). Column 0 ANDs with $D6, column 39 with $6B, row 0 with $F8, row 39 with $1F.",
    "$BFB0-$BFFF holds the 40+40 byte row address table of the $F000 map ($F000+40*row), built here at boot and used by readMapCell ($25FA) and every other map accessor. It sits in the 192 bytes of the VIC bank left over above the bitmap ($A000-$BF3F), so anything that clears the bitmap must stop at $BF40.",
    "There are two independent font systems. plotGlyph ($2AC8, main program) uses gameFont at $9426 (114 glyphs) with fontColorTable at $93B4. The $C000 overlay's plotter ($C1F0/$C24B) uses a 59-glyph set that exists twice: multicolour/double-width at $98BE and hires at $9A96 ($98BE+$1D8), selected by bit 4 of the $D016 shadow $9001. Only the second pair is inverted at start-up by $031B - on disk both are positives (1 = ink), at run time both are negatives.",
    "VIC bank 2 is selected here, not by the boot loader's title code: $035E sets CIA2_DDRA |= $03 and CIA2_PRA = $05 (bank 2 = $8000-$BFFF, plus the RS-232 TXD latch high), which is what makes bitmap $A000 / screen $8C00 / sprite data $8A00 work.",
    "The game RNG ($57-$59, stepped by nextGameRandom $FD5D) is seeded deterministically with $49/$19/$02 at every cold start, so an unmodified boot always produces the same first random sequence until the joystick/keyboard reseeding kicks in.",
    "Label hygiene: XREF.txt and the include lists of main_0800.s / ovl_6F00_A.s carry stale names for addresses in this unit - $0300 is called basicVectorHijack and $02B8/$02EC eaLoadGame/eaFileName (all from boot/ea.s, which loaded to $02A8-$030B during booting), and $0313 is called commandDispatchLoop (from the 1541 fast loader at $0300-$05FF in drive RAM). None of those meanings apply once the game is running; proposed names here are initGameSystems for $0300 and contourRuleTable for the $0200 page."
  ]
}
