a2zip/alds/zip.mac

2984 lines
56 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

TITLE Infocom INTERLOGIC interpreter disassembly, 5/27/84
; ***************************************************************************
; * *
; * Infocom INTERLOGIC interpreter disassembly *
; * Apple II/6502 version, release 3 *
; * As used in interactive fiction games *
; * *
; * The INTERLOGIC interpreter is copyrighted by Infocom, Inc. *
; * *
; * This disassembly and the comments thereof are copyright (C) 1984 by *
; * Eric L. Smith *
; * 230 South 500 West Suite 133 *
; * Salt Lake City, Utah 84101 *
; * (801) 582-3371 *
; * *
; * This disassembly represents well over 300 hours of intense study. It *
; * is intended for private, noncommercial use only. Any comments or *
; * questions about it should be addressed to the above address. There is *
; * no warranty, express or implied, as to the accuracy of this disassembly *
; * or its fitness for any particular purpose. I assume no liability for *
; * any damages, actual or alleged, direct or indirect, resulting from the *
; * use of, or inability to use this disassembly. *
; * *
; ***************************************************************************
PAGE
.6502
.SALL
.SFCOND
VERSN EQU 0 ; 0 is old version, 1 is new
RNGDBG EQU 0 ; RNG debug
LC40 EQU 0 ; 40 column lower case
; define memory usage
LDORG EQU $0100 ; where to load
ZPORG EQU $7F ; origin of zero page usage
BUFFER EQU $0200 ; I/O buffer
STCKMX EQU $E0 ; maximum size of stack in words
STCKLC EQU $03E8 ; base address of stack (works down)
STKLIM EQU STCKLC-2*STCKMX ; lower limit of stack
PRTWDT EQU $0779 ; printer carriage width
IFF VERSN
MAINOR EQU $0800 ; origin of main program
VMTORG EQU MAINOR+$1A00 ; origin of virtual memory tables
RWTSOR EQU VMTORG+$0200 ; origin of RWTS routines
FIRFLC EQU RWTSOR+$0800 ; first location available
LSTFLC EQU $C000-1 ; last potential location available
ENDIF
VMT1LC EQU VMTORG+$0000 ; virtual memory page tables
VMT2LC EQU VMTORG+$0080
VMT3LC EQU VMTORG+$0100
VMT4LC EQU VMTORG+$0180
RWTS EQU RWTSOR+$0500 ; entry point of RWTS routines
; Control characters
CRCHAR EQU $0D ; carriage return
LFCHAR EQU $0A ; line feed
TBCHAR EQU $09 ; horizontal tab
FFCHAR EQU $0C ; form feed
; Apple monitor ROM's zero page locations
WNDLFT EQU $20 ; screen window parameters
WNDWDT EQU $21
WNDTOP EQU $22
WNDBOT EQU $23
CURSRH EQU $24 ; cursor position
CURSRV EQU $25
INVFLG EQU $32 ; inverse video flag
PROMPT EQU $33 ; line input prompt
CSWL EQU $36 ; character output vector
RNDLOC EQU $4E ; location randomized by keyboard input
; Apple monitor rotuines
VTAB EQU $FC22 ; adjust video pointer after cursor move
HOME EQU $FC58 ; clear screen window
CLREOL EQU $FC9C ; clear to end of line
RDKEY EQU $FD0C ; get a key from keyboard
GETLN1 EQU $FD6F ; get a line from keyboard
COUT EQU $FDED ; output a char to current device
COUT1 EQU $FDF0 ; output a char to screen
IFT RNGDBG
ENDIF
PAGE
; define our own zero page usage
DSECT
ORG ZPORG
SECPTK DS 1 ; number of sectors per track on disk
OPCODE DS 1 ; opcode of current instruction
ARGCNT DS 1 ; instruction arguments
ARG1 DS 2
ARG2 DS 2
ARG3 DS 2
ARG4 DS 2
PRGIDX DS 1 ; PC low byte, index into page
PRGLPG DS 2 ; PC logical page number
PRGMPT DS 2 ; PC mem loc of logical page
PRGUPD DS 1 ; PC new page flag
PRGPPG DS 1 ; PC physical page number
AUXLPG DS 2 ; AUX logical page number
AUXIDX DS 1 ; AUX low byte, index into page
AUXMPT DS 2 ; AUX mem loc of logical page
AUXUPD DS 1 ; AUX new page flag
AUXPPG DS 1 ; AUX physical page number
GLBVAR DS 2 ; pointer to global variables
LOCVAR DS 30 ; storage of local variables
SWPMEM DS 2 ; address of first swappable page
FRZMEM DS 2 ; address of first frozen page
FRZPGS DS 1 ; number of frozen pages
SWPPGS DS 1 ; number of swappable phys. pages
MRUPAG DS 1 ; phys. pg. # of most recently used page
LRUPAG DS 1 ; phys. pg. # of least recently used page
VMTAB1 DS 2 ; virtual memory table pointers
VMTAB2 DS 2
VMTAB3 DS 2
VMTAB4 DS 2
STKCNT DS 1 ; # items on stack
STKPNT DS 2 ; stack pointer
STKPSV DS 2 ; stack ptr save during call
STKCSV DS 1 ; stack cnt save during call
TMPMOD DS 1 ; string output temporary char. mode
PRMMOD DS 1 ; string output perm. char. mode
PNYBCN DS 1 ; string output nybble counter
PNYBBF DS 2 ; string output nybble buffer
INWORD DS 6 ; word to be packed
LD9 DS 1
PKWORD DS 4 ; packed word
LDE DS 1
LDF DS 1
LE0 DS 1
LE1 DS 1
SBWDPT DS 2
ACB DS 2
ACC DS 2
ACD DS 2
MDFLAG DS 1 ; negative arg count for mul/div
CHRPTR DS 1 ; char out buffer pointer
CHRPT2 DS 1 ; char out buffer pointer 2
LINCNT DS 1 ; output line counter
PRCSWL DS 2 ; CSWL vector contents for printer
DS 3
STLTYP DS 1 ; status line type (time vs. score)
DEND
PAGE
; define offsets into game header
DSECT
ORG 0
HDRIRL DS 1 ; required interpreter release (should be 3)
HDRTYP DS 1 ; game type flags (score/time, etc.)
HDRREL DS 2 ; game release
HDRFRZ DS 2 ; log. addr. of end of frozen memory
HDRSTR DS 2 ; log. addr. of start of code
HDRVCB DS 2 ; log. addr. of vocab. table
HDRTHG DS 2 ; log. addr. of thing table
HDRGBV DS 2 ; log. addr. of global variables
HDRIMP DS 2 ; log. addr. of end of impure storage
HDRFLG DS 2 ; flags (script, etc.)
HDRSER DS 6 ; game serial no. (release data)
HDRSBW DS 2 ; log. addr. of subword table
HDRCKA DS 2 ; half of last log. addr. to checksum
HDRCKV DS 2 ; expected checksum value
; define thing table offsets
ORG 0
THGATT DS 4 ; attribute bits
THGPAR DS 1 ; parent thing number
THGSIB DS 1 ; sibling thing number
THGCHD DS 1 ; child thing number
THGPRP DS 2 ; property list pointer
DEND
INCLUDE ZIPMAC
PAGE
; start of interpreter
ASEG
ORG LDORG ; load at one address
.PHASE MAINOR ; but assemble for another
START: CLD ; very important
LDA #$00 ; clear our section of zero page
LDX #$80
L0805: STA $00,X
IXBNE L0805
LDX #$FF ; init hardware stack
TXS
JSR INITSC ; init and clear screen window
MOV <#$00>,<PRGUPD,AUXUPD> ; indicate no pages loaded
MOV <#$01>,STKCNT ; init software stack
DMOVI STCKLC,STKPNT
MOV <#$FF>,LD9
DMOVI VMT1LC,VMTAB1 ; init virtual memory table pointers
DMOVI VMT2LC,VMTAB2
DMOVI VMT3LC,VMTAB3
DMOVI VMT4LC,VMTAB4
LDY #$00 ; init virtual memory tables
LDX #$80
L084A: MOV <#$FF>,<<(VMTAB1),Y>,<(VMTAB2),Y>>
TYA
ADD ,<#$01>,<<(VMTAB3),Y>>
TYA
SUB ,<#$01>,<<(VMTAB4),Y>>
INY
DXBNE L084A
DEY
MOV <#$FF>,<<(VMTAB3),Y>>
MOV <#$00>,MRUPAG
MOV <#$7F>,LRUPAG
DMOVI FIRFLC,FRZMEM ; init memory pointers
DMOV FRZMEM,ACC ; read log page 0 to first frozen page
DMOVI $0000,ACB
JSR DRDBKF
LDY #HDRFRZ+1 ; setup frozen storage page count
MOV <#$FF>,<<(FRZMEM),Y>> ; bump up to page boundary - 1
DEY
MOV <(FRZMEM),Y>,FRZPGS
INC FRZPGS
LDA #$00 ; read in rest of frozen memory
L0897: ADD ,<#$01>
TAX
ADC FRZMEM+1
STA ACC+1
MOV FRZMEM,ACC
TXA
CMPBE FRZPGS,L08B6
PHA
STA ACB
MOV <#$00>,ACB+1
JSR DRDBKF
PLA
JMP L0897
L08B6: LDY #HDRTYP ; setup for proper type of statu sline
LDA (FRZMEM),Y
AND #$02
STA STLTYP
LDY #HDRSTR+1 ; init PC
MOV <(FRZMEM),Y>,PRGIDX
DEY
MOV <(FRZMEM),Y>,PRGLPG
MOV <#$00>,PRGLPG+1
LDY #HDRGBV+1 ; init global variable pointer
MOV <(FRZMEM),Y>,GLBVAR
DEY
ADD <(FRZMEM),Y>,FRZMEM+1,GLBVAR+1
LDY #HDRSBW+1 ; init sub-word table pointer
MOV <(FRZMEM),Y>,SBWDPT
DEY
ADD <(FRZMEM),Y>,FRZMEM+1,SBWDPT+1
MOV <#$00>,SWPMEM ; swpmem := frzmem + 256 * frzpgs
ADD FRZPGS,FRZMEM+1,SWPMEM+1
JSR FNDMEM ; determine nnumber of pages of memory
SUB ,SWPMEM+1 ; swppgs := (maxmem - swpmem) / 256
BCC L090A ; if swppgs < 0 then fatal error
TAY
INY
STY SWPPGS
TAY
STY LRUPAG
MOV <#$FF>,<<(VMTAB3),Y>>
JMP MNLOOP ; start the game!
L090A: JSR FATAL
PAGE
; class C instructions (implicit or no operand)
OPTAB1: DW OPRTNT ; return with TRUE
DW OPRTNF ; return with FALSE
DW OPPSI ; print string immediate
DW OPPSIC ; print string immediate, CRLF, return true
DW OPNULL ; no-op
DW OPSVGM ; save game status to disk
DW OPRSGM ; restore game status from disk
DW START ; restart game
DW OPRTNV ; return with value
DW PULLWD ; drop a word from the stack
DW OPENDS ; end the game
DW OPCRLF ; print CRLF
DW OPPRST ; print status line
DW OPCKSM ; checksum the program
OPMAX1 EQU (*-OPTAB1)/2
; class B instructions (single operand)
OPTAB2: DW OPTSTZ ; compare ARG1=0 (ARG1<>0)
DW OPGTSB ; get thing's sibling
DW OPGTCH ; get thing's child
DW OPGTPR ; get thing's parent
DW OPGTPL ; get length of property (given addr)
DW OPINC ; increment variable
DW OPDEC ; decrement variable
DW OPPSB ; print string at byte address
DW FATAL
DW OPDSTT ; destroy thing
DW OPPRTN ; print thing name
DW OPRTN ; return
DW OPJUMP ; unconditional jump
DW OPPSW ; print string at word address
DW OPMOVE ; move var ARG1 to var
DW OPNOT ; 1's complement
OPMAX2 EQU (*-OPTAB2)/2
PAGE
; class A instructions (variable number of operands, may use short form
; opcode)
OPTAB3: DW FATAL
DW OPMTCH ; match ARG1 against ARG2, ARG3, or ARG4
DW L0EB7 ; ??? compare ARG1<=ARG2 (ARG1>ARG2)
DW L0ECF ; ??? compare ARG1>=ARG2 (ARG1<ARG2)
DW OPDECB ; decrement variable and branch
DW OPINCB ; increment variable and branch
DW OPTINT ; is thing ARG1 in thing ARG2
DW L0F23
DW OPOR ; logical OR
DW OPAND ; logical AND
DW OPTSTA ; test thing attribute
DW OPSETA ; set thing attribute
DW OPCLRA ; clear thing attribute
DW L0F97 ; move ARG2 into var ARG1
DW OPMOVT ; move thing ARG1 into thing ARG2
DW OPGTWD ; get a word
DW OPGTBY ; store a word
DW OPGTP ; get thing property
DW OPGTPA ; get address of property
DW OPGTNP ; get next property
DW OPADD ; add
DW OPSUB ; subtract
DW OPMUL ; multiply
DW OPDIV ; divide
DW OPRMD ; remainder
OPMAX3 EQU (*-OPTAB3)/2
; class D instructions (variable number of operands)
OPTAB4: DW OPCALL ; call procedure
DW OPPTWD ; store a word
DW OPPTBY ; store a byte
DW OPPTP ; store into thing property
DW OPGTLN ; get a line of input
DW OPPRCH ; print a character
DW OPPRNM ; print number
DW OPRNDM ; generate random number
DW OPPUSH ; push ARG1 to stack
DW OPPULL ; pull var from stack
OPMAX4 EQU (*-OPTAB4)/2
PAGE
MNLOOP: MOV <#$00>,ARGCNT ; default no arguments
JSR FTPRBA ; get opcode
STA OPCODE
CMPJL #$80,OPCGPA ; is it class A ($00-$7F)?
CMPJL #$B0,OPCGPB ; how about class B ($80-$AF)?
CMPBL #$C0,OPCGPC ; perhaps class C ($B0-$BF)?
; JMP OPCGPD ; nope, it's class D ($C0-$FF).
; process opcode group D ($C0-$FF)
OPCGPD: JSR FTPRBA ; get operand specification byte
LDX #$00 ; init operand count
L09AF: PHA ; save the operand specification byte
TAY ; in Y and on stack
TXA ; save operand count on stack
PHA
TYA ; get back operand specification byte
AND #$C0 ; look at top two bits
JSREQ FTPRWD,L09D7 ; if they're 00, operand is word immed.
CMPJSE #$80,<GTVARP,L09D7> ; 10? variable
CMPJSE #$40,<FTPRBY,L09D7> ; 01? byte immediate
PLA ; must be 11, no more operands
PLA ; pull operand spec byte and count
JMP L09ED ; and finish up
L09D7: PLA ; get operand count back
TAX ; to use as index
MOV ACC,<<ARG1,X>> ; store operand in proper ARG locatoin
MOV ACC+1,<<ARG1+1,X>>
INX ; increment ARG pointer
INX
INC ARGCNT ; and count
PLA ; pull arg spec byte
SEC ; shift top two bits off left, while
ROL A ; shifting 11 in from right (to
SEC ; indicate no more operands)
ROL A
JMP L09AF ; try for another
L09ED: DMOVI OPTAB4,ACC ; assume class D
LDA OPCODE ; but if it's $C0-$DF then it's class A
CMPJL #$E0,L0A98
SBC #$E0 ; adjust to $00..$1F
CMPBG #OPMAX4,L0A2B ; make sure it's not illegal
GODOIT: ASL A ; get address from table (base in ACC)
TAY ; word indexed by A and execute
MOV <(ACC),Y>,DSPTCH+1
INY
MOV <(ACC),Y>,DSPTCH+2
DSPTCH: JSR DSPTCH
JMP MNLOOP
; process opcode group C ($80-$BF)
OPCGPC: SUB ,<#$B0> ; adjust to $00..$0F
CMPBG #OPMAX1,L0A2B ; make sure it's not illegal
PHA ; save it temp.
DMOVI OPTAB1,ACC ; get base address of proper table
PLA
JMP GODOIT
L0A2B: JSR FATAL ; oops! illegal opcode
; process opcode group B ($80-$AF)
OPCGPB: AND #$30 ; mask off operand type bits
JSREQ FTPRWD,L0A45 ; 00? then it's word immediate
CMPJSE #$10,<FTPRBY,L0A45> ; 01? byte immediate
JSR GTVARP ; must be 10, variable
L0A45: MOV <#$01>,ARGCNT ; one argument
DMOV ACC,ARG1
LDA OPCODE ; adjust opcode to $00..$0F
AND #$0F
CMPBG #OPMAX2,L0A2B ; make sure it's not illegal
PHA ; save tmep.
DMOVI OPTAB2,ACC ; get appropriate table base addr
PLA
JMP GODOIT ; and go do it!
; process opcode group A ($00-$7F)
OPCGPA: AND #$40 ; get type bit for ARG1
JSREQ FTPRBY,L0A73 ; 0: byte immediate
JSR GTVARP ; 1: variable/stack
L0A73: DMOV ACC,ARG1 ; save it
LDA OPCODE ; get type bit for ARG2
AND #$20
JSREQ FTPRBY,L0A8A ; 0: byte immediate
JSR GTVARP ; 1: variable/stack
L0A8A: DMOV ACC,ARG2 ; save it
MOV <#$02>,ARGCNT ; indicate two operands
LDA OPCODE ; get opcode back
L0A98: AND #$1F ; adjust to $00..$1F
CMPBG #OPMAX3,L0A2B ; make sure it's not illegal
PHA ; save temp.
DMOVI OPTAB3,ACC ; get base addr of appropriate table
PLA
JMP GODOIT ; and go do it!
PAGE
; fetch byte immediate into ACC
FTPRBY: JSR FTPRBA ; get a byte form program into A
STA ACC ; sero-fill to 16 bits in ACC
MOV <#$00>,ACC+1
RTS ; return
; fetch word immediate into ACC
FTPRWD: JSR FTPRBA ; get high byte from program into A
PHA ; save it temp.
JSR FTPRBA ; get low byte from program into A
STA ACC ; store low byte
PUL ACC+1 ; store high byte
RTS ; return
GTVRA1: TSTABE L0AD0 ; fetch ACC from var in A, keep if stack
JMP GTVARA
PTVRA1: TSTABE L0AD6 ; store ACC into var in A, replace if stack
JMP PTVARA
L0AD0: JSR PULLWD ; read stack non-destructive
JMP PUSHWD
L0AD6: DPSH ACC ; replace TOS w/ ACC
JSR PULLWD
DPUL ACC
JMP PUSHWD
PAGE
GTVARP: JSR FTPRBA ; fetch ACC from var ind. by program
TSTABE L0B26
GTVARA: CMPBG <#$10>,L0B02 ; fetch ACC from var in A
SUB ,<#$01>
ASL A
TAX
MOV <LOCVAR,X>,ACC+1
INX
MOV <LOCVAR,X>,ACC
RTS
L0B02: SUB ,<#$10>
ASL A
STA ACB
LDA #$00
ROL A
STA ACB+1
DADD GLBVAR,ACB,ACB
LDY #$00
MOV <(ACB),Y>,ACC+1
INY
MOV <(ACB),Y>,ACC
RTS
L0B26: JSR PULLWD
RTS
PAGE
PTVRPZ: LDA #$00 ; store 0 in var. ind. by program
PTVRPA: STA ACC ; store byte in A in var. ind. by prog.
MOV <#$00>,ACC+1
PTVRP1: JMP PTVARP ; unnecessary!!!
PTVARP: DPSH ACC ; store ACC in var. ind. by program
JSR FTPRBA
TAX
DPUL ACC
TXA
PTVARA: TSTAJE PUSHWD ; store ACC in var. in A
CMPBG <#$10>,L0B60
DECA
ASL A
TAX
MOV ACC+1,<<LOCVAR,X>>
INX
MOV ACC,<<LOCVAR,X>>
RTS
L0B60: SUB ,<#$10>
ASL A
STA ACB
LDA #$00
ROL
STA ACB+1
DADD GLBVAR,ACB,ACB
LDY #$00
MOV ACC+1,<<(ACB),Y>>
INY
MOV ACC,<<(ACB),Y>>
RTS
PAGE
PREDTR: JSR FTPRBA ; fetch first displacement byte
TSTABM L0B9C ; complement condition if necessary
BPL L0B94
PREDFL: JSR FTPRBA ; fetch first displacement byte
TSTABP L0B9C ; complement condition if necessary
; BMI L0B94
L0B94: AND #$40 ; branch not taken
JSREQ FTPRBA ; fetch second displacement byte if
RTS ; necessary and discard it
L0B9C: TAX ; branch take, save first disp. byte
AND #$40 ; do we need a second byte?
BEQ L0BAD ; yes
TXA ; no, extend what we have w/ zeros
AND #$3F
STA ACC
MOV <#$00>,ACC+1
JMP L0BC3 ; and go do it!
L0BAD: TXA ; get rest of displacement
AND #$3F
PHA
JSR FTPRBA
STA ACC
PUL ACC+1
AND #$20
BEQ L0BC3
LDA ACC+1
ORA #$C0
STA ACC+1
L0BC3: DTSTBE ACC,OPRTNF ; if displacement = 0, return false
DDEC ACC
DTSTBE ACC,OPRTNT ; if displacement = 1, return true
L0BDA: DDEC ACC
MOV ACC+1,ACB ; copy high byte of displacement to ACB
ASL A ; and sign extend to 17 bits
LDA #$00
ROL A
STA ACB+1
ADD PRGIDX,ACC ; add low byte of displacement to PC
BCC L0BFC ; increment high 8 bits of displacement
DINC ACB ; if overflow
L0BFC: STA PRGIDX
DTSTBE ACB,L0C17 ; if high 9 bits of disp. =0, all done
CLC ; add hgih 9 bits of disp. to PC log page
LDA ACB
ADC PRGLPG
STA PRGLPG
LDA ACB+1
ADC PRGLPG+1
AND #$01 ; mod 2^17
STA PRGLPG+1
MOV <#$00>,PRGUPD ; indicate page chagne
L0C17: RTS ; all done
PAGE
OPRTNT: LDA #$01 ; return true ($01)
L0C1A: STA ARG1 ; return byte in A
MOV <#$00>,ARG1+1 ; make high byte of return value $00
JMP OPRTN ; and do the return
OPRTNF: LDA #$00 ; return false ($00)
JMP L0C1A
OPPSI: MOV PRGIDX,AUXIDX ; copy PC to AUX
DMOV PRGLPG,AUXLPG
MOV <#$00>,AUXUPD ; indicate new log. page
JSR PRNTST ; print the string
MOV AUXIDX,PRGIDX ; copy AUX back to PC
DMOV AUXLPG,PRGLPG
MOV AUXUPD,PRGUPD
DMOV AUXMPT,PRGMPT
OPNULL: RTS ; done
OPPSIC: JSR OPPSI ; print string immediate
LDA #CRCHAR ; print CRLF (could use JSR OPCRLF)
JSR BFCHAR
LDA #LFCHAR
JSR BFCHAR
JMP OPRTNT ; return true
OPRTNV: JSR PULLWD ; pull value off stack
DMOV ACC,ARG1 ; save it for posterity
JMP OPRTN ; return with it
OPCRLF: LDA #CRCHAR ; print CRLF
JSR BFCHAR
LDA #LFCHAR
JMP BFCHAR ; implicit RTS
PAGE
OPCKSM: LDY #HDRCKA+1 ; get checksum end log. address (word
MOV <(FRZMEM),Y>,ARG2 ; index)
DEY
MOV <(FRZMEM),Y>,ARG2+1
MOV <#$00>,<ARG3,ARG1,ARG1+1,ACC+1,ARG4> ; initialize everything
MOV <#ARG4>,L1807+1 ; patch VM routine to swap in all pages
ASL ARG2 ; convert end address to byte index
ROL ARG2+1
ROL ARG3
MOV <#$40>,ACC ; start at log. address $00040
JSR SETAXB
L0CA5: JSR FTAXBA ; get a byte
DADDB2 ARG1 ; and add it to checksum
LDA AUXIDX ; compare AUX to end address
CMPBN ARG2,L0CA5 ; if not done, loop
LDA AUXLPG
CMPBN ARG2+1,L0CA5
LDA AUXLPG+1
CMPBN ARG3,L0CA5
MOV <#FRZPGS>,L1807+1 ; unpatch VM routine
LDY #HDRCKV+1 ; compare computed vs. expected checksum
LDA (FRZMEM),Y
CMPBN ARG1,L0CDA
DEY
LDA (FRZMEM),Y
CMPJE ARG1+1,PREDTR
L0CDA: JMP PREDFL
PAGE
OPTSTZ: DTSTJN ARG1,PREDFL
L0CE6: JMP PREDTR
OPGTSB: LDA ARG1 ; get sibling of thing, predicate
JSR SETUPT
LDY #THGSIB
JMP L0CFA
OPGTCH: LDA ARG1 ; get child of thing, predicate
JSR SETUPT
LDY #THGCHD
L0CFA: PSH <<(ACC),Y>>
STA ACC
MOV <#$00>,ACC+1
JSR PTVARP
PLA
TSTABN L0CE6
JMP PREDFL
OPGTPR: LDA ARG1 ; get parent of thing
JSR SETUPT
LDY #THGPAR
MOV <(ACC),Y>,ACC
MOV <#$00>,ACC+1
JMP PTVRP1
OPGTPL: DADD ARG1,FRZMEM,ACC
DDEC ACC
LDY #$00
JSR GTPLEN
ADD ,<#$01>
JMP PTVRPA
; increment variable ARG1
OPINC: LDA ARG1
JSR GTVRA1
DINC ACC
L0D4E: DPSH ACC
LDA ARG1
JSR PTVRA1
DPUL ACC
RTS
; decrement variable ARG1
OPDEC: LDA ARG1
JSR GTVRA1
DDEC ACC
JMP L0D4E
; print string at byte address in ARG1
OPPSB: DMOV ARG1,ACC ; set AUX to point to string at
JSR SETAXB ; byte address
JMP L0E9D ; and print it!
PAGE
; destroy thing ARG1 (move to location 0)
OPDSTT: LDA ARG1
JSR SETUPT
LDY #THGPAR
LDA (ACC),Y
RTSEQ
TAX
DPSH ACC
TXA
JSR SETUPT
LDY #THGCHD
LDA (ACC),Y
CMPBN ARG1,L0DB7
DPUL ACB
DPSH ACB
LDY #THGSIB
LDA (ACB),Y
LDY #THGCHD
STA (ACC),Y
JMP L0DD2
L0DB7: JSR SETUPT
LDY #THGSIB
LDA (ACC),Y
CMPBN ARG1,L0DB7
DPUL ACB
DPSH ACB
MOV <(ACB),Y>,<<(ACC),Y>>
L0DD2: DPUL ACC
LDY #THGPAR
MOV <#$00>,<<(ACC),Y>>
INY ; to THGSIB
STA (ACC),Y
RTS
PAGE
OPPRTN: LDA ARG1 ; print thing name
L0DE4: JSR SETUPT ; set up pointer to thing
LDY #THGPRP ; get address of thing's property list
MOV <(ACC),Y>,ACB+1
INY
MOV <(ACC),Y>,ACB
DMOV ACB,ACC
DINC ACC ; skip name length byte
JSR SETAXB ; set AUX to point to it
JMP PRNTST ; and print it and return
PAGE
OPRTN: DMOV STKPSV,STKPNT ; restore pre-call stack pointer, count
MOV STKCSV,STKCNT
JSR PULLWD ; are there any local variables to restore?
LDA ACC
BEQ L0E4C ; no, skip it
DMOVI LOCVAR-2,ACB ; yes, calc. addr. of last var to restore
MOV ACC,ACD
ASL A
DADDB2 ACB
L0e2F: JSR PULLWD ; pull the value of the var
LDY #$01 ; store it in the var
MOV ACC,<<(ACB),Y>>
DEY
MOV ACC+1,<<(ACB),Y>>
DDEC2 ACB ; decrement the var pointer
DECBN ACD,L0E2F ; and the count and loop if more to do
L0E4C: JSR PULLWD ; pull the PC log. page
DMOV ACC,PRGLPG
JSR PULLWD ; pull the stack pointer save
DMOV ACC,STKPSV
JSR PULLWD ; pull the stack count save and PC
MOV ACC+1,PRGIDX ; low byte
MOV ACC,STKCSV
MOV <#$00>,PRGUPD ; indicate need to locate new page
DMOV ARG1,ACC ; store the return value and return
JMP PTVRP1
PAGE
; jump to address ARG1
OPJUMP: DMOV ARG1,ACC ; setup to jump into middle of
DDEC ACC ; predicate routine
JMP L0BDA ; and do it!
OPPSW: DMOV ARG1,ACC ; set AUX to point to string at
JSR SETAXW ; word address
L0E9D: JMP PRNTST ; and print it!
OPMOVE: LDA ARG1 ; get number of first variable
JSR GTVRA1 ; get its contents
JMP PTVRP1 ; store into another variable
OPNOT: D1COMP ARG1,ACC
JMP PTVRP1
L0EB7: DMOV ARG1,ACC
DMOV ARG2,ACB
JSR L16DE
BCC L0F10
JMP PREDFL
L0ECF: DMOV ARG1,ACB
DMOV ARG2,ACC
JSR L16DE
BCC L0F10
JMP PREDFL
OPDECB: JSR OPDEC
DMOV ARG2,ACB
JMP L0F08
OPINCB: JSR OPINC
DMOV ACC,ACB
DMOV ARG2,ACC
L0F08: JSR L16DE
JCS PREDFL
L0F10: JMP PREDTR
OPTINT: LDA ARG1
JSR SETUPT
LDY #$04
LDA ARG2
CMPBE <(ACC),Y>,L0F10
JMP PREDFL
L0F23: MOV ARG2+1,ACC+1
AND ARG1+1
STA ACB+1
MOV ARG2,ACC
AND ARG1
STA ACB
JSR L16E9
BEQ L0F10
JMP PREDFL
OPOR: DOR ARG2,ARG1,ACC
JMP PTVRP1
OPAND: DAND ARG2,ARG1,ACC
JMP PTVRP1
PAGE
; test attribute bit ARG2 of thing ARG1
OPTSTA: JSR SETUPA
LDA ACB+1
AND ACD+1
STA ACB+1
LDA ACB
AND ACD
ORA ACB+1
BNE L0F10
JMP PREDFL
; set attribute bit ARG2 of thing ARG1
OPSETA: JSR SETUPA
LDY #$01
LDA ACB
ORA ACD
STA (ACC),Y
DEY
LDA ACB+1
ORA ACD+1
STA (ACC),Y
RTS
; clear attribute bit ARG2 of thing ARG1
OPCLRA: JSR SETUPA
LDY #$01
LDA ACD
EOR #$FF
AND ACB
STA (ACC),Y
DEY
LDA ACD+1
EOR #$FF
AND ACB+1
STA (ACC),Y
RTS
PAGE
L0F97: DMOV ARG2,ACC
LDA ARG1
L0FA1: JMP PTVRA1
OPMOVT: JSR OPDSTT
LDA ARG1
JSR SETUPT
DPSH ACC
LDY #THGPAR
MOV ARG2,<<(ACC),Y>>
JSR SETUPT
LDY #THGCHD
LDA (ACC),Y
TAX
MOV ARG1,<<(ACC),Y>>
DPUL ACC
TXA
BEQ L0FD1
LDY #THGSIB
STA (ACC),Y
L0FD1: RTS
OPGTWD: DASL ARG2
DADD ARG2,ARG1,ACC
JSR SETAXB
JSR FTAXWD
JMP PTVRP1
OPGTBY: DADD ARG2,ARG1,ACC
JSR SETAXB
JSR FTAXBA
STA ACC
MOV <#$00>,ACC+1
JMP PTVRP1
PAGE
; get property ARG2 of thing ARG1
OPGTP: JSR SETUPP
L100B: JSR GTPNUM
CMPBE ARG2,L103B
JSRCS ADVPPT,L100B
LDY #HDRTHG+1
CLC
LDA (FRZMEM),Y
ADC FRZMEM
STA ACB
DEY
LDA (FRZMEM),Y
ADC FRZMEM+1
STA ACB+1
LDA ARG2
ASL A
TAY
DEY
MOV <(ACB),Y>,ACC
DEY
MOV <(ACB),Y>,ACC+1
JMP PTVRP1
L103B: JSR GTPLEN
INY
CMPBE <#$00>,L105E
CMPJSN <#$01>,FATAL
MOV <(ACC),Y>,ACB+1
INY
MOV <(ACC),Y>,ACB
DMOV ACB,ACC
JMP PTVRP1
L105E: MOV <(ACC),Y>,ACC
MOV <#$00>,ACC+1
JMP PTVRP1
PAGE
; get address of property ARG2 of thing ARG1
OPGTPA: JSR SETUPP
L106C: JSR GTPNUM
CMPBE ARG2,L107E
JCC PTVRPZ
JSR ADVPPT
JMP L106C
L107E: DINC ACC
CLC
TYA
ADC ACC
STA ACC
BCC L10BE
INC ACC+1
L10BE: DSUB ACC,FRZMEM,ACC
JMP PTVRP1
PAGE
; get number of next property of thing ARG1 after property ARG2
OPGTNP: JSR SETUPP
LDA ARG2
BEQ L10B7
L10A5: JSR GTPNUM
CMPBE ARG2,L10BD
JCC PTVRPZ
JSR ADVPPT
JMP L10A5
L10B7: JSR GTPNUM
JMP PTVRPA
L10BD: JSR ADVPPT
JMP L10B7
PAGE
; add ARG1 and ARG2
OPADD: DADD ARG1,ARG2,ACC
JMP PTVRP1
; subtract ARG2 from ARG1
OPSUB: DSUB ARG1,ARG2,ACC
JMP PTVRP1
; multiply ARG1 by ARG2
OPMUL: DMOV ARG1,ACC
DMOV ARG2,ACB
JSR L15FB
LDA ACB+1
BNE L1104
LDA ACB
CMPBE <#$02>,L1111
CMPBE <#$04>,L110D
L1104: JSR L1568
L1107: JSR L160A
JMP PTVRP1
L110D: DASL ACC
L1111: DASL ACC
JMP L1107
PAGE
; divide ARG1 by ARG2
OPDIV: DMOV ARG1,ACC
DMOV ARG2,ACB
JSR L15FB
LDA ACB+1
BNE L1139
LDA ACB
CMPBE <#$02>,L1143
CMPBE <#$04>,L113F
L1139: JSR DIVIDE
JMP L1107
L113F: DLSR ACC
L1143: DLSR ACC
JMP L1107
; get remainder of ARG1 divided by ARG2
OPRMD: DMOV ARG1,ACC
DMOV ARG2,ACB
JSR L15FB
JSR DIVIDE
DMOV ACB,ACC
JMP PTVRP1
PAGE
; test whether ARG1 is equal to any of the other args
OPMTCH: LDX ARGCNT
DXBNE L1173
JSR FATAL
L1173: LDA ARG1
CMPBN ARG2,L117F
LDA ARG1+1
CMPBE ARG2+1,L11A0
L117F: DXBEQ L119D
LDA ARG1
CMPBN ARG3,L118E
LDA ARG1+1
CMPBE ARG3+1,L11A0
L118E: DXBEQ L119D
LDA ARG1
CMPBN ARG4,L1173
LDA ARG1+1
CMPBE ARG4+1,L11A0
L119D: JMP PREDFL
L11A0: JMP PREDTR
PAGE
; call procedure at addr. ARG1 and optionally pass ARG2, ARG3, and ARG4
; as arguments
OPCALL: DTS2BN ARG1,L11B4 ; if argument 1 (call address/2) is
DMOVI $0000,ACC ; zero, just put zero in var
JMP PTVRP1 ; these three lines could be replaced
; with "DTS2BE PTVRPZ"
L11B4: MOV STKCSV,ACC ; push the stack count save and low byte
MOV PRGIDX,ACC+1 ; of the PC
JSR PUSHWD
DMOV STKPSV,ACC ; push the stack pointer save
JSR PUSHWD
DMOV PRGLPG,ACC ; push the PC logical page
JSR PUSHWD
MOV <#$00>,PRGUPD ; indicate need to search for new page
DASL ARG1,PRGIDX ; make new PC := ARG1 * 2
LDA #$00
ROL A
STA PRGLPG+1
JSR FTPRBA ; get first byte of routine
PHA ; and save it
TSTABE L1220 ; if it's zero, no local variables
; push the local variables the routine will use
LDX #$00
L11F2: PHA
MOV <LOCVAR,X>,ACC+1
INX
MOV <LOCVAR,X>,ACC
DEX
TXA
PHA
JSR PUSHWD
JSR FTPRBA
PHA
JSR FTPRBA
STA ACC
PUL ACC+1
PLA
TAX
MOV ACC+1,<<LOCVAR,X>>
INX
MOV ACC,<<LOCVAR,X>>
INX
PLA
SUB ,<#$01>
BNE L11F2
L1220: MOV ARGCNT,ACD ; do we pass any parameters?
DECBE ACD,L124C ; no
MOV <#$00>,ACB ; yes, copy them in
MOV <#$00>,ACC
L1230: LDX ACB
LDA ARG2+1,X
LDX ACC
STA LOCVAR,X
INC ACC
LDX ACB
LDA ARG2,X
LDX ACC
STA LOCVAR,X
INC ACC
INC ACB
INC ACB
DECBN ACD,L1230 ; loop if more parameters to pass
L124C: PUL ACC ; get first porgram byte again
JSR PUSHWD ; and push it so return can restore
; the local variables
MOV STKCNT,STKCSV ; save the stack pointer and count
DMOV STKPNT,STKPSV
RTS ; all done!
PAGE
; store word ARG3 at log. addr. ARG2 (offset) * 2 + ARG1 (base)
; should have test to insure no overrun of end of frozen storage!
OPPTWD: LDA ARG2 ; calculate logical address
ASL A
ROL ARG2+1
CLC
ADC ARG1
STA ACC
LDA ARG2+1
ADC ARG1+1
STA ACC+1
DADD ACC,FRZMEM,ACC ; add base of frozen mem. to get phys. addr.
LDY #$00 ; store the word
MOV ARG3+1,<<(ACC),Y>>
INY
MOV ARG3,<<(ACC),Y>>
RTS ; and return
; store byte ARG3 at log. addr. ARG2 (offset) + ARG1 (base)
; should have test to insure no overrun of end of frozen storage!
OPPTBY: LDA ARG2 ; calculate logical address
CLC
ADC ARG1
STA ACC
LDA ARG2+1
ADC ARG1+1
STA ACC+1
DADD ACC,FRZMEM,ACC ; add base of frozen mem. to get phys addr.
LDY #$00 ; store the byte
MOV ARG3,<<(ACC),Y>>
RTS ; and return
PAGE
; store ARG3 as property of ARG2 of thing ARG1
OPPTP: JSR SETUPP ; setup for thing property operations
L12AC: JSR GTPNUM ; get the property number
CMPBE ARG2,L12BE ; if it is the one, go do it!
JSRCC FATAL ; oops! past it!
JSR ADVPPT ; advance pointer
JMP L12AC ; and try again
; got the property we wand
L12BE: JSR GTPLEN ; get property length
INY
CMPBE #$00,L12D7 ; if it is byte sized, go store it
CMPJSN #$01,FATAL ; if it isn't word sized, fatal error
MOV ARG3+1,<<(ACC),Y>> ; yes, store high byte
INY
MOV ARG3,<<(ACC),Y>> ; these two lines are unnecessary
RTS
L12D7: MOV ARG3,<<(ACC),Y>> ; store low byte
RTS ; and return
PAGE
OPGTLN: JSR OPPRST
DADD ARG1,FRZMEM,ARG1
DADD ARG2,FRZMEM,ARG2
JSR GETLIN
STA ACD+1
MOV <#$00>,ACD
LDY #$01
MOV <#$00>,<<(ARG2),Y>>
MOV <#$02>,LE0
MOV <#$01>,LE1
L1310: LDY #$00
LDA (ARG2),Y
INY
CMPRE <(ARG2),Y>
DTSTRE ACD
LDA ACD
CMPJSE <#$06>,L13BA
LDA ACD
BNE L135C
LDY #$06
LDX #$00
L1332: MOV <#$00>,<<$D3,X>>
INX
DYBNE L1332
LDA LE1
LDY LE0
INY
INY
INY
STA (ARG2),Y
LDY LE1
LDA (ARG1),Y
JSR L13F1
BCS L137A
LDY LE1
LDA (ARG1),Y
JSR L13E0
BCC L135C
INC LE1
DEC ACD+1
JMP L1310
L135C: LDA ACD+1
BEQ L1382
LDY LE1
LDA (ARG1),Y
JSR L13DA
BCS L1382
LDY LE1
LDA (ARG1),Y
LDX ACD
STA INWORD,X
DEC ACD+1
INC ACD
INC LE1
JMP L1310
L137A: STA INWORD
INC ACD
DEC ACD+1
INC LE1
L1382: LDA ACD
BEQ L1310
PSH ACD+1
LDY LE0
INY
INY
MOV ACD,<<(ARG2),Y>>
JSR CRNWRD
JSR L141F
LDY LE0
MOV ACB+1,<<(ARG2),Y>>
INY
MOV ACB,<<(ARG2),Y>>
INY
INY
INY
STY LE0
LDY #$01
ADD <(ARG2),Y>,<#$01>,<<(ARG2),Y>>
PUL ACD+1
MOV <#$00>,ACD
JMP L1310
L13BA: LDA ACD+1
RTSEQ
LDY LE1
LDA (ARG1),Y
JSR L13DA
RTSCS
INC LE1
DEC ACD+1
INC ACD
JMP L13BA
SEPTAB: DB ' .,?',CRCHAR,LFCHAR,TBCHAR,FFCHAR
L13DA: JSR L13F1
RTSCS
L13E0: LDY #$00
LDX #$08
L13E4: CMPBE <SEPTAB,Y>,L13EF
INY
DXBNE L13E4
L13ED: CLC
RTS
L13EF: SEC
L13F0: RTS
L13F1: PHA
JSR GTVCBA
LDY #$00
LDA (ACC),Y
TAX
PLA
L13FB: BEQ L13ED
INY
CMPBE <(ACC),Y>,L13EF
DEX
JMP L13FB
GTVCBA: LDY #HDRVCB
MOV <(FRZMEM),Y>,ACC+1
INY
MOV <(FRZMEM),Y>,ACC
DADD ACC,FRZMEM,ACC
RTS
L141F: JSR GTVCBA
LDY #$00
LDA (ACC),Y
TAY
INY
LDA (ACC),Y
ASL A
ASL A
ASL A
ASL A
STA ACD
INY
MOV <(ACC),Y>,ACB+1
INY
MOV <(ACC),Y>,ACB
INY
TYA
ADD ,ACC,ACC
BCC L1445
INC ACC+1
L1445: LDY #$00
JMP L1450
L144A: LDA (ACC),Y
CMPBG PKWORD+1,L1470
L1450: DADDB1 ACC,ACD,ACC
DSUBB1 ACB,<#$10>,ACB
LDA ACB+1
BMI L1470
BNE L144A
LDA ACB
BNE L144A
L1470: DSUBB1 ACC,ACD,ACC
DADDB1 ACB,<#$10>,ACB
LDA ACD
LSR A
LSR A
LSR A
LSR A
STA ACD
L148E: LDY #$00
LDA PKWORD+1
CMPBL <(ACC),Y>,L14D0
BNE L14B4
INY
LDA PKWORD
CMPBL <(ACC),Y>,L14D0
BNE L14B4
LDY #$02
LDA PKWORD+3
CMPBL <(ACC),Y>,L14D0
BNE L14B4
INY
LDA PKWORD+2
CMPBL <(ACC),Y>,L14D0
BEQ L14D7
L14B4: DADDB1 ACC,ACD,ACC
DDEC ACB
DTS2BN ACB,L148E
L14D0: MOV <#$00>,<ACB+1,ACB>
RTS
L14D7: DSUB ACC,FRZMEM,ACB
RTS
PAGE
; print ASCII character ARG1
OPPRCH: LDA ARG1
JMP BFCHAR
; print decimal number ARG1
OPPRNM: DMOV ARG1,ACC
JMP PRNTNM ; unnecessary
; print decimal number in ACC
PRNTNM: LDA ACC+1 ; negative?
JSRMI L152E ; yes, print '-' and negate
MOV <#$00>,ACD ; initialize digit count to 0
L150D: DTSTBE ACC,L1519 ; if the remainder is zero, print it now
DMOVI $000A,ACB ; set up divisor of 10
JSR DIVIDE ; divide
PSH ACB ; push remainder onto stack
INC ACD ; incrmeent digit count
JMP L150D ; do it again
L1519: LDA ACD ; is digit count zero?
BEQ L1529 ; yes, just print a '0' and return
L151D: PLA ; pull a digit off stack
ADD ,<#'0'> ; convert to ASCII
JSR BFCHAR ; print it
DECBN ACD,L151D ; decrement digit count, loop if more
RTS ; return to caller
L1529: LDA #'0' ; get code for '0'
JMP BFCHAR ; print it and return to caller
L152E: LDA #'-' ; get code for '-'
JSR BFCHAR ; print it
JMP L1611 ; negate the number, return
PAGE
; get a random number from 1 to ARG1
IFF RNGDBG
OPRNDM: DMOV ARG1,ACB ; save range
JSR L21A0 ; get the "random" number
JSR DIVIDE ; divide by range
DMOV ACB,ACC ; get the remainder
DINC ACC ; increment it (base of result is 1)
JMP PTVRP1 ; and store it
ENDIF
; push ARG1 on stack
OPPUSH: DMOV ARG1,ACC
JMP PUSHWD
; pull stack into variable ARG1
OPPULL: JSR PULLWD
LDA ARG1
JMP L0FA1
L1568: DPSH ACD
DMOVI $0000,ACD
LDX #$10
L1578: LDA ACB
CLC
AND #$01
BEQ L158B
DADC ACC,ACD,ACD
L158B: DROR ACD
DROR ACB
DXBNE L1578
DMOV ACB,ACC
DMOV ACD,ACB
DPUL ACD
RTS
PAGE
; divide ACC by ACB, quotient to ACC, remainder to ACB
DIVIDE: DPSH ACD
DMOV ACC,ACD
DMOVI $0000,ACC
LDX #$11
L15C5: SEC
LDA ACC
SBC ACB
TAY
LDA ACC+1
SBC ACB+1
BCC L15D6
STA ACC+1
TYA
STA ACC
L15D6: DROL ACD
DROL ACC
DXBNE L15C5
CLC
DROR ACC,ACB
DMOV ACD,ACC
DPUL ACD
RTS
L15FB: MOV <#$00>,MDFLAG
LDA ACC+1
JSR L161F
LDA ACB+1
JSR L161F
RTS
L160A: LDA MDFLAG
AND #$01
RTSEQ
L1611: SEC
LDA #$00
SBC ACC
STA ACC
LDA #$00
SBC ACC+1
STA ACC+1
RTS
L161F: TSTARP ; if positive, return
INC MDFLAG
JMP L1611
PAGE
; setup stuff for thing attribute bit operations
SETUPA: LDA ARG1
JSR SETUPT
LDA ARG2
CMPBL <#$10>,L1643
SUB ,<#$10>
DINC ACC
DINC ACC
L1643: STA ACB
DMOVI $0001,ACD
SUB <#$0F>,ACB
TAX
L1653: BEQ L165D
DASL ACD
DEX
JMP L1653
L165D: LDY #$00
MOV <(ACC),Y>,ACB+1
INY
MOV <(ACC),Y>,ACB
RTS
; setup stuff for thing property operations
SETUPP: LDA ARG1
JSR SETUPT
LDY #THGPRP
MOV <(ACC),Y>,ACB+1
INY
MOV <(ACC),Y>,ACB
DADD ACB,FRZMEM,ACC
LDY #$00
LDA (ACC),Y
ASL A
TAY
INY
RTS
; get number of property pointed to by ACC
GTPNUM: LDA (ACC),Y
AND #$1F
RTS
; get lenght of property pointed to by ACC
GTPLEN: LDA (ACC),Y
REPT 5
ROR A
ENDM
AND #$07
RTS
; advance ACC to point to next property
ADVPPT: JSR GTPLEN
TAX
L16A1: INY
DXBPL L16A1
INY
RTS
; setup stuff for thing operations
SETUPT: STA ACC
MOV <#$00>,ACC+1
LDA ACC
REPT 3
DASL ACC
ENDM
ADD ,ACC
BCC L16C3
INC ACC+1
CLC
L16C3: ADC #$35
STA ACC
BCC L16CB
INC ACC+1
L16CB: LDY #HDRTHG+1
ADD <(FRZMEM),Y>,ACC,ACC
DEY
LDA (FRZMEM),Y
ADC ACC+1
ADC FRZMEM+1
STA ACC+1
RTS
PAGE
L16DE: LDA ACB+1
EOR ACC+1
BPL L16E9
LDA ACB+1
CMP ACC+1
RTS
L16E9: LDA ACC+1
CMPBN ACB+1,L16F3
LDA ACC
CMP ACB
L16F3: RTS
PUSHWD: DDEC STKPNT
LDY #$00
MOV ACC,<<(STKPNT),Y>>
DDEC STKPNT
MOV ACC+1,<<(STKPNT),Y>>
INC STKCNT
LDA STKCNT
CMPJSG <#STCKMX>,FATAL
RTS
PULLWD: LDY #$00
MOV <(STKPNT),Y>,ACC+1
DINC STKPNT
MOV <(STKPNT),Y>,ACC
DINC STKPNT
DEC STKCNT
JSREQ FATAL
RTS
PAGE
; fetch next byte from PC into A
FTPRBA: LDA PRGUPD ; need to find a new page?
BEQ L1757 ; yes, go do it!
LDY PRGIDX ; get the byte
LDA (PRGMPT),Y
INY ; increment the low byte of the PC
STY PRGIDX
RTSNE ; return unless we've entered a new page
LDY #$00 ; unnecessary!
STY PRGUPD ; indicate new page
DINC PRGLPG ; increment page number
RTS ; return
L1757: LDA PRGLPG+1 ; is the page we're looking for frozen?
BNE L1761
LDA PRGLPG
CMPBL FRZPGS,L1778
L1761: DMOV PRGLPG,ACC ; no, see if it is swapped in
JSR FNDPAG
STA PRGPPG ; save phys. page no.
BCS L1788 ; not found
; we have the swappable page, fix up the pointers, etc.
L1770: JSR MRKPAG ; indicate that we're using this page
CLC ; add phys. page number to number
LDA PRGPPG ; of frozen pages
ADC FRZPGS
; fix the memory pointers
L1778: ADD ,FRZMEM+1,PRGMPT+1 ; add base of frozen memory
MOV <#$00>,PRGMPT
MOV <#$FF>,PRGUPD ; indicate that we have the page
JMP FTPRBA ; and go get the byte
; we need to load the page from disk
L1788: CMPBN AUXPPG,L1790 ; if we are about to load a new logical
MOV <#$00>,AUXUPD ; page into the physical page AUX points
; to, mark it as new page
L1790: DMOV SWPMEM,ACC ; setup to read the page
ADD PRGPPG,ACC+1,ACC+1
DMOV PRGLPG,ACB
JSR DRDBKF ; read the page (die if error)
LDY PRGPPG ; copy the new log. page number into
MOV PRGLPG,<<(VMTAB1),Y>> ; the VM table
MOV PRGLPG+1,<<(VMTAB2),Y>>
TYA
JMP L1770 ; go fix up the pointers and fetch the byte
PAGE
; set AUX to byte address in ACC
SETAXB: MOV ACC,AUXIDX
MOV ACC+1,AUXLPG
MOV <#$00>,AUXLPG+1
L17C4: MOV <#$00>,AUXUPD
RTS
; set AUX to word address in ACC
SETAXW: LDA ACC
ASL A
STA AUXIDX
LDA ACC+1
ROL A
STA AUXLPG
LDA #$00
ROL A
STA AUXLPG+1
JMP L17C4
; fetch next word from AUX into ACC
FTAXWD: JSR FTAXBA
PHA
JSR FTAXBA
STA ACC
PUL ACC+1
RTS
PAGE
; fetch next byte from AUX into A
FTAXBA: LDA AUXUPD ; need to find a new page?
BEQ L1801 ; yes, go to it!
LDY AUXIDX ; get the byte
LDA (AUXMPT),Y
INY ; increment the low byte of AUX
STY AUXIDX
RTSNE ; return uness we've entered a new page
LDY #$00 ; unnecessary!
STY AUXUPD ; indicate new page
DINC AUXLPG ; increment page number
RTS ; return
L1801: LDA AUXLPG+1 ; is the page we're looking for frozen?
BNE L180B
LDA AUXLPG
L1807: CMPBL FRZPGS,L1822
L180B: DMOV AUXLPG,ACC ; no, see if it is swapped in
JSR FNDPAG
STA AUXPPG ; save phys. page no.
BCS L1832 ; not fount
; we have the swappable page, fix up the pointers, etc.
L181A: JSR MRKPAG ; indicate that we're using this page
CLC ; add phys. page number to number of
LDA AUXPPG ; frozen pages
ADC FRZPGS
; fix the memory pointers
L1822: ADD ,FRZMEM+1,AUXMPT+1 ; add base of memory
MOV <#$00>,AUXMPT
MOV <#$FF>,AUXUPD ; indicate that we have the page
JMP FTAXBA ; and go get the byte
; we need to load the page from disk
L1832: CMPBN PRGPPG,L183A ; if we are about to load a new logical
MOV <#$00>,PRGUPD ; page into the physical page the PC
; points to, mark it as a new page
L183A: DMOV SWPMEM,ACC ; setup to read the page
ADD AUXPPG,ACC+1,ACC+1
DMOV AUXLPG,ACB
JSR DRDBKF ; read the page (die if error)
LDY AUXPPG ; copy the new log. page number into
MOV AUXLPG,<<(VMTAB1),Y>> ; the VM table
MOV AUXLPG+1,<<(VMTAB2),Y>>
TYA
JMP L181A ; go fix up the pointers and fetch the byte
PAGE
; we've just started using a new logical page, move it to the front of our list
; this makes least recently used pages first candidates to be removed
MRKPAG: CMPBE MRUPAG,L1891
LDX MRUPAG
STA MRUPAG
TAY
MOV <(VMTAB3),Y>,ACC
TXA
STA (VMTAB3),Y
MOV <(VMTAB4),Y>,ACC+1
MOV <#$FF>,<<(VMTAB4),Y>>
LDY ACC+1
MOV ACC,<<(VMTAB3),Y>>
TXA
TAY
MOV MRUPAG,<<(VMTAB4),Y>>
LDA ACC
CMPBE <#$FF>,L1892
TAY
MOV ACC+1,<<(VMTAB4),Y>>
L1891: RTS
L1892: MOV ACC+1,LRUPAG
RTS
; search virtual memory table for logical page # in ACC
FNDPAG: LDX SWPPGS
LDY #$00
LDA ACC
L189D: CMPBN <(VMTAB1),Y>,L18A9
LDA ACC+1
CMPBE <(VMTAB2),Y>,L18B1
LDA ACC
L18A9: INY
DXBNE L189D
LDA LRUPAG
SEC
RTS
L18B1: TYA
CLC
RTS
PAGE
; print string at AUX
PRNTST: MOV <#$00>,<PRMMOD,PNYBCN>
MOV <#$FF>,TMPMOD
DONEXT: JSR GETNYB
RTSCS
STA ACD
BEQ DOSPAC
CMPBL <#$04>,DOSBWD
CMPBL <#$06>,NEWMOD
JSR TSTMOD
TSTABN L18E2
LDA #$5B
L18D9: ADD ,ACD
L18DC: JSR BFCHAR
JMP DONEXT
L18E2: CMPBN <#$01>,DOSPCL
LDA #$3B
JMP L18D9
DOSPCL: SUB ACD,<#$07>
BCC DOASCI
BEQ DOCRLF
TAY
DEY
LDA SPCLCH,Y
JMP L18Dc
DOASCI: JSR GETNYB
REPT 5
ASL A
ENDM
PHA
JSR GETNYB
STA ACD
PLA
ORA ACD
JMP L18DC
PAGE
DOSPAC: LDA #' '
JMP L18DC
DOCRLF: LDA #CRCHAR
JSR BFCHAR
LDA #LFCHAR
JMP L18DC
NEWMOD: SUB ,<#$03>
TAY
JSR TSTMOD
BNE L192D
STY TMPMOD
JMP DONEXT
L192D: STY PRMMOD
CMPBE PRMMOD,L1937
LDY #$00
STY PRMMOD
L1937: JMP DONEXT
PAGE
L193A: DB $00
DOSBWD: DECA
REPT 6
ASL A
ENDM
STA L193A
JSR GETNYB
ASL A
ADC #$01
ADC L193A
TAY
MOV <(SBWDPT),Y>,ACC
DEY
MOV <(SBWDPT),Y>,ACC+1
PSH <PRMMOD,PNYBCN>
DPSH PNYBBF
PSH AUXIDX
DPSH AUXLPG
JSR SETAXW
JSR PRNTST
DPUL AUXLPG
PUL AUXIDX
MOV <#$00>,AUXUPD
DPUL PNYBBF
PUL <PNYBCN,PRMMOD>
MOV <#$FF>,TMPMOD
JMP DONEXT
SPCLCH: DB '0123456789.,!?_#''"/\-:()'
TSTMOD: LDA TMPMOD
BPL L19B4
LDA PRMMOD
RTS
L19B4: LDY #$FF
STY TMPMOD
RTS
PAGE
GETNYB: LDA PNYBCN
BPL L19BF
SEC
RTS
L19BF: BNE L19D6
INC PNYBCN
JSR FTAXWD
DMOV ACC,PNYBBF
LDA PNYBBF+1
LSR A
LSR A
AND #$1F
CLC
RTS
L19D6: DECABN L19F3
MOV <#$02>,PNYBCN
LDA PNYBBF+1
LSR A
LDA PNYBBF
ROR A
TAY
LDA PNYBBF+1
LSR A
LSR A
TYA
ROR A
LSR A
LSR A
LSR A
AND #$1F
CLC
RTS
L19F3: MOV <#$00>,PNYBCN
LDA PNYBBF+1
BPL L19FF
MOV <#$FF>,PNYBCN
L19FF: LDA PNYBBF
AND #$1F
CLC
RTS
PAGE
; crunch word to compare with vocab table entries
CRNWRD: LDX #$00
LDY #$06
L1A09: MOV <#$05>,<<PKWORD,X>>
INX
DYBNE L1A09
MOV <#$06>,ACD+1
MOV <#$00>,<ACB,ACC>
L1A1B: LDX ACC
INC ACC
MOV <INWORD,X>,ACD
BNE L1A2A
LDA #$05
JMP L1A52
L1A2A: LDA ACD
JSR TSTCHR
TSTABE L1A43
ADD ,<#$03>
LDX ACB
STA PKWORD,X
INC ACB
DECJE ACD+1,L1ACA
L1A43: LDA ACD
JSR TSTCHR
DECABP L1A62
SUB ACD,<#$5B>
L1A52: LDX ACB
STA PKWORD,X
INC ACB
DECJN ACD+1,L1A1B
JMP L1ACA
L1A62: BNE L1A6C
SUB ACD,<#$3B>
JMP L1A52
L1A6C: LDA ACD
JSR L1A99
BNE L1A52
LDA #$06
LDX ACB
STA PKWORD,X
INC ACB
DECBE ACD+1,L1ACA
LDA ACD
REPT 5
LSR A
ENDM
AND #$03
LDX ACB
STA PKWORD,X
INC ACB
DECBE ACD+1,L1ACA
LDA ACD
AND #$1F
JMP L1A52
L1A99: LDX #$24
L1A9B: CMPBE <SPCLCH,X>,L1AA6
DXBPL L1A9B
LDY #$00
RTS
L1AA6: TXA
ADD ,<#$08>
RTS
TSTCHR: CMPBL <#'a'>,L1AB6
CMPBG <#'z'+1>,L1AB6
LDA #$00
RTS
L1AB6: CMPBL <#'A'>,L1AC1
CMPBG <#'Z'+1>,L1AC1
LDA #$01
RTS
L1AC1: TSTABE L1AC9
BMI L1AC9
LDA #$02
L1AC9: RTS
L1ACA: LDA PKWORD+1
REPT 4
ASL A
ENDM
ROL PKWORD
ASL A
ROL PKWORD
LDX PKWORD
STX PKWORD+1
ORA PKWORD+2
STA PKWORD
LDA LDE
REPT 4
ASL A
ENDM
ROL PKWORD+3
ASL A
ROL PKWORD+3
LDX PKWORD+3
STX PKWORD+3
ORA LDF
STA PKWORD+2
LDA PKWORD+3
ORA #$80
STA PKWORD+3
RTS
PAGE
; init output routine and screen window
INITSC: MOV <#$C1>,PRCSWL+1
IFF RNGDBG ; if RNG debug, save 2 lines at top!
MOV <#$01>,WNDTOP
ENDIF
MOV <#$00>,<WNDLFT,L1BA0>
MOV <#$28>,WNDWDT
MOV <#$18>,WNDBOT
MOV <#$BE>,PROMPT
MOV <#$FF>,INVFLG
; clear the screen
CLRSCR: JSR HOME
MOV WNDTOP,LINCNT
RTS
; find the highest usable page of memory
FNDMEM: DMOVI2 LSTFLC+$0100,ACC
LDY #$00
L1B28: DEC ACC+1
LDA (ACC),Y
CMPBN <(ACC),Y>,L1B28
EOR #$FF
STA (ACC),Y
CMPBN <(ACC),Y>,L1B28
EOR #$FF
STA (ACC),Y
LDA ACC+1
RTS
PAGE
; buffer a character for output
BFCHAR: LDX CHRPTR ; get buffer pointer
CMPJE <#CRCHAR>,PRNTBF ; if char is a CR, flush buffer
CMPBL <#' '>,L1B61 ; if it is a control character, discard it
CMPBL <#$60>,L1B57 ; if it is in 64 char subset, buffer it as is
IFT LC40
BIT INVFLG ; if inverse, convert LC to UC
BMI L1B57
ELSE
CMP #$80 ; is it in LC range ($60 <= char < $80)?
BGE L1B57
ENDIF
SUB ,<#$20> ; yes, convert o upper case
L1B57: ORA #$80 ; set high bit for Apple
STA BUFFER,X ; store it in buffer
CPXBG WNDWDT,L1B64 ; if buffer is full, print some of it
INX ; increment pointer
L1B61: STX CHRPTR ; save pointer
RTS ; return
; find last spac ein buffer, if any
L1B64: LDA #" " ; load a space for comparison
L1B66: CMPBE <BUFFER,X>,L1B70 ; if this is one, we've got it
DXBNE L1B66 ; no, loop if no character in buffer
LDX WNDWDT ; no space... use last character
L1B70: STX CHRPT2 ; save pointer
STX CHRPTR
JSR PRNTBF ; print line up to this point
; move rest of line back to beginning of buffer
L1B77: INC CHRPT2 ; get pointer to next char
LDX CHRPT2
CPXRGT WNDWDT ; if it is past the last char, return
LDA BUFFER,X ; get the character
LDX CHRPTR ; get the pointer to the new loc
STA BUFFER,X ; store the character there
INC CHRPTR ; and increment the pointer
LDX CHRPT2 ; unnecessary!
JMP L1B77 ; try for another one
PAGE
; output the buffer to the screen, and to the printer if enabled
OUTBUF: LDY #HDRFLG+1
LDA (FRZMEM),Y
AND #$01
JSRNE PRTBUF
JSR DSPBUF
RTS
; output the buffer to the printer
L1BA0: DB $00 ; printer initialization flag
PRTBUF: DPSH CSWL ; save our output vector
PSH CURSRH ; and cursor column
DMOV PRCSWL,CSWL ; get vector for printer
LDX #$00 ; start with position 0 in buffer
LDA L1BA0 ; is printer initialized?
BNE L1BD5 ; yes, go print it
INC L1BA0 ; no, but now will be
LDA #$89 ; output ^I80N
JSR COUT ; (this sets printer width to 80
LDA #$91 ; characters, thereby disabling
STA PRTWDT ; screen echo (we hope!))
LDA #$B8
JSR COUT
LDA #$B0
JSR COUT
LDA #$CE
JSR COUT
L1BD5: CPXBE CHRPTR,L1BE3 ; are we done yet?
LDA BUFFER,X ; no, get character
JSR COUT ; and output it
INX ; increment pointer
JMP L1BD5 ; and go for another one
L1BE3: DMOV CSWL,PRCSWL ; save print vector again (may have changed)
PUL CURSRH ; restore cursor column
DPUL CSWL ; and display vector
RTS ; and return
; output the buffer to the display
DSPBUF: LDX #$00 ; start with position 0 in buffer
L1BF7: CPXBE CHRPTR,L1C05 ; are we done yet?
LDA BUFFER,X ; get the character
JSR COUT1 ; and output it
INX ; increment pointer
JMP L1BF7 ; and go for another one
L1C05: LDX #$00 ; reset pointer to beginning
STX CHRPTR
RTS ; and return
PAGE
MOREMS: DB '[MORE]'
MRMSLN EQU *-MOREMS
PRNTBF: INC LINCNT
LDA LINCNT
CMPBL WNDBOT,L1C40
DMOVI MOREMS,ACC
LDX #MRMSLN
MOV <#$3F>,INVFLG
JSR SHWMSG
MOV <#$FF>,INVFLG
JSR RDKEY
SUB CURSRH,<#$06>,CURSRH
JSR CLREOL
MOV WNDTOP,LINCNT
INC LINCNT
L1C40: PSH CHRPTR
JSR OUTBUF
PLA
CMPBE WNDWDT,L1C50
LDA #$8D
JSR COUT1
L1C50: LDY #HDRFLG+1
LDA (FRZMEM),Y
AND #$01
BEQ L1C79
DPSH CSWL
DMOV PRCSWL,CSWL
LDA #$8D
JSR COUT
DMOV CSWL,PRCSWL
DPUL CSWL
L1C79: LDX #$00
JMP L1B61
PAGE
SCORMS: DB 'SCORE:'
SCMSLN EQU *-SCORMS
TIMEMS: DB 'TIME:'
TMMSLN EQU *-TIMEMS
L1C89: DB $00
OPPRST: JSR OUTBUF ; print what's in the buffer
PSH <CURSRH,CURSRV> ; save the cursor position
MOV <#$00>,<CURSRH,CURSRV> ; home the cursor
JSR VTAB
MOV <#$3F>,INVFLG ; set inverse mode
LDA #$10 ; get global var 0
JSR GTVRA1
LDA ACC ; is it save as last time?
CMPBE L1C89,L1CB8 ; yes, don't print it
STA L1C89 ; no, save for next time's compare
JSR L0DE4 ; output thing name
JSR DSPBUF ; send it to display
JSR CLREOL ; clear rest of line
L1CB8: MOV <#$19>,CURSRH ; tab over
LDA STLTYP ; score or time?
BNE L1CDB ; time
DMOVI SCORMS,ACC ; score, print "SCORE:"
LDX #SCMSLN
JSR SHWMSG
INC CURSRH ; one space
LDA #$11 ; get global var 1 (score)
JSR GTVRA1
JSR PRNTNM ; output it as decimal number
LDA #'/' ; separator
BNE L1D05 ; always taken
L1CDB: DMOVI TIMEMS,ACC ; print "TIME:"
LDX #TMMSLN
JSR SHWMSG
INC CURSRH ; one space
LDA #$11 ; get global var 1 (time)
JSR GTVRA1
LDA ACC ; is it zero?
BNE L1CF5
LDA #$18 ; yes, make it 24:00
L1CF5: CMPBM <#$0C>,L1D00 ; is it A.M. or P.M.?
BEQ L1D00
SEC ; P.M., convert to 1-12 range
SBC #$0C ; by subtracting 12
STA ACC
L1D00: JSR PRNTNM ; print out hours
LDA #':'
L1D05: JSR BFCHAR ; print the separator
LDA #$12 ; get global var 2 (turns/minutes)
JSR GTVRA1
LDA STLTYP ; time?
BEQ L1D40 ; no, go print turns
LDA ACC ; yes, are minutes < 10?
CMPBG <#$0A>,L1D1C ; no
LDA #$B0 ; yes, print a space (?)
JSR BFCHAR
L1D1C: JSR PRNTNM ; print the minutes
LDA #$A0 ; print a space
JSR BFCHAR
LDA #$11 ; get global var 1 (hours)
JSR GTVRA1
LDA ACC ; is it A.M. or P.M.?
CMPBP <#$0C>,L1D33 ; P.M.
LDA #"A" ; A.M.
BNE L1D35
L1D33: LDA #"P"
L1D35: JSR BFCHAR ; print the "A" or "P"
LDA #"M"
JSR BFCHAR ; print the "M"
JMP L1D43
L1D40: JSR PRNTNM ; print the score
L1D43: JSR DSPBUF ; display the buffer
JSR CLREOL ; clear out the line
MOV <#$FF>,INVFLG ; back to normal video mode
PUL <CURSRV,CURSRH> ; and the old cursor loc
JSR VTAB
RTS ; return to caller
SHWMSG: LDY #$00
L1D59: LDA (ACC),Y
ORA #$80
JSR COUT1
INY
DXBNE L1D59
RTS
PAGE
GETLIN: JSR OUTBUF
MOV WNDTOP,LINCNT
JSR GETLN1
INC LINCNT
MOV <#$8D>,<<BUFFER,X>>
INX
TXA
PHA
LDY #HDRFLG+1
LDA (FRZMEM),Y
AND #$01
BEQ L1D8B
TXA
STA CHRPTR
JSR PRTBUF
MOV <#$00>,CHRPTR
L1D8B: PLA
LDY #$00
CMPBL <(ARG1),Y>,L1D94
LDA (ARG1),Y
L1D94: PHA
BEQ L1DB1
TAX
L1D98: LDA BUFFER,Y
AND #$7F
CMPBL <#'A'>,L1DA7
CMPBG <#'Z'+1>,L1DA7
ORA #$20
L1DA7: INY
STA (ARG1),Y
CMPBE <#CRCHAR>,L1DB1
DXBNE L1D98
L1DB1: PLA
RTS
PAGE
IOB: DB $01 ; IOB type
IOBSLT: DB $60 ; Slot * 16
IOBDRV: DB $01 ; Drive
DB $00 ; Volume
IOBTRK: DB $00 ; Track
IOBSCT: DB $00 ; Sector
DW DCT ; Device Characteristics Table
IOBBUF: DW $0000 ; I/O buffer
DW $0000 ; unused
IOBCMD: DB $00 ; Command
DB $00 ; Status
DB $00 ; Actual volume
DB $60 ; Previous slot * 16
DB $01 ; Previous drive
DCT: DB $00,$01,$EF,$D8
DISKIO: STA IOBCMD
DMOV ACC,IOBBUF
MOV #$03,IOBTRK
LDA ACB
LDX ACB+1
SEC
L1DDF: SBC SECPTK
BCS L1DE7
DXBMI L1DED
SEC
L1DE7: INC IOBTRK
JMP L1DDF
L1DED: ADD ,SECPTK,IOBSCT
LDA #>IOB
LDY #<IOB
JMP RWTS
DRDBUF: DMOVI BUFFER,ACC
DRDNXT: DINC ACB
DRDBLK: LDA #$01
JMP DISKIO
DRDBKF: JSR DRDBLK
JSRCS FATAL
RTS
DWRBUF: DMOVI BUFFER,ACC
DWRNXT: DINC ACB
LDA #$02
JMP DISKIO
PAGE
OUTMSG: STX ACD
LDY #$00
STY ACD+1
L1E2F: LDY ACD+1
LDA (ACC),Y
JSR BFCHAR
INC ACD+1
DECBN ACD,L1E2F
RTS
L1E3D: DB 'PLEASE INSERT SAVE DISKETTE,'
L1E59: DB $00
L1E5A: DB 'SLOT (1-7):'
L1E69: DB '618'
L1E6C: DB 'DRIVE (1-2):'
L1E7B: DB '213'
L1E7E: DB 'POSITION (0-7):'
L1E8D: DB '008'
L1E90: DB 'DEFAULT = '
L1E9A: DB '--- PRESS ''RETURN'' KEY TO BEGIN ---'
PAGE
L1EBD: JSR CLRSCR
JSR PRNTBF
JSR PRNTBF
DMOVI L1E3D,ACC
LDX #$1C
JSR OUTMSG
JSR PRNTBF
MOV <#$24>,L1E59
JSR L1F4C
STA L1E8D
JSR BFCHAR
MOV <#$00>,L1E59
JSR L1F4C
TAX
AND #$07
REPT 4
ASL A
ENDM
STA IOBSLT
TXA
STA L1E69
JSR BFCHAR
MOV <#$12>,L1E59
JSR L1F4C
TAX
AND #$03
STA IOBDRV
TXA
STA L1E7B
JSR BFCHAR
L1F12: JSR PRNTBF
DMOVI L1E9A,ACC
LDX #$23
JSR OUTMSG
JSR OUTBUF
JSR RDKEY
CMPBN <#$8D>,L1F12
MOV <#$FF>,<ACB,ACB+1>
LDA L1E8D
AND #$07
BEQ L1F48
TAY
L1F3A: DADDB2 ACB,<#$40>
DYBNE L1F3A
L1F48: JSR PRNTBF
RTS
PAGE
L1F4C: JSR PRNTBF
DMOVI L1E5A,ACC
DADDB2 ACC,L1E59
LDX #$0F
JSR OUTMSG
JSR OUTBUF
MOV <#$19>,CURSRH
MOV <#$3F>,INVFLG
DMOVI L1E90,ACC
LDX #$0A
JSR SHWMSG
DMOVI L1E69,ACC
DADDB2 ACC,L1E59
LDX #$01
JSR SHWMSG
MOV <#$FF>,INVFLG
JSR RDKEY
PHA
MOV <#$19>,CURSRH
JSR CLREOL
PLA
LDY L1E59
CMPBN <#$8D>,L1FB3
LDA L1E69,Y
L1FB3: AND #$7F
CMPBL <L1E69+1,Y>,L1F4C
CMPBG <L1E69+2,Y>,L1F4C
RTS
PAGE
L1FC0: DB 'PLEASE RE-INSERT GAME DISKETTE,'
L1FDF: DB '--- PRESS ''RETURN'' KEY TO CONTINUE ---'
L2005: LDA IOBSLT
CMPBN <#$60>,L2040
LDA IOBDRV
CMPBN <#$01>,L2040
JSR PRNTBF
DMOVI L1FC0,ACC
LDX #$1F
JSR OUTMSG
L2023: JSR PRNTBF
DMOVI L1FDF,ACC
LDX #$26
JSR OUTMSG
JSR OUTBUF
JSR RDKEY
CMPBN <#$8D>,L2023
JSR PRNTBF
L2040: MOV <#$60>,IOBSLT
MOV <#$01>,IOBDRV
RTS
PAGE
OPSVGM: JSR L1EBD ; setup for disk I/O
LDX #$00 ; copy game release # to buffer
LDY #HDRREL
MOV <(FRZMEM),Y>,<<BUFFER,X>>
INX
INY
MOV <(FRZMEM),Y>,<<BUFFER,X>>
INX
DMOVI PRGIDX,ACC ; copy PC to buffer
LDY #$03
JSR SVGMMV
DMOVI LOCVAR,ACC ; copy local variables to buffer
LDY #$1E
JSR SVGMMV
DMOVI STKCNT,ACC ; copy SP and SP save to buffer
LDY #$06
JSR SVGMMV
JSR DWRBUF ; write it out
BCS SVGMFL ; fail if error
LDX #$00 ; copy lowest 256 bytes of stack
DMOVI STKLIM,ACC ; to buffer
LDY #$00
JSR SVGMMV
JSR DWRBUF ; write it out
BCS SVGMFL ; fail if error
LDX #$00 ; copy high 192 bytes of stack
DMOVI STKLIM+$0100,ACC ; to buffer
LDY #$C0
JSR SVGMMV
JSR DWRBUF ; write it out
BCS SVGMFL ; fail if error
DMOV FRZMEM,ACC ; figure out how many pages of
LDY #HDRIMP ; impure storage there are tobe
MOV <(FRZMEM),Y>,ACD ; written out, and set up for first
INC ACD ; one
L20C3: JSR DWRNXT ; write one page of impure storage
BCS SVGMFL ; fail if error
INC ACC+1 ; increment buffer address
DECBN ACD,L20C3 ; decrement page count, loop if more
JSR DWRNXT ; write final page
BCS SVGMFL ; fail if error
JSR L2005 ; make sure we have game disk
JMP PREDTR ; return true (no error)
SVGMFL: JSR L2005 ; make sure we have game disk
JMP PREDFL ; return false (error)
SVGMMV: DEY ; copy memory into buffer to write
MOV <(ACC),Y>,<<BUFFER,X>>
INX
CPYBN <#$00>,SVGMMV ; if more, loop
RTS ; no, return
PAGE
OPRSGM: JSR L1EBD ; setup for disk I/O
JSR DRDBUF ; read in a bufferful
JCS RSGMFL ; fail if error
LDX #$00 ; check release of game, fail if wrong
LDY #HDRREL
LDA (FRZMEM),Y
CMPBN <BUFFER,X>,L210A
INX
INY
LDA (FRZMEM),Y
CMPBE <BUFFER,X>,L210D
L210A: JMP RSGMFL
L210D: LDY #HDRFLG+1 ; preserve SCRIPT flag
MOV <(FRZMEM),Y>,MDFLAG
INX ; restore PC
DMOVI PRGIDX,ACC
LDY #$03
JSR RSGMMV
MOV <#$00>,PRGUPD
DMOVI LOCVAR,ACC ; restore local variables
LDY #$1E
JSR RSGMMV
DMOVI STKCNT,ACC ; restore SP and SP save
LDY #$06
JSR RSGMMV
JSR DRDBUF ; read a bufferful
BCS RSGMFL ; fail if error
LDX #$00 ; restore first 256 bytes of stack
DMOVI STKLIM,ACC
LDY #$00
JSR RSGMMV
JSR DRDBUF ; read a bufferful
BCS RSGMFL ; fail if error
LDX #$00 ; restore last 192 bytes of stack
DMOVI STKLIM+$100,ACC
LDY #$C0
JSR RSGMMV
DMOV FRZMEM,ACC ; figure out how many pages of
LDY #HDRIMP ; impure storage there are to be
MOV <(FRZMEM),Y>,ACD ; read in, and set up to read first
INC ACD ; one
L2177: JSR DRDNXT ; read in next page of impure storage
BCS RSGMFL ; fail if error
INC ACC+1 ; increment buffer pointer
DECBN ACD,L2177 ; decrement page count, loop if more
LDA MDFLAG ; restore SCRIPT flag
LDY #HDRFLG+1
STA (FRZMEM),Y
JSR L2005 ; make sure we have game disk
JMP PREDTR ; return true (no error)
RSGMFL: JSR L2005 ; make sure we have game disk
JMP PREDFL ; return false (error)
RSGMMV: DEY ; copy buffer to memory (read)
MOV <BUFFER,X>,<<(ACC),Y>>
INX
CPYBN <#$00>,RSGMMV
RTS
PAGE
L21A0: INC RNDLOC ; get a 'random' number
INC RNDLOC+1
DMOV RNDLOC,ACC
RTS
ENDMSG: DB '-- END OF SESSION --'
ENMSLN EQU *-ENDMSG
FTLMSG: DB 'INTERNAL ERROR #'
FTMSLN EQU *-FTLMSG
FATAL: JSR PRNTBF ; flush anything left in buffer
DMOVI FTLMSG,ACC ; output fatal message
LDX #FTMSLN
JSR OUTMSG
DPUL2 ACC ; output address where error detected
JSR PRNTNM
OPENDS: JSR PRNTBF ; flush anything left in buffer
DMOVI ENDMSG,ACC ; output end of session message
LDX #ENMSLN
JSR OUTMSG
JSR PRNTBF ; flush the buffer
HALT: JMP HALT ; die horribly
.DEPHASE
END START