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