Files
erkyrath.infocom-zcode-terps/apple/ezip/io.asm
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

681 lines
13 KiB
NASM

PAGE
SBTTL "--- GAME I/O: APPLE II ---"
; --------------
; INTERNAL ERROR
; --------------
; ENTRY: ERROR CODE IN [A]
; EXIT: HA!
ERRM: DB "Internal error "
ENUMB: DB "00. "
ERRML EQU $-ERRM
ZERROR: LDY #1 ; CONVERT ERROR BYTE IN [A]
ZERR0: LDX #0 ; TO DB II AT "ENUMB"
ZERR1: CMP #10
BCC ZERR2
SBC #10
INX
BNE ZERR1
ZERR2: ORA #'0'
STA ENUMB,Y
TXA
DEY
BPL ZERR0
LDX #<ERRM
LDA #>ERRM
LDY #ERRML
JSR DLINE ; PRINT ERROR MESSAGE
JMP ZQUIT1
; ----
; QUIT
; ----
ZQUIT: JSR ZCRLF ; FLUSH BUFFER
ZQUIT1: LDX #<ENDM
LDA #>ENDM
LDY #ENDML
JSR DLINE ; "END OF STORY"
FREEZE: JMP FREEZE ; AND STOP
ENDM: DB "End of session."
DB EOL
ENDML EQU $-ENDM
; -------
; RESTART
; -------
ZSTART: LDX #0
STX WTOP ; RESET FULL SCREEN FOR CLEAR
LDA SCRIPTF ; PRINTING?
BEQ REX ; NO
DEX ; = $FF
STX PSTAT ; MAKE TO CONTINUE PRINTING AFTER RESTART
REX: JSR SIDE1 ; NEED SIDE 1 AGAIN
JMP WARM ; AND DO WARMSTART
; --------------------------
; RETURN TOP RAM PAGE IN [A]
; --------------------------
MEMTOP: LDA #$FB ; FOR NOW, ASSUME LAST "BUFFER"
RTS ; OF AUX MEMORY
; --------------------------------
; RETURN RANDOM BYTES IN [A] & [X]
; --------------------------------
RANDOM: INC RNUM1
DEC RNUM2
LDA RNUM1 ; GENERATED BY MONITOR GETBYT
ADC RAND1
TAX
LDA RNUM2
SBC RAND2
STA RAND1
STX RAND2
RTS
; -------------------
; Z-PRINT A CHARACTER
; -------------------
; ENTRY: ASCII CHAR IN [A]
; COMMENT: SCRIPTING IS HANDLED IN UNBUFR AND FLUSH,
; SO CAN OUTPUT TO PRINTER AS A LINE. TABLE AND SCREEN
; OUTPUT IS SET UP HERE, HANDLED A BYTE AT A TIME
; (DIROUT CHANGES 6/24/85)
COUT: STA IOCHAR ; HOLD IT A SEC
LDX TABLEF ; OUTPUT TO TABLE?
BEQ COUT4 ; NO
JMP TBLRTN ; YES, DO IT (TBL ONLY)
COUT4: LDX SCREENF ; OUTPUT TO SCREEN?
BNE COUT5 ; YES
LDX SCRIPTF ; OUTPUT TO PRINTER?
BNE COUT5 ; YES
RTS ; NO, SO DONE
COUT5: LDA IOCHAR ; RETRIEVE CHAR
LDX BUFFLG ; UNBUFFERED OUTPUT?
BNE UNBUFR ; YES, PLACE ON SCREEN IMMED.
CMP #$0D ; IF ASCII EOL,
BNE COUT0
JMP ZCRLF ; DO IT
COUT0: CMP #SPACE ; IGNORE ALL OTHER
BCC CEX ; CONTROLS
LDX INVFLG ; CHECK IF NORMAL
BPL COUT3 ; OR INVERSE
ORA #%10000000 ; SET HIGH BIT FOR NORMAL
COUT3: LDX CHRCNT ; GET LINE POINTER
STA LBUFF,X ; ADD CHAR TO BUFFER
LDY LENGTH ; GET LINE LENGTH COUNTER
CPY XSIZE ; END OF SCREEN LINE?
BCC COUT2
JMP FLUSH ; YES, FLUSH THE LINE
COUT2: INC LENGTH ; ELSE UPDATE
INC CHRCNT
CEX: RTS
; --------------------------
; DIRECT, UNBUFFERED DISPLAY
; --------------------------
UNBUFR: STA IOCHAR ; HOLD IN CASE NEED TO PRINT
CMP #SPACE ; IGNORE CONTROLS
BCC UNBEX
LDA EHZ ; CHECK IF BEYOND SCREEN
CMP #80
BCS UNBEX ; YES, LEAVE
LDA CHZ ; CHECK FOR IIE ALSO
CMP #80
BCS UNBEX
LDA SPLITF ; CHECK WHICH WINDOW
BEQ UNBBOT ; BOTTOM WINDOW
LDA CV ; CHECK IF WITHIN WINDOW
CMP WTOP
BCS UNBEX ; NO, JUST LEAVE
BCC UNBDIS ; YES, GO DISPLAY
UNBBOT: LDA CV
CMP WTOP
BCC UNBEX ; NOT WITHIN WINDOW, LEAVE
UNBDIS: LDA SCREENF ; DISPLAY TO SCREEN?
BEQ UNBPRN ; NO, CHECK IF PRINTING
LDA IOCHAR
ORA #%10000000 ; SET BIT 7 FOR NORMAL DISPLAY IF WANTED
JSR MCOUT
UNBPRN: LDA SPLITF ; SPLIT (NON-TEXT) SCREEN
BNE UNBEX ; DON'T PRINT
;SEND CHAR TO PRINTER
LDA SCRIPT ; SCRIPTING INTERNALLY ENABLED?
BEQ UNBEX ; NO
LDA SCRIPTF ; SCRIPTING ON ?
BEQ UNBEX ; NO
LDA CSW+LO ; SAVE NORMAL OUTPUT HOOK
PHA
LDA CSW+HI
PHA
LDA EHZ ; + CURRENT CURSOR POSITION
PHA
LDA CHZ ; AND FOR IIE ALSO
PHA
LDA ALTCSW+LO
STA CSW+LO
LDA ALTCSW+HI
STA CSW+HI
LDA IOCHAR ; GET CHAR
JSR MCOUT ; PRINT IT @ CURRENT EH
PLA ; RESET TO NORMAL
STA CHZ
PLA
STA EHZ ; IIe USES CH ALSO
PLA
STA CSW+HI
PLA
STA CSW+LO
UNBEX: RTS
; ---------------
; OUTPUT TO TABLE
; ---------------
TBLRTN: TAX ; HOLD CHAR A SEC.
;PUT BYTE IN TABLE AT CURRENT OFFSET
LDA DIRITM+LO ; ADD IN OFFSET
CLC
ADC DIRTBL+LO
STA I+LO
LDA DIRITM+HI
ADC DIRTBL+HI
STA I+HI
LDY #0
TXA ; PICK UP DB II CHAR
STA (I),Y ; STORE IT IN TBL @ BYTE ALIGNED @
;SET ITM OFFSET TO NEXT POSITION, INCREMENT COUNTER
INC DIRITM+LO ; INC OFFSET TO NEXT BYTE
BNE TBLRTS
INC DIRITM+HI
TBLRTS: RTS
; -------------------
; FLUSH OUTPUT BUFFER
; -------------------
; ENTRY: LENGTH OF BUFFER IN [X]
FLUSH: LDA #$A0 ; SPACE
STX OLDEND ; SAVE CURRENT END OF LINE
FL0: CMP LBUFF,X ; FIND LAST SPACE CHAR
BEQ FL1 ; IN THE LINE
DEX
BNE FL0 ; IF NONE FOUND,
LDX XSIZE ; FLUSH ENTIRE LINE
FL1: STX OLDLEN ; SAVE OLD LINE POS HERE
STX CHRCNT ; MAKE IT THE NEW LINE LENGTH
JSR ZCRLF ; PRINT LINE UP TO LAST SPACE
; START NEW LINE WITH REMAINDER OF OLD
LDX OLDLEN ; GET OLD LINE POS
LDY #0 ; START NEW LINE AT BEGINNING
FL2: INX
CPX OLDEND ; CONTINUE IF
BCC FL3 ; INSIDE OR
BEQ FL3 ; AT END OF LINE
STY LENGTH ; ELSE SET NEW LINE LENGTH
STY CHRCNT
RTS
FL3: LDA LBUFF,X ; GET CHAR FROM OLD LINE
STA LBUFF,Y ; MOVE TO START OF NEW LINE
INY ; UPDATE LENGTH OF NEW LINE
BNE FL2 ; (ALWAYS)
; ---------------
; CARRIAGE RETURN
; ---------------
ZCRLF:
LDX CHRCNT
LDA #$8D ; INSTALL EOL AT
STA LBUFF,X ; END OF CURRENT LINE
INC CHRCNT ; UPDATE LINE LENGTH
LDA SCREENF ; CHECK IF DISPLAYING TO SCREEN
BEQ ZCRLFX ; NO, GO HANDLE IF PRINTING
LDA SPLITF ; AT SPLIT SCREEN
BNE ZCRLF0 ; YES
INC LINCNT ; NEW LINE GOING OUT
ZCRLF0: LDX LINCNT ; IS IT TIME TO
INX ; (A LINE FOR "MORE")
CPX WBOTM ; PRINT "MORE" YET?
BCC ZCRLFX ; NO, CONTINUE
LDA WTOP
STA LINCNT ; RESET LINE COUNTER
INC LINCNT ; LEAVE 1 LINE ON SCREEN
BIT ANYKEY ; CLEAN STROBE SO GET CLEAN READING
LDA #>MORE
LDX #<MORE
LDY #MOREL
JSR DLINE
WAIT: BIT KBD
BPL WAIT
BIT ANYKEY ; CLEAR STROBE SO THIS KEY WILL BE DISCOUNTED
LDY #MOREL ; ERASE [MORE]
WWLOOP: LDA #08
JSR MCOUT
DEY
BNE WWLOOP
JSR CLEOL ; CLEAR TO EOL
ZCRLFX: JSR LINOUT ; DISPLAY LINE
LDA #0
STA LENGTH ; AND RESET LINE COUNT
STA CHRCNT
RTS
LINOUT: LDY CHRCNT ; IF BUFFER EMPTY,
BEQ LINEX ; DON'T PRINT ANYTHING
STY PRLEN ; SAVE LENGTH HERE FOR "PPRINT"
LDA SCREENF ; DISPLAY TO SCREEN?
BEQ LOUT1 ; NO, GO CHECK IF PRINT
LDX #0 ; SEND CONTENTS OF [LBUFF]
LOUT: LDA LBUFF,X ; TO SCREEN
JSR CHAR
INX
DEY
BNE LOUT
LOUT1: LDA SPLITF ; DON'T PRINT IF SPLIT (NON-TEXT) SCREEN (EZIP)
BNE LINEX
JSR PPRINT ; PRINT [LBUFF] IF ENABLED
LINEX: RTS ; AND RETURN
; ----------------------
; UPDATE THE STATUS LINE
; ----------------------
; NOT APPLICABLE IN EZIP.
ZUSL: RTS
; ------
; BUFOUT
; ------
; INPUT: ARG1 = BUFFERED (1) OR NONBUFFERED (0) OUTPUT CHOICE
; EXIT: FLAG (BUFFLG) IS SET TO TELL COUT WHICH TO DO
ZBUFOUT: LDX ARG1+LO
BNE ZBUF1 ; SET TO BUFFERED OUTPUT
JSR LINOUT ; CLEAR BUFFER (DON'T RESET LINE COUNT)
LDX #0
STX CHRCNT
INX
STX BUFFLG ; SET FUTURE OUTPUT TO BE UNBUFFERED
RTS
ZBUF1: DEX
BNE ZBUFEX ; INVALID
STX BUFFLG ; SET TO BUFFERED
ZBUFEX: RTS
; ------
; DIROUT
; ------
; ARG1 CONTAINS VALUE OF WHICH DEVICE TO SELECT
; OR DESELECT, ARG2 = THE TABLE ADDR FOR TABLE OUTPUT
; MULTIPLE DEVICE USAGE IS POSSIBLE.
ZDIRT: LDX ARG1+LO
BMI DIRRES ; NEGATIVE VALUE, DESELECTING
DEX
BEQ DIR1 ; 1 = SET OUTPUT TO SCREEN
DEX
BEQ DIR2 ; 2 = SCRIPTING
DEX
BEQ DIR3 ; 3 = TABLE
DEX
BEQ DIR4 ; 4 = RECORDING DEVICE
RTS ; INVALID VALUE
DIRRES: INX
BEQ DRES1 ; -1 = RESET TO SCREEN
INX
BEQ DRES2
INX
BEQ DRES3
INX
BEQ DRES4
RTS ; INVALID VALUE, JUST LEAVE
DIR1: INX ; 1, TURN SCREEN OUTPUT ON
STX SCREENF
RTS
DRES1: STX SCREENF ; 0, TURN SCREEN OFF
RTS
DIR2: INX
STX SCRIPTF ; SET SCRIPT FLAG ON
LDA ZBEGIN+ZSCRIP+1 ; SET GAME FLAG ALSO
ORA #%00000001
STA ZBEGIN+ZSCRIP+1
LDA PSTAT ; CHECK IF PRINTER ALREADY INIT'D
BNE DIR2A
JSR PCHK ; NO, GO DO IT
DIR2A: RTS ; YES, READY TO LEAVE
DRES2: STX SCRIPTF ; TURN PRINTER OFF
LDA ZBEGIN+ZSCRIP+1 ; AND TURN OFF GAME FLAG TOO
AND #%11111110
STA ZBEGIN+ZSCRIP+1
RTS
DIR3: INX
STX TABLEF ; TURN TABLE OUTPUT FLAG ON
LDA ARG2+HI ; SET UP TBL
CLC
ADC ZCODE
LDX ARG2+LO ; TO STORE CHARS IN
STX DIRTBL+LO
STA DIRTBL+HI
LDA #2
STA DIRITM+LO
LDA #0
STA DIRITM+HI
RTS
DRES3: LDA TABLEF ; IF OFF ALREADY (LZIP)
BEQ OUT3 ; LEAVE AS IS (LZIP)
STX TABLEF ; TURN TBL OUTPUT OFF
LDA DIRITM+LO ; MARK END OF CHARS IN TBL
CLC ; WITH A NULL CHAR
ADC DIRTBL+LO
STA I+LO
LDA DIRITM+HI
ADC DIRTBL+HI
STA I+HI ; ALIGNED AT EOL
LDA #0
TAY
STA (I),Y ; PLACE 0 IN TBL
LDY #1 ; GET CHAR COUNT
LDA DIRITM+LO ; (2 LESS THAN [DIRITM])
SEC
SBC #2
STA (DIRTBL),Y
BCS RESET0
DEC DIRITM+HI
RESET0: LDA DIRITM+HI
DEY
STA (DIRTBL),Y ; STORE CHAR COUNT IN TBL
LDA #0 ; CLEAR COUNT FOR NEXT TIME
STA DIRFLG ; SET OUTPUT TO SCREEN
OUT3: RTS
DIR4:
DRES4: RTS ; NOT YET IMPLEMENTED
; ------
; CURSET
; ------
; SET CURSOR AT LINE (ARG1) AS OFFSET FROM TOP OF WINDOW
; AND AT COLUMN (ARG2)
ZCURST: LDA ZBEGIN+ZMODE
AND #%00010000
BEQ ZCUREX ; NOT ENABLED
LDY BUFFLG
BEQ ZCUREX ; NOT ALLOWED IF OUTPUT BUFFERED
LDY SPLITF
BEQ ZCUREX ; ONLY ALLOWED IN NON SCROLLING SCREEN
LDX ARG1+LO ; GET LINE
DEX ; ZERO ALIGN IT
STX CV
LDX ARG2+LO ; GET COLUMN
DEX ; ZERO ALIGN IT
STX EHZ
STX CHZ ; IIe SEEMS TO USE BOTH
JMP BASCAL ; MOVE THE CURSOR
ZCUREX: RTS
; --------------
; CURGET & DIRIN
; --------------
; NOT YET IMPLEMENTED, BUT RESERVED
ZCURGT:
ZDIRIN: RTS
; ------
; HLIGHT
; ------
ZLIGHT: LDA ARG1+LO ; GET CHOICE OF MODE
BNE ZL1
LDA #$FF ; NORMAL DISPL
STA INVFLG
ZLEX: RTS
ZL1: CMP #1 ; INVERSE?
BNE ZLEX ; NO OTHER OPTIONS ON APPLE
LDA ZBEGIN+ZMODE ; CHECK IF ENABLED
AND #%00000010
BEQ ZLEX ; NOPE
LDA #$3F ; SET INVERSE DISPL
STA INVFLG
RTS
; -----
; ERASE
; -----
ZERASE: LDA ZBEGIN+ZMODE ; ENABLED?
AND #%00010000
BEQ ZEROUT ; NO
LDA ARG1+LO
CMP #1
BNE ZEROUT ; INVALID
JMP CLEOL ; CLEAR TO END OF LINE
ZEROUT: RTS
; -----
; CLEAR
; -----
ZCLR: LDA ZBEGIN+ZMODE
AND #%00000001
BEQ ZEROUT ; NOT ENABLED
LDA ARG1+LO ; CHECK WHAT TO DO
BEQ CLR0 ; BOTTOM SCREEN
CMP #1
BEQ CLR1 ; TOP SCREEN
CMP #$FF
BNE ZEROUT ; INVALID
; UNSPLIT SCREEN & CLEAR IT
JSR NORL ; RESET TO FULL
JMP CLS ; & CLEAR IT
CLR0: LDA WTOP ; SET COUNT
STA LINCNT ; FOR "MORE"
JSR CLS ; CLEAR & HOME
LDA #$17 ; SET CURSOR @
STA CV ; BOTTOM OF SCREEN
JMP BASCAL
CLR1: LDA WTOP ; SAVE SCROLLING TOP
PHA
LDX #0 ; TOP OF SCREEN
STX WTOP
STA WBOTM ; MAKE BOTTOM OF TOP SCREEN
JSR CLS
LDA #$18 ; RESET TOP & BOTTOM
STA WBOTM
PLA
STA WTOP
STA CV ; SET CURSOR TO LAST LINE
DEC CV ; OF TOP SCREEN
JMP BASCAL
; -----
; INPUT
; -----
ZINPUT: LDA ARG1+LO
CMP #1 ; KEYBOARD?
BNE ZINPEX ; NO, INVALID
LDA WTOP ; RESET LINE COUNT
STA LINCNT
INC LINCNT ; just to save command line for later
LDA #0
; STA LENGTH ; SET LINE COUNT TO 0
STA CHRCNT
DEC NARGS
BEQ ZINP3 ; NO TIME LIMIT
LDA ARG2+LO ; GET DELAY WANTED
STA I+HI
LDA #0 ; SET FCN IF IS ONE
STA J+HI
STA J+LO
DEC NARGS
BEQ ZINP4 ; NO FCN
LDA ARG3+LO
STA J+LO
LDA ARG3+HI
STA J+HI
ZINP4: BIT ANYKEY ; CLEAR STROBE
ZINP0: LDA I+HI
STA I+LO ; RESET EA TIME THRU
ZINP1: LDX #10 ; .1 SEC
ZINP2: LDA #$40 ; .01 SEC
JSR MWAIT
DEX
BNE ZINP2
BIT KBD ; CHECK FOR KEYSTROKE
BMI ZINP3 ; GOT ONE
DEC I+LO
BNE ZINP1 ; SOME TIME LEFT, TRY AGAIN
; TIME OUT, CHECK IF THERE IS A FCN TO CALL
LDA J+LO ; FCN IN J IF THERE IS ONE
ORA J+HI
BEQ ZINPEX ; NO FCN, SEND 0 FOR FAILED
JSR INTCLL ; INTERNAL CALL
LDA VALUE+LO ; GET RESULTS
BNE ZINPEX ; ABORT
BEQ ZINP0 ; TRY AGAIN
ZINP3: JSR GETKEY ; OK, FIND WHICH CHAR WAS PRESSED
LDX #0
JMP PUTBYT ; RETURN CHAR
ZINPEX: JMP RET0 ; OOPS
INTCLL: LDA #>ZIRET ; SET ZRETURN TO RETURN HERE
STA PATCHI+HI
LDA #<ZIRET
STA PATCHI+LO
LDA I+HI ; SAVE VALUES FOR CALLING RTN
PHA
LDA J+HI
PHA
LDA J+LO
PHA
LDX OLDZSP+LO ; STUFF TAKEN FROM CALL.
LDA OLDZSP+HI
JSR PUSHXA
LDA ZPCL
JSR PUSHXA
LDX ZPCM
LDA ZPCH
JSR PUSHXA
; FORM QUAD ALIGNED ADDR FROM [ARG3]
LDA #0
ASL J+LO ; *4
ROL J+HI
ROL A
STA ZPCH
ASL J+LO
ROL J+HI
ROL ZPCH
LDA J+HI ; PICK UP NEW LOW BYTES
STA ZPCM
LDA J+LO
STA ZPCL
JSR VLDZPC
JSR NEXTPC ; FETCH # LOCALS TO PASS
STA J+LO ; SAVE HERE FOR COUNTING
STA J+HI ; AND HERE FOR LATER REFERENCE
BEQ INT2 ; SKIP IF NO LOCALS
LDA #0
STA I+LO ; ELSE INIT STORAGE INDEX
INT1: LDY I+LO
LDX LOCALS+LO,Y ; GET LSB OF LOCAL INTO [X]
LDA LOCALS+HI,Y ; AND MSB INTO [A]
JSR PUSHXA ; PUSH LOCAL IN [X/A] ONTO Z-STACK
JSR NEXTPC ; GET MSB OF NEW LOCAL
STA I+HI ; SAVE IT HERE
JSR NEXTPC ; NOW GET LSB
LDY I+LO ; RESTORE INDEX
STA LOCALS+LO,Y ; STORE LSB INTO [LOCALS]
LDA I+HI ; RETRIEVE MSB
STA LOCALS+HI,Y ; STORE IT INTO [LOCALS]
INY
INY ; UPDATE
STY I+LO ; THE STORAGE INDEX
DEC J+LO ; ANY MORE LOCALS?
BNE INT1 ; YES, KEEP LOOPING
INT2: LDX J+HI ; # OF LOCALS
TXA
JSR PUSHXA
LDA ZSP+LO
STA OLDZSP+LO
LDA ZSP+HI
STA OLDZSP+HI
JMP MLOOP ; GO DO FCN
; RETURN FROM FCN WILL COME HERE
ZIRET: LDA #>PUTVAL ; REPAIR ZRETURN
STA PATCHI+HI
LDA #<PUTVAL
STA PATCHI+LO
PLA ; GET RID OF RTS FROM ZRET
PLA
PLA ; RESTORE FOR CALLING RTN
STA J+LO
PLA
STA J+HI
PLA
STA I+HI
RTS ; GO BACK TO CALLER
;
;
MORE: DB "[MORE]"
MOREL EQU $-MORE
SLOTM: DB EOL
DB "Printer Slot 1-7: "
SLOTML EQU $-SLOTM
STRYM: DB "The story is loading ..."
STRYML EQU $-STRYM
END