modemwars/disassembly/zeropage.inc
2026-08-23 02:09:40 -05:00

231 lines
26 KiB
PHP
Generated

; zeropage.inc - zero-page variables used by Modem Wars (auto-generated from annotations)
cpuPortDdr := $00 ; 6510 data direction register (listings show CPU_DDR); the film code drives it together with $01
cpuPortReg := $01 ; 6510 port (CPU_PORT): $35 = I/O visible, no ROMs; briefly $34 while the film buffer under $D000 is read/written
zp_03 := $03
oldLoadDestLo := $04 ; destination pointer (lo) of an earlier build of the fast loader; only touched by the unreachable leftoverCheckDiskId at $C3C4
oldLoadDestHi := $05 ; high byte of oldLoadDestLo (dead leftover)
zp_06 := $06
zp_09 := $09
zp_0A := $0A
zp_0B := $0B
zp_0C := $0C
zp_0D := $0D
zp_0E := $0E
zp_0F := $0F
zp_10 := $10
zp_11 := $11
zp_13 := $13
zp_15 := $15
zp_16 := $16
scratch18 := $18 ; general scratch, used by every unit: multiply/divide operand ($FCCD/$FD0A), character row in the text plotters, the film header checksum accumulated by $5900, the overview character row in drawOverviewMap, loop counters and sums
scratch19 := $19 ; general scratch, partner of scratch18: product/quotient, character column in the text plotters, the page counter of the film unit snapshot ($5967), the overview character column in drawOverviewMap
scratch1A := $1A ; general scratch: third math temp, right column of a frame box, low byte of the trainer's 16-bit scores; in finishRound the stack pointer of the pending-unit stack at $0464
scratch1B := $1B ; general scratch: bottom row of a frame box, division remainder (lo), max column returned by computeGroupBounds; in finishRound the cursor into unitBaseOrder, in processUnitStep the direction of the best fire target
scratch1C := $1C ; general scratch: frame tile code, division remainder (mid), member count / max row of a group; also the running best score of the trainer's 2x2 bombardment search
scratch1D := $1D ; general scratch: bounds mode flag of computeGroupBounds (bit 7 = use destinations), division remainder (hi); the trainer's bombardment search keeps the chosen target unit here
scratch1E := $1E ; general scratch: running terrain height in the line-of-sight walk; computeGroupCentroid leaves the group's average ordered destination column here
scratch1F := $1F ; general scratch: line-of-sight rise flag, divide bit counter; computeGroupCentroid leaves the group's average ordered destination row here
scratch20 := $20 ; general scratch: half width in magnifyWindow2x, the pass flag of scanVisibleEnemies (bit 7 set = attack-target pass, clear = spotting pass), unit type being counted on the STATS tab
scratch21 := $21 ; general scratch: half height in magnifyWindow2x, index of the unit doing the scan in scanVisibleEnemies, terrain neighbour mask in the map generator
cellColA := $22 ; map column of point A for distanceSquared/cellDistance; the trainer also uses it as the group's wanted target column, as the direction-rank index in findTrainerAdvanceCell and as the unit loop counter in issueTrainerGroupOrders
scratch23 := $23 ; general scratch: first (clipped) column of the area scan square; distance/direction accumulator in the trainer's move search, and the trainer's reluctance-to-fire score in runAiMissileTurn ($ED46)
cellRowA := $24 ; map row of point A for distanceSquared/cellDistance; the trainer's wanted target row and, while computeTrainerGroupStats runs, the group's rightmost ordered destination column
scanColCount := $25 ; columns left to scan on the current row of an area scan; computeTrainerGroupStats reuses it as the group's bottom-most ordered destination row
scanRowCount := $26 ; rows left to scan in an area scan; the trainer keeps the direction chosen by findTrainerAdvanceCell here
cellColB := $27 ; map column of point B (the reference point) for distanceSquared/cellDistance; the trainer's search origin column
cellRowB := $28 ; map row of point B (the reference point); the trainer's search origin row
scanListIndex := $29 ; index of the last entry written to the area-scan result lists at $0400/$0432/$0464 ($FF = empty); the trainer's missile code parks the pending reload time here ($ED49)
scratch2A := $2A ; scratch: hill-site index in the map generator; in the trainer the group's column movement delta, and the candidate distance inside the direction search
scratch2B := $2B ; general scratch: lane or cluster-seed counter in the map generator, group destination row delta in the trainer, and the 'AI comcen is stunned' flag of runAiMissileTurn ($ED31, $FF = stunned)
zp_2C := $2C
contourScanRow := $2D ; map generator: row of the cell being examined by applyContourTiles
contourScanCol := $2E ; map generator: column of the cell being examined by applyContourTiles
scanResultCount := $2F ; index of the last entry of the area-scan result lists (count-1, $FF = none); drawViewport reuses it as the counter of the 5 cell rows of the tactical view
magnifySrcRow := $30 ; source row counter of magnifyWindow2x
magnifySrcCol := $31 ; source column counter of magnifyWindow2x; drawViewport reuses it as the counter of the 7 cells across the tactical view and as the offset of the cell inside the map row
tileColour := $32 ; colour byte of the map tile being rendered: first the terrain colour written into both nybbles of the screen RAM cells, then the unit colour (blue/red/white) written into colour RAM
spriteFlashPhase := $33 ; frame counter rotated right twice inside the raster IRQ so bit 7 mirrors bit 0 of frameCounter; gates the two-colour sprite flashing
zp_34 := $34 ; not a real variable: the only reference is the stray byte pair $CE,$34 at the very end of the text engine ($CFFE)
zp_35 := $35
zp_36 := $36
zp_37 := $37
irqInProgress := $38 ; re-entrancy guard of rasterIrqHandler (non-zero while the handler runs with interrupts enabled)
textWindowTop := $39 ; text engine: first screen row of the text window
textWindowBottom := $3A ; text engine: row just below the text window; the window clears fill while the cursor row is less than this
textWindowLeft := $3B ; text engine: left screen column of the text window; added to textCursorCol to get the absolute column
textWindowWidth := $3C ; text engine: window width in characters (wrap point) and the default centring width; also the width of a menu highlight bar
textColour := $3D ; text engine: colour byte written for each printed character cell, and the EOR mask used for the menu highlight
textFillGlyph := $3E ; text engine: glyph number used as the blank/fill character by the clear, pad and backspace routines (glyph 0 = blank)
textCursorCol := $3F ; text engine: cursor column relative to textWindowLeft; magnifyWindow2x borrows it as the destination left column of the 2x zoom
textCursorRow := $40 ; text engine: absolute cursor row (0-24); magnifyWindow2x borrows it as the destination top row of the 2x zoom
screenBuiltFlag := $41 ; set to 1 by every screen builder and never read anywhere; a spare slot of the 12-byte text state saved to savedTextWindow
textPadColour := $42 ; text engine: colour used for the blanks that pad a centred string
rawGlyphMode := $43 ; text engine: bit 7 set = printChar takes A as a glyph number, skipping the ASCII translation and the control codes
doubleSizeText := $44 ; text engine: bit 7 set = characters are drawn 2x2 cells and the cursor advances two columns/rows
frameCounter := $45 ; low byte of the free-running 24-bit frame counter incremented by the raster IRQ
frameCounterMid := $46 ; middle byte of frameCounter
frameCounterHi := $47 ; high byte of frameCounter
mapCellPtr := $48 ; pointer (lo) to a cell of the $F000 battlefield map, set by readMapCell ($25FA); also the running pointer of the block fill/copy loops, and in the trainer setup overlay the pointer to the 50 group ids of the selected opening play inside the playbook at $0200
mapCellPtrHi := $49 ; high byte of mapCellPtr
fillEndPtr := $4A ; end address (lo) compared by advanceFillPointer ($C3F9); reused as the film-directory entry pointer, the trainer's plan column pointer and the 99..0 unit loop counter of moveGroupKeepingFormation ($4A52)
fillEndPtrHi := $4B ; high byte of fillEndPtr
planRowPtr := $4C ; trainer setup: pointer (lo) to the 50 destination rows of the selected opening play inside the loaded playbook
planRowPtrHi := $4D ; high byte of planRowPtr
fillCounter := $4E ; 16-bit counter incremented as a side effect by advanceFillPointer ($C3F9); nothing reads it
fillCounterHi := $4F ; high byte of fillCounter
zp_50 := $50
zp_51 := $51
savedRegA := $54 ; A save slot of saveRegsAXY/restoreRegsAXY ($C0E8/$C030), so printChar can preserve the caller's registers
savedRegX := $55 ; X save slot of saveRegsAXY/restoreRegsAXY; the map drawing code uses it as the cell column
savedRegY := $56 ; Y save slot of saveRegsAXY/restoreRegsAXY; the map drawing code uses it as the cell row
gameRngState0 := $57 ; byte 0 of the 24-bit game RNG stepped by nextGameRandom ($FD5D); seeded with $49 at $030B so both machines match
gameRngState1 := $58 ; byte 1 of the game RNG state (seeded $19)
gameRngState2 := $59 ; byte 2 of the game RNG state (seeded $02)
scenarioSeed0 := $5A ; byte 0 of the 24-bit scenario/map seed stepped by nextScenarioRandom ($FD4A); also the first answer byte of the manual look-up check, and the value the sound driver adds to a voice frequency for the bit-7 'jitter' script command ($66BF)
scenarioSeed1 := $5B ; byte 1 of the scenario seed; its bit 7 gives the sign in addRandomJitter; second manual answer byte
scenarioSeed2 := $5C ; byte 2 of the scenario seed; third manual answer byte
joyDirection := $5D ; joystick 2 direction nibble latched by the IRQ, active low ($0F = centred); indexes joystickDirectionTable
droneJoyDirection := $5E ; direction code 0-7 of the last joystick steer on the drone screen; steerDrone maps it to a clockwise heading through joyDirToHeadingTable ($7FCE)
joyFireUp := $5F ; joystick 2 fire state latched by the IRQ: 0 = button down, 1 = released
joyDirectionCopy := $60 ; second copy of joyDirection written by the IRQ at $1216; no reader anywhere (dead store)
joyFireUpCopy := $61 ; second copy of joyFireUp written by the IRQ at $1210; no reader anywhere (dead store)
zp_63 := $63
zp_64 := $64
requestedScreenKey := $66 ; last key delivered by pollKeyboardEvent: $FF = none, 0-3 = F1/F3/F5/F7 = the screen the player asked for (the only values switchToRequestedScreen acts on), any other value = the PETSCII|$80 code of the key just typed, which reads as 'no screen change wanted' and so cancels a stale F-key request
gridCursorCol := $67 ; missile screen: column 0-20 of the target cursor in the 21x17 radar grid (comcen at 10)
gridCursorRow := $68 ; missile screen: row 0-16 of the target cursor (comcen at 8)
mergeFillIndex := $69 ; number of bytes already placed in mergedCmdBuffer while the own and the received packet are merged into one turn; also the index at which the second player's block starts
packetReadIndex := $6A ; read offset into the packet currently being merged; advancePacketCursor ($4F5E) sets it to the offset of the next command
targetDirection := $6B ; direction 0-3 of the unit's chosen target, copied into the facing bits of unitFlagsTable; processUnitStep pre-loads it at $439A with the unit's current facing so the sight and attack scans prefer that quadrant; the map generator reuses it as the blob's tried-direction mask
joyRepeatTimer := $6C ; first of the six IRQ frame countdowns $6C-$71: joystick auto-repeat delay, also used as the 4-frame step delay of the animated mini-map path marker ($2506)
fireDebounceTimer := $6D ; frame countdown after an accepted fire press; clicks are ignored while it is non-zero
menuBlinkTimer := $6E ; frame countdown between menu-highlight toggles and console-tab blinks; scrollViewToUnit reuses it as the delay between animated scroll steps
markerBlinkTimer := $6F ; frame countdown for the repair-marker and missile-button blink; printUnitStatusLines also loads it with 20 to hold FIRED in the WEAPON field of the info panel ($2424)
keyRepeatTimer := $70 ; frame countdown before a held key produces another key event
frameTimer71 := $71 ; sixth of the IRQ frame countdowns $6C-$71; nothing ever loads it (spare slot)
messageTimer := $72 ; frames the current status-line message stays up, decremented every 4th frame by updateFrameTimers; 0 = ready for the next message. handleMessageReviewKeys also uses it as the minimum airtime of a scrolled-back message (it only steps on once the timer has fallen below $23)
cmdParam0 := $73 ; first argument byte of the command being queued or executed: unit index, group byte, session-control reason, recycler mode or map-seed byte 0
cmdParam1 := $74 ; second argument byte of the command: usually the map column, but also the unit index of the 3-byte group commands ($87, $88, $9A, $A3) and map-seed byte 1
cmdParam2 := $75 ; third argument byte of the command: usually the map row, but also the target unit, group byte, option value or map-seed byte 2
cmdFromOpponent := $76 ; bit 7 set while the command being merged or executed came from the opponent: its coordinates are mirrored with 39-v, its side is playerSide EOR 1, and most sound/message side effects are suppressed for our own copy
ownUnitColour := $77 ; colour RAM value for the local player's units (6 = blue)
enemyUnitColour := $78 ; colour RAM value for the opponent's units (2 = red)
fireButtonArmed := $79 ; fire-button edge latch: set when checkFirePressed/isFireHeld see the button released, cleared when a press is accepted, so one press produces exactly one click
pendingMessageId := $7A ; id of the message the status bar should print next; bit 7 set = already consumed, $80 = fully idle
shownMessageId := $7B ; id of the message currently on the status bar; bit 7 set = the bar is free
zp_7C := $7C
unusedByte7D := $7D ; written with 0 by animateRingBurst ($3D2A) and read nowhere (dead store)
decimalValueHigh := $7E ; high (third) byte of the 24-bit value printDecimal converts; cleared by convertToDecimalDigits
linkWaitTimer := $7F ; countdown decremented every 8th frame; completeExchange and the link waits load it with $4B (about ten seconds) and hang the modem up if the exchange has not completed by then
loaderTimingPad := $80 ; never written: BIT $80 is used purely as a 3-cycle delay in the fast-loader receive loops ($096F here, $C10E in the boot loader)
zp_81 := $81
zp_82 := $82
zp_83 := $83
zp_84 := $84
zp_85 := $85
zp_86 := $86
zp_87 := $87
zp_88 := $88
zp_89 := $89
zp_8A := $8A
lineErrRow := $8C ; line stepper: Bresenham error accumulator of the row axis, stepped by |dRow| and wrapped at the major length $8E; initLineStepper preloads it with majorLen/2 when the column is the major axis; the map generator reuses it as the random-bit count
lineErrCol := $8D ; line stepper: error accumulator of the column axis, stepped by |dCol|; preloaded with majorLen/2 when the row is the major axis; the map generator reuses it as the random bit buffer
lineMajorLen := $8E ; line stepper: length of the line along its major axis, max(|dRow|,|dCol|); the contour passes reuse it as the terrain class that counts as high ground (6 summit, 4 lower hill)
lineDeltaRow := $8F ; line stepper: |end row - start row|
lineDeltaCol := $90 ; line stepper: |end column - start column|
lineStepsLeft := $91 ; line stepper: steps still to walk (0 = finished); returned in A by initLineStepper/stepLine; the contour passes reuse it as the terrain class of the ring being redrawn (5 or 3)
lineCurRow := $92 ; line stepper: current map row; computeTrainerGroupStats leaves the group centre row here for the trainer's line and search code
lineCurCol := $93 ; line stepper: current map column; computeTrainerGroupStats leaves the group centre column here
lineEndRow := $94 ; line stepper: target map row; the trainer's wanted group destination row before it is copied into zp_24
lineEndCol := $95 ; line stepper: target map column; the trainer's wanted group destination column before it is copied into zp_22
lineStepRow := $96 ; line stepper: row increment per major step ($01 or $FF)
lineStepCol := $97 ; line stepper: column increment per major step ($01 or $FF)
spritePlotPtr := $98 ; pointer (lo) to the sprite shape byte being modified by plotSpritePixel; loadDirectionShapeSprite reuses it as the $0200 + shape*64 copy source
spritePlotPtrHi := $99 ; high byte of spritePlotPtr ($8A/$90)
kernalMsgFlag := $9D ; KERNAL MSGFLG; the ea boot file stores 0 so the KERNAL LOAD stays silent (not a game variable)
zp_9E := $9E
zp_9F := $9F
zp_A0 := $A0
zp_A1 := $A1
stringPtr := $A2 ; pointer (lo) to the bit-7 terminated string being printed; left just past the terminator
stringPtrHi := $A3 ; high byte of stringPtr
zp_A4 := $A4
viewOriginCol := $A5 ; map column of the left edge of the 7x5 battlefield view (may be negative); the cursor cell is viewOriginCol+3; the map generator reuses it as the column of the cell being painted or scanned
viewOriginRow := $A6 ; map row of the top edge of the battlefield view; the cursor cell is viewOriginRow+2; the map generator reuses it as the row of the cell being painted or scanned
blobOriginCol := $A7 ; map generator: column where the current terrain blob started
blobOriginRow := $A8 ; map generator: row where the current terrain blob started
isDiagonalStep := $A9 ; set to 1 by stepLine when the step moved along both axes, 0 for an orthogonal step and 0 when the line was already finished; a diagonal step costs 8 extra movement points at $45DF
rasterIrqLine := $AA ; raster line the IRQ handler re-arms VIC_RASTER with ($FA)
irqVectorShadowLo := $AB ; low byte of the IRQ vector that rasterIrqHandler writes back to $FFFE on every interrupt
irqVectorShadowHi := $AC ; high byte of the IRQ vector written back to $FFFF on every interrupt
circleDxPtr := $AD ; pointer (lo) to the dx list of the circle radius being drawn into a sprite
circleDxPtrHi := $AE ; high byte of circleDxPtr
circleDyPtr := $AF ; pointer (lo) to the dy list of the circle radius being drawn
circleDyPtrHi := $B0 ; high byte of circleDyPtr
gamePhase := $B1 ; game phase: 0 only while the battle runs. Bit 7 = still waiting for the map seed (cleared by command $8B/$A6), bit 5 = side selection still open (cleared to $DF by command $9D), bits 0-1 = the two sides' 'not ready' bits cleared one at a time by command $9E through getPauseClearMask
glyphPtr := $B2 ; pointer (lo) to the 8 bytes of the glyph/tile being drawn; also the blob stack index and the RLE destination
glyphPtrHi := $B3 ; high byte of glyphPtr; growTerrainBlob reuses it as the count of cells painted so far
bitmapPtr := $B4 ; pointer (lo) to the current 8x8 cell in the $A000 bitmap, from the row/column tables at $9300
bitmapPtrHi := $B5 ; high byte of bitmapPtr
screenPtr := $B6 ; pointer (lo) to the colour byte of the current cell in screen RAM $8C00; renderMapTile adds $4C to the high byte on the way out, so it points into colour RAM $D800 when a unit was drawn
screenPtrHi := $B7 ; high byte of screenPtr
blockPtr := $B8 ; pointer (lo) to the character-block/frame-tile data being drawn; paintRadarSweepRow reuses it as the video-matrix ($8C00) row pointer while screenPtr addresses the matching colour RAM
blockPtrHi := $B9 ; high byte of blockPtr
magnifyEdgeMask := $BA ; quadrant suppression mask of plotGlyphDoubleSize: bit 0 skip the top cells, bit 1 the bottom, bit 2 the left, bit 3 the right
cursorTargetMode := $BB ; target cursor mode: 0 = move order, >0 = range-limited attack cursor, <0 = free cell pick reported in pickedCellCol/Row; the group menus also use it as the group-editor mode (0 = MEMBERSHIP, $80 = custom FORMATION)
filmPtr := $BC ; pointer (lo) into the game film buffer in the RAM under the I/O area ($D000-$DFEF); reached only through readFilmByte/writeFilmByte with Y as the offset, so it doubles as the header base ($D000) and as the write position of the command stream
filmPtrHi := $BD ; high byte of filmPtr; compareFilmPtrToEnd stops recording when the pair reaches filmEndPtr $92F1/$92F2
pauseState := $BE ; pause/disconnect state: bit 0 own pause, bit 1 opponent pause, 3 after a timeout, bit 7 = voice pause / hang-up. handlePauseKey toggles bit 0 directly in a solo or film game and otherwise waits for the command interpreter to set it from the opponent's $8C packet
zp_C0 := $C0
zp_C1 := $C1
zp_C2 := $C2
zp_C3 := $C3
zp_C4 := $C4
zp_C5 := $C5
zp_C6 := $C6
zp_C7 := $C7
zp_C8 := $C8
zp_C9 := $C9
zp_CA := $CA
zp_CC := $CC
zp_CD := $CD
zp_CE := $CE
zp_D0 := $D0
zp_D4 := $D4
soundScriptPtr := $D8 ; sound script read pointer (lo) of SID voice 0; the driver indexes it with voice*2, so voices 1 and 2 use $DA/$DB and $DC/$DD
soundScriptPtrHi := $D9 ; high byte of soundScriptPtr (voice 0)
soundScriptPtr1 := $DA ; sound script read pointer (lo) of SID voice 1
soundScriptPtr1Hi := $DB ; high byte of soundScriptPtr1
soundScriptPtr2 := $DC ; sound script read pointer (lo) of SID voice 2
soundScriptPtr2Hi := $DD ; high byte of soundScriptPtr2
zp_DE := $DE
ldTrack := $E0 ; fast loader: track of the sector being transferred
ldSector := $E1 ; fast loader: sector being transferred, incremented after each good sector
ldDestPtr := $E2 ; fast loader: destination pointer (lo) of the 256-byte receive loop
ldDestPtrHi := $E3 ; fast loader: destination pointer (hi), advanced one page per sector
ldCia2Bits := $E4 ; fast loader: CIA2 port A bits 0-1 (VIC bank) rewritten on every handshake strobe and EORed out of the assembled byte
wrSrcPtr := $E5 ; fast loader: source pointer (lo) of the sector being written back to disk
wrSrcPtrHi := $E6 ; fast loader: source pointer (hi) of the sector being written
ldCount := $E7 ; fast loader: sectors left to transfer
zp_E8 := $E8
zp_E9 := $E9
zp_EA := $EA
zp_EB := $EB
zp_EC := $EC
zp_ED := $ED
zp_EE := $EE
zp_EF := $EF
scrollDeltaCol := $F0 ; column step applied to the battlefield view: set to -1/0/+1 by scrollViewBy (0 when the step was clamped), then biased to a table index 0/1/2 by scrollViewBitmap, which leaves it that way
scrollDeltaRow := $F1 ; row step applied to the battlefield view, same encoding as scrollDeltaCol
bitmapRowStride := $F2 ; signed 16-bit stride (lo) added between bitmap rows while the view scrolls (+320 or -320)
bitmapRowStrideHi := $F3 ; high byte of bitmapRowStride
screenRowStride := $F4 ; signed 16-bit stride (lo) between screen RAM rows while the view scrolls (+40 or -40)
screenRowStrideHi := $F5 ; high byte of screenRowStride
scrollRowCount := $F6 ; number of character rows to copy while the view scrolls (8 or 10)
redrawCellCount := $F7 ; cells left to redraw along the edge that a scroll exposed: 5 for a column, 7 for a row
viewRowLimit := $F8 ; exclusive map-row limit for the centre cell of the battlefield view: 40 during the battle, 20 while gamePhase is non-zero so a player only sees his own half
zp_F9 := $F9
driveCmdStrPtr := $FB ; C128 boot sector: pointer (lo) to the DOS command string being sent; not used by the game
driveCmdStrPtrHi := $FC ; high byte of driveCmdStrPtr (always $0B)
zp_FF := $FF