* AUXMEM.VDU.S * (c) Bobbi 2021-2022 GPLv3 * * Apple //e, //c & IIGS VDU Driver for 40/80 column mode (PAGE2) * * 15-Aug-2021 Optimised address calculations and PRCHRC. * Entry point to move copy cursor. * Start to consolidate VDU workspace. * 16-Aug-2021 Added COPY cursor handling. * 21-Aug-2021 CHR$(&80+n) is inverse of CHR$(&00+n) * 21-Aug-2021 If screen scrolls, copy cursor adjusted. * 05-Sep-2021 Starting to prepare VDU workspace. * 09-Sep-2021 New dispatch routine. * 22-Sep-2021 More VDU workspace, started MODE definitions. * 23-Sep-2021 More or less sorted VDU workspace. * 26-Sep-2021 Merged together JGH VDU updates and Bobbi GFX updates. * Moved all graphics screen access code to gfx.s * All 65816-specific code disabled. * 29-Sep-2021 Windows VDU 26, VDU 28, VDU 29, colours VDU 20. * 01-Oct-2021 VDU 18 (GCOL), start on updating VDU 25 (PLOT). ********************************** * VDU DRIVER WORKSPACE LOCATIONS * ********************************** * # marks variables that can't be moved * * VDU DRIVER ZERO PAGE ********************** * $00D0-$00DF VDU driver zero page workspace VDUSTATUS EQU $D0 ; $D0 # VDU status * bit 7 = VDU 21 VDU disabled * bit 6 = COPY cursor active * bit 5 = VDU 5 Text at graphics cursor * bit 4 = (Master shadow display) * bit 3 = VDU 28 Text window defined * bit 2 = VDU 14 Paged scrolling active * bit 1 = Don't scroll (COPY cursor or VDU 5 mode) * bit 0 = VDU 2 printer echo active * VDUCHAR EQU VDUSTATUS+1 ; $D1 current control character VDUTEMP EQU VDUCHAR ; &D1 VDUADDR EQU VDUSTATUS+2 ; $D2 address of current char cell VDUBANK EQU VDUADDR+2 ; $D4 screen bank VDUADDR2 EQU VDUADDR+3 ; $D5 address being scrolled VDUBANK2 EQU VDUBANK+3 ; $D7 screen bank being scrolled PLOTACTION EQU VDUSTATUS+8 ; &D8 OLDCHAR EQU OSKBD1 ; &EC character under cursor COPYCHAR EQU OSKBD2 ; &ED character under copy cursor * VDU DRIVER MAIN WORKSPACE *************************** FXLINES EQU BYTEVARBASE+217 ; Paged scrolling line counter FXVDUQLEN EQU BYTEVARBASE+218 ; Length of pending VDU queue VDUVARS EQU $290 VDUVAREND EQU $2ED GFXWINLFT EQU VDUVARS+$00 ; # graphics window left GFXWINBOT EQU VDUVARS+$02 ; # graphics window bottom \ window GFXWINRGT EQU VDUVARS+$04 ; # graphics window right / size GFXWINTOP EQU VDUVARS+$06 ; # graphics window top TXTWINLFT EQU VDUVARS+$08 ; # text window left TXTWINBOT EQU VDUVARS+$09 ; # text window bottom \ window TXTWINRGT EQU VDUVARS+$0A ; # text window right / size TXTWINTOP EQU VDUVARS+$0B ; # text window top GFXORIGX EQU VDUVARS+$0C ; graphics X origin GFXORIGY EQU VDUVARS+$0E ; graphics Y origin * GFXPOSNX EQU VDUVARS+$10 ; current graphics X posn GFXPOSNY EQU VDUVARS+$12 ; current graphics Y posn GFXLASTX EQU VDUVARS+$14 ; last graphics X posn GFXLASTY EQU VDUVARS+$16 ; last graphics Y posn VDUTEXTX EQU VDUVARS+$18 ; # absolute text X posn = POS+WINLFT VDUTEXTY EQU VDUVARS+$19 ; # absolute text Y posn = VPOS+WINTOP VDUCOPYX EQU VDUVARS+$1A ; absolute COPY text X posn VDUCOPYY EQU VDUVARS+$1B ; absolute COPY text Y posn * PIXELPLOTX EQU VDUVARS+$1C ; PLOT graphics X in pixels PIXELPLOTY EQU VDUVARS+$1E ; PLOT graphics Y in pixels PIXELPOSNX EQU VDUVARS+$20 ; current graphics X in pixels PIXELPOSNY EQU VDUVARS+$22 ; current graphics Y in pixels PIXELLASTX EQU VDUVARS+$24 ; last graphics X in pixels PIXELLASTY EQU VDUVARS+$26 ; last graphics Y in pixels VDUWINEND EQU PIXELLASTY+1 ; VDU 26 clears up to here * CURSOR EQU VDUVARS+$28 ; character used for cursor CURSORCP EQU VDUVARS+$29 ; character used for copy cursor CURSORED EQU VDUVARS+$2A ; character used for edit cursor * VDUQ EQU VDUVARS+$2B ; $2B..$33 VDUQGFXWIND EQU VDUQ+1 ; Neatly becomes VDUVARS+$2C VDUQPLOT EQU VDUQ+5 ; Neatly becomes VDUVARS+$30 VDUQCOORD EQU VDUQ+5 * VDUVAR34 EQU VDUVARS+$34 VDUMODE EQU VDUVARS+$35 ; # current MODE VDUSCREEN EQU VDUVARS+$36 ; # MODE type TXTFGD EQU VDUVARS+$37 ; # Text foreground TXTBGD EQU VDUVARS+$38 ; # Text background GFXFGD EQU VDUVARS+$39 ; # Graphics foreground GFXBGD EQU VDUVARS+$3A ; # Graphics background GFXPLOTFGD EQU VDUVARS+$3B ; # Foreground GCOL action GFXPLOTBGD EQU VDUVARS+$3C ; # Background GCOL action VDUBORDER EQU VDUVARS+$3D ; Border colour VDUCOLEND EQU VDUBORDER ; VDU 20 clears up to here * VDUVAR3E EQU VDUVARS+$3E VDUBYTES EQU VDUVARS+$3F ; bytes per char, 1=text only VDUCOLOURS EQU VDUVARS+$40 ; # colours-1 VDUPIXELS EQU VDUVARS+$41 ; # pixels per byte VDUWORKSP EQU VDUVARS+$42 ; 28 bytes of general workspace VDUWORKSZ EQU VDUVAREND-VDUWORKSP+1 * * Screen definitions * 0 1 3 4 6 7 ; MODEs sort-of completed SCNTXTMAXX DB 79, 39, 39, 79, 39, 39, 39, 39 ; Max text column SCNTXTMAXY DB 23, 23, 23, 23, 23, 23, 23, 23 ; Max text row SCNBYTES DB 08, 08, 08, 01, 08, 01, 01, 01 ; Bytes per character SCNCOLOURS DB 03, 15, 15, 01, 07, 01, 01, 01 ; Colours-1 SCNPIXELS DB 04, 02, 02, 00, 07, 00, 00, 00 ; Pixels per byte SCNFALLBACK DB 03, 04, 05, 03, 04, 05, 06, 07 ; Fall back if unsupported SCNTYPE DB 65, 64, 66, 01,128, 02, 00, 32 ; Screen type * b7=FastDraw -> HGR mode * b6=SHR mode on Apple IIgs * b5=Teletext * b1=40COL/20COL * b0=40COL/80COL * Colour table CLRTRANS16 DB 00,01,04,08,02,14,11,10 DB 05,09,12,13,06,03,07,15 CLRTRANS8 DB 00,05,01,01,06,02,02,07 ******************************************************************** * Note that we use PAGE2 80 column mode ($800-$BFF in main and aux) * and PAGE1 HGR mode ($2000-$23ff in main only) ******************************************************************** * Addresses of start of text rows in PAGE2 SCNTAB DW $800,$880,$900,$980,$A00,$A80,$B00,$B80 DW $828,$8A8,$928,$9A8,$A28,$AA8,$B28,$BA8 DW $850,$8D0,$950,$9D0,$A50,$AD0,$B50,$BD0 * Output character to VDU driver ******************************** * On entry: A=character * On exit: All registers trashable * CS if printer echo enabled for this character * OUTCHAR LDX FXVDUQLEN BNE ADDTOQ ; Waiting for chars CMP #$7F BEQ CTRLDEL ; =$7F - control char CMP #$20 BCC CTRLCHAR ; <$20 - control char BIT VDUSTATUS BMI OUTCHEXIT ; VDU disabled OUTCHARCP JSR PRCHRC ; Store char, checking keypress OUTCHARCP2 JSR VDU09 ; Move cursor right * OSBYTE &75 - Read VDUSTATUS ***************************** BYTE75 OUTCHEXIT LDA VDUSTATUS TAX LSR A ; Return Cy=Printer Echo Enabled RTS CTRLDEL LDA #$20 ; $7F becomes $20 CTRLCHAR CMP #$01 BEQ ADDQ ; One param CMP #$11 BCC CTRLCHARGO ; Zero params ADDQ STA VDUCHAR ; Save initial character AND #$0F TAX LDA QLEN,X STA FXVDUQLEN ; Number of params to queue BEQ CTRLCHARGO1 ; Zero, do it now QDONE CLC ; CLC=Don't echo VDU queue to printer RTS ADDTOQ STA VDUQ-256+9,X INC FXVDUQLEN BNE QDONE CTRLCHARGO1 LDA VDUCHAR CTRLCHARGO ASL A TAY CMP #$10 ; 8*2 BCC CTRLCHARGO2 ; ctrl<$08, don't echo to printer EOR #$FF ; ctrl>$0D, don't echo to printer CMP #$E5 ; (13*2) EOR 255 CTRLCHARGO2 PHP ; Save CS=(ctrl>=8 && ctrl<=13) JSR CTRLCHARJMP ; Call routine PLP BCS OUTCHEXIT ; If echoable, test if printer enabled RTS ; Return, CC=Don't echo to printer OUTCHARGO ASL A ; Entry point to move COPY cursor TAY CTRLCHARJMP CPY #6*2 BEQ CTRLCHAR6 ; Always allow VDU 6 through BIT VDUSTATUS BMI VDU00 ; VDU disabled CTRLCHAR6 LDA CTRLADDRS+1,Y PHA LDA CTRLADDRS+0,Y PHA VDU27 VDU00 RTS QLEN DB -0,-1,-2,-5,-0,-0,-1,-9 ; 32,1 or 17,18,19,20,21,22,23 DB -8,-5,-0,-0,-4,-4,-0,-2 ; 24,25,26,27,28,29,30,31 CTRLADDRS DW VDU00-1,VDU01-1,VDU02-1,VDU03-1 DW VDU04-1,VDU05-1,VDU06-1,BEEP-1 DW VDU08-1,VDU09-1,VDU10-1,VDU11-1 DW VDU12-1,VDU13-1,VDU14-1,VDU15-1 DW VDU16-1,VDU17-1,VDU18-1,VDU19-1 DW VDU20-1,VDU21-1,VDU22-1,VDU23-1 DW VDU24-1,VDU25-1,VDU26-1,VDU27-1 DW VDU28-1,VDU29-1,VDU30-1,VDU31-1 DW VDU127-1 * Turn things on and off ************************ * VDU 2 - Start print job VDU02 * JSR select printer LDA #$01 ; Set PrinterEcho On BNE SETSTATUS * VDU 5 - Text at graphics cursor VDU05 LDX VDUPIXELS BEQ SETEXIT ; 0 pixels per char, text only CPX #$07 ; 7 pixels per char, HGR BEQ SETEXIT LDA #$20 ; Set VDU 5 mode BNE SETSTATUS * VDU 14 - Select paged scrolling VDU14 STZ FXLINES ; Reset line counter LDA #$04 ; Set Paged Mode BNE SETSTATUS * VDU 21 - Disable VDU VDU21 LDA #$80 ; Set VDU disabled SETSTATUS ORA VDUSTATUS ; Set bits in VDU STATUS STA VDUSTATUS SETEXIT RTS * VDU 3 - End print job VDU03 * JSR flush printer LDA #$FE ; Clear Printer Echo BNE CLRSTATUS * VDU 4 - Text at text cursor VDU04 LDA #$DF ; Clear VDU 5 mode BNE CLRSTATUS * VDU 15 - Disable paged scrolling VDU15 LDA #$FB ; Clear paged scrolling BRA CLRSTATUS * VDU 6 - Enable VDU VDU06 LDA #$7F ; Clear VDU disabled CLRSTATUS AND VDUSTATUS STA VDUSTATUS RTS * Editing cursor **************** * Move editing cursor * A=cursor key, CS from caller COPYMOVE PHA BIT VDUSTATUS BVS COPYMOVE2 ; Edit cursor already on JSR GETCHRC STA COPYCHAR LDA CURSORED JSR SHOWWTCURSOR ; Show write cursor SEC JSR COPYSWAP2 ; Initialise copy cursor ROR FLASHER ASL FLASHER ; Ensure b0=0 LDA #$42 ORA VDUSTATUS STA VDUSTATUS ; Turn cursor editing on COPYMOVE2 PLA AND #3 ; Convert to 8/9/10/11 ORA #8 COPYMOVE3 JMP OUTCHARGO ; Move edit cursor * Swap between edit and copy cursors COPYSWAP1 CLC ; CC=Swap TEXT and COPY COPYSWAP2 LDX #1 COPYSWAPLP LDY VDUCOPYX,X LDA VDUTEXTX,X STA VDUCOPYX,X BCS COPYSWAP3 ; CS=Copy TEXT to COPY TYA STA VDUTEXTX,X COPYSWAP3 DEX BPL COPYSWAPLP COPYSWAP4 RTS * Write character to screen *************************** * Perform backspace & delete operation VDU127 JSR VDU08 ; Move cursor back LDA VDUSTATUS AND #$20 ; Bit 5 VDU5 mode BEQ :NOTVDU5 >>> XF2MAIN,SHRVDU127 RTS :NOTVDU5 LDA #' ' ; Overwrite with a space BRA PUTCHRC * Display character at current (TEXTX,TEXTY) PRCHRC PHA ; Save character LDA VDUSTATUS AND #$20 ; Bit 5 VDU5 mode BEQ :S1 JMP PRCHR7 ; Jump over text mode stuff :S1 BIT ESCFLAG BMI :RESUME JSR ESCPOLL BCS :RESUME BMI :RESUME CMP #$13 BNE :RESUME :PAUSE0 JSR ESCPOLL BMI :RESUME BCS :PAUSE0 CMP #$11 BNE :PAUSE0 BRA :RESUME LDA KEYBOARD BPL :RESUME ; No key pressed EOR #$80 :PAUSE1 JSR KBDCHKESC ; Ask KBD to test if Escape BIT ESCFLAG BMI :RESUMEACK ; Escape, skip pausing CMP #$13 BNE :RESUME ; Not Ctrl-S STA KBDSTRB ; Ack. keypress :PAUSE2 LDA KEYBOARD BPL :PAUSE2 ; Loop until keypress EOR #$80 CMP #$11 ; Ctrl-Q BEQ :RESUMEACK ; Stop pausing JSR KBDCHKESC ; Ask KBD to test if Escape BIT ESCFLAG BPL :PAUSE2 ; No Escape, keep pausing :RESUMEACK STA KBDSTRB ; Ack. keypress :RESUME PLA * Put character to screen * Puts character to text screen buffer, then in graphics mode, * writes bitmap to graphics screen PUTCHRC PHA EOR #$80 ; Convert character to screen code TAX AND #$A0 BNE PRCHR4 CPX #$20 BCS PRCHR3 ; Not $80-$9F LDA #$20 BIT VDUSCREEN BEQ PRCHR3 ; Not teletext LDX #$E0 ; Convert $80-$9F to space PRCHR3 TXA EOR #$40 TAX PRCHR4 JSR CHARADDR ; Find character address TXA ; Get character back BIT VDUBANK BPL PRCHR5 ; Not AppleGS, use short write >>> WRTMAIN STA [VDUADDR],Y >>> WRTAUX BRA PRCHR7 PRCHR5 BCC PRCHR6 ; Aux memory >>> WRTMAIN STA (VDUADDR),Y ; Store in main >>> WRTAUX BRA PRCHR7 PRCHR6 STA (VDUADDR),Y ; Store in aux PRCHR7 PLA BIT VDUSCREEN BPL :NOTHGR JMP HGRPRCHAR ; Write character to HGR :NOTHGR BVC :NOTSHR JMP SHRPRCHAR ; Write character to SHR :NOTSHR RTS * Wrapper around PUTCHRC used when showing the read cursor * On entry: A - character used for cursor SHOWRDCURSOR TAX ; Preserve character BIT VDUSCREEN BVS :SHR TXA JMP PUTCHRC :SHR TXA ; Recover character SEC ; CS: Show cursor CLV ; VC: Read cursor JMP SHRCURSOR * Wrapper around PUTCHRC used when showing the write cursor * On entry: A - character used for cursor SHOWWTCURSOR TAX ; Preserve character BIT VDUSCREEN BVS :SHR TXA JMP PUTCHRC :SHR TXA ; Recover character SEC ; CS: Show cursor BIT SETV ; VS: Write cursor JMP SHRCURSOR * Wrapper around PUTCHRC used when removing the read cursor * On entry: A - character which was obscured by cursor REMRDCURSOR TAX ; Preserve character BIT VDUSCREEN BVS :SHR TXA JMP PUTCHRC :SHR TXA ; Recover character CLC ; CC: Remove cursor CLV ; VC: Read cursor JMP SHRCURSOR * Wrapper around PUTCHRC used when removing the write cursor * On entry: A - character which was obscured by cursor REMWTCURSOR TAX ; Preserve character BIT VDUSCREEN BVS :SHR TXA JMP PUTCHRC :SHR TXA ; Recover character CLC ; CC: Remove cursor BIT SETV ; VS: Write cursor JMP SHRCURSOR * Wrapper around OUTCHARCP used when drawing the read cursor * On entry: A - character which was obscured by cursor PUTCOPYCURS TAX ; Preserve character BIT VDUSCREEN BVS :SHR TXA JMP OUTCHARCP :SHR TXA ; Recover character CLC ; CC: Remove cursor CLV ; VC: Read cursor JSR SHRCURSOR JMP OUTCHARCP2 * OSBYTE &87 - Read character at cursor *************************************** * Fetch character from screen at (TEXTX,TEXTY) and return MODE in Y * Always read from text screen (which we maintain even in graphics mode) BYTE87 GETCHRC JSR CHARADDR ; Find character address BIT VDUBANK BMI GETCHRGS BCC GETCHR6 ; Aux memory STZ RDMAINRAM ; Read main memory (IRQs off) GETCHR6 LDA (VDUADDR),Y ; Get character STZ RDCARDRAM ; Read aux memory TAY ; Convert character AND #$A0 BNE GETCHR7 TYA EOR #$40 TAY GETCHR7 TYA EOR #$80 LDY VDUMODE ; Y=MODE TAX ; X=char GETCHROK RTS GETCHRGS BCC GETCHR8 ; Aux memory STZ RDMAINRAM ; Read main memory (IRQs off) GETCHR8 LDA [VDUADDR],Y ; Get character STZ RDCARDRAM ; Read aux memory TAY ; Convert character AND #$A0 BNE GETCHR9 TYA EOR #$40 TAY GETCHR9 TYA EOR #$80 LDY VDUMODE ; Y=MODE TAX ; X=char, set EQ/NE RTS * OSBYTE &86 - Get text cursor position *************************************** BYTE86 LDY VDUTEXTY LDX VDUTEXTX RTS * Calculate character address ***************************** * NB: VDUBANK at VDUADDR+2 is set by VDU22 CHARADDR LDA VDUTEXTY CHARADDRY ASL TAY LDA SCNTAB+0,Y ; LSB of row address STA VDUADDR+0 LDA SCNTAB+1,Y ; MSB of row address STA VDUADDR+1 LDA VDUTEXTX BIT RD80VID SEC BPL CHARADDR40 ; 40-col LSR A CHARADDR40 TAY ; Y=offset into this row LDA VDUBANK AND #$FE BCS CHARADDROK ORA #$01 CHARADDROK STA VDUBANK RTS * (VDUADDR),Y=>character address * VDUBANK = AppleGS screen bank * CC=auxmem, CS=mainmem, X=preserved * Handle paged mode when moving up the screen VDUUP DEC FXLINES BPL :DONE STZ FXLINES :DONE RTS * Handle paged mode when moving down the screen VDUDOWN LDA VDUSTATUS AND #$04 ; Bit 2 -> paged mode BEQ :DONE LDA TXTWINBOT SEC SBC TXTWINTOP STA :HEIGHT INC FXLINES LDA FXLINES CMP :HEIGHT BCC :DONE ; FXLINES <= limit :L1 JSR BYTE76 ; Check keyboard LDA FXKBDSTATE AND #$01 ; See if Open Apple depressed BEQ :L1 ; If not, spin STZ FXLINES :DONE RTS :HEIGHT DB $00 * Generic return for all SHRVDUxx returns to aux mem VDUXXRET >>> ENTAUX ; SHRVDU08 returns here RTS * Move text cursor position *************************** * Move cursor left VDU08 LDA VDUSTATUS AND #$20 ; Bit 5 -> VDU5 mode BEQ VDU08VDU4 ; VDU5 not in effect BIT VDUSCREEN BVC VDU08DONE ; VDU5 but not SHR >>> XF2MAIN,SHRVDU08 VDU08VDU4 LDA VDUTEXTX ; COL CMP TXTWINLFT BEQ :S1 DEC VDUTEXTX ; COL BRA VDU08DONE :S1 LDA VDUTEXTY ; ROW CMP TXTWINTOP BEQ VDU08DONE DEC VDUTEXTY ; ROW LDA TXTWINRGT STA VDUTEXTX ; COL JSR VDUUP ; Handle paged mode VDU08DONE RTS * Move cursor right VDU09 LDA VDUSTATUS AND #$20 ; Bit 5 VDU 5 mode BEQ VDU09VDU4 ; VDU5 not in effect BIT VDUSCREEN BVC VDU09DONE ; VDU5 but not SHR >>> XF2MAIN,SHRVDU09 VDU09VDU4 LDA VDUTEXTX ; COL CMP TXTWINRGT BCC VDU09RGHT LDA TXTWINLFT STA VDUTEXTX ; COL JSR VDUDOWN ; Handle paged mode LDA VDUTEXTY ; ROW CMP TXTWINBOT BEQ SCROLL INC VDUTEXTY ; ROW VDU09DONE RTS VDU09RGHT INC VDUTEXTX ; COL BRA VDU09DONE SCROLL JSR SCROLLER LDA TXTWINLFT STA VDUTEXTX JSR CLREOL RTS * Move cursor down VDU10 LDA VDUSTATUS AND #$20 ; Bit 5 -> VDU5 mode BEQ VDU10VDU4 ; VDU5 not in effect BIT VDUSCREEN BVC VDU10DONE ; VDU5 but not SHR >>> XF2MAIN,SHRVDU10 VDU10VDU4 JSR VDUDOWN ; Handle paged mode LDA VDUTEXTY ; ROW CMP TXTWINBOT BEQ VDU10SCRL INC VDUTEXTY ; ROW VDU10DONE RTS VDU10SCRL JMP SCROLL * Move cursor up VDU11 LDA VDUSTATUS AND #$20 ; Bit 5 -> VDU5 mode BEQ VDU11VDU4 ; VDU5 not in effect BIT VDUSCREEN BVC VDU11DONE ; VDU5 but not SHR >>> XF2MAIN,SHRVDU11 VDU11VDU4 LDA VDUTEXTY ; ROW CMP TXTWINTOP BNE VDU11UP LDA VDUTEXTX ; COL CMP TXTWINLFT BNE VDU11DONE JSR RSCROLLER LDA TXTWINLFT STA VDUTEXTX JSR CLREOL RTS VDU11UP DEC VDUTEXTY ; ROW JSR VDUUP ; Handle paged mode VDU11DONE RTS * Move to start of line VDU13 LDA VDUSTATUS AND #$20 ; Bit 5 -> VDU5 mode BEQ VDU13VDU4 ; VDU5 not in effect BIT VDUSCREEN BVC VDU13DONE ; VDU5 but not SHR >>> XF2MAIN,SHRVDU13 VDU13VDU4 LDA #$BF JSR CLRSTATUS ; Turn copy cursor off LDA TXTWINLFT STA VDUTEXTX ; COL VDU13DONE RTS * Move to (0,0) VDU30 LDA TXTWINTOP STA VDUTEXTY ; ROW LDA TXTWINLFT STA VDUTEXTX ; COL RTS * Move to (X,Y) VDU31 LDY VDUQ+8 CPY #24 BCS :DONE LDX VDUQ+7 CPX #80 BCS :DONE BIT RD80VID BMI :T9A CPX #40 BCS :DONE :T9A STX VDUTEXTX ; COL STY VDUTEXTY ; ROW :DONE RTS * Initialise VDU driver *********************** * On entry, A=MODE to start in * VDUINIT STA VDUQ+8 * JSR FONTIMPLODE ; Reset VDU 23 font * VDU 22 - MODE n ***************** * MODEs available: * MODE 0 - 640x200 SHR graphics, 80x24 bitmap text (GS only) * MODE 1 - 320x200 SHR graphics, 40x24 bitmap text (GS only) * MODE 2 --> MODE 1 * MODE 3 - 80x24 text * MODE 4 - 280x192 HGR graphics, 40x24 bitmap text * MODE 5 --> MODE 6 * MODE 6 - 40x24 text * MODE 7 - 40x24 with $80-$9F converted to spaces * * On //e, MODE 0 -> MODE 3 * MODE 1 -> MODE 4 * MODE 2 -> MODE 5 * VDU22 JSR NEGCALL ; Find machine type AND #$0F BEQ :NOTGS ; MCHID=$x0 -> Not AppleGS, bank=0 LDA #$E0 ; Not $x0 -> AppleGS, point to screen bank :NOTGS STA VDUBANK LDA VDUQ+8 AND #$07 ; jgh BIT VDUBANK BMI :INIT ; All MODEs supported CMP #$03 BCS :INIT ADC #$03 ; Fall back to replacement MODE ; BIT VDUBANK ; BMI :INIT ; Skip if GS ; CMP #$00 ; Mode 0? ; BNE :S1 ; LDA #$03 ; --> Mode 3 instead ; BRA :INIT ;:S1 CMP #$01 ; Mode 1? ; BNE :INIT ; LDA #$06 ; --> Mode 6 instead :INIT TAX ; Set up MODE STX VDUMODE ; Screen MODE LDA SCNCOLOURS,X STA VDUCOLOURS ; Colours-1 LDA SCNBYTES,X STA VDUBYTES ; Bytes per char LDA SCNPIXELS,X STA VDUPIXELS ; Pixels per byte >>> WRTMAIN STA SHRPIXELS >>> WRTAUX LDA SCNTYPE,X STA VDUSCREEN ; Screen type LDA #$01 JSR CLRSTATUS ; Clear everything except PrinterEcho LDA #'_' ; Set up default cursors STA CURSOR ; Normal cursor STA CURSORCP ; Copy cursor when editing LDA #$A0 STA CURSORED ; Edit cursor when editing JSR VDU20 ; Default colours JSR VDU26 ; Default windows STA FULLGR ; Clear MIXED mode BIT VDUSCREEN BPL :NOTHGR JMP HGRVDU22 ; b7=1, HGR mode :NOTHGR BVC :NOTSHR JMP SHRVDU22 ; b6=1, SHR mode :NOTSHR LDA VDUSCREEN AND #$01 ; 40col/80col bit TAX STA CLR80VID,X ; Select 40col/80col STA TEXTON ; Enable Text STA PAGE2 ; PAGE2 STA SETALTCHAR ; Enable alt charset LDA #$80 ; Most significant bit TRB NEWVIDEO ; Turn off SHR * Fall through into CLS * Clear areas of the screen *************************** VDU12 STZ FXLINES LDA TXTWINTOP STA VDUTEXTY LDA TXTWINLFT STA VDUTEXTX * Clear the text screen buffer :L1 JSR CLREOL BIT VDUSCREEN BPL :NOTHGR JSR HGRCLREOL BRA :NOTSHR :NOTHGR BVC :NOTSHR JSR SHRCLREOL :NOTSHR LDA VDUTEXTY ; ROW CMP TXTWINBOT BEQ :S1 INC VDUTEXTY ; ROW BRA :L1 :S1 LDA TXTWINTOP STA VDUTEXTY ; ROW LDA TXTWINLFT STA VDUTEXTX ; COL RTS * Clear the graphics screen buffer VDU12SOFT JMP VDU16 ; *TEMP* * Clear to EOL, respecting text window boundaries CLREOL JSR CHARADDR ; Set VDUADDR=>start of line INC TXTWINRGT BIT VDUBANK BMI CLREOLGS ; AppleGS BIT RD80VID BPL :FORTY ; 40-col mode :EIGHTY LDX VDUTEXTX ; Addr offset for column :L1 TXA ; Column/2 into Y LSR TAY LDA #$A0 BCS :MAIN ; Odd cols in main mem STA (VDUADDR),Y ; Even cols in aux BRA :SKIPMAIN :MAIN >>> WRTMAIN STA (VDUADDR),Y >>> WRTAUX :SKIPMAIN INX CPX TXTWINRGT BMI :L1 BRA CLREOLDONE :FORTY LDA #$A0 :L2 >>> WRTMAIN STA (VDUADDR),Y >>> WRTAUX INY CPY TXTWINRGT BMI :L2 CLREOLDONE DEC TXTWINRGT BIT VDUSCREEN BPL :NOHGR JMP HGRCLREOL ; Clear an HGR line :NOHGR BVC :NOSHR JMP SHRCLREOL ; Clear an SHR line :NOSHR RTS CLREOLGS BIT RD80VID BPL :FORTY ; 40-col mode :EIGHTY LDX VDUTEXTX ; Addr offset for column :L1 TXA ; Column/2 into Y LSR TAY BCS :E0 ; Odd cols LDA #$E1 STA VDUBANK LDA #$A0 >>> WRTMAIN STA [VDUADDR],Y ; Even cols in bank $E1 >>> WRTAUX BRA :SKIPE0 :E0 LDA #$E0 STA VDUBANK LDA #$A0 >>> WRTMAIN STA [VDUADDR],Y ; Odd cols in bank $E0 >>> WRTAUX :SKIPE0 INX CPX TXTWINRGT BMI :L1 BRA CLREOLDONE :FORTY LDA #$E0 STA VDUBANK LDA #$A0 :L2 >>> WRTMAIN STA [VDUADDR],Y >>> WRTAUX INY CPY TXTWINRGT BMI :L2 BRA CLREOLDONE * Scroll areas of the screen **************************** * Scroll text window up one line SCROLLER LDA TXTWINTOP :L1 PHA JSR SCR1LINE BIT VDUSCREEN BPL :NOTHGR JSR HGRSCR1LINE ; Scroll HGR screen BRA :NOTSHR :NOTHGR BVC :NOTSHR JSR SHRSCR1LINE ; Scroll SHR screen :NOTSHR PLA INC CMP TXTWINBOT BNE :L1 BIT VDUSTATUS BVC :S1 ; Copy cursor not active JSR COPYSWAP1 LDA #11 JSR OUTCHARGO JSR COPYSWAP1 :S1 RTS * Scroll text window down one line RSCROLLER DEC TXTWINTOP LDA TXTWINBOT DEC A :L1 PHA JSR RSCR1LINE BIT VDUSCREEN BPL :NOTHGR JSR HGRRSCR1LINE ; Reverse scroll HGR screen BRA :NOTSHR :NOTHGR BVC :NOTSHR JSR SHRRSCR1LINE ; Reverse scroll SHR screen :NOTSHR PLA DEC A CMP TXTWINTOP BNE :L1 BIT VDUSTATUS BVC :S1 ; Copy cursor not active JSR COPYSWAP1 LDA #11 JSR OUTCHARGO JSR COPYSWAP1 :S1 INC TXTWINTOP RTS * Copy line A to line A+1, respecting text window boundaries RSCR1LINE PHA INC A JSR CHARADDRY ; VDUADDR=>line A+1 LDX #2 :L0 LDA VDUADDR,X ; Copy VDUADDR->VDUADDR2 STA VDUADDR2,X DEX BPL :L0 PLA PHA JSR CHARADDRY ; VDUADDR=>line A+1 BRA DOSCR1LINE * Copy line A+1 to line A, respecting text window boundaries SCR1LINE PHA JSR CHARADDRY ; VDUADDR=>line A LDX #2 :L0 LDA VDUADDR,X ; Copy VDUADDR->VDUADDR2 STA VDUADDR2,X DEX BPL :L0 PLA PHA INC A JSR CHARADDRY ; VDUADDR=>line A+1 DOSCR1LINE INC TXTWINRGT BIT VDUBANK BMI SCR1LINEGS ; AppleGS LDX TXTWINLFT ; Addr offset for column BIT RD80VID BPL :FORTY ; 40-col mode :EIGHTY :L1 TXA ; Column/2 into Y LSR TAY BCS :MAIN ; Odd cols in main mem LDA (VDUADDR),Y ; Even cols in aux STA (VDUADDR2),Y BRA :SKIPMAIN :MAIN >>> WRTMAIN STZ RDMAINRAM ; Read main memory (IRQs off) LDA (VDUADDR),Y STA (VDUADDR2),Y STZ RDCARDRAM ; Read aux memory >>> WRTAUX :SKIPMAIN INX CPX TXTWINRGT BMI :L1 BRA SCR1LNDONE :FORTY TXA TAY :L2 >>> WRTMAIN STZ RDMAINRAM ; Read main memory (IRQs off) LDA (VDUADDR),Y STA (VDUADDR2),Y STZ RDCARDRAM ; Read aux memory >>> WRTAUX INY CPY TXTWINRGT BMI :L2 SCR1LNDONE DEC TXTWINRGT PLA RTS SCR1LINEGS LDX TXTWINLFT BIT RD80VID BPL :FORTY ; 40-col mode :EIGHTY :L1 TXA ; Column/2 into Y LSR TAY BCS :E0 ; Odd cols LDA #$E1 STA VDUBANK STA VDUBANK2 >>> WRTMAIN STZ RDMAINRAM ; Read main memory (IRQs off) LDA [VDUADDR],Y ; Even cols in bank $E1 STA [VDUADDR2],Y STZ RDCARDRAM ; Read aux memory >>> WRTAUX BRA :SKIPE0 :E0 LDA #$E0 STA VDUBANK STA VDUBANK2 >>> WRTMAIN STZ RDMAINRAM ; Read main memory (IRQs off) LDA [VDUADDR],Y ; Odd cols in bank $E0 STA [VDUADDR2],Y STZ RDCARDRAM ; Read aux memory >>> WRTAUX :SKIPE0 INX CPX TXTWINRGT BMI :L1 BRA SCR1LNDONE :FORTY TXA TAY LDA #$E0 STA VDUBANK :L2 >>> WRTMAIN STZ RDMAINRAM ; Read main memory (IRQs off) LDA [VDUADDR],Y STA [VDUADDR2],Y STZ RDCARDRAM ; Read aux memory >>> WRTAUX INY CPY TXTWINRGT BMI :L2 BRA SCR1LNDONE * VDU 16 - CLG, clear graphics window VDU16 BIT VDUSCREEN BPL :NOTHGR JMP HGRCLEAR :NOTHGR BVC :NOTSHR JMP SHRCLEAR :NOTSHR RTS * Colour control **************** * VDU 20 - Reset to default colours VDU20 BIT VDUBANK ; Check if GS BPL :S1 ; If not, skip SHR call JSR SHRDEFPAL ; Default palette LDA #$F0 STA TBCOLOR ; Set text palette B&W STZ CLOCKCTL ; Set border :S1 LDX #VDUCOLEND-TXTFGD LDA #$00 VDU20LP STA TXTFGD,X ; Clear all colours DEX ; and gcol actions BPL VDU20LP LDA #$80 ; Black background JSR SETTCOL ; Set txt background LDX #$00 ; GCOL 'set' mode LDA #$80 ; Black background JSR HGRSETGCOL ; Set HGR background BIT VDUBANK BPL :S1 ; Skip if not GS LDX #$00 ; GCOL 'set' mode LDA #$80 ; Black background JSR SHRSETGCOL ; Set SHR background :S1 LDA VDUCOLOURS AND #$07 PHA STA TXTFGD ; Note txt foreground JSR SETTCOL ; Set txt foreground LDX #$00 ; GCOL 'set' mode PLA STA GFXFGD ; Note gfx foreground JSR HGRSETGCOL ; Set gfx foreground BIT VDUBANK BPL :S2 ; Skip if not GS LDX #$00 ; Default GCOL action LDA #$07 ; White JSR SHRSETGCOL ; Set SHR foreground :S2 RTS * VDU 17 - COLOUR n - select text or border colour VDU17 LDA VDUQ+8 CMP #$C0 BCS VDU17BORDER JMP SETTCOL VDU17BORDER AND #$0F STA VDUBORDER TAX LDA CLRTRANS16,X STA CLOCKCTL RTS * Helper function to set text FG/BG colour in HGR & SHR modes SETTCOL JSR HGRSETTCOL ; Set txt foreground BIT VDUBANK BPL :NOTGS JSR SHRSETTCOL ; Set txt background :NOTGS RTS * VDU 18 - GCOL k,a - select graphics colour and plot action VDU18 LDY #$02 ; Y=>gfd settings LDA VDUQ+8 ; GCOL colour PHA CMP #$80 BCC VDU18A INY ; Y=>bgd settings VDU18A LDA VDUQ+7 ; GCOL action STA GFXPLOTFGD-2,Y ; Store GCOL action TAX ; X=GCOL action PLA PHA AND VDUCOLOURS STA GFXFGD-2,Y ; Store GCOL colour PLA BIT VDUBANK BPL :S1 ; Skip if not GS JSR SHRSETGCOL ; Set SHR background :S1 TAY LDA CLRTRANS8,Y ; Trans. to physical PHP ROL A PLP ROR A ; Get bit 7 back JMP HGRSETGCOL * VDU 19 - Select palette colours * VDU 19, logcol, physcol, red, green, blue VDU19 LDA VDUQ+5 ; Second parm CMP #16 ; If 16, then use RBG values BEQ :RGB LDA VDUQ+4 ; First parm (logcol) ASL ; Double it TAX ; Log colour in X LDA VDUQ+5 ; Second parm (physcol) ASL ; Double it TAY ; Phys colour in X BIT VDUBANK ; Check if GS BPL :S1 ; If not, skip SHR call TXA ; Copy log colour to A for call >>> XF2MAIN,SHRPALCHANGE :S1 RTS :RGB LDA VDUQ+6 ; 3rd parm (red) AND #$0F TAY ; Red in Y LDA VDUQ+4 ; First parm (logcol) ASL ; Double it TAX ; Log colour in X LDA VDUQ+7 ; 4th parm (green) AND #$0F ASL ASL ASL ASL STA :TMP LDA VDUQ+8 ; 5th parm (blue) AND #$0F ORA :TMP ; Green+Blue in A BIT VDUBANK ; Check if GS BPL :S1 ; If not, just return >>> WRTMAIN STX SHRVDUQ ; Stash X for call to main >>> WRTAUX >>> XF2MAIN,SHRPALCUSTOM :TMP DB $00 * Window (viewport) control *************************** * VDU 26 - Reset to default windows VDU26 LDA #$F7 JSR CLRSTATUS ; Clear 'soft window' VDU26A LDX #VDUWINEND-VDUVARS LDA #$00 VDU26LP STA VDUVARS,X ; Clear all windows DEX ; and all coords BPL VDU26LP ; and origin, etc. LDY VDUMODE LDA SCNTXTMAXY,Y STA TXTWINBOT ; Text window height LDA SCNTXTMAXX,Y STA TXTWINRGT ; Text window width LDY VDUPIXELS BEQ VDU26QUIT ; No graphics BIT VDUBANK ; Is this a GS? BPL VDU26PT2 ; Nope >>> XF2MAIN,SHRVDU26 VDU26RET >>> ENTAUX VDU26PT2 LDX #GFXWINRGT-VDUVARS JSR VDU26SCALE ; GFXWID=TXTWID*PIXELS-1 LDA TXTWINBOT LDY #8 ; GFXHGT=TXTHGT*8-1 LDX #GFXWINTOP-VDUVARS * * Convert text count to pixel count * VDUVARS,X=(A+1)*Y-1 VDU26SCALE PHA CLC ADC VDUVARS+0,X ORA #$01 STA VDUVARS+0,X LDA VDUVARS+1,X ADC #$00 STA VDUVARS+1,X PLA DEY BNE VDU26SCALE VDU26QUIT RTS * VDU 28,left,bottom,right,top - define text window VDU28 LDX VDUMODE LDA VDUQCOORD+2 ; right CMP VDUQCOORD+0 ; left BCC VDU28EXIT ; rightwidth VDU28B LDA VDUQCOORD+1 ; bottom CMP VDUQCOORD+3 ; top BCC VDU28EXIT ; bottomheight VDU28C LDY #TXTWINLFT+3-VDUVARS ; Copy to txt window params BEQ VDU28EXIT JSR VDUCOPY4 LDA TXTWINLFT ; Cursor to top-left of window STA VDUTEXTX LDA TXTWINTOP STA VDUTEXTY VDU28EXIT RTS * VDU 24,left;bottom;right;top; - define graphics window VDU24 BIT VDUBANK ; Check if this is a GS BMI :GS RTS ; If not, hasta la vista :GS LDX #$05 JSR ADJORIG ; Adjust x2,y2 LDX #$01 JSR ADJORIG ; Adjust x1,y1 LDX #$00 >>> WRTMAIN :L1 LDA VDUQGFXWIND,X ; Copy to main mem for SHR STA SHRVDUQ,X INX CPX #$08 BNE :L1 >>> WRTAUX >>> XF2MAIN,SHRVDU24 VDU24RET >>> ENTAUX LDY #GFXWINLFT+7-VDUVARS ; Copy to gfx window params LDA #$08 BNE COPYVDUQ * VDU 29,x;y; - define graphics origin VDU29 LDY #GFXORIGX+3-VDUVARS ; Copy to ORIGIN * Copy four bytes from VDU queue to VDU workspace VDUCOPY4 LDA #$04 ; 4 bytes to copy * Copy parameters in VDU Queue to VDU workspace COPYVDUQ LDX #VDUQ+$08-VDUVARS ; End of VDU queue * Copy A bytes from VDUVARS,X to VDUVARS,Y VDUCOPY STA VDUTEMP VDUCOPYLP LDA VDUVARS,X STA VDUVARS,Y DEX DEY DEC VDUTEMP BNE VDUCOPYLP VDUCOPYEXIT RTS * PLOT master dispatch ********************** * VDU 25,k,x;y; - PLOT k,x,y - PLOT point, line, etc. * * The PLOT canvass extends in four directions, with the visible * screen a portion in the positive quadrant. * | * (-ve,+ve) | (+ve,+ve) * +---------+ * | | * | visible | * | screen | * ------------+---------+-- * (0,0) * | * | * (-ve,-ve) | (+ve,-ve) * | * | * * PLOT actions occur over the whole canvas, with the result of * the actions that cross the visible screen written to the graphics * buffer. For example, a trangle draw between (-100,-100), (-100,+100), * (+100,+150) will draw a partial triangle in the visible screen. * * k is in VDUQ+4 * x is in VDUQ+5,VDUQ+6 * y is in VDUQ+7,VDUQ+8 * * TO DO: Clip to viewport VDU25 LDA VDUQ+4 AND #$04 ; Bit 2 set -> absolute BNE :S0 JSR RELCOORD ; Relative->Absolute coords BRA :S1 :S0 LDX #$05 ; Coords at VDUQ+5 JSR ADJORIG ; Adjust graphics origin :S1 LDX #7 VDU25BACKUP1 LDA PIXELPLOTX+0,X ; Copy pixel coords STA PIXELPLOTX+4,X ; POSN becomes LAST DEX ; and PLOT becomes POSN BPL VDU25BACKUP1 LDX #3 ; Copy PLOT coords VDU25BACKUP2 LDA GFXPOSNX,X ; POSN becomes LAST STA GFXLASTX,X LDA VDUQPLOT,X ; and PLOT becomes POSN STA GFXPOSNX,X DEX BPL VDU25BACKUP2 LDA VDUPIXELS BEQ :S2 JSR GFXPLOTTER :S2 LDA KEYBOARD ; This and PRCHRC need to be EOR #$80 ; made more generalised BMI VDU25EXIT ; No key pressed JSR KBDCHKESC ; Ask KBD to test if Escape VDU25EXIT RTS * Wrapper around call to HGR/SHR plotting routine GFXPLOTTER LDX #3 :L1 LDA VDUQ+5,X PHA DEX BPL :L1 BIT VDUSCREEN BPL :S1 JSR HGRPLOT BRA GFXPLOTTER2 :S1 BVC GFXPLOTTER2 JSR VDUCOPYMAIN ; Copy VDUQ to main mem >>> XF2MAIN,SHRPLOT GFXPLOTRET >>> ENTAUX GFXPLOTTER2 LDX #0 :L1 LDA VDUQ+5,X STA PIXELPLOTX,X PLA STA VDUQ+5,X INX CPX #4 BCC :L1 RTS * Adjust graphics origin * On entry: X - offset into VDUQ ADJORIG CLC LDA GFXORIGX+0 ADC VDUQ+0,X STA VDUQ+0,X LDA GFXORIGX+1 ADC VDUQ+1,X STA VDUQ+1,X CLC LDA GFXORIGY+0 ADC VDUQ+2,X STA VDUQ+2,X LDA GFXORIGY+1 ADC VDUQ+3,X STA VDUQ+3,X RTS * Add coordinates to GFXPOSNX, GFXPOSNY RELCOORD CLC LDA GFXPOSNX+0 ADC VDUQ+5 STA VDUQ+5 LDA GFXPOSNX+1 ADC VDUQ+6 STA VDUQ+6 CLC LDA GFXPOSNY+0 ADC VDUQ+7 STA VDUQ+7 LDA GFXPOSNY+1 ADC VDUQ+8 STA VDUQ+8 RTS * Program video system and define characters * VDU 23,charnum,row1,row2,row3,row4,row5,row6,row7,row8 VDU23 BIT VDUSCREEN ; Check we are in SHR mode BVS :SHR RTS :SHR JSR VDUCOPYMAIN ; Copy VDUQ to main mem >>> XF2MAIN,SHRUSERCHAR * Copy VDUQ to SHRVDUQ in main memory VDUCOPYMAIN LDY #$00 :L1 LDA VDUQ,Y ; Copy VDUQ to SHRVDUQ >>> WRTMAIN STA SHRVDUQ,Y >>> WRTAUX INY CPY #16 BNE :L1 * Read from VDU system ********************** * OSWORD &09 - Read POINT WORD09 RTS * OSWORD &0A - Read character bitmap WORD0A RTS * OSWORD &0B - Read palette WORD0B RTS * OSWORD &0C - Write palette WORD0C RTS * OSWORD &0D - Read gfx coords WORD0D RTS * OSBYTE &A0 - Read VDU variable BYTEA0 CPX #$40 ; Index into VDU variables BCC BYTEA02 TXA SBC #$20 TAX BYTEA02 LDY VDUVARS+1,X LDA VDUVARS+0,X TAX RTS * PRINTER DRIVER **************** * VDU 1 - Send one character to printer VDU01 RTS