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

528 lines
11 KiB
NASM

PAGE
SBTTL "--- MACHINE-DEPENDENT I/O: APPLE II ---"
; ----------------------------
; FETCH ASCII KEYCODE INTO [A]
; ----------------------------
; EXIT: ASCII IN [A] & [IOCHAR]
GETKEY: CLD
TXA ; SAVE [X] & [Y]
PHA
TYA
PHA
GKEY0: JSR RDKEY ;GET A CHAR
;CHECK TO MAKE SURE KEY IS VALID, ONLY ACCEPT IT IF IT IS
AND #$7F ;SCREEN OUT SHIFTS
CMP #EOL ;CHECK FOR GOOD (BAD) CHAR
BNE GK0
JMP OK
GK0: CMP #BACKSP
BNE GK1
JMP OK
;CHECK FOR "ARROWS", CONVERT FOR USE (EZIP)
;ALSO : CHANGE HIGH _LOW )@%^&*( TO ,-.0256789
GK1: LDX #ENDKEY ; GET LENGTH OF LIST
GK2: CMP HAVE,X ; CHECK AGAINST LIST OF UNWANTED KEYS
BEQ GK3 ; FOUND IT
DEX
BPL GK2 ; CHECK THSM ALL
BMI GK4 ; NOT FOUND, CONTINUE OTHER CHECKS
GK3: LDA WANT,X ; GET KEY TO USE INSTEAD
BNE OK ; JMP
GK4: CMP #SPACE ; NO CTRL CHARS ACCEPTABLE
BCC BADKEY ; IF HIGH SPACE, BAD
;
; 6/3/87 jdarnold -- please allow '+'
;
; CMP #$2B
; BEQ BADKEY
CMP #$3C
BCC OK
CMP #$3F
BEQ OK
MASK0: CMP #'z'+1 ;PICK OUT LETTERS NOW
BCS BADKEY ;IF LOW BAD
CMP #'a'
BCS OK ;IF LOW OK
CMP #'A'
BCC BADKEY
CMP #'Z'+1
BCC OK ;IF HIGH OK
BADKEY: JSR BEEP ;BAD KEY, GIVE WARNING NOISE
JMP GKEY0 ;TRY AGAIN
OK: STA IOCHAR ;HOLD ON TO IT
ADC RNUM1 ;FUTZ WITH RANDOM
STA RNUM1
EOR RNUM2
STA RNUM2
PLA ; RESTORE
TAY ; EVERYTHING
PLA
TAX
LDA IOCHAR ; GET CHAR INTO [A]
RTS ; AND RETURN IT
HAVE: DB $08,$15,$0B,$0A,$3C,$5F,$3E,$40,$25,$26,$5E
WANT: DB $0B,$07,$0E,$0D,$2C,$2D,$2E,$32,$35,$37,$0E
ENDKEY EQU $-WANT-1
; -----------------
; PRINT CHAR IN [A]
; -----------------
CHAR: STA IOCHAR ; SAVE HERE
TXA ; SAVE [X] AND [Y]
PHA
TYA
PHA
LDA IOCHAR
CHAR1: JSR MCOUT
PLA ; RESTORE [X] AND [Y]
TAY
PLA
TAX
RTS
; ---------------------
; FETCH A LINE OF INPUT
; ---------------------
; ENTRY: ABS ADDR OF READ BUFFER IN [ARG1]
; EXIT: # CHARS READ IN [A]
INPUT: JSR LINOUT ; FLUSH [LBUFF]
LDA #0 ; RESET LINE COUNT
STA LENGTH
STA CHRCNT
LDY WTOP
STY LINCNT ; RESET LINE COUNT
DEC NARGS ; CHECK IF TIME LIMIT (EZIP)
DEC NARGS
BEQ INP2 ; NO
LDA ARG3+LO ; GET DELAY WANTED
STA I+HI
LDA #0
STA J+HI
STA J+LO
DEC NARGS ; IS THERE A FCN?
BEQ INP5 ; NO
LDA ARG4+LO ; YES, SET IT
STA J+LO
LDA ARG4+HI
STA J+HI
INP5: BIT ANYKEY ; CLEAR STROBE
INP4: LDA I+HI
STA I+LO
INP0: LDX #10 ; .1 SEC
INP1: LDA #$40 ; .O1 SEC
JSR MWAIT
DEX
BNE INP1
BIT KBD ; CHECK FOR KEYSTROKE
BMI INP2 ; OK, HE'S THERE, CONTINUE
DEC I+LO ; 10TH'S OF SECONDS TO WAIT
BNE INP0 ; SOME TIME LEFT
;TIME OUT, CHECK FOR A FCN
LDA J+LO ; IS THERE A FCN
ORA J+HI
BNE INP3
JMP LEXBAD ; NO FCN, LEAVE WITH NOTHING
INP3: JSR INTCLL ; INTERNALLY CALL THE FCN
LDA VALUE+LO ; CHECK RESULTS
BEQ INP4 ; ELSE TRY AGAIN (END EZIP)
JMP LEXBAD ; ELSE ABORT
INP2: LDY #0 ; AND CHAR COUNT
INLOOP: JSR GETKEY ; GET ASCII INTO [A] AND [IOCHAR]
CMP #14
BEQ CBAD ; CLEAR OFF ARROWS (EZIP)
CMP #7
BEQ CBAD
CMP #EOL ; EOL?
BEQ ENDLIN ; LINE DONE IF SO
CMP #BACKSP ; BACKSPACE?
BEQ BACKUP ; SPECIAL HANDLING
CMP #11 ; LEFT ARROW (BACKSPACE)?
BEQ BACKUP
STA LBUFF,Y ; ELSE ADD CHAR TO INPUT BUFFER
INY ; NEXT POSITION IN LINE
SHOWIT: LDX INVFLG
BPL SHOW1 ; INVERSE
ORA #%10000000 ; ELSE MAKE IT NORMAL
SHOW1: JSR CHAR ; SEND TO SCREEN
CPY #77 ; ALL THE CHARS ALLOWED?
BCC INLOOP ; NO, GET ANOTHER CHAR
; HANDLE LINE OVERFLOW
NOMORE: JSR GETKEY
CMP #EOL ; IF EOL,
BEQ ENDLIN ; WRAP UP THE LINE
CMP #BACKSP ; BACKSPACE
BEQ BACKUP ; IS OKAY TOO
CMP #11 ; HIGH -
BEQ BACKUP
JSR BEEP ; ELSE COMPLAIN
JMP NOMORE ; AND INSIST
; HANDLE BACKSPACE
BACKUP: DEY ; BACK UP THE POINTER
BMI BBAD
LDA #$08 ;BACKSP STRANGE SO DO 082008
JSR CHAR
LDA #$A0
JSR CHAR
LDA #$08
BNE SHOWIT ;JMP
BBAD: LDY #0 ; RESET POINTER
CBAD: JSR BEEP ; ELSE SCREAM WITH PAIN
JMP INLOOP ; AND WAIT FOR SOMETHING BETTER
; HANDLE END OF LINE
ENDLIN: LDA #$8D ; MUST BE THERE FOR PRINTER
STA LBUFF,Y ; SHIP EOL TO BUFFER
INY ; UPDATE INDEX
STY LINLEN ; SAVE HERE FOR "READ"
STY PRLEN ; AND HERE FOR "PPRINT"
JSR CHAR ; AND SEND EOL TO SCREEN
; MOVE [LBUFF] TO [ARG1] W/LC CONVERSION
LEX0: LDA LBUFF-1,Y ; GET A CHAR FROM [LBUFF]
CMP #'A' ; IF CHAR IS ALPHA,
BCC LEX2 ; CONVERT TO LOWER CASE
CMP #'Z'+1
BCS LEX2
ADC #$20
LEX2: AND #$7F
STA (RDTBL1),Y ; MOVE CHAR TO INPUT BUFFER AT [ARG1]
DEY ; LOOP TILL
BNE LEX0 ; ALL CHARS MOVED
JSR PPRINT ; SCRIPT [LBUFF] IF ENABLED
LDA LINLEN ; RESTORE # CHARS
RTS ; INTO [A]
LEXBAD: LDA #0 ; TIME OUT OCCURRED (EZIP)
RTS ; ZERO CHARS OBTAINED
; -----------------------
; DIRECT PRINT LINE [X/A]
; -----------------------
; ENTRY: STRING ADDRESS IN [X/A] (LSB/MSB)
; STRING LENGTH IN [Y]
DLINE: STX STRING+LO ; DROP STRING ADDRESS
STA STRING+HI ; INTO DUMMY BYTES
STY J ; COUNTER
LDX #0 ; INIT CHAR-FETCH INDEX
DOUT: DB $BD ; 6502 "LDA nnnn,X" OPCODE
STRING: DW $0000 ; DUMMY OPERAND BYTES
LDY INVFLG ; INVERSE?
BPL DOUT1 ; YES
ORA #%10000000 ; ELSE MAKE IT NORMAL
DOUT1: JSR CHAR
INX
DEC J ; LOOP TILL
BNE DOUT ; OUT OF CHARS
RTS
; -----------------------
; SEND [LBUFF] TO PRINTER
; -----------------------
; ENTRY: LENTH OF LINE IN [PRLEN]
PLEAV: RTS
PPRINT: LDA SCRIPT ; SCRIPTING INTERNALLY ENABLED?
BEQ PLEAV ; NO, SCRAM IMMEDIATELY
LDA SCRIPTF ; SCRIPTING ON?
BEQ PLEAV ; NO, EXIT
LDA CSW+LO ;SAVE NORMAL OUTPUT HOOK
PHA
LDA CSW+HI
PHA
LDA CHZ ;SAVE CURRENT CURSOR POSITION
PHA
LDA EHZ ; IF 80 COL
PHA
LDA ALTCSW+LO ;LOAD SCRIPTING HOOK
STA CSW+LO
LDA ALTCSW+HI
STA CSW+HI
LDA #0
STA CHZ
STA EHZ
LDY #0
PP5: LDA LBUFF,Y ;GET A CHAR TO SEND OUT
JSR MCOUT
INY
DEC PRLEN ;LINE COUNT
BNE PP5 ;PRINT WHOLE LINE
;ALL DONE, RESET TO NORMAL AND LEAVE
PLA ;RETRIEVE CURRENT CURSOR POSITION
STA EHZ
PLA
STA CHZ
PLA
STA CSW+HI
PLA
STA CSW+LO
RTS
PSTAT: DB 0 ;SET TO CLEAR WHEN BOOT,
;I PUT IT HERE SO RESTART WON'T ALTER
ALTCSW: DB 0,0 ;(WORD) PRINTER COUT
; FIRST TIME USING PRINTER, INITIALIZE IT
PCHK: LDX #<SLOTM ;ASK WHICH SLOT PRINTER IS IN
LDA #>SLOTM
LDY #SLOTML
JSR DLINE
LDA #0 ;ACTUALLY SLOT 1
JSR DODEF ;DISPLAY IT AS DEFAULT
JSR GETKEY
CMP #EOL
BEQ PC1 ;USE DEFAULT
SEC
SBC #'0'
CMP #8 ;1-7
BCS PCHK ;OOPS
BCC PC2 ;SKIP AROUND DEFAULT
PC1: LDA #1 ;WHICH IS 1
PC2: CLC
ADC #$C0
STA ALTCSW+HI
JSR PISSER ;SEND HIGH CRLOW TO SCREEN FOR NEATNESS
INC PSTAT ;SET TO ON
LDA CSW+LO ;SAVE NORMAL OUTPUT HOOK
PHA
LDA CSW+HI
PHA
LDA ALTCSW+LO ;LOAD SCRIPTING HOOK
STA CSW+LO
LDA ALTCSW+HI
STA CSW+HI
LDA #$89 ; OUTPUT PRINTER SETUP SEQUENCE
JSR MCOUT ; START WITH COMMAND CHAR HIGH CTRL-ILOW
LDA #$B8 ; 8 (80 COL WIDE)
JSR MCOUT
LDA #$B0 ; 0
JSR MCOUT
LDA #$CE ; N (LF AFTER CR)
JSR MCOUT
LDA CSW+LO ; SAVE REAL PRINTER OUTPUT
STA ALTCSW+LO ; LOC. FOR NEXT TIME
LDA CSW+HI
STA ALTCSW+HI
PLA ; RESET NORMAL OUTPUT
STA CSW+HI
PLA
STA CSW+LO
; PRINTER SETUP ON THE IIc COPIES THE ROM INTERRUPT VECTOR
; FROM $FFFE IN ROM TO BOTH MAIN & AUX. RAM PAGES @ $FFFE
; THAT PAGE IN MAIN RAM CONTAINS THE MONITOR STUFF SO IS OK
; BUT THAT PAGE IN AUX. RAM IS BEING USED TO CONTAIN A PAGE
; OF GAME CODE. THE FOLLOWING RTN CAUSES THE NEXT USE OF THAT
; PAGE TO READ IT IN NEW FROM THE DISK SO THAT THE VALUES
; WILL ALL BE CORRECT. (6/14/85 Le)
;
; THAT PAGE IS SECTOR $4F IN RAMDSK
; AND IT IS NOT USED
; ASK 85
RTS
; ------------
; SPLIT SCREEN
; ------------
; SPLIT SCREEN AT LINE [ARG1]
; DISABLE SPLIT IF [ARG1] = 0
; IGNORE IF SPLIT ALREADY ENABLED OR [ARG1] LOW = 20
ZSPLIT: LDA ZBEGIN+ZMODE
AND #%00100000 ;CHECK IF ENABLED (EZIP)
BEQ ZSPOUT ;NOT, LEAVE
LDA ARG1+LO ;GET # OF LINES FOR SCREEN
BEQ NORL ;IF 0 THEN RESTORE SCREEN
CMP #24 ;IS SPLIT REALLY = WHOLE SCREEN
BCS ZSPOUT ;YES, IGNORE
LDX SPSTAT ;CHECK IF ALREADY ENABLED
BEQ ZSPL1 ; NO
LDA WTOP ; BOTTOM OF SCREEN 1
SEC
SBC ARG1+LO ; COMPARE NEW SIZE, IF EXISTING SIZE
BCS ZSPL2 ; LOW = DON'T CLEAR, SCREEN SHRINKING
ZSPL1: LDA ARG1+LO ; CLEAR LINES OF NEW, OR BEING ADDED
STA SPSTAT ;NON ZERO = SCREEN IS SPLIT
ZSPL2: LDA #$18 ;RESTORE BOTTOM FOR SCROLL
STA WBOTM
LDA ARG1+LO ; GET BOTTOM OF SPLIT SCREEN (AGAIN)
STA WTOP ;MAKE THAT THE TOP OF THE SECOND SCREEN
CMP LINCNT ; IS SCROLLING SCREEN NOW LESS THAN LINCNT?
BCC ZSPL3 ; NO
STA LINCNT ; YES
ZSPL3: LDA #0
STA CHZ
STA EHZ
LDA #$17
STA CV ;RESTORE CURSOR AFTER HOME CALL
JSR BASCAL ;HIGH CRLOW TO MAKE CV WORK
ZSPOUT: RTS
NORL: ;RESTORE SCREEN TO FULL SCREEN MODE
LDA #0 ;PUT CURSOR AT TOP OF SCREEN
STA WTOP ;RESTORE FULL SCREEN ALIGNMENT
STA LINCNT
STA SPSTAT ;FLAG NOT SPLIT
RTS
; ------
; SCREEN
; ------
; GO TO TOP WINDOW (TOP OF SCREEN) IF [A] = 1
; GO TO BOTTOM OF SCREEN IF [A] = 0
; IGNORE IF SPLIT NOT ENABLED OR [A] HIGH LOW 0 OR 1
; FLAG SPLITF WILL BE SET FOR OUTPUT TO DETERMINE
; IF AND WHICH WINDOW TO DISPLAY TO
; (0=BOTTOM 1=TOP)
ZSCRN: LDA ZBEGIN+ZMODE
AND #%00000001 ;CHECK IF ENABLED (EZIP)
BEQ ZSPOUT ;NOT, LEAVE
LDA SPSTAT ;CHECK IF SCREEN IS SPLIT
BEQ ZSPOUT ;NO, SO JUST LEAVE
LDA ARG1+LO ;CHECK WHICH WINDOW
BNE SCRN1 ;TOP SCREEN
LDA #$FF ; SCROLLING SCREEN SO
STA SCRIPT ; ALLOW SCRIPTING
LDA #0
STA SPLITF ;SET FLAG TO SPLIT SCREEN (0)
LDA LENGTH ; get saved cursor horizontal
STA EHZ ; and use it
STA CHZ ; and use it
LDA #$17 ; assume last line (?)
STA CV
JMP SCRNP ;JMP TO HIGH CRLOW RTN
SCRN1: CMP #01
BNE ZSPOUT ;INVALID SCREEN ID
STA SPLITF ;SET FLAG TO UNSCROLLING SCREEN (1)
LDA #0
STA SCRIPT ; SET SCRIPTNG OFF, NOT ALLOWED THIS SCREEN
STA CHZ
STA EHZ
STA CV ;ALIGN AT TOP OF SCREEN
SCRNP: JMP BASCAL ;SET CURSOR (+ LEAVE)
; ------------
; CLEAR SCREEN
; ------------
CLS EQU HOME ;CLEAR & HOME CURSOR
PISSER: LDA #$8D
JMP MCOUT
; -----
; SOUND
; -----
; ARG1 = BOOP (2) BEEP (1) ALL OTHERS INVALID
; (EZIP)
ZSOUND: LDA ZBEGIN+ZMODE
AND #%00100000
BEQ ZSOEX ; NOT ENABLED
LDX ARG1+LO ; GET SOUND WANTED
DEX
BEQ BEEP
DEX
BNE ZSOEX ; INVALID
LDY #$FF ; DURATION ($C0 = .1 SEC)
BOOP: LDA #$10 ; TONE ($0C = 1 KHZ)
JSR MWAIT
LDA SPKR ; TOGGLE SPEAKER
DEY
BNE BOOP
ZSOEX: RTS
BEEP: JMP BELL ; QUICK BEEP ( 1KHZ @ .1 SEC)
; ------------------------
; CHECK IF 128 K OF MEMORY
; ------------------------
; EXIT: CARRY SET IF NOT 128K, CLEAR IF THERE IS
MEMCHK: LDA #0 ; START @ 0
STA TSTVAL
MLOOP1: LDY #0
MLOOP2: STA $1000,Y ; WRITE [TSTVAL] TO
INY ; MAIN MEMORY
BNE MLOOP2
INC TSTVAL
LDA TSTVAL
STA WRTBNK+AUX ; SET TO AUX MEMORY
MLOOP3: STA $1000,Y ; WRITE NEXT VALUE
INY ; TO AUX MEMOYR
BNE MLOOP3
STA WRTBNK+MAIN ; SET TO MAIN MEMORY
DEC TSTVAL ; RESET TO [TSTVAL] WRITTEN TO MAIN
MLOOP4: LDA $1000,Y ; CHECK IF WHAT WRITTEN
CMP TSTVAL ; 1ST TO MAIN MEM PG $10
BNE NO128 ; IS STILL THERE
INY
BNE MLOOP4
INC TSTVAL
STA RDBNK+AUX ; & SET TO AUX MEMORY
MLOOP5: LDA $1000,Y ; & SEE IF WHAT WROTE
CMP TSTVAL ; TO AUX MEM IS STILL THERE
BNE NO128
INY
BNE MLOOP5
STA RDBNK+MAIN ; RESET TO MAIN MEM
LDA TSTVAL ; LAST THING WAS INC'D
BNE MLOOP1 ; GO TRY W/ NEXT SET OF VALUES, DO 0,1 -LOW FF,O
CLC
RTS ; SIGNAL OK
NO128: STA RDBNK+MAIN ; RESET TO MAIN MEM
SEC
RTS ; OOPS, ONLY 64K
END