Files
erkyrath.infocom-zcode-terps/64/zip/machine.src
Andrew Plotkin b642da811e Initial commit.
2023-11-16 18:19:54 -05:00

612 lines
12 KiB
Plaintext

PAGE
SBTTL "--- MACHINE-DEPENDENT I/O: CBM64 ---"
; ----------------------------
; FETCH ASCII KEYCODE INTO [A]
; ----------------------------
; EXIT: ASCII IN [A] & [IOCHAR]
CYCLE EQU $E0 ; SHORT BLINK CYCLE
GETKEY: TXA ; SAVE [X] & [Y]
PHA
TYA
PHA
GKEY0: LDX #$FF
STX CURSOR ; FORCE THE CURSOR "ON"
INX ; = 0
STX BLINK+LO ; RESET THE BLINK COUNTER
STX BLINK+HI ; FOR A LONG DELAY
SEC ; GET CURSOR POSITION
JSR PLOT ; [Y]=XPOS, [X]=YPOS
TXA ; CALC SPRITE Y-POS
ASL A
ASL A
ASL A
CLC
ADC #57
STA SP0Y
TYA ; GET X-POS INTO [A]
CMP #40 ; STRIP OFF
BCC NOLOG ; LOGICAL LINE OFFSET
SBC #40
NOLOG: LDX #0
CMP #29 ; IF X-POS < 29
BCC CURX ; MSB OF SPRITE POS IS ZERO
INX ; ELSE SET BIT 0
CURX: STX MSIGX ; OF X-POS MSB
ASL A ; CALC LSB OF SPRITE X-POS
ASL A
ASL A
CLC
ADC #24
STA SP0X
GKEY1: JSR GETIN ; GET A KEY
TAX ; SAVE HERE
INC BLINK+LO ; TIME TO BLINK YET?
BNE NOBLIN ; NOT TILL BOTH BLINK TIMERS
INC BLINK+HI ; ARE ZERO
BNE NOBLIN
LDA #CYCLE ; RESET MSB OF BLINK COUNTER
STA BLINK+HI ; FOR SHORT BLINK INTERVAL
LDA CURSOR ; FLIP THE CURSOR
EOR #$FF ; SHAPE
STA CURSOR ; AND UPDATE IT
NOBLIN: TXA ; KEY BEING PRESSED?
BEQ GKEY1 ; NOT IF CODE WAS ZERO
; CONVERT & MASK KEYCODE IN [A]
CMP #'A' ; CONVERT UNSHIFTED ALPHA
BCC MASK ; TO ASCII LOWER CASE
CMP #'Z'+1
BCS MASK
ADC #$20
MASK: AND #%01111111 ; SCREEN OUT SHIFTS
CMP #EOL ; EOL?
BEQ TICK
CMP #BACKSP ; BACKSPACE?
BEQ TICK
CMP #SPACE ; ANYTHING ELSE < "SPACE"
BCC BADKEY ; IS BAD
CMP #'<' ; CHANGE "<"
BNE MASK0 ; TO ","
LDA #','
BNE TICK
MASK0: CMP #'>' ; CHANGE ">"
BNE MASK1 ; TO "."
LDA #'.'
BNE TICK
MASK1: CMP #'z'+1 ; PASS L-C ALPHA
BCS BADKEY
CMP #'a'
BCS TICK
CMP #'Z'+1 ; PASS U-C ALPHA
BCC TICK ; AND OTHER ASCII CHARS
BADKEY: JSR BOOP ; REJECT BAD KEYPRESS
JMP GKEY0 ; AND TRY AGAIN
; "CLICK" THE KEY
TICK: STA IOCHAR ; SAVE KEYCODE HERE
LDA #30
STA FRELO1 ; FREQ LSB
LDA #134
STA FREHI1 ; FREQ MSB
LDA #0
TAY ; SET UP CLICK DELAY
STA SUREL1 ; ZERO SUSTAIN
LDA #%10001111
STA SIGVOL ; FULL VOLUME, VOICE #3 OFF
LDA #%00010001
STA VCREG1 ; ACTIVATE TRIANGLE WAVE
CLICK: DEY ; [Y] = 0 ON ENTRY
BNE CLICK
STY VCREG1 ; STOP THE SOUND
LDA #%10000000 ; ZERO VOLUME
STA SIGVOL ; WITH VOICE #3 OFF
PLA ; RESTORE [X] & [Y]
TAY
PLA
TAX
LDA IOCHAR ; RESTORE CODE INTO [A]
RTS
; -------------------------
; OUTPUT AN ASCII CHARACTER
; -------------------------
LETTER: CMP #'a' ; LOWER-CASE?
BCC LET0 ; NO, CONTINUE
CMP #'z'+1
BCS LET1
AND #%01011111 ; ELSE MASK FOR LOWER-CASE
JMP CHROUT
LET0: CMP #'A' ; UPPER-CASE?
BCC LET1
CMP #'Z'+1
BCS LET1
ORA #%00100000 ; MAKE UPPER
JMP CHROUT
LET1: CMP #$5F ; SB _
BNE LET2
LDA #$AF ; MAKE IT THAT
BNE LETEX
LET2: CMP #$7C ; SB |
BNE LETEX
LDA #$7D ; MAKE IT THAT
LETEX: JMP CHROUT
; -----------------
; PRINT CHAR IN [A]
; -----------------
CHAR: STA IOCHAR ; SAVE HERE
TXA ; SAVE [X] AND [Y]
PHA
TYA
PHA
SEC ; GET CURSOR X- AND Y-POS
JSR PLOT ; INTO [Y] AND [X], RESPECTIVELY
TYA
CMP #40 ; STRIP OFF THE
BCC CHKEOL ; LOGICAL LINE OFFSET
SBC #40 ; UPDATE [Y] IF NECESSARY
TAY
CHKEOL: LDA IOCHAR ; RESTORE CHAR
CMP #EOL ; IS IT EOL?
BEQ OUTEOL ; YES, SPECIAL HANDLING
; HANDLE A NON-EOL CHAR
CPX #YSIZE-1 ; ON LAST SCREEN LINE?
BCC NOSCRL ; NO, NO SCROLL NEEDED
CPY #XSIZE ; LAST CHAR ON LINE?
BCC NOSCRL ; NO, DON'T SCROLL
; SCROLL THE SCREEN
DOSCRL: DEX ; PUSH CURSOR UP ONE LINE
CLC
JSR PLOT ; RESET THE CURSOR
LDX SLINE ; GET CURRENT SCROLL LINE
SRL0: CPX #YSIZE
BEQ SRL2 ; SCROLL DONE
LDA LOLINE,X ; GET ADDR OF DEST LINE
STA LTO+LO ; INTO [LTO]
LDA HILINE,X
STA LTO+HI
INX
LDA LOLINE,X ; GET ADDR OF SOURCE LINE
STA LFROM+LO ; INTO [LFROM]
LDA HILINE,X
STA LFROM+HI
LDY #XSIZE
SRL1: LDA (LFROM),Y ; MOVE SOURCE LINE
STA (LTO),Y ; TO DEST LINE
DEY
BPL SRL1
BMI SRL0 ; LOOP TILL [X] = YSIZE
SRL2: LDX #XSIZE
LDA #SPACE
SRL3: STA SCREEN+960,X ; CLEAR LAST LINE
DEX ; OF SCREEN RAM
BPL SRL3
NOSCRL: LDA IOCHAR ; RESTORE CHAR
JSR LETTER ; OFF TO THE SCREEN!
PLA ; RESTORE [X] AND [Y]
TAY
PLA
TAX
RTS
; HANDLE EOL
OUTEOL: CPX #YSIZE-1 ; LAST SCREEN LINE?
BCC NOSCRL ; NO, DON'T SCROLL
BCS DOSCRL ; ELSE SCROLL
; ---------------------
; FETCH A LINE OF INPUT
; ---------------------
; ENTRY: ABS ADDR OF READ BUFFER IN [ARG1]
; EXIT: # CHARS READ IN [A]
INPUT: JSR LINOUT ; FLUSH [LBUFF]
JSR CURSON ; ACTIVATE CURSOR, CLEAR KEY QUEUE
LDY #0
STY LINCNT ; RESET LINE COUNT
INLOOP: JSR GETKEY ; GET ASCII INTO [A] AND [IOCHAR]
CMP #EOL ; EOL?
BEQ ENDLIN ; LINE DONE IF SO
CMP #BACKSP ; BACKSPACE?
BEQ BACKUP ; SPECIAL HANDLING
STA LBUFF,Y ; ELSE ADD CHAR TO INPUT BUFFER
INY ; NEXT POSITION IN LINE
SHOWIT: JSR CHAR ; SEND TO SCREEN
CPY #77 ; 2 SCREEN LINES FULL?
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
JSR BOOP ; ELSE COMPLAIN
JMP NOMORE ; AND INSIST
; HANDLE BACKSPACE
BACKUP: DEY ; BACK UP THE POINTER
BPL SHOWIT ; SEND BS IF NOT START OF LINE
JSR BOOP ; ELSE SCREAM WITH PAIN
LDY #0 ; RESET POINTER
BEQ INLOOP ; AND WAIT FOR SOMETHING BETTER
; HANDLE END OF LINE
ENDLIN: STA LBUFF,Y ; SHIP EOL TO BUFFER
INY ; UPDATE INDEX
STY LINLEN ; SAVE HERE FOR "READ"
STY PRLEN ; AND HERE FOR "PPRINT"
LDX #0
STX SPENA ; DISABLE CURSOR DMA
JSR CHAR ; AND SEND EOL TO SCREEN
; MOVE [LBUFF] TO [ARG1] W/LC CONVERSION
LEX1: LDA LBUFF-1,Y ; GET A CHAR FROM [LBUFF]
AND #%01111111 ; MAKE POSITIVE
CMP #'A' ; IF CHAR IS ALPHA,
BCC LEX2 ; CONVERT TO LOWER CASE
CMP #'Z'+1
BCS LEX2
ADC #$20
LEX2: STA (ARG1),Y ; MOVE CHAR TO INPUT BUFFER AT [ARG1]
DEY ; LOOP TILL
BNE LEX1 ; ALL CHARS MOVED ("BNE" 8/14/85 BM)
JSR PPRINT ; SCRIPT [LBUFF] IF ENABLED
LDA LINLEN ; RESTORE # CHARS
RTS ; INTO [A]
; -----------------------
; 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
LDX #0 ; INIT CHAR-FETCH INDEX
DOUT: DB $BD ; 6502 "LDA nnnn,X" OPCODE
STRING: DW $0000 ; DUMMY OPERAND BYTES
JSR CHAR
INX
DEY ; LOOP TILL
BNE DOUT ; OUT OF CHARS
RTS
; -----------------------
; SEND [LBUFF] TO PRINTER
; -----------------------
; ENTRY: LENTH OF LINE IN [PRLEN]
; NOW WITH IMPROVED ERROR PROTECTION! (BM 11/24/84)
SFLAG: DB 0 ; PREVIOUS SCRIPT MODE (BM 5/14/85)
PPRINT: LDA SCRIPT ; SCRIPTING INTERNALLY ENABLED?
BEQ PEX ; NO, SCRAM IMMEDIATELY
LDA ZBEGIN+ZSCRIP+1 ; CHECK SCRIPT FLAG
AND #%00000001 ; SCRIPTING ON?
BEQ PP3 ; NO, CHECK FOR "UNSCRIPT"
LDA PSTAT ; CHECK PRINTER STATUS
BMI PEX ; CAN'T OPEN IF NEGATIVE
BNE PP1 ; ALREADY OPEN, SCRIPT THE LINE
; OPEN THE PRINTER FOR OUTPUT
LDA FAST ; FAST-READ ENGAGED?
BEQ PP0 ; NO, IGNORE
JSR FOFF ; ELSE DISENGAGE
LDA #8
JSR DOPEN ; AND RESET THE DRIVE
PP0: LDX #0
STX FAST ; BYE, FAST DRIVE!
INX ; = 1
STX PSTAT ; SET STATUS TO "PRINTER OPENED" (1)
LDA #4 ; LOGICAL FILE #4
TAX ; DEVICE #4
LDY #7 ; ALLOW UPPER/LOWER CASE
JSR SETLFS ; SET UP LOGICAL FILE
BCS PPERR ; ERROR IF CARRY SET
LDA #0
JSR SETNAM ; NO FILENAME REQUIRED
BCS PPERR ; ERROR IF CARRY SET
JSR OPEN ; OPEN THE CHANNEL
BCC PP1 ; OPEN OKAY IF CARRY CLEAR
PPERR: LDA #$FF ; ELSE SET PRINTER STATUS
STA PSTAT ; TO "CAN'T OPEN"
BNE PP5 ; AND SIMULATE AN "UNSCRIPT"
PP1: LDX #4 ; SET PRINTER CHANNEL
JSR CHKOUT ; TO "OUTPUT"
BCS PPERR ; ERROR IF CARRY SET
LDY #0 ; INIT INDEX
PP2: LDA LBUFF,Y
JSR LETTER
BCS PPERR ; ERROR IF CARRY SET
INY
DEC PRLEN
BNE PP2
BEQ PEX ; RESET & RETURN
; CHECK FOR "UNSCRIPT"
PP3: LDA PSTAT ; CHECK PRINTER STATUS
BEQ PEX ; EXIT IF PRINTER WAS OFF
BMI PEX ; OR UNOPENABLE
PCLOSE: LDA #0 ; RESET PRINTER STATUS FLAG
STA PSTAT ; TO "CLOSED"
; ENTRY FOR PRINTER ERROR
PP5: LDA #4
JSR CLOSE ; CLOSE THE PRINTER CHANNEL
LDA FAST ; FAST-READ AVAILABLE?
BEQ PEX ; NO, EXIT
LDA #8 ; ELSE
JSR DOPEN ; RESET BOOT DRIVE
JMP FINIT ; RE-ENGAGE FAST-READ & RETURN
PEX: JMP CLRCHN
; ------------
; SPLIT SCREEN
; ------------
; SPLIT SCREEN AT LINE [ARG1]
; DISABLE SPLIT IF [ARG1] = 0
; IGNORE IF SPLIT ALREADY ENABLED OR [ARG1] >= 20
ZSPLIT: LDX ARG1+LO ; IF [ARG1] = 0,
BEQ OFFSPL ; TURN OFF SPLIT SCREEN
LDA SPSTAT ; SPLIT ALREADY ENABLED?
BNE SPLEX ; IGNORE REQUEST IF SO
CPX #20 ; IF [ARG1] >= 20,
BCS SPLEX ; IGNORE
INX
STX SLINE ; ELSE SET NEW SPLIT LINE
STX SPSTAT ; SET "SPLIT ENABLED" FLAG
SPL0: LDA LOLINE,X ; MAKE [LFROM] POINT TO
STA LFROM+LO ; LINE [X] IN WINDOW
LDA HILINE,X
STA LFROM+HI
LDY #XSIZE ; CLEAR LINE [X]
LDA #SPACE
SPL1: STA (LFROM),Y
DEY
BPL SPL1
DEX ; DONE ALL LINES?
BNE SPL0 ; LOOP TILL WINDOW CLEARED
STX LINCNT ; RESET LINE COUNT TO ZERO
SPCALC: LDA #YSIZE-1 ; CALCULATE # LINES TO SCROLL
SEC ; BEFORE "MORE" APPEARS:
SBC SLINE ; LMAX = YSIZE-SLINE-1
STA LMAX
DEC LMAX
SPLEX: RTS
; --------------------
; DISABLE SPLIT SCREEN
; --------------------
OFFSPL: JSR TOBOT
SPLOFF: LDX #1
STX SLINE ; SPLIT AT LINE 1
DEX ; = 0
STX SPSTAT ; TURN OFF STATUS FLAG
STX LINCNT ; RESET LINE COUNT
LDA #21
STA LMAX ; SET MAXIMUM LINE SCROLL
RTS
; ------
; SCREEN
; ------
; GO TO TOP WINDOW IF [A] = 0
; GO TO BOTTOM IF [A] = 1
; IGNORE IF SPLIT NOT ENABLED OR [A] <> 0 OR 1
ZSCRN: LDA SPSTAT ; IF SPLIT NOT ENABLED,
BEQ SPLEX ; IGNORE REQUEST
LDA ARG1+LO ; IF [ARG1] = 0,
ORA ARG1+HI
BEQ TOBOT ; GO TO BOTTOM WINDOW
CMP #1 ; IF [ARG1] <> 1,
BNE SPLEX ; IGNORE THE REQUEST
; SET TO TOP WINDOW
TOTOP: LDX #21 ; TEMPORARILY RESET
STX LMAX ; [LMAX] TO KILL "MORE"
LDX #1 ; Y-POS = 1
BNE DOSCRN
; SET TO BOTTOM WINDOW
TOBOT: JSR SPCALC ; RE-CALC [LMAX]
LDX #23 ; Y-POS = 23
DOSCRN: LDY #0 ; X-POS = 0
STY LINCNT ; RESET LINE COUNT
CLC
JSR PLOT ; SET CURSOR TO X=[Y], Y=[X]
JMP NEWLOG ; RESET LINE TABLE & RETURN
; ---------
; RAZZ USER
; ---------
BOOP: LDA #$00
STA FRELO1 ; FREQ LSB
LDA #$05
STA FREHI1 ; FREQ MSB
LDA #%11110000
STA SUREL1 ; FULL SUSTAIN
LDA #%10001111
STA SIGVOL ; FULL VOLUME
LDA #%01000001
STA VCREG1 ; START PULSE
LDA #252 ; WAIT 4 JIFFIES
STA TIME
RAZZ: LDA TIME
BNE RAZZ
STA VCREG1 ; STOP PULSE
LDA #%10000000
STA SIGVOL ; VOLUME OFF
RTS
; ------------------------
; CLEAR SCREEN & COLOR RAM
; ------------------------
CLS: LDA #HIGH SCREEN ; POINT [I] TO
STA I+HI ; SCREEN RAM
LDA #HIGH COLRAM ; POINT [J] TO
STA J+HI ; COLOR RAM
LDY #0 ; RESET PAGE INDEX
STY I+LO ; BOTH RAMS START
STY J+LO ; ON PAGE BOUNDARIES
STY SPENA ; MAKE SURE CURSOR IS DEAD!
LDX #4 ; CLEAR 4 PAGES
CLS0: LDA #SPACE ; SPACE CHAR
STA (I),Y ; FOR SCREEN
LDA #1 ; "WHITE" CODE
STA (J),Y ; FOR COLOR RAM
INY
BNE CLS0
INC I+HI ; POINT TO
INC J+HI ; NEXT PAGE
DEX ; 4 PAGES DONE?
BNE CLS0 ; LOOP TILL EMPTY
LDA #13 ; RESET THE
STA SPT0 ; SPRITE RAM POINTER
JSR TOTOP ; SET CURSOR TO (0,1)
JSR SPLOFF ; DISABLE SPLIT SCREEN
SEI
LDA #LOW DORTI ; POINT THE SYSTEM NMI VECTOR
STA NMINV+LO ; TO A SIMPLE "RTI" INSTRUCTION
LDA #HIGH DORTI ; TO DISABLE THE STOP/RESTORE EXIT
STA NMINV+HI
CLI
; FALL THROUGH ...
; ----------------------------
; RESET THE LOGICAL LINE TABLE
; ----------------------------
NEWLOG: LDX #24
NLG0: LDA HILINE,X ; GET MSB OF LINE ADDRESS
ORA #%10000000 ; SET THE HIGH BIT
STA LDTB1,X ; STORE IN THE LINE TABLE
DEX
BPL NLG0
RTS
DORTI: RTI ; RTI INSTRUCTION FOR NMI
; -------------------
; LINE ADDRESS TABLES
; -------------------
LOLINE: DB $00,$28,$50,$78,$A0,$C8,$F0,$18
DB $40,$68,$90,$B8,$E0,$08,$30,$58
DB $80,$A8,$D0,$F8,$20,$48,$70,$98
DB $C0
HILINE: DB $04,$04,$04,$04,$04,$04,$04,$05
DB $05,$05,$05,$05,$05,$06,$06,$06
DB $06,$06,$06,$06,$07,$07,$07,$07
DB $07
END