PAGE SBTTL "--- MACHINE-DEPENDENT I/O: ATARI ---" ; ---------------------------- ; FETCH ASCII KEYCODE INTO [A] ; ---------------------------- ; EXIT: ASCII IN [A] & [IOCHAR] BADKEY: JSR BOOP JMP GKEY0 GETKEY: CLD TXA ; SAVE [X] & [Y] PHA TYA PHA GKEY0: LDA #0 STA BLINK+LO ; LENGTHEN BLINK DELAY STA BLINK+HI ; TO MAXIMUM LDA COLCRS+LO ; CALC CURSOR X-POS ASL A ASL A CLC ADC #48 STA HPOSM0 LDA ROWCRS ; CALC CURSOR Y-POS ASL A ASL A ASL A CLC ADC #39 TAY ; MOVE HERE FOR DRAWING LDA #%00000011 ; FORCE CURSOR "ON" STA CSHAPE STA MISSL,Y ; AND DRAW IT GKEY1: LDX CH ; CHECK HARDWARE FOR A KEYPRESS INC BLINK+LO BNE NOBLIN INC BLINK+HI BNE NOBLIN LDA #$80 STA BLINK+HI ; RESET BLINK TIMER LDA CSHAPE EOR #%00000011 STA CSHAPE ; FLIP CURSOR SHAPE STA MISSL,Y ; DRAW CURSOR INTO MISSILE RAM NOBLIN: CPX #$FF ; KEY PRESSED? BEQ GKEY1 ; NO, KEEP SCANNING LDA #$FF STA CH ; RESET KEY HARDWARE TXA BMI BADKEY ; REJECT CTRL KEYS LDA ATASCI,X ; GET CODE INTO [A] CMP #EOL ; WAS IT EOL? BEQ CLICK ; OKAY IF SO TAX ; ANY OTHER NEGATIVE CODE BMI BADKEY ; IS ILLEGAL ; ERASE CURSOR, "CLICK" THE SPEAKER CLICK: STA IOCHAR ; SAVE KEYCODE LDA #0 STA MISSL,Y ; ERASE CURSOR LDY #$80 CLK0: STY CONSOL LDX #8 CLK1: DEX BNE CLK1 DEY BNE CLK0 PLA ; RESTORE TAY ; EVERYTHING PLA TAX LDA IOCHAR ; GET CHAR INTO [A] RTS ; AND RETURN IT ; ----------------- ; PRINT CHAR IN [A] ; ----------------- CHAR: STA IOCHAR ; SAVE HERE TXA ; SAVE [X] AND [Y] PHA TYA PHA LDY ROWCRS ; Y-POS INTO [Y] LDX COLCRS+LO ; X-POS INTO [X] LDA IOCHAR ; RESTORE CHAR CMP #EOL ; IS IT EOL? BEQ OUTEOL ; YES, SPECIAL HANDLING CMP #$0D ; ALSO CHECK FOR BEQ OUTEOL ; ASCII EOL ; HANDLE A NON-EOL CHAR CPY #YSIZE-1 ; ON LAST SCREEN LINE? BCC NOSCRL ; NO, NO SCROLL NEEDED CPX #XSIZE ; LAST CHAR ON LINE? BCC NOSCRL ; NO, DON'T SCROLL ; SCROLL THE SCREEN DOSCRL: DEY ; PUSH CURSOR UP ONE LINE STY ROWCRS 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 #0 SRL3: STA SCREEN+920,X ; CLEAR LAST LINE DEX ; OF SCREEN RAM BPL SRL3 NOSCRL: LDA IOCHAR ; RESTORE CHAR LDX #$0B ; CIO "PUT CHAR" STX ICCOM ; COMMAND LDX #0 ; IOCB #0 (E:) STX ICBLEN+LO ; ZERO THE STX ICBLEN+HI ; BUFFER LENGTH JSR CIOV ; SEND IT OUT! PLA ; RESTORE [X] AND [Y] TAY PLA TAX RTS ; HANDLE EOL OUTEOL: LDA #$9B ; MAKE SURE [IOCHAR] STA IOCHAR ; IS AN ATASCII EOL CPY #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] LDY #$FF STY CH ; CLEAR KEYBOARD INY ; = 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" 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 #EOL ; ATASCII EOL? BNE LEX1 ; IF SO, LDA #$0D ; CONVERT TO ASCII BNE LEX2 LEX1: 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 BPL LEX0 ; ALL CHARS MOVED 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] PNAME: DB "P:" ; FILENAME FOR PRINTER DB EOL SFLAG: DB 0 ; PREVIOUS SCRIPTING STATE PPRINT: LDA SCRIPT ; SCRIPTING INTERNALLY ENABLED? BEQ PEX ; NO, SCRAM IMMEDIATELY LDA ZBEGIN+ZSCRIP+1 ; CHECK SCRIPT FLAG AND #%00000001 ; SCRIPTING ON? BEQ PEX ; NO, EXIT LDA PSTAT ; CHECK PRINTER STATUS BMI PEX ; CAN'T OPEN IF NEGATIVE BNE PP1 ; ALREADY OPEN, SCRIPT THE LINE ; OPEN THE PRINTER FOR OUTPUT JSR CLOSEP ; CLOSE IOCB #1 FIRST FOR SAFETY LDX #$10 ; IOCB #1 (P:) LDA #LOW PNAME ; POINT STA ICBADR+LO,X ; TO LDA #HIGH PNAME ; P: STA ICBADR+HI,X ; FILENAME LDA #$03 ; CIO "OPEN" STA ICCOM,X ; COMMAND LDA #$08 ; SET CHANNEL STA ICAUX1,X ; FOR WRITE-ONLY LDA #0 STA ICAUX2,X ; ZERO THIS BYTE JSR CIOV ; OPEN IT! TYA ; STATUS CODE IN [Y] BMI BADP ; ERROR IF NEGATIVE LDA #$70 STA POKMSK STA IRQEN ; DISABLE BREAK KEY LDA #1 ; SET [PSTAT] STA PSTAT ; TO INDICATE "PRINTER READY" ; PRINT [LBUFF] PP1: LDX #$10 ; IOCB #1 (P:) LDA #LOW LBUFF ; TELL CIO STA ICBADR+LO,X ; WHERE LDA #HIGH LBUFF ; [LBUFF] STA ICBADR+HI,X ; IS HIDING LDA PRLEN ; # CHARS TO PRINT STA ICBLEN+LO,X LDA #0 ; CLEAR THE STA ICBLEN+HI,X ; MSB OF LINE LENGTH LDA #$0B ; CIO "PUT BUFFER" COMMAND (BM 4/9/85) STA ICCOM,X ; COMMAND JSR CIOV TYA BPL PEX ; EXIT IF NO ERROR ; HANDLE PRINTER ERROR BADP: LDA #$FF ; SET PRINTER STATUS STA PSTAT ; TO "CAN'T OPEN" ; CLOSE PRINTER CHANNEL (IOCB #1) CLOSEP: LDX #$10 ; IOCB #1 (P:) LDA #$0C ; CIO "CLOSE" STA ICCOM,X ; COMMAND JSR CIOV ; CLOSE THE CHANNEL PEX: RTS ; ------------ ; 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 #0 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 TOBOT1 ; SET CURSOR TO BOTTOM 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 BNE NEWLOG ; RESET LINE MAP & RETURN ; ------ ; 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 TOBOT0 ; GO TO BOTTOM WINDOW CMP #1 ; IF [ARG1] <> 1, BNE SPLEX ; IGNORE THE REQUEST ; SET TO TOP WINDOW TOTOP: LDY #21 ; TEMPORARILY RESET STY LMAX ; [LMAX] TO KILL "MORE" LDY #1 ; Y-POS = 1 BNE DOSCRN ; SET TO BOTTOM WINDOW TOBOT0: JSR SPCALC ; RE-CALC [LMAX] TOBOT1: LDY #23 ; Y-POS = 23 DOSCRN: STY ROWCRS ; Y-POS = [Y] LDA #0 ; X-POS = 0 STA COLCRS+LO STA LINCNT ; RESET LINE COUNT ; FALL THROUGH ... ; ---------------------- ; RESET LOGICAL LINE MAP ; ---------------------- NEWLOG: LDA #$FF STA LOGMAP STA LOGMAP+1 STA LOGMAP+2 RTS ; --------- ; RAZZ USER ; --------- BOOP: LDA #200 ; SET STA AUDF1 ; FREQUENCY LDA #$AA ; PURE TONE, VOLUME #10 STA AUDC1 LDA #252 ; 4 JIFFY DELAY STA RTCLOK BOOP0: LDA RTCLOK BNE BOOP0 STA AUDC1 ; SHUT OFF SOUND RTS ; ------------ ; CLEAR SCREEN ; ------------ CLS: LDA #LOW SCREEN STA I+LO LDA #HIGH SCREEN ; POINT [I] TO STA I+HI ; SCREEN RAM LDA #0 STA LENGTH ; RESET LINE LENGTH TAY LDX #4 ; CLEAR 4 PAGES CLS0: STA (I),Y ; FOR SCREEN INY BNE CLS0 INC I+HI ; POINT TO NEXT PAGE DEX ; 4 PAGES DONE? BNE CLS0 ; LOOP TILL EMPTY LDY #1 ; SET Y-POS TO 1 STY ROWCRS DEY ; X-POS TO 0 STY COLCRS+LO JMP SPLOFF ; DISABLE SPLIT-SCREEN & RETURN ; ------------------- ; LINE ADDRESS TABLES ; ------------------- LOLINE: DB $40,$68,$90,$B8,$E0,$08,$30,$58 DB $80,$A8,$D0,$F8,$20,$48,$70,$98 DB $C0,$E8,$10,$38,$60,$88,$B0,$D8 HILINE: DB $BC,$BC,$BC,$BC,$BC,$BD,$BD,$BD DB $BD,$BD,$BD,$BD,$BE,$BE,$BE,$BE DB $BE,$BE,$BF,$BF,$BF,$BF,$BF,$BF ; ------------------------ ; ATASCII CONVERSION TABLE ; ------------------------ ATASCI: DB $6C,$6A,$3B,$FF,$FF,$6B,$FF,$FF ; UNSHIFTED DB $6F,$FF,$70,$75,$9B,$69,$2D,$FF DB $76,$FF,$63,$FF,$FF,$62,$78,$7A DB $34,$FF,$33,$36,$FF,$35,$32,$31 DB $2C,$20,$2E,$6E,$FF,$6D,$2F,$FF DB $72,$FF,$65,$79,$FF,$74,$77,$71 DB $39,$FF,$30,$37,$7E,$38,$FF,$FF DB $66,$68,$64,$FF,$FF,$67,$73,$61 DB $4C,$4A,$3A,$FF,$FF,$4B,$FF,$FF ; SHIFTED DB $4F,$FF,$50,$55,$9B,$49,$2D,$FF DB $56,$FF,$43,$FF,$FF,$42,$58,$5A DB $24,$FF,$23,$36,$FF,$35,$22,$21 DB $2C,$20,$2E,$4E,$FF,$4D,$3F,$FF DB $52,$FF,$45,$59,$FF,$54,$57,$51 DB $39,$FF,$30,$27,$7E,$38,$FF,$FF DB $46,$48,$44,$FF,$FF,$47,$53,$41 END