From c1553c5a373d5bbda125b362730946a772ed750c Mon Sep 17 00:00:00 2001 From: Bobbi Webber-Manners Date: Tue, 21 Sep 2021 22:59:11 -0400 Subject: [PATCH] Everything builds in Merlin-16 again. --- applecorn.po | Bin 819200 -> 819200 bytes applecorn.s | 2 + auxmem.bytwrd.s | 2 + auxmem.chario.s | 2 + auxmem.gfx.s | 94 ----- auxmem.hostfs.s | 32 +- auxmem.init.s | 2 + auxmem.misc.s | 40 ++- auxmem.mosequ.s | 2 + auxmem.oscli.s | 2 + auxmem.vdu.s | 384 ++++++++++---------- fdraw/FDRAW.CIRCLE.S | 752 ---------------------------------------- fdraw/FDRAW.LINE.S | 588 ------------------------------- fdraw/FDRAW.S | 805 ------------------------------------------ fdraw/FDRAW.TABLES.S | 339 ------------------ fdraw/fdraw.circle.s | 754 ++++++++++++++++++++++++++++++++++++++++ fdraw/fdraw.line.s | 590 +++++++++++++++++++++++++++++++ fdraw/fdraw.s | 807 +++++++++++++++++++++++++++++++++++++++++++ fdraw/fdraw.tables.s | 341 ++++++++++++++++++ mainmem.fsequ.s | 2 + mainmem.init.s | 2 + mainmem.ldr.s | 10 +- mainmem.lists.s | 2 + mainmem.menu.s | 2 + mainmem.misc.s | 2 + mainmem.path.s | 2 + mainmem.svc.s | 28 +- mainmem.wild.s | 2 + memmap.txt | 49 ++- 29 files changed, 2804 insertions(+), 2835 deletions(-) delete mode 100644 auxmem.gfx.s delete mode 100644 fdraw/FDRAW.CIRCLE.S delete mode 100644 fdraw/FDRAW.LINE.S delete mode 100644 fdraw/FDRAW.S delete mode 100644 fdraw/FDRAW.TABLES.S create mode 100644 fdraw/fdraw.circle.s create mode 100644 fdraw/fdraw.line.s create mode 100644 fdraw/fdraw.s create mode 100644 fdraw/fdraw.tables.s diff --git a/applecorn.po b/applecorn.po index fc0c0e593cc8427a6bc03bd9680815ea301c02d2..838c14dbe2dda5c496f0280eac8066ea45f32ee1 100644 GIT binary patch delta 64324 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�##ui!ANcBVtX4g0@zh)# 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 - STA ZP1+1 ; X-coord -> ZP1 and ZP2 - STA ZP2+1 - LDA VDUQ+5 - STA ZP1+0 - ASL A ; ZP2 *= 8 - ROL ZP2+1 - ASL A - ROL ZP2+1 - ASL A - ROL ZP2+1 - SEC ; ZP2-ZP1->ZP2 - SBC ZP1+0 - STA ZP2+0 - LDA ZP2+1 - SBC ZP1+1 - LSR A ; ZP2 /= 32 - ROR ZP2+0 - LSR A - ROR ZP2+0 - LSR A - ROR ZP2+0 - LSR A - ROR ZP2+0 - LSR A - ROR ZP2+0 - STA VDUQ+6 ; ZP2 -> X-coord - LDA ZP2+0 - STA VDUQ+5 - -* Y-coordinate in VDUQ+7,+8 1024*3/16=192 -:YCOORD LDA VDUQ+8 ; MSB of Y-coord - AND #$FC - BNE :BIGY ; Y>1023 - LDA VDUQ+8 ; Y-coord -> ZP1 - STA ZP1+1 - STA ZP2+1 - LDA VDUQ+7 - STA ZP1+0 - ASL A ; ZP2 *= 2 - ROL ZP2+1 - CLC ; ZP2+ZP1->ZP2 - ADC ZP1+0 - STA ZP2+0 - LDA ZP2+1 - ADC ZP1+1 - LSR A ; ZP2 /= 16 - ROR ZP2+0 - LSR A - ROR ZP2+0 - LSR A - ROR ZP2+0 - LSR A - ROR ZP2+0 - STZ VDUQ+8 ; MSB always zero - SEC - LDA #191 ; 191 - ZP2 -> Y-coord - SBC ZP2+0 - STA VDUQ+7 - RTS -:BIGY STZ VDUQ+7 ; Y too large, row zero - STZ VDUQ+8 - RTS -:BIGX LDA #$17 ; X too large, use 279 - STA VDUQ+5 - LDA #$01 - STA VDUQ+6 - BRA :YCOORD - -* Add coordinates to XPIXEL, YPIXEL -RELCOORD CLC - LDA XPIXEL+0 - ADC VDUQ+5 - STA VDUQ+5 - LDA XPIXEL+1 - ADC VDUQ+6 - STA VDUQ+6 - CLC - LDA YPIXEL - ADC VDUQ+7 - STA VDUQ+7 - RTS - diff --git a/auxmem.hostfs.s b/auxmem.hostfs.s index ebda712..8cfb175 100644 --- a/auxmem.hostfs.s +++ b/auxmem.hostfs.s @@ -16,7 +16,7 @@ FSAREG EQU $B2 FSCTRL EQU FSXREG FSPTR1 EQU $B4 FSPTR2 EQU $B6 -FSNUM EQU $C8 ; *TEMP* +FSNUM EQU $C8 ; *TEMP* FSCMDLINE EQU $CE @@ -671,19 +671,19 @@ FREERET LDA AUXBLK+3 ; MSB of total blks SBC AUXBLK+1 ; MSB of blocks used TAY - LDA #$00 ; *TO DO* b16-b23 of free + LDA #$00 ; *TO DO* b16-b23 of free * NEW - JSR :FREEDEC ; Print 'AAYYXX blocks aaayyyxxx bytes ' + JSR :FREEDEC ; Print 'AAYYXX blocks aaayyyxxx bytes ' LDX #<:FREE LDY #>:FREE - JSR OUTSTR ; Print 'free' - LDX AUXBLK+0 ; Blocks used + JSR OUTSTR ; Print 'free' + LDX AUXBLK+0 ; Blocks used LDY AUXBLK+1 - LDA #$00 ; *TO DO* b16-b23 of used - JSR :FREEDEC ; Print 'AAYYXX blocks aaayyyxxx bytes ' + LDA #$00 ; *TO DO* b16-b23 of used + JSR :FREEDEC ; Print 'AAYYXX blocks aaayyyxxx bytes ' LDX #<:USED LDY #>:USED - JMP OUTSTR ; Print 'used' + JMP OUTSTR ; Print 'used' * OLD * JSR PRDECXY ; Print in decimal @@ -706,20 +706,20 @@ FREERET STA FSNUM+3 * What's the maximum number of blocks? * JSR PRHEX ; Blocks b16-b23 in hex - JSR PR2HEX ; Blocks b0-b15 in hex + JSR PR2HEX ; Blocks b0-b15 in hex LDX #<:BLOCKS LDY #>:BLOCKS - JSR OUTSTR ; ' blocks ' - STZ FSNUM+0 ; FSNUM=blocks*512 + JSR OUTSTR ; ' blocks ' + STZ FSNUM+0 ; FSNUM=blocks*512 ASL FSNUM+1 ROL FSNUM+2 ROL FSNUM+3 - LDX #FSNUM ; X=>number to print - LDY #8 ; Y=pad up to 8 digits - JSR PRINTDEC ; Print it in decimal + LDX #FSNUM ; X=>number to print + LDY #8 ; Y=pad up to 8 digits + JSR PRINTDEC ; Print it in decimal LDX #<:BYTES LDY #>:BYTES - JMP OUTSTR ; ' bytes ' + JMP OUTSTR ; ' bytes ' :BLOCKS ASC ' blocks ' DB 0 :BYTES ASC ' bytes ' @@ -979,3 +979,5 @@ ERROR5E DW $C000 ERROR2E DW $C800 ASC 'Disk changed' ; $2E - Disk switched DB $00 + + diff --git a/auxmem.init.s b/auxmem.init.s index 737544b..14744ae 100644 --- a/auxmem.init.s +++ b/auxmem.init.s @@ -180,3 +180,5 @@ BYTE00A BRK HELLO ASC 'Applecorn MOS 2021-09-21' DB $00 ; Unify MOS messages + + diff --git a/auxmem.misc.s b/auxmem.misc.s index 2f1bc90..732054c 100644 --- a/auxmem.misc.s +++ b/auxmem.misc.s @@ -133,43 +133,43 @@ PRDECPAD STX OSNUM+0 STY OSNUM+1 STZ OSNUM+2 STZ OSNUM+3 -:PRDEC16 LDY #$05 ; 5 digits - LDX #OSNUM ; number stored in OSNUM +:PRDEC16 LDY #$05 ; 5 digits + LDX #OSNUM ; number stored in OSNUM * Print up to 32-bit decimal number * See forum.6502.org/viewtopic.php?f=2&t=4894 * X=>four byte zero page locations * Y= number of digits, 0 for no padding * -PRINTDEC sty OSPAD ; Number of padding+digits - ldy #0 ; Digit counter -PRDECDIGIT lda #32 ; 32-bit divide +PRINTDEC sty OSPAD ; Number of padding+digits + ldy #0 ; Digit counter +PRDECDIGIT lda #32 ; 32-bit divide sta OSTEMP - lda #0 ; Remainder=0 - clv ; V=0 means div result = 0 -PRDECDIV10 cmp #10/2 ; Calculate OSNUM/10 + lda #0 ; Remainder=0 + clv ; V=0 means div result = 0 +PRDECDIV10 cmp #10/2 ; Calculate OSNUM/10 bcc PRDEC10 - sbc #10/2+$80 ; Remove digit & set V=1 to show div result > 0 - sec ; Shift 1 into div result -PRDEC10 rol 0,x ; Shift /10 result into OSNUM + sbc #10/2+$80 ; Remove digit & set V=1 to show div result > 0 + sec ; Shift 1 into div result +PRDEC10 rol 0,x ; Shift /10 result into OSNUM rol 1,x rol 2,x rol 3,x - rol a ; Shift bits of input into acc (input mod 10) + rol a ; Shift bits of input into acc (input mod 10) dec OSTEMP - bne PRDECDIV10 ; Continue 32-bit divide + bne PRDECDIV10 ; Continue 32-bit divide ora #48 - pha ; Push low digit 0-9 to print + pha ; Push low digit 0-9 to print iny - bvs PRDECDIGIT ; If V=1, result of /10 was > 0 & do next digit + bvs PRDECDIGIT ; If V=1, result of /10 was > 0 & do next digit lda #32 PRDECLP1 cpy OSPAD - bcs PRDECLP2 ; Enough padding pushed - pha ; Push leading space characters + bcs PRDECLP2 ; Enough padding pushed + pha ; Push leading space characters iny bne PRDECLP1 -PRDECLP2 pla ; Pop character left to right - jsr OSWRCH ; Print it +PRDECLP2 pla ; Pop character left to right + jsr OSWRCH ; Print it dey bne PRDECLP2 rts @@ -532,3 +532,5 @@ MOSVEND AUXBLK ASC '**ENDOFCODE**' DS $200-13 + + diff --git a/auxmem.mosequ.s b/auxmem.mosequ.s index a9923df..3176175 100644 --- a/auxmem.mosequ.s +++ b/auxmem.mosequ.s @@ -71,3 +71,5 @@ OSFILECB EQU $2EE ; OSFILE control block + + diff --git a/auxmem.oscli.s b/auxmem.oscli.s index 0415f7f..f282cf3 100644 --- a/auxmem.oscli.s +++ b/auxmem.oscli.s @@ -499,3 +499,5 @@ ECHOLP1 JSR GSREAD JSR OSWRCH JMP ECHOLP1 + + diff --git a/auxmem.vdu.s b/auxmem.vdu.s index 21f33cf..851237e 100644 --- a/auxmem.vdu.s +++ b/auxmem.vdu.s @@ -21,7 +21,7 @@ * VDU DRIVER ZERO PAGE ********************** * $00D0-$00DF VDU driver zero page workspace -VDUSTATUS EQU $D0 ; $D0 # VDU status +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 @@ -31,40 +31,40 @@ VDUSTATUS EQU $D0 ; $D0 # VDU status * bit 1 = Don't scroll (COPY cursor or VDU 5 mode) * bit 0 = VDU 2 printer echo active * -VDUCHAR EQU VDUSTATUS+1 ; $D1 -VDUADDR EQU VDUSTATUS+4 ; $D4 address of current char cell +VDUCHAR EQU VDUSTATUS+1 ; $D1 +VDUADDR EQU VDUSTATUS+4 ; $D4 address of current char cell * TO DO: move these to VDU -OLDCHAR EQU OSKBD1 ; *TEMP* ; character under cursor -COPYCHAR EQU OSKBD2 ; *TEMP* ; character under copy cursor +OLDCHAR EQU OSKBD1 ; *TEMP* ; character under cursor +COPYCHAR EQU OSKBD2 ; *TEMP* ; 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 +FXLINES EQU BYTEVARBASE+217 ; Paged scrolling line counter +FXVDUQLEN EQU BYTEVARBASE+218 ; Length of pending VDU queue VDUVARS EQU $290 -VDUTWINL EQU VDUVARS+$08 ; # text window left -VDUTWINB EQU VDUVARS+$09 ; # text window bottom \ window -VDUTWINR EQU VDUVARS+$0A ; # text window right / size -VDUTWINT EQU VDUVARS+$0B ; # text window top +VDUTWINL EQU VDUVARS+$08 ; # text window left +VDUTWINB EQU VDUVARS+$09 ; # text window bottom \ window +VDUTWINR EQU VDUVARS+$0A ; # text window right / size +VDUTWINT EQU VDUVARS+$0B ; # text window top * -VDUPIXELS EQU VDUVARS+$13 ; *TEMP* -VDUBYTES EQU VDUVARS+$14 ; *TEMP* ; bytes per char -VDUMODE EQU VDUVARS+$15 ; *TEMP* ; current MODE -VDUSCREEN EQU VDUVARS+$16 ; *TEMP* ; Screen type, MODE 7? +VDUPIXELS EQU VDUVARS+$13 ; *TEMP* +VDUBYTES EQU VDUVARS+$14 ; *TEMP* ; bytes per char +VDUMODE EQU VDUVARS+$15 ; *TEMP* ; current MODE +VDUSCREEN EQU VDUVARS+$16 ; *TEMP* ; Screen type, MODE 7? * -VDUTEXTX EQU VDUVARS+$18 ; absolute POS -VDUTEXTY EQU VDUVARS+$19 ; absolute VPOS -VDUCOPYX EQU VDUVARS+$1A ; absolute COPY cursor X posn -VDUCOPYY EQU VDUVARS+$1B ; absolute COPY cursor Y posn +VDUTEXTX EQU VDUVARS+$18 ; absolute POS +VDUTEXTY EQU VDUVARS+$19 ; absolute VPOS +VDUCOPYX EQU VDUVARS+$1A ; absolute COPY cursor X posn +VDUCOPYY EQU VDUVARS+$1B ; absolute COPY cursor Y posn * -CURSOR EQU VDUVARS+$20 ; *TEMP* character used for cursor -CURSORED EQU VDUVARS+$21 ; *TEMP* character used for edit cursor -CURSORCP EQU VDUVARS+$22 ; *TEMP* character used for copy cursor +CURSOR EQU VDUVARS+$20 ; *TEMP* character used for cursor +CURSORED EQU VDUVARS+$21 ; *TEMP* character used for edit cursor +CURSORCP EQU VDUVARS+$22 ; *TEMP* character used for copy cursor * -VDUQ EQU VDUVARS+$27 ; *TEMP* $27..$2F +VDUQ EQU VDUVARS+$27 ; *TEMP* $27..$2F * Output character to VDU driver @@ -74,31 +74,31 @@ VDUQ EQU VDUVARS+$27 ; *TEMP* $27..$2F * CS if printer echo enabled for this character * OUTCHAR LDX FXVDUQLEN - BNE ADDTOQ ; Waiting for chars + BNE ADDTOQ ; Waiting for chars CMP #$7F - BEQ CTRLDEL ; =$7F - control char + BEQ CTRLDEL ; =$7F - control char CMP #$20 - BCC CTRLCHAR ; <$20 - control char + BCC CTRLCHAR ; <$20 - control char BIT VDUSTATUS - BMI OUTCHEXIT ; VDU disabled -OUTCHARCP JSR PRCHRC ; Store char, checking keypress - JSR VDU09 ; Move cursor right + BMI OUTCHEXIT ; VDU disabled +OUTCHARCP JSR PRCHRC ; Store char, checking keypress + JSR VDU09 ; Move cursor right OUTCHEXIT LDA VDUSTATUS - LSR A ; Return Cy=Printer Echo Enabled + LSR A ; Return Cy=Printer Echo Enabled RTS -CTRLDEL LDA #$20 ; $7F becomes $20 +CTRLDEL LDA #$20 ; $7F becomes $20 CTRLCHAR CMP #$01 - BEQ ADDQ ; One param + BEQ ADDQ ; One param CMP #$11 - BCC CTRLCHARGO ; Zero params -ADDQ STA VDUCHAR ; Save initial character + 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 + 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 @@ -106,28 +106,28 @@ ADDTOQ STA VDUQ-256+9,X 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 + 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 - JSR CTRLCHARJMP ; Call routine + JSR CTRLCHARJMP ; Call routine PLP - BCS OUTCHEXIT ; If echoable, test if printer enabled - RTS ; Return, CC=Don't echo to printer + 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 ; (TEMP and scroll screen) +OUTCHARGO ASL A ; Entry point to move COPY cursor + TAY ; (TEMP and scroll screen) CTRLCHARJMP CPY #6*2 - BEQ CTRLCHAR6 ; Always allow VDU 6 through + BEQ CTRLCHAR6 ; Always allow VDU 6 through BIT VDUSTATUS - BMI VDU00 ; VDU disabled + BMI VDU00 ; VDU disabled CTRLCHAR6 LDA CTRLADDRS+1,Y PHA LDA CTRLADDRS+0,Y PHA VDU27 -VDU00 RTS ; Enters code with CS=(ctrl>=8 && ctrl<=13) +VDU00 RTS ; Enters code with CS=(ctrl>=8 && ctrl<=13) 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 @@ -148,46 +148,46 @@ CTRLADDRS DW VDU00-1,VDU01-1,VDU02-1,VDU03-1 * VDU 2 - Start print job VDU02 * JSR select printer - LDA #$01 ; Set Printer Echo On + LDA #$01 ; Set Printer Echo On BNE SETSTATUS * VDU 5 - Text at graphics cursor VDU05 LDX VDUPIXELS - BEQ SETEXIT ; 0 pixels per char, text only + BEQ SETEXIT ; 0 pixels per char, text only * Turn cursor off and other stuff - LDA #$20 ; Set VDU 5 mode + LDA #$20 ; Set VDU 5 mode BNE SETSTATUS * VDU 14 - Select paged scrolling -VDU14 STZ FXLINES ; Reset line counter - LDA #$04 ; Set Paged Mode +VDU14 STZ FXLINES ; Reset line counter + LDA #$04 ; Set Paged Mode BNE SETSTATUS * VDU 21 - Disable VDU -VDU21 LDA #$80 ; Set VDU disabled +VDU21 LDA #$80 ; Set VDU disabled -SETSTATUS ORA VDUSTATUS ; Set bits in VDU STATUS +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 + LDA #$FE ; Clear Printer Echo BNE CLRSTATUS * VDU 4 - Text at text cursor VDU04 * Turn cursor on and other stuff - LDA #$DF ; Clear VDU 5 mode + LDA #$DF ; Clear VDU 5 mode BNE CLRSTATUS * VDU 15 - Disable paged scrolling -VDU15 LDA #$FB ; Clear paged scrolling +VDU15 LDA #$FB ; Clear paged scrolling BRA CLRSTATUS * VDU 6 - Enable VDU -VDU06 LDA #$7F ; Clear VDU disabled +VDU06 LDA #$7F ; Clear VDU disabled CLRSTATUS AND VDUSTATUS STA VDUSTATUS @@ -199,22 +199,22 @@ CLRSTATUS AND VDUSTATUS * A=cursor key, CS from caller COPYMOVE PHA BIT VDUSTATUS - BVS COPYMOVE2 ; Edit cursor already on + BVS COPYMOVE2 ; Edit cursor already on JSR GETCHRC STA COPYCHAR LDA CURSORED - JSR PUTCHRC ; Edit cursor + JSR PUTCHRC ; Edit cursor SEC - JSR COPYSWAP2 ; Initialise copy cursor + JSR COPYSWAP2 ; Initialise copy cursor ROR FLASHER - ASL FLASHER ; Ensure b0=0 + ASL FLASHER ; Ensure b0=0 LDA #$42 ORA VDUSTATUS - STA VDUSTATUS ; Turn cursor editing on + STA VDUSTATUS ; Turn cursor editing on COPYMOVE2 PLA - AND #3 ; Convert to 8/9/10/11 + AND #3 ; Convert to 8/9/10/11 ORA #8 -COPYMOVE3 JMP OUTCHARGO ; Move edit cursor +COPYMOVE3 JMP OUTCHARGO ; Move edit cursor ** Turn editing cursor on/off *COPYCURSOR BIT VDUSTATUS @@ -233,12 +233,12 @@ COPYMOVE3 JMP OUTCHARGO ; Move edit cursor * Swap between edit and copy cursors *COPYSWAP BIT VDUSTATUS * BVC COPYSWAP4 ; Edit cursor off -COPYSWAP1 CLC ; CC=Swap TEXT and COPY +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 + BCS COPYSWAP3 ; CS=Copy TEXT to COPY TYA STA VDUTEXTX,X COPYSWAP3 DEX @@ -247,18 +247,18 @@ COPYSWAP4 RTS * Clear to EOL -CLREOL LDA VDUTEXTY ; ROW +CLREOL LDA VDUTEXTY ; ROW ASL TAX - LDA SCNTAB,X ; LSB of row + LDA SCNTAB,X ; LSB of row STA ZP1 - LDA SCNTAB+1,X ; MSB of row + LDA SCNTAB+1,X ; MSB of row STA ZP1+1 - LDA VDUTEXTX ; COL + LDA VDUTEXTX ; COL PHA - STZ VDUTEXTX ; COL + STZ VDUTEXTX ; COL :L1 - LDA VDUTEXTX ; COL + LDA VDUTEXTX ; COL LSR TAY BCC :S1 @@ -266,42 +266,42 @@ CLREOL LDA VDUTEXTY ; ROW :S1 LDA #" " STA (ZP1),Y >>> WRTAUX - LDA VDUTEXTX ; COL + LDA VDUTEXTX ; COL CMP #79 BEQ :S2 - INC VDUTEXTX ; COL + INC VDUTEXTX ; COL BRA :L1 :S2 PLA - STA VDUTEXTX ; COL + STA VDUTEXTX ; COL RTS * Clear the screen -CLEAR STZ VDUTEXTY ; ROW - STZ VDUTEXTX ; COL +CLEAR STZ VDUTEXTY ; ROW + STZ VDUTEXTX ; COL :L1 JSR CLREOL -:S2 LDA VDUTEXTY ; ROW +:S2 LDA VDUTEXTY ; ROW CMP #23 BEQ :S3 - INC VDUTEXTY ; ROW + INC VDUTEXTY ; ROW BRA :L1 -:S3 STZ VDUTEXTY ; ROW - STZ VDUTEXTX ; COL +:S3 STZ VDUTEXTY ; ROW + STZ VDUTEXTX ; COL RTS * Calculate character address CHARADDR LDA VDUTEXTY ASL TAX - LDA SCNTAB+0,X ; LSB of row address + LDA SCNTAB+0,X ; LSB of row address STA VDUADDR+0 - LDA SCNTAB+1,X ; MSB of row address + LDA SCNTAB+1,X ; MSB of row address STA VDUADDR+1 LDA VDUTEXTX BIT $C01F SEC - BPL CHARADDR40 ; 40-col + BPL CHARADDR40 ; 40-col LSR A -CHARADDR40 TAY ; Y=offset into this row +CHARADDR40 TAY ; Y=offset into this row RTS * (VDUADDR),Y=>character address * CC=auxmem @@ -309,29 +309,29 @@ CHARADDR40 TAY ; Y=offset into this row * Print char in A at ROW,COL -PRCHRC PHA ; Save character +PRCHRC PHA ; Save character LDA $C000 - BPL :RESUME ; No key pressed + BPL :RESUME ; No key pressed EOR #$80 -:PAUSE1 JSR KBDCHKESC ; Ask KBD to test if Escape +:PAUSE1 JSR KBDCHKESC ; Ask KBD to test if Escape BIT ESCFLAG - BMI :RESUMEACK ; Escape, skip pausing + BMI :RESUMEACK ; Escape, skip pausing CMP #$13 - BNE :RESUME ; Not Ctrl-S - STA $C010 ; Ack. keypress + BNE :RESUME ; Not Ctrl-S + STA $C010 ; Ack. keypress :PAUSE2 LDA $C000 - BPL :PAUSE2 ; Loop until keypress + BPL :PAUSE2 ; Loop until keypress EOR #$80 - CMP #$11 ; Ctrl-Q - BEQ :RESUMEACK ; Stop pausing - JSR KBDCHKESC ; Ask KBD to test if Escape + 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 $C010 ; Ack. keypress + BPL :PAUSE2 ; No Escape, keep pausing +:RESUMEACK STA $C010 ; Ack. keypress :RESUME PLA * Put character to screen -PUTCHRC EOR #$80 ; Convert character +PUTCHRC EOR #$80 ; Convert character TAY AND #$A0 BNE PRCHR4 @@ -339,29 +339,29 @@ PUTCHRC EOR #$80 ; Convert character EOR #$40 TAY PRCHR4 PHY - JSR CHARADDR ; Find character address - PLA ; Get character back - PHP ; Disable IRQs while - SEI ; toggling memory - BCC PRCHR6 ; Aux memory - STA $C004 ; Switch to main memory -PRCHR6 STA (VDUADDR),Y ; Store it - STA $C005 ; Back to aux memory - PLP ; Restore IRQs + JSR CHARADDR ; Find character address + PLA ; Get character back + PHP ; Disable IRQs while + SEI ; toggling memory + BCC PRCHR6 ; Aux memory + STA $C004 ; Switch to main memory +PRCHR6 STA (VDUADDR),Y ; Store it + STA $C005 ; Back to aux memory + PLP ; Restore IRQs RTS * Return char at ROW,COL in A and X, MODE in Y BYTE87 -GETCHRC JSR CHARADDR ; Find character address - PHP ; Disable IRQs while - SEI ; toggling memory - BCC GETCHR6 ; Aux memory - STA $C002 ; Switch to main memory -GETCHR6 LDA (VDUADDR),Y ; Get character - STA $C003 ; Back to aux memory - PLP ; Restore IRQs - TAY ; Convert character +GETCHRC JSR CHARADDR ; Find character address + PHP ; Disable IRQs while + SEI ; toggling memory + BCC GETCHR6 ; Aux memory + STA $C002 ; Switch to main memory +GETCHR6 LDA (VDUADDR),Y ; Get character + STA $C003 ; Back to aux memory + PLP ; Restore IRQs + TAY ; Convert character AND #$A0 BNE GETCHR7 TYA @@ -369,16 +369,16 @@ GETCHR6 LDA (VDUADDR),Y ; Get character TAY GETCHR7 TYA EOR #$80 - TAX ; X=char for OSBYTE + TAX ; X=char for OSBYTE LDY #$00 BIT $C01F BMI GETCHROK - INY ; Y=MODE + INY ; Y=MODE GETCHROK RTS -BYTE86 LDY VDUTEXTY ; ROW ; $86 = read cursor pos - LDX VDUTEXTX ; COL +BYTE86 LDY VDUTEXTY ; ROW ; $86 = read cursor pos + LDX VDUTEXTX ; COL RTS * Perform backspace & delete operation @@ -391,40 +391,40 @@ DELETE JSR BACKSPC * Perform backspace/cursor left operation VDU08 BACKSPC - LDA VDUTEXTX ; COL + LDA VDUTEXTX ; COL BEQ :S1 - DEC VDUTEXTX ; COL + DEC VDUTEXTX ; COL BRA :S3 -:S1 LDA VDUTEXTY ; ROW +:S1 LDA VDUTEXTY ; ROW BEQ :S3 - DEC VDUTEXTY ; ROW + DEC VDUTEXTY ; ROW LDA #39 BIT $C01F BPL :S2 LDA #79 :S2 - STA VDUTEXTX ; COL + STA VDUTEXTX ; COL :S3 RTS VDU10 - LDA VDUTEXTY ; ROW + LDA VDUTEXTY ; ROW CMP #23 - BEQ :TOSCRL ; JGH - INC VDUTEXTY ; ROW + BEQ :TOSCRL ; JGH + INC VDUTEXTY ; ROW RTS -:TOSCRL JMP SCROLL ; JGH +:TOSCRL JMP SCROLL ; JGH VDU11 - LDA VDUTEXTY ; ROW + LDA VDUTEXTY ; ROW BEQ :DONE - DEC VDUTEXTY ; ROW + DEC VDUTEXTY ; ROW :DONE RTS VDU13 LDA #$BF - JSR CLRSTATUS ; Turn copy cursor off - STZ VDUTEXTX ; COL + JSR CLRSTATUS ; Turn copy cursor off + STZ VDUTEXTX ; COL RTS * Initialise VDU driver @@ -447,33 +447,33 @@ VDUINIT STA VDUQ+8 VDU22 LDA VDUQ+8 AND #$07 STA VDUMODE - LDX #$01 ; 80-col + LDX #$01 ; 80-col CMP #$00 - BEQ VDU22A ; MODE 0 -> MODE 3, 80x24, text + BEQ VDU22A ; MODE 0 -> MODE 3, 80x24, text CMP #$03 - BEQ VDU22A ; MODE 3 -> MODE 3, 80x24 text + BEQ VDU22A ; MODE 3 -> MODE 3, 80x24 text CMP #$02 - BEQ VDU22G ; MODE 2 -> 280x192 HGR - DEX ; All other MODEs default to 40-col -VDU22A STA $C051 ; Enable Text - STA $C00C,X ; Select 40col/80col - STA $C055 ; PAGE2 - STA $C052 ; Clear MIXED - STA $C00F ; Enable alt charset + BEQ VDU22G ; MODE 2 -> 280x192 HGR + DEX ; All other MODEs default to 40-col +VDU22A STA $C051 ; Enable Text + STA $C00C,X ; Select 40col/80col + STA $C055 ; PAGE2 + STA $C052 ; Clear MIXED + STA $C00F ; Enable alt charset BRA VDU22C -VDU22G STA $C050 ; Enable Graphics - STA $C057 ; Hi-Res - STA $C054 ; PAGE1 - STA $C052 ; Clear MIXED - JSR VDU16 ; Clear HGR screen +VDU22G STA $C050 ; Enable Graphics + STA $C057 ; Hi-Res + STA $C054 ; PAGE1 + STA $C052 ; Clear MIXED + JSR VDU16 ; Clear HGR screen * Set up default cursors VDU22C LDA #'_' - STA CURSOR ; Normal cursor - STA CURSORCP ; Copy cursor when editing + STA CURSOR ; Normal cursor + STA CURSORCP ; Copy cursor when editing LDA #$A0 - STA CURSORED ; Edit cursor when editing + STA CURSORED ; Edit cursor when editing * JSR VDU15 ; Turn off paged scrolling * JSR VDU20 ; Reset colours * JSR VDU26 ; Reset windows @@ -484,8 +484,8 @@ VDU12 JMP CLEAR VDU30 - STZ VDUTEXTY ; ROW - STZ VDUTEXTX ; COL + STZ VDUTEXTY ; ROW + STZ VDUTEXTX ; COL RTS VDU31 @@ -500,13 +500,13 @@ VDU31 CPX #40 BCS :DONE :T9A - STX VDUTEXTX ; COL - STY VDUTEXTY ; ROW + STX VDUTEXTX ; COL + STY VDUTEXTY ; ROW :DONE RTS * Perform cursor right operation VDU09 - LDA VDUTEXTX ; COL + LDA VDUTEXTX ; COL CMP #39 BCC :S2 BIT $C01F @@ -514,13 +514,13 @@ VDU09 CMP #79 BCC :S2 :T11 - STZ VDUTEXTX ; COL - LDA VDUTEXTY ; ROW + STZ VDUTEXTX ; COL + LDA VDUTEXTY ; ROW CMP #23 BEQ SCROLL - INC VDUTEXTY ; ROW + INC VDUTEXTY ; ROW :DONE RTS -:S2 INC VDUTEXTX ; COL +:S2 INC VDUTEXTX ; COL BRA :DONE SCROLL JSR SCROLLER JSR CLREOL @@ -535,7 +535,7 @@ SCROLLER LDA #$00 CMP #23 BNE :L1 BIT VDUSTATUS - BVC :L2 ; Copy cursor not active + BVC :L2 ; Copy cursor not active JSR COPYSWAP1 LDA #11 JSR OUTCHARGO @@ -543,13 +543,13 @@ SCROLLER LDA #$00 :L2 RTS * Copy line A+1 to line A -SCR1LINE ASL ; Dest addr->ZP1 +SCR1LINE ASL ; Dest addr->ZP1 TAX LDA SCNTAB,X STA ZP1 LDA SCNTAB+1,X STA ZP1+1 - INX ; Source addr->ZP2 + INX ; Source addr->ZP2 INX LDA SCNTAB,X STA ZP2 @@ -558,11 +558,11 @@ SCR1LINE ASL ; Dest addr->ZP1 LDY #$00 :L1 LDA (ZP2),Y STA (ZP1),Y - STA $C002 ; Read main mem + STA $C002 ; Read main mem >>> WRTMAIN LDA (ZP2),Y STA (ZP1),Y - STA $C003 ; Read aux mem + STA $C003 ; Read aux mem >>> WRTAUX INY CPY #40 @@ -593,25 +593,25 @@ VDU16RET >>> ENTAUX VDU17 RTS * VDU 18 - GCOL k,a - select graphics colour and plot action -VDU18 LDA VDUQ+7 ; Argument 'k' - CMP #$04 ; k=4 means XOR - LDA #$00 ; Normal drawing mode +VDU18 LDA VDUQ+7 ; Argument 'k' + CMP #$04 ; k=4 means XOR + LDA #$00 ; Normal drawing mode BNE :NORM - LDA #$01 ; XOR mode + LDA #$01 ; XOR mode :NORM >>> WRTMAIN STA LINETYPE STA FDRAWADDR+5 >>> WRTAUX >>> XF2MAIN,SETLINE VDU18RET1 >>> ENTAUX -:NORM LDA VDUQ+8 ; Argument 'a' - BPL :FOREGND ; <128 is foreground +:NORM LDA VDUQ+8 ; Argument 'a' + BPL :FOREGND ; <128 is foreground >>> WRTMAIN - STA BGCOLOR ; Stored in main memory + STA BGCOLOR ; Stored in main memory >>> WRTAUX RTS :FOREGND >>> WRTMAIN - STA FGCOLOR ; Stored in main memory + STA FGCOLOR ; Stored in main memory >>> WRTAUX RTS @@ -631,29 +631,29 @@ VDU24 RTS * x is in VDUQ+7,VDUQ+8 * y is in VDUQ+5,VDUQ+6 * k is in VDUQ+4 -VDU25 JSR CVTCOORD ; Convert coordinate system +VDU25 JSR CVTCOORD ; Convert coordinate system LDA VDUQ+4 - AND #$04 ; Bit 2 set -> absolute + AND #$04 ; Bit 2 set -> absolute BNE :ABS - JSR RELCOORD ; Add coords to XPIXEL/YPIXEL + JSR RELCOORD ; Add coords to XPIXEL/YPIXEL :ABS LDA VDUQ+4 AND #$03 - CMP #$0 ; Bits 0,1 clear -> just move + CMP #$0 ; Bits 0,1 clear -> just move BNE :NOTMOVE - JMP HGRPOS ; Just update pos + JMP HGRPOS ; Just update pos :NOTMOVE LDA VDUQ+4 AND #$C0 - CMP #$40 ; Bit 7 clr, bit 6 set -> point + CMP #$40 ; Bit 7 clr, bit 6 set -> point BNE :LINE >>> WRTMAIN LDA VDUQ+4 STA PLOTMODE LDA VDUQ+5 - STA FDRAWADDR+6 ; LSB of X1 + STA FDRAWADDR+6 ; LSB of X1 LDA VDUQ+6 - STA FDRAWADDR+7 ; MSB of X1 + STA FDRAWADDR+7 ; MSB of X1 LDA VDUQ+7 - STA FDRAWADDR+8 ; Y1 + STA FDRAWADDR+8 ; Y1 >>> WRTAUX >>> XF2MAIN,DRAWPNT :LINE >>> WRTMAIN @@ -666,11 +666,11 @@ VDU25 JSR CVTCOORD ; Convert coordinate system LDA YPIXEL STA FDRAWADDR+8 LDA VDUQ+5 - STA FDRAWADDR+9 ; LSB of X1 + STA FDRAWADDR+9 ; LSB of X1 LDA VDUQ+6 - STA FDRAWADDR+10 ; MSB of X1 + STA FDRAWADDR+10 ; MSB of X1 LDA VDUQ+7 - STA FDRAWADDR+11 ; Y1 + STA FDRAWADDR+11 ; Y1 >>> WRTAUX >>> XF2MAIN,DRAWLINE VDU25RET >>> ENTAUX @@ -683,8 +683,8 @@ HGRPOS LDA VDUQ+5 LDA VDUQ+7 STA YPIXEL RTS -XPIXEL DW $0000 ; Previous plot x-coord -YPIXEL DB $00 ; Previous plot y-coord +XPIXEL DW $0000 ; Previous plot x-coord +YPIXEL DB $00 ; Previous plot y-coord * VDU 26 - Reset to default windows VDU26 RTS @@ -706,7 +706,7 @@ BYTE75 LDX VDUSTATUS * TEST code for VIEW * OSBYTE &A0 - Read VDU variable ******************************** -BYTEA0 LDY #79 ; Read VDU variable $09,$0A +BYTEA0 LDY #79 ; Read VDU variable $09,$0A LDX #23 RTS * TEST @@ -716,3 +716,5 @@ BYTEA0 LDY #79 ; Read VDU variable $09,$0A + + diff --git a/fdraw/FDRAW.CIRCLE.S b/fdraw/FDRAW.CIRCLE.S deleted file mode 100644 index bfe84db..0000000 --- a/fdraw/FDRAW.CIRCLE.S +++ /dev/null @@ -1,752 +0,0 @@ -******************************** -* * -* Fast Apple II Graphics * -* By Andy McFadden * -* Version 0.3, Aug 2015 * -* * -* Circle rendering * -* (Included by FDRAW.S) * -* * -* Developed with Merlin-16 * -* * -******************************** - -* TODO: if USE_FAST is 0, replace the outline circle -* plot code with calls to DrawPoint (or maybe a -* common sub-function so we don't trash the input -* parameters). Saves a little space. - - -******************************** -* -* Draw a circle. The radius is in in_rad, and -* the center is at in_x0l+in_x0h,in_y0. -* -******************************** -DrawCircle - lda #$20 ;JSR - cmp _cp08 ;configured for outline? - beq :okay - jsr fixcplot -:okay - jmp calc_circle - - -******************************** -* -* Draw filled circle. -* -******************************** -FillCircle - lda #$2c ;BIT - cmp _cp08 ;configured for fill? - beq :okay - jsr fixcplot -:okay - jsr calc_circle - jmp FillRaster - - -* Calculate a circle, using Bresenham's algorithm. The -* results are placed into the rasterization buffers. -* -* in_rad must be from 0 to 255. The x/y center -* coordinates must be on the screen, but the circle -* can extend off the edge. -* -* The computed values are stored in the rasterization -* tables. For an outline circle, we also plot the -* points immediately. - - do USE_FAST ;***** -* local storage -- not used often enough to merit DP -circ_8bit ds 1 -circ_clip ds 1 - fin ;***** - -calc_circle -max_fast_rad equ 41 -]cxl equ zloc0 -]cxh equ zloc1 -]cy equ zloc2 -]dlo equ zloc3 -]dhi equ zloc4 -]xsav equ zloc5 -]ysav equ zloc6 -]min_x equ zloc7 ;min/max offsets from center -]max_x equ zloc8 ;(min is above center, max -]min_y equ zloc9 ; is below) -]max_y equ zloc10 -]hitmp equ zloc11 -* only used by hplot for outline circles -]hbasl equ zptr0 -]andmask equ zloc11 ;overlaps with ]hitmp -]savxreg equ zloc12 -]savyreg equ zloc13 - -* Special-case radius=0. It removes an annoying -* edge case (first y-- becomes 0xff, but 6502 cmp -* is unsigned). - lda in_rad - bne :notzero - ldy in_y0 - sty rast_top - sty rast_bottom - lda in_x0l - sta rastx0l,y - sta rastx1l,y - lda in_x0h - sta rastx0h,y - sta rastx1h,y - rts - -* Use different version of function for small -* circles, because we can do it all in 8 bits. -:notzero - do USE_FAST ;***** - ldy #$01 - cmp #max_fast_rad ;in_rad in Acc - blt :use_fast - dey -:use_fast sty circ_8bit - fin ;***** - - lda in_x0l ;copy center to DP for speed - sta ]cxl - lda in_x0h - sta ]cxh - lda in_y0 - sta ]cy - -* Compute min/max values, based on offset from center. -* These are compared against offset-from-center x/y. -* We need tight bounds on Y because we use it to -* compute the rast_render top/bottom. Getting tight -* bounds on X is not so important, but we still need -* it for the no-clip optimization. - ldx #$04 ;count edges needing clip - - lda #NUM_ROWS-1 ;191 - sec - sbc ]cy ;maxY = 191-cy - cmp in_rad - blt :ylimok - lda in_rad ;clamp to radius - dex -:ylimok sta ]max_y ;maxY = 191-cy - - lda ]cy ;minY = cy - cmp in_rad - blt :ylimok2 - lda in_rad ;clamp to radius - dex -:ylimok2 sta ]min_y - - lda ]cxh - beq :xlimlo -* Examples (note # bad, must use rad -* cx=24, 23-24=255 + carry clear --> ok, chk rad -* cx=255, 23-255=24 + carry clear --> ok, chk rad -:xlimlo - lda # 255) ? - cmp in_rad - blt :xlimok2 - lda in_rad ;clamp to radius - dex -:xlimok2 sta ]min_x - -:xlimdone - - do USE_FAST ;***** - stx circ_clip - fin ;***** - -* set top/bottom rows for rasterizer - lda ]cy - clc - adc ]max_y - sta rast_bottom - lda ]cy - sec - sbc ]min_y - sta rast_top - - DO 0 ;debug debug debug - LDA ]min_x ;save a copy where the - STA $0380 ; monitor won't trash it - LDA ]max_x - STA $0381 - LDA ]min_y - STA $0382 - LDA ]max_y - STA $0383 - FIN - -* Set initial conditions for Bresenham. - ldx #0 ;:x = 0 - stx ]xsav - ldy in_rad ;:y = rad - sty ]ysav - lda #1 ;:d = 1 - rad - sec - sbc ]ysav ;in_rad - sta ]dlo - bcs :hizero ;C==1 if in_rad<=1 - ldx #$ff ;C was 0, make neg -:hizero stx ]dhi - -* -* Outer loop -- plot 8 points, then update values. -* -circ_loop - - do USE_FAST ;***** - lda circ_clip - beq ncypy - jmp with_clip - -* Quick version, no clipping required -* row cy+y: cx-x and cx+x -ncypy - lda ]ysav - clc - adc ]cy - tay ;y-coord in Y-reg - - lda ]cxl - sec - sbc ]xsav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp00 jsr cplotl - - lda ]cxl - clc - adc ]xsav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp01 jsr cplotrn - -* row cy-y: cx-x and cx+x -ncymy - lda ]cy - sec - sbc ]ysav - tay ;y-coord in Y-reg - - lda ]cxl - sec - sbc ]xsav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp02 jsr cplotl - - lda ]cxl - clc - adc ]xsav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp03 jsr cplotrn - -* row cy+x: cx-y and cx+y -ncypx - lda ]xsav ;off bottom? - clc - adc ]cy - tay ;y-coord in Y-reg - - lda ]cxl - sec - sbc ]ysav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp04 jsr cplotl - - lda ]cxl - clc - adc ]ysav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp05 jsr cplotrn - -* row cy-x: cx-y and cx+y -ncymx - lda ]cy - sec - sbc ]xsav - tay ;y-coord in Y-reg - - lda ]cxl - sec - sbc ]ysav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp06 jsr cplotl - - lda ]cxl - clc - adc ]ysav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp07 jsr cplotrn - -* CLICK - jmp circ_plot_done - - fin ;***** (USE_FAST) - -* -* Same thing, but this time clipping edges. -* -with_clip - -* row cy+y: cx-x and cx+x -ccypy - lda ]ysav ;off bottom? - cmp ]max_y - beq :cypy_ok - bge cypy_skip ;completely off screen -:cypy_ok clc - adc ]cy - tay ;y-coord in Y-reg - - ldx ]xsav ;handle cx-x - cpx ]min_x - blt :cxmx_ok - beq :cxmx_ok - lda #0 ;clip at 0 - sta rastx0l,y - sta rastx0h,y - beq cxmx_done0 ;always - BREAK -:cxmx_ok lda ]cxl - sec - sbc ]xsav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp08 jsr cplotl -cxmx_done0 - - cpx ]max_x ;handle cx+x - blt :cxpx_ok - beq :cxpx_ok - lda #NUM_COLS-1 - sta rastx1h,y - bne cxpx_done0 ;always - BREAK -:cxpx_ok lda ]cxl - clc - adc ]xsav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp09 jsr cplotr -cxpx_done0 -cypy_skip - -* row cy-y: cx-x and cx+x -ccymy - lda ]ysav ;off top? - cmp ]min_y - beq :cymy_ok - bge cymy_skip -:cymy_ok lda ]cy - sec - sbc ]ysav - tay ;y-coord in Y-reg - - ldx ]xsav ;handle cx-x - cpx ]min_x - blt :cxmx_ok - beq :cxmx_ok - lda #0 ;clip at 0 - sta rastx0l,y - sta rastx0h,y - beq cxmx_done1 ;always - BREAK -:cxmx_ok lda ]cxl - sec - sbc ]xsav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp10 jsr cplotl -cxmx_done1 - - cpx ]max_x ;handle cx+x - blt :cxpx_ok - beq :cxpx_ok - lda #NUM_COLS-1 - sta rastx1h,y - bne cxpx_done1 ;always - BREAK -:cxpx_ok lda ]cxl - clc - adc ]xsav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp11 jsr cplotr -cxpx_done1 -cymy_skip - -* row cy+x: cx-y and cx+y -ccypx - lda ]xsav ;off bottom? - cmp ]max_y - beq :cypx_ok - bge cypx_skip -:cypx_ok clc - adc ]cy - tay ;y-coord in Y-reg - - ldx ]ysav ;handle cx-y - cpx ]min_x - blt :cxmy_ok - beq :cxmy_ok - lda #0 ;clip at 0 - sta rastx0l,y - sta rastx0h,y - beq cxmy_done2 ;always - BREAK -:cxmy_ok lda ]cxl - sec - sbc ]ysav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp12 jsr cplotl -cxmy_done2 - - cpx ]max_x ;handle cx+y - blt :cxpy_ok - beq :cxpy_ok - lda #NUM_COLS-1 - sta rastx1h,y - bne cxpy_done2 ;always - BREAK -:cxpy_ok lda ]cxl - clc - adc ]ysav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp13 jsr cplotr -cxpy_done2 -cypx_skip - -* row cy-x: cx-y and cx+y -ccymx - lda ]xsav ;off top? - cmp ]min_y - beq :cymx_ok - bge cymx_skip -:cymx_ok lda ]cy - sec - sbc ]xsav - tay ;y-coord in Y-reg - - ldx ]ysav ;handle cx-y - cpx ]min_x - blt :cxmy_ok - beq :cxmy_ok - lda #0 ;clip at 0 - sta rastx0l,y - sta rastx0h,y - beq cxmy_done3 ;always - BREAK -:cxmy_ok lda ]cxl - sec - sbc ]ysav - sta rastx0l,y - lda ]cxh - sbc #$00 - sta rastx0h,y -_cp14 jsr cplotl -cxmy_done3 - - cpx ]max_x ;handle cx+y - blt :cxpy_ok - beq :cxpy_ok - lda #NUM_COLS-1 - sta rastx1h,y - bne cxpy_done3 ;always - BREAK -:cxpy_ok lda ]cxl - clc - adc ]ysav - sta rastx1l,y - lda ]cxh - adc #$00 - sta rastx1h,y -_cp15 jsr cplotr -cxpy_done3 -cymx_skip - -circ_plot_done -* Update X/Y/D. Up to about radius=41 we can maintain -* 'd' in an 8-bit register. - do USE_FAST ;***** - lda circ_8bit - beq circ_slow - -* -* Bresenham update, with 8-bit 'd'. -* - ldx ]xsav - lda ]dlo - bmi :dneg - txa ;:d = d + ((x-y)*4) +5 - sec - sbc ]ysav ;x <= y, may be neg or 0 - asl - asl - clc ;can't know carry - adc #5 - clc ;still don't want carry - adc ]dlo - sta ]dlo - dec ]ysav ;:y-- - jmp :loopbot -:dneg txa ;:d = d + (x*4) +3 - asl - asl ;x always pos, C=0 - DO 0 - BCC :TEST ;debug - BREAK ;debug -:TEST ;debug - FIN - adc #3 - adc ]dlo - sta ]dlo -:loopbot - inx ;:x++ - stx ]xsav - cpx ]ysav - beq :again - bge circ_done -:again jmp circ_loop - - fin ;***** - -* -* Bresenham update, with 16-bit 'd' -* -circ_slow - CLICK - ldx ]xsav - lda ]dhi - bmi :dneg - lda ]dlo - clc - adc #5 - sta ]dlo - bcc :noinc - inc ]dhi -:noinc - txa ;:d = d + ((x-y)*4) +5 - ldy #$00 - sty ]hitmp - sec - sbc ]ysav ;x <= y, may be neg or 0 - beq :xeqy ;if x==y, nothing to add - ldy #$ff - sty ]hitmp - asl - rol ]hitmp - asl - rol ]hitmp - clc - adc ]dlo - sta ]dlo - lda ]dhi - adc ]hitmp - sta ]dhi -:xeqy - dec ]ysav ;:y-- - jmp :loopbot - -:dneg lda ]dlo ;:d = d + (x*4) + 3 - clc - adc #3 - sta ]dlo - bcc :noinc2 - inc ]dhi -:noinc2 txa - ldy #0 ;x always positive - sty ]hitmp - asl - rol ]hitmp - asl - rol ]hitmp - clc ;not needed? - adc ]dlo - sta ]dlo - lda ]dhi - adc ]hitmp - sta ]dhi -:loopbot - inx ;:x++ - stx ]xsav - cpx ]ysav - beq :again - bge circ_done -:again jmp circ_loop - - -circ_done rts - - -* Plot a point for outline circle rendering. -* -* X and Y must be preserved. Y holds the current line -* number. -* -* Most DP locations are in use -- see the variable -* declarations at the start of the circle function. - -* cplotl is the entry point for the leftmost point. -cplotl - stx ]savxreg - sty ]savyreg - - lda ylooklo,y - sta ]hbasl - lda ylookhi,y -_pg_or2 ora #$20 - sta ]hbasl+1 - -* Convert the X coordinate into byte/bit. - ldx rastx0l,y ;x coord, lo - lda rastx0h,y ;>= 256? - beq :lotabl ;no, use the low table - ldy div7hi,x - lda mod7hi,x - bpl cplotcom ;always - BREAK ;debug -:lotabl ldy div7lo,x - lda mod7lo,x - jmp cplotcom - -* cplotr is the entry point for the rightmost point. -* We use rastx1 instead of rastx0. -cplotr - lda ylooklo,y - sta ]hbasl - lda ylookhi,y -_pg_or3 ora #$20 - sta ]hbasl+1 - -* If we just plotted the left point on the same line, -* we can skip the Y-lookup by jumping here. -cplotrn - stx ]savxreg - sty ]savyreg - - ldx rastx1l,y ;x coord, lo - lda rastx1h,y ;>= 256? - beq :lotabl ;no, use the low table - ldy div7hi,x - lda mod7hi,x - bpl cplotcom ;always - BREAK ;debug -:lotabl ldy div7lo,x - lda mod7lo,x - -* Plot the point. The byte offset (0-39) is in Y, -* the bit offset (0-6) is in A. -cplotcom - tax - lda colorline,y ;start with color pattern - eor (]hbasl),y ;flip all bits - and andmask,x ;clear other bits - eor (]hbasl),y ;restore ours, set theirs - sta (]hbasl),y - - ldx ]savxreg - ldy ]savyreg - rts - -* Reconfigure calc_circle to either JSR to cplotl/r, -* or just BIT the address (a 4-cycle no-op). The -* desired instruction is in A. -fixcplot - do USE_FAST ;***** - sta _cp00 - sta _cp01 - sta _cp02 - sta _cp03 - sta _cp04 - sta _cp05 - sta _cp06 - sta _cp07 - fin ;***** - sta _cp08 - sta _cp09 - sta _cp10 - sta _cp11 - sta _cp12 - sta _cp13 - sta _cp14 - sta _cp15 - rts diff --git a/fdraw/FDRAW.LINE.S b/fdraw/FDRAW.LINE.S deleted file mode 100644 index db0df77..0000000 --- a/fdraw/FDRAW.LINE.S +++ /dev/null @@ -1,588 +0,0 @@ -******************************** -* * -* Fast Apple II Graphics * -* By Andy McFadden * -* Version 0.3, Aug 2015 * -* * -* Point and line functions * -* (Included by FDRAW.S) * -* * -* Developed with Merlin-16 * -* * -******************************** - - -******************************** -* -* Draw a single point in the current color. -* -******************************** -DrawPoint -]hbasl equ zptr0 - - ldy in_y0 - lda ylooklo,y - sta ]hbasl - lda ylookhi,y - ora g_page - sta ]hbasl+1 - - ldx in_x0l ;x coord, lo - lda in_x0h ;>= 256? - beq :lotabl ;no, use the low table - ldy div7hi,x - lda mod7hi,x - bpl :plotit ;always - BREAK ;debug -:lotabl ldy div7lo,x - lda mod7lo,x - -* Plot the point. The byte offset (0-39) is in Y, -* the bit offset (0-6) is in A. -:plotit - tax - lda colorline,y ;start with color pattern - eor (]hbasl),y ;flip all bits - and andmask,x ;clear other bits - eor (]hbasl),y ;restore ours, set theirs - sta (]hbasl),y - rts - - -******************************** -* -* Draw a line between two points. -* -******************************** -DrawLine - -]hbasl equ zptr0 -]xposl equ zloc0 ;always left edge -]xposh equ zloc1 -]ypos equ zloc2 ;top or bottom -]deltaxl equ zloc3 -]deltaxh equ zloc4 -]deltay equ zloc5 -]count equ zloc6 -]counth equ zloc7 -]diff equ zloc8 -]diffh equ zloc9 -]andmask equ zloc10 -]wideflag equ zloc11 ;doesn't really need DP - -* We use a traditional Bresenham run-length approach. -* Run-slicing is possible, but the code is larger -* and the increased cost means it's only valuable -* for longer lines. An optimal solution would switch -* approaches based on line length. -* -* Start by identifying where x0 or x1 is on the -* left. To make life simpler we always work from -* left to right, flipping the coordinates if -* needed. -* -* We also need to figure out if the line is more -* than 255 pixels long -- which, because of -* inclusive coordinates, means abs(x0-x1) > 254. - lda in_x1l ;assume x0 on left - sec - sbc in_x0l - tax - beq checkvert ;low bytes even, check hi - lda in_x1h - sbc in_x0h - bcs lx0left - -* x1 is on the left, so the values are negative -* (hi byte in A, lo byte in X) -lx0right eor #$ff ;invert hi - sta ]deltaxh ;store - txa - eor #$ff ;invert lo - sta ]deltaxl - inc ]deltaxl ;add one for 2s complement - bne :noinchi ;rolled into high byte? - inc ]deltaxh ;yes -:noinchi lda in_x1l ;start with x1 - sta ]xposl - lda in_x1h - sta ]xposh - lda in_y1 - sta ]ypos - sec - sbc in_y0 ;compute deltay - jmp lncommon - -checkvert - lda in_x1h ;diff high bytes - sbc in_x0h ;(carry still set) - blt lx0right ;width=256, x0 right - bne lx0left ;width=256, x0 left - jmp vertline ;all zero, go vert - -* (branch back from below) -* This is a purely horizontal line. We farm the job -* out to the raster fill code for speed. (There's -* no problem with the line code handling it; its just -* more efficient to let the raster code do it.) -phorizontal - ldy ]ypos - sty rast_top - sty rast_bottom - lda ]xposl - sta rastx0l,y - clc - adc ]deltaxl ;easier to add delta back - sta rastx1l,y ; in than sort out which - lda ]xposh ; arg is left vs. right - sta rastx0h,y - adc ]deltaxh - sta rastx1h,y - jmp FillRaster - -* x0 is on the left, so the values are positive -lx0left stx ]deltaxl - sta ]deltaxh - lda in_x0l ;start with x0 - sta ]xposl - lda in_x0h - sta ]xposh - lda in_y0 ;and y0 - sta ]ypos - sec - sbc in_y1 ;compute deltay - -* Value of (starty - endy) is in A, flags still set. -lncommon - bcs :posy - eor #$ff ;negative, invert - adc #$01 - sta ]deltay - lda #$e8 ;INX - bne gotdy -:posy -_lmb beq phorizontal - sta ]deltay - lda #$ca ;DEX -gotdy sta _hmody - sta _vmody - sta _wmody - - do 0 ;***** for regression test - ldx #$01 - lda ]deltaxh - bne :iswide - lda ]deltaxl - cmp #$ff ;== 255? - beq :iswide - ldx #$00 ;notwide -:iswide stx $300 - lda ]xposl - sta $301 - lda ]xposh - sta $302 - lda ]ypos - sta $303 - ldx ]deltaxl - stx $304 - ldx ]deltaxh - stx $305 - ldx ]deltay - stx $306 - lda _hmody - and #$20 ;nonzero means inc, - sta $307 ; zero means dec - fin ;***** - -* At this point we have the initial X position in -* ]startxl/h, the initial Y position in ]starty, -* deltax in ]deltaxl, deltay in ]deltay, and we've -* tweaked the Y-update instructions to either INC or -* DEC depending on the direction of movement. -* -* The next step is to decide whether the line is -* horizontal-dominant or vertical-dominant, and -* branch to the appropriate handler. -* -* The core loops for horiz and vert take about -* 80 cycles when moving diagonally, and about -* 20 fewer when moving in the primary direction. -* The wide-horiz is a bit slower. - ldy #$01 ;set "wide" flag to 1 - lda ]deltaxl - ldx ]deltaxh - bne horzdom ;width >= 256 - cmp #$ff ;width == 255 - beq horzdom - dey ;not wide - cmp ]deltay - bge horzdom ; for diagonal lines - jmp vertdom - -* We could special-case pure-diagonal lines here -* (just BEQ a couple lines up). It does -* represent our worst case. I'm not convinced -* we'll see them often enough to make it worthwhile. - - -* horizontal-dominant -horzdom - sty ]wideflag - sta ]count ;:count = deltax + 1 - inc ]count - lsr ;:diff = deltax / 2 - sta ]diff - -* set Y to the byte offset in the line -* load the AND mask into ]andmask - ldx ]xposl - lda ]xposh ;>= 256? - beq :lotabl ;no, use the low table - ldy div7hi,x - lda mod7hi,x - bpl :gottab ;always -* BREAK ;debug -:lotabl ldy div7lo,x - lda mod7lo,x -:gottab - tax - lda andmask,x - sta ]andmask - -* Set initial value for line address. - ldx ]ypos - lda ylooklo,x - sta ]hbasl - lda ylookhi,x - ora g_page - sta ]hbasl+1 - - lda ]wideflag ;is this a "wide" line? - beq :notwide ;nope, stay local - jmp widedom - -:notwide lda colorline,y ;set initial color mask - sta _hlcolor+1 - jmp horzloop - -hrts rts - -* bottom of loop, essentially -hnoroll sta ]diff ;3 -hdecc dec ]count ;5 :count-- - beq hrts ;2 :while (count != 0) - ;= 7 or 10 - -* We keep the byte offset in the line in Y, and the -* line index in X, for the entire loop. -horzloop -_hlcolor lda #$00 ;2 start with color pattern -_lmdh eor (]hbasl),y ;5 flip all bits - and ]andmask ;3 clear other bits - eor (]hbasl),y ;5 restore ours, set theirs - sta (]hbasl),y ;6 = 21 - -* Move right. We shift the bit mask that determines -* the pixel. When we shift into bit 7, we know it's -* time to advance another byte. -* -* If this is a shallow line we would benefit from -* keeping the index in X and just doing a 4-cycle -* indexed load to get the mask. Not having the -* line number in X makes the line calc more -* expensive for steeper lines though. - lda ]andmask ;3 - asl ;2 shift, losing hi bit - eor #$80 ;2 set the hi bit - bne :noh8 ;3 cleared hi bit? -* We could BEQ away and branch back in, but this -* happens every 7 iterations, so on average it's -* a very small improvement. If we happen to branch -* across a page boundary the double-branch adds -* two more cycles and we lose. - iny ;2 advance to next byte - lda colorline,y ;4 update color mask - sta _hlcolor+1 ;4 - lda #$81 ;2 reset -:noh8 sta ]andmask ;3 = 13 + ((12-1)/7) = 14 - -* Update error diff. - lda ]diff ;3 - sec ;2 - sbc ]deltay ;3 :diff -= deltay - bcs hnoroll ;2+ :if (diff < 0) ... - ;= 11 level, 10 up/down - adc ]deltaxl ;3 : diff += deltax - sta ]diff ;3 -_hmody inx ;2 : ypos++ (or --) - lda ylooklo,x ;4 update hbasl after line - sta ]hbasl ;3 change - lda ylookhi,x ;4 -_pg_or4 ora #$20 ;2 - sta ]hbasl+1 ;3 - bne hdecc ;3 = +27 this path -> 37 - BREAK -* horizontal: 10+21+14+11=56 cycles/pixel -* diagonal: 7+21+14+37=79 cycles/pixel - - -* Vertical-dominant line. Could go up or down. -vertdom - ldx in_y0 - cpx ]ypos ;starting at y0? - bne :endy0 ;yup - ldx in_y1 ;nope -:endy0 stx _vchk+1 ;end condition - - lda ]deltay - lsr - sta ]diff ;:diff = deltay / 2 - -* set Y to the byte offset in the line -* load the AND mask into ]andmask - ldx ]xposl - lda ]xposh ;>= 256? - beq :lotabl ;no, use the low table - ldy div7hi,x - lda mod7hi,x - bpl :gottab ;always - BREAK ;debug -:lotabl ldy div7lo,x - lda mod7lo,x -:gottab - tax - lda andmask,x ;initial pixel mask - sta ]andmask - - lda colorline,y ;initial color mask - sta _vlcolor+1 - - ldx ]ypos - jmp vertloop - -* We keep the byte offset in the line in Y, and the -* line index in X, for the entire loop. - -* Bottom of loop, essentially. -vnoroll sta ]diff ;3 - -vertloop - lda ylooklo,x ;4 - sta ]hbasl ;3 - lda ylookhi,x ;4 -_pg_or5 ora #$20 ;2 - sta ]hbasl+1 ;3 = 16 - -_vlcolor lda #$00 ;2 start with color pattern -_lmdv eor (]hbasl),y ;5 flip all bits - and ]andmask ;3 clear other bits - eor (]hbasl),y ;5 restore ours, set theirs - sta (]hbasl),y ;6 = 21 - -_vchk cpx #$00 ;2 was this last line? - beq vrts ;2 yes, done -_vmody inx ;2 :ypos++ (or --) - -* Update error diff. - lda ]diff ;3 - sec ;2 - sbc ]deltaxl ;3 :diff -= deltax - bcs vnoroll ;2 :if (diff < 0) ... - ;= 10 vert, 9 move right - - adc ]deltay ;3 : diff += deltay - sta ]diff ;3 -* Move right. We shift the bit mask that determines -* the pixel. When we shift into bit 7, we know it's -* time to advance another byte. - lda ]andmask ;3 - asl ;2 shift, losing hi bit - eor #$80 ;2 set the hi bit - beq :is8 ;2+ goes to zero on 8th bit - sta ]andmask ;3 - bne vertloop ;3 = 21 + (18/7) = 24 - BREAK - -:is8 iny ;2 advance to next byte - lda colorline,y ;4 update color - sta _vlcolor+1 ;4 - lda #$81 ;2 reset - sta ]andmask ;3 - bne vertloop ;3 = 18 - BREAK -vrts rts -* vertical: 3 + 16 + 21 + 6 + 10 = 56 cycles -* diagonal: 16 + 21 + 6 + 9 + 24 = 76 cycles - - -* "Wide" horizontally-dominant loop. We have to -* maintain error-diff and deltax as 16-bit values. -* Most of the setup from the "narrow" version carried -* over, but we have to re-do the count and diff. -* -* Normally we set count to (deltax + 1) and decrement -* to zero, but it's actually easier to set it equal -* to deltax and check for -1. -widedom - lda ]deltaxh ;:count = deltax - sta ]counth - ldx ]deltaxl - stx ]count - stx ]diff - lsr ;:diff = deltax / 2 - ror ]diff - sta ]diffh - ldx ]ypos - - lda colorline,y ;set initial color mask - sta _wlcolor+1 - -* We keep the byte offset in the line in Y, and the -* line index in X, for the entire loop. -wideloop -_wlcolor lda #$00 ;2 start with color pattern -_lmdw eor (]hbasl),y ;5 flip all bits - and ]andmask ;3 clear other bits - eor (]hbasl),y ;5 restore ours, set theirs - sta (]hbasl),y ;6 = 21 - -* Move right. We shift the bit mask that determines -* the pixel. When we shift into bit 7, we know it's -* time to advance another byte. - lda ]andmask ;3 - asl ;2 shift, losing hi bit - eor #$80 ;2 set the hi bit - bne :not7 ;3 goes to zero on 8th bit - iny ; 2 advance to next byte - lda colorline,y ; 4 update color mask - sta _hlcolor+1 ; 4 - lda #$81 ; 2 reset -:not7 sta ]andmask ;3 = 13 usually, 25 every 7 - -* Update error diff, which is a positive number. If -* it goes negative ("if (diff < 0)") we act. - lda ]diff - sec - sbc ]deltay ;:diff -= deltay - bcs wnoroll ;didn't even roll low byte - dec ]diffh ;check hi byte - bpl wnoroll ;went 1->0, keep going - - adc ]deltaxl ;: diff += deltax - sta ]diff - lda ]diffh - adc ]deltaxh - sta ]diffh -_wmody inx ;: ypos++ (or --) - lda ylooklo,x ;update hbasl after line - sta ]hbasl ; change - lda ylookhi,x -_pg_or6 ora #$20 - sta ]hbasl+1 - bne wdecc - BREAK - -wnoroll sta ]diff - -wdecc dec ]count ;5 :count-- - lda ]count ;3 - cmp #$ff ;2 - bne wideloop ;3 :while (count > -1) - dec ]counth ;low rolled, decr high - beq wideloop ;went 1->0, keep going - rts - - -* Pure-vertical line. These are common in certain -* applications, and checking for it only adds two -* cycles to the general case. -vertline - ldx in_y0 - ldy in_y1 - cpx in_y1 ;y0 < y1? - blt :usey0 ;yes, go from y0 to y1 - txa ;swap X/A - tay - ldx in_y1 -:usey0 stx ]ypos - iny - sty _pvytest+1 - - ldx in_x0l ;xc lo - lda in_x0h ;>= 256? - beq :lotabl - ldy div7hi,x - lda mod7hi,x - bpl :gotit ;always -:lotabl ldy div7lo,x - lda mod7lo,x - -* Byte offset is in Y, mod-7 value is in A. -:gotit tax - lda andmask,x - sta _pvand+1 ;this doesn't change - - lda colorline,y - sta _pvcolor+1 ;nor does this - - ldx ]ypos ;top line - -* There's a trick where, when (linenum & 0x07) is -* nonzero, you just add 4 to hbasl+1 instead of -* re-doing the lookup. However, TXA+AND+BEQ -* followed by LDA+CLC+ADC+STA is 16 cycles, the same -* as our self-modified lookup, so it's not a win. -* (And if we used a second ylookhi and self-modded -* the table address, we could shave off another 2.) - -* Main pure-vertical loop -pverloop - lda ylooklo,x ;4 - sta ]hbasl ;3 - lda ylookhi,x ;4 -_pg_or7 ora #$20 ;2 - sta ]hbasl+1 ;3 (= 16) - -_pvcolor lda #$00 ;2 start with color pattern -_lmdpv eor (]hbasl),y ;5 flip all bits -_pvand and #$00 ;2 clear other bits - eor (]hbasl),y ;5 - sta (]hbasl),y ;6 (= 20) - - inx ;2 -_pvytest cpx #$00 ;2 done? - bne pverloop ;3 = 7 - rts -* 43 cycles/pixel - - -******************************** -* -* Set the line mode according to in_arg -* -* A slightly silly feature to get xdraw lines -* without really working for it. -* -******************************** -SetLineMode - lda in_arg - beq :standard - -* configure for xdraw - lda #$24 ;BIT dp - sta _lmb - sta _lmdh - sta _lmdv - sta _lmdw - sta _lmdpv - rts - -* configure for standard drawing -:standard lda #$f0 ;BEQ - sta _lmb - lda #$51 ;EOR (dp),y - sta _lmdh - sta _lmdv - sta _lmdw - sta _lmdpv - rts diff --git a/fdraw/FDRAW.S b/fdraw/FDRAW.S deleted file mode 100644 index f4118d8..0000000 --- a/fdraw/FDRAW.S +++ /dev/null @@ -1,805 +0,0 @@ -******************************** -* * -* Fast Apple II Graphics * -* By Andy McFadden * -* Version 0.3, Aug 2015 * -* * -* Main source file * -* * -* Developed with Merlin-16 * -* * -******************************** - -* Set to 1 to build FDRAW.FAST, set to zero to -* build FDRAW.SMALL. -USE_FAST equ 1 - -* Set to 1 to turn on beeps/clicks for debugging. -NOISE_ON equ 0 - - - lst off - org $9400 ;;; CUSTOMIZED FOR APPLECORN - -* -* Macros. -* -spkr equ $c030 -bell equ $ff3a - -* If enabled, click the speaker (changes flags only). -CLICK mac - do NOISE_ON - bit spkr - fin - <<< -* If enabled, beep the speaker (scrambles regs). -BEEP mac - do NOISE_ON - jsr bell - fin - <<< -* If enabled, insert a BRK. -BREAK mac - do NOISE_ON - brk $99 - fin - <<< - -* In "fast" mode, we align tables on page boundaries so we -* don't take a 1-cycle hit when the indexing crosses a page. -* In "small" mode, we skip the alignment. -PG_ALIGN mac - do USE_FAST - ds \ - fin - <<< - -* -* Hi-res screen constants. -* -BYTES_PER_ROW = 40 -NUM_ROWS = 192 -NUM_COLS = 280 - -* -* Variable storage. We assign generic names to -* zero-page scratch locations, then assign variables -* with real names to these. -* -* 06-09 are unused (except by SWEET-16) -* 1a-1d are Applesoft hi-res scratch -* cc-cf are only used by INTBASIC -* eb-ef and ff appear totally unused by ROM routines -* -zptr0 equ $1a ;2b -zloc0 equ $06 -zloc1 equ $07 -zloc2 equ $08 -zloc3 equ $09 -zloc4 equ $1c -zloc5 equ $1d -zloc6 equ $cc -zloc7 equ $cd -zloc8 equ $ce -zloc9 equ $cf -zloc10 equ $eb -zloc11 equ $ec -zloc12 equ $ed -zloc13 equ $ee - - -******************************** -* -* Entry points for external programs. -* -******************************** -Entry - jmp Init ;initialize data tables - dfb 0,3 ;version number - -* -* Parameters passed from external programs. -* -in_arg ds 1 ;generic argument -in_x0l ds 1 ;X coordinate 0, low part -in_x0h ds 1 ;X coordinate 0, high part -in_y0 ds 1 ;Y coordinate 0 -in_x1l ds 1 -in_x1h ds 1 -in_y1 ds 1 -in_rad ds 1 ;radius for circles - - ds 3 ;pad to 16 bytes - - jmp SetColor - jmp SetPage - jmp Clear - jmp DrawPoint - jmp DrawLine - jmp DrawRect - jmp FillRect - jmp DrawCircle - jmp FillCircle - jmp SetLineMode - jmp noimpl ;reserved2 - jmp FillRaster - -* Raster fill values. Top, bottom, and pointers to tables -* for the benefit of external callers. -rast_top ds 1 -rast_bottom ds 1 - da rastx0l - da rastx0h - da rastx1l - da rastx1h - -noimpl rts - - -******************************** -* -* Global variables. -* -******************************** - -g_inited dfb 0 ;initialized? -g_color dfb 0 ;hi-res color (0-7) -g_page dfb $20 ;hi-res page ($20 or $40) - - -******************************** -* -* Initialize. -* -******************************** -Init - lda #$00 - sta in_arg - jsr SetColor ;set color to zero - jsr SetLineMode ;set normal lines - lda #$20 - sta in_arg - sta g_inited - jmp SetPage ;set hi-res page 1 - - -******************************** -* -* Set the color. -* -******************************** -SetColor - lda in_arg - cmp g_color ;same as the old color? - beq :done - - and #$07 ;safety first - sta g_color - -* Update the "colorline" table, which provides a quick color -* lookup for odd/even bytes. We could also have one table -* per color and self-mod the "LDA addr,y" instructions to -* point to the current one, but that uses a bunch of memory -* and is kind of ugly. Takes 16 + (12 * 40) = 496 cycles. - tax ;2 - lda xormask,x ;4 - sta :_xormsk+1 ;4 - - lda oddcolor,x ;4 - ldy #BYTES_PER_ROW-1 ;2 -]loop sta colorline,y ;5 -:_xormsk eor #$00 ;2 - dey ;2 - bpl ]loop ;3 - -:done rts - - -******************************** -* -* Set the page. -* -******************************** -SetPage - lda g_inited ;let's just check this - beq noinit ; (not called too often) - - lda in_arg - cmp #$20 - beq :good - cmp #$40 - beq :good - jmp bell -:good - sta g_page - - do 0 ;***** - cmp ylookhi - beq :tabok -* Check to see if the values currently in the Y-lookup table -* match our current page setting. If they don't, we need to -* adjust the code that does lookups. - -* This approach modifies the table itself, paying a large -* cost now so we don't have to pay it on every lookup. -* However, this costs 2+(16*192)=3074 cycles, while an -* "ORA imm" only adds two to each lookup, so we'd have -* to do a lot of drawing to make this worthwhile. -* (Note: assumes ylookhi is based at $2000 not $0000) - ldy #NUM_ROWS ;2 -]loop lda ylookhi-1,y ;4 - eor #$60 ;2 $20 <--> $40 - sta ylookhi-1,y ;5 - dey ;2 - bne ]loop ;3 - - else ;***** - -* This approach uses self-modifying code to update the -* relevant instructions. It's a bit messy to have it -* here, but it saves us from having to do it on -* every call. -* -* We could also have a second y-lookup table and -* use this to update the pointers. That would let -* us drop the "ORA imm" entirely, without the cost -* of the rewrite above, but eating up another 192 bytes. - sta _pg_or1+1 ;rastfill - sta _pg_or2+1 ;circle hplot - sta _pg_or3+1 ;circle hplot - sta _pg_or4+1 ;drawline - sta _pg_or5+1 ;drawline - sta _pg_or6+1 ;drawline - sta _pg_or7+1 ;drawline - - fin ;***** - -:tabok rts - -noinit ldy #$00 -]loop lda :initmsg,y - beq :done - jsr $fded ;cout - iny - bne ]loop -:done rts - -:initmsg asc "FDRAW NOT INITIALIZED",87,87,00 - - -******************************** -* -* Clear the screen to the current color. -* -******************************** -Clear - - do USE_FAST ;***** -* This performs a "visually linear" clear, erasing the screen -* from left to right and top to bottom. To reduce the amount -* of code required we erase in thirds (top/middle/bottom). -* -* Compare to a "venetian blind" clear, which is what you get -* if you erase memory linearly. -* -* The docs discuss different approaches. This version -* requires ((2 + 5*64 + 11) * 40 + 14) * 3 = 40002 cycles. -* If we didn't divide it into thirds to keep the top-down -* look, we'd need (5*64 + 9) * 120 = 39480 cycles, so -* we're spending 522 cycles to avoid the venetian look. - lda :clrloop+2 - cmp g_page - beq :pageok - -* We're on the wrong hi-res page. Flip to the other one. -* 4 + (20*64) = 1284 cycles to do the flip (+ a few more -* because we're probably crossing a page boundary). - BEEP - ldy #NUM_ROWS ;2 -]loop lda :clrloop-3+2,y ;4 - eor #$60 ;2 - sta :clrloop-3+2,y ;5 - dey ;2 - dey ;2 - dey ;2 - bne ]loop ;3 - -:pageok ldx g_color ;grab the current color - lda xormask,x - sta :_xormsk+1 - lda evencolor,x - - ldy #0 - jsr :clearthird - ldy #BYTES_PER_ROW - jsr :clearthird - ldy #BYTES_PER_ROW*2 -* fall through into :clearthird for final pass - -:clearthird - ldx #BYTES_PER_ROW-1 ;2 -:clrloop sta $2000,y ;5 (* 64) - sta $2400,y ;this could probably be - sta $2800,y ; done with LUP math - sta $2c00,y - sta $3000,y - sta $3400,y - sta $3800,y - sta $3c00,y - sta $2080,y - sta $2480,y - sta $2880,y - sta $2c80,y - sta $3080,y - sta $3480,y - sta $3880,y - sta $3c80,y - sta $2100,y - sta $2500,y - sta $2900,y - sta $2d00,y - sta $3100,y - sta $3500,y - sta $3900,y - sta $3d00,y - sta $2180,y - sta $2580,y - sta $2980,y - sta $2d80,y - sta $3180,y - sta $3580,y - sta $3980,y - sta $3d80,y - sta $2200,y - sta $2600,y - sta $2a00,y - sta $2e00,y - sta $3200,y - sta $3600,y - sta $3a00,y - sta $3e00,y - sta $2280,y - sta $2680,y - sta $2a80,y - sta $2e80,y - sta $3280,y - sta $3680,y - sta $3a80,y - sta $3e80,y - sta $2300,y - sta $2700,y - sta $2b00,y - sta $2f00,y - sta $3300,y - sta $3700,y - sta $3b00,y - sta $3f00,y - sta $2380,y - sta $2780,y - sta $2b80,y - sta $2f80,y - sta $3380,y - sta $3780,y - sta $3b80,y - sta $3f80,y -:_xormsk eor #$00 ;2 flip odd/even bits - iny ;2 - dex ;2 - bmi :done ;2 - jmp :clrloop ;3 -:done rts - - else ;***** not USE_FAST - -* This version was suggested by Marcus Heuser on -* comp.sys.apple2.programmer. It does a "venetian blind" -* clear, and takes (5 * 32 + 7) * 248 = 41416 cycles. -* It overwrites half of the screen holes. - lda :clrloop+5 - cmp g_page - beq :pageok - -* We're on the wrong hi-res page. Flip to the other one. -* 12 + (20*31) = 632 cycles to do the flip. We have to -* single out the first entry because it's $1f not $20. - BEEP - lda :clrloop+2 ;4 - eor #$20 ;2 $1f <-> $3f - sta :clrloop+2 ;4 - ldy #31*3 ;2 -]loop lda :clrloop+2,y ;4 - eor #$60 ;2 $20 <-> $40 - sta :clrloop+2,y ;5 - dey ;2 - dey ;2 - dey ;2 - bne ]loop ;3 - -:pageok ldx g_color - lda xormask,x - sta :_xormsk+1 - lda oddcolor,x - ldy #248 ;120 + 8 + 120 -:clrloop -]addr = $1fff - lup 32 ;begin a loop in assembler - sta ]addr,y ;5 -]addr = ]addr+$100 ;sta 20ff,21ff,... - --^ -:_xormsk eor #$00 ;2 - dey ;2 - bne :clrloop ;3 - rts - - fin ;***** not USE_FAST - - -******************************** -* -* Draw rectangle outline. -* -******************************** -DrawRect -* We could just issue 4 line draw calls here, maybe -* adjusting the vertical lines by 1 pixel up/down to -* avoid overdraw. But if the user wanted 4 lines, -* they could just draw 4 lines. Instead, we're going -* to draw a double line on each edge to ensure that -* the outline rectangle always has the correct color. -* -* Rather than draw two vertical lines, we draw a -* two-pixel-wide filled rectangle on each side. -* -* We don't want to double-up if the rect is only one -* pixel wide, so we have to check for that. -* -* If the rect is one pixel high, it's just a line. -* If it's two pixels high, we don't need to draw -* the left/right edges, just the top/bottom lines. -* If it's more than two tall, we don't need to draw -* the left/right edges on the top and bottom lines, -* so we save a few cycles by skipping those. - - lda in_y1 ;copy top/bottom to local - sta rast_bottom - dec rast_bottom ;move up one - sec - sbc in_y0 - beq :isline ;1 pixel high, just draw line - cmp #1 - beq :twolines ;2 pixels high, lines only - ldy in_y0 - iny ;start down a line - sty rast_top - - lda in_x0h ;check to see if left/right - cmp in_x1h ; coords are the same; if - bne :notline ; so, going +1/-1 at edge - lda in_x0l ; will overdraw. - cmp in_x1l - bne :notlin1 - -:isline jmp DrawLine ;just treat like line - -* Set up left edge. Top line is in Y. -:notline lda in_x0l -:notlin1 sta rastx0l,y - clc - adc #1 - sta rastx1l,y - lda in_x0h - ora #$80 ;"repeat" flag - sta rastx0h,y - and #$7f - adc #0 - sta rastx1h,y - jsr FillRaster - - ldy rast_top - lda in_x1l ;now set up right edge - sta rastx1l,y - sec - sbc #1 - sta rastx0l,y - lda in_x1h - sta rastx1h,y - sbc #0 - ora #$80 ;"repeat" flag - sta rastx0h,y - jsr FillRaster - -* Now the top/bottom lines. -:twolines - ldy in_y0 - jsr :drawline - ldy in_y1 - -:drawline - sty rast_top - sty rast_bottom - lda in_x0l ;copy left/right to the - sta rastx0l,y ; table entry for the - lda in_x0h ; appropriate line - sta rastx0h,y - lda in_x1l - sta rastx1l,y - lda in_x1h - sta rastx1h,y - jmp FillRaster - - -******************************** -* -* Draw filled rectangle. -* -******************************** -FillRect -* Just fill out the raster table and call the fill routine. -* We require y0=top, y1=bottom, x0=left, x1=right. - ldy in_y0 - sty rast_top - lda in_y1 - sta rast_bottom - - lda in_x0l - sta rastx0l,y - lda in_x0h - ora #$80 ;"repeat" flag - sta rastx0h,y - lda in_x1l - sta rastx1l,y - lda in_x1h - sta rastx1h,y - - jmp FillRaster - - -******************************** -* -* Fill an area defined by the raster tables. -* -******************************** -FillRaster - -* Render rasterized output. The left and right edges -* are stored in the rastx0/rastx1 tables, and the top -* and bottom-most pixels are in rast_top/rast_bottom. -* -* This can be used to render an arbitrary convex -* polygon after it has been rasterized. -* -* If the high bit of the high byte of X0 is set, we -* go into "repeat" mode, where we just repeat the -* previous line. This saves about 40 cycles of -* overhead per line when drawing rectangles, plus -* what we would have to spend to populate multiple -* lines of the raster table. It only increases the -* general per-line cost by 3 cycles. -* -* We could use the "repeat" flag to use this code to -* draw vertical lines, though that's mostly of value -* to an external caller who knows ahead of time that -* the line is vertical. The DrawLine code is pretty -* good with vertical lines, and adding additional -* setup time to every vertical-dominant line to -* decide if it should call here seems like a -* losing proposition. - -]hbasl equ zptr0 -]hbash equ zptr0+1 -]lftbyte equ zloc0 -]lftbit equ zloc1 -]rgtbyte equ zloc2 -]rgtbit equ zloc3 -]line equ zloc4 -]andmask equ zloc5 -]cur_line equ zloc6 -]repting equ zloc7 - - ldx g_color ;configure color XOR byte - lda xormask,x - do USE_FAST ;***** - cmp rast_unroll+3 ;already configured? - beq :goodmask - jsr fixrastxor -:goodmask - else - sta _xorcolor+1 - fin ;***** - - lda #$00 - sta ]repting - - ldy rast_top - -* Main rasterization loop. Y holds the line number. -rastloop - sty ]cur_line ;3 - ldx ylooklo,y ;4 - stx ]hbasl ;3 - lda ylookhi,y ;4 -_pg_or1 ora #$20 ;2 will be $20 or $40 - sta ]hbash ;3 = 19 cycles - do USE_FAST-1 ;***** i.e. not USE_FAST - stx _wrhires+1 - sta _wrhires+2 - fin ;***** - -* divide left edge by 7 - ldx rastx0l,y ;4 line num in Y - lda rastx0h,y ;4 - bpl :noflag ;2 - sta rastx0h+1,y ;4 propagate - lda ]repting ;3 first time through? - beq :firstre ;2 yup, finish calculations - lda ]rgtbyte ;3 need this in A - bpl :repeat ;3 always -:firstre lda rastx0h,y ;reload - sta ]repting ;any nonzero will do - and #$7f ;strip repeat flag -:noflag beq :lotabl - lda mod7hi,x - sta ]lftbit - lda div7hi,x - sta ]lftbyte - bpl :gotlft ;always - BREAK ;debug -:lotabl lda mod7lo,x - sta ]lftbit - lda div7lo,x - sta ]lftbyte -:gotlft - -* divide right edge by 7 - ldx rastx1l,y ;4 line num in Y - lda rastx1h,y ;4 - beq :lotabr ;3 - lda mod7hi,x - sta ]rgtbit - lda div7hi,x - sta ]rgtbyte - bpl :gotrgt ;always - BREAK ;debug -:lotabr lda mod7lo,x ;4 - sta ]rgtbit ;3 - lda div7lo,x ;4 - sta ]rgtbyte ;3 = 25 for X1 < 256 -:gotrgt - -:repeat - cmp ]lftbyte ;3 - bne :not1byte ;3 - -* The left and right edges are in the same byte. We -* need to set up the mask differently, so we deal with -* it as a special case. - ldy ]lftbit - lda leftmask,y ;create the AND mask - ldx ]rgtbit - and rightmask,x ;strip out bits on right - sta ]andmask - - ldy ]lftbyte - lda colorline,y ;get color bits - eor (]hbasl),y ;combine w/screen - and ]andmask ;remove not-ours - eor (]hbasl),y ;combine again - sta (]hbasl),y - jmp rastlinedone - -* This is the more general case. We special-case the -* left and right edges, then byte-stomp the middle. -* On entry, ]rgtbyte is in A -:not1byte - sec ;2 compute number of full - sbc ]lftbyte ;3 and partial bytes to - tax ;2 draw - inx ;2 - - ldy ]rgtbit ;3 - cpy #6 ;2 - beq :rgtnospcl ;3 - lda rightmask,y ;handle partial-byte right - sta ]andmask - ldy ]rgtbyte - lda colorline,y - eor (]hbasl),y - and ]andmask - eor (]hbasl),y - sta (]hbasl),y - dex ;adjust count -:rgtnospcl - - ldy ]lftbit ;3 check left for partial - beq :lftnospcl ;3 - lda leftmask,y ;handle partial-byte left - sta ]andmask - ldy ]lftbyte - lda colorline,y - eor (]hbasl),y - and ]andmask - eor (]hbasl),y - sta (]hbasl),y - dex ;adjust count - beq rastlinedone ;bail if all done - iny ;advance start position - bne :liny ;always - BREAK -:lftnospcl - - ldy ]lftbyte ;3 -:liny - - do USE_FAST ;***** "fast" loop -* Instead of looping, jump into an unrolled loop. -* Cost is 10 cycles per byte with an extra 14 cycles -* of overhead, so we start to win at 4 bytes. - lda rastunidx,x ;4 - sta :_rastun+1 ;4 - lda colorline,y ;4 get odd/even color val -:_rastun jmp rast_unroll ;3 - - else ;***** "slow" loop -* Inner loop of the renderer. This runs 0-40x. -* Cost is 14 cycles/byte. - lda colorline,y ;get appropriate odd/even val -_wrhires sta $2000,y ;5 replaced with line addr -_xorcolor eor #$00 ;2 replaced with $00/$7f - iny ;2 - dex ;2 - bne _wrhires ;3 - - fin ;***** - -rastlinedone - ldy ]cur_line ;3 more lines to go? - cpy rast_bottom ;4 - bge :done ;2 - iny ;2 - jmp rastloop ;3 must have line in Y - -:done rts - -fixrastxor - do USE_FAST ;***** -* Update the EOR statements in the unrolled rastfill code. -* Doing this with a loop takes ~600 cycles, doing it with -* unrolled stores takes 160. We only do this when we -* need to, so changing the color from green to blue won't -* cause this to run. -* -* Call with the XOR value in A. -]offset = 0 - lup BYTES_PER_ROW - sta rast_unroll+3+]offset -]offset = ]offset+5 - --^ - BEEP - rts - fin ;***** - - -* include the line functions - put FDRAW.LINE - -* include the circle functions - put FDRAW.CIRCLE - - lst on -CODE_END equ * ;end of code section - lst off - -* include the data tables - put FDRAW.TABLES - - lst on -DAT_END equ * ;end of data / BSS - lst off - -* Save the appropriate object file. - do USE_FAST - sav FDRAW.FAST - else - sav FDRAW.SMALL - fin diff --git a/fdraw/FDRAW.TABLES.S b/fdraw/FDRAW.TABLES.S deleted file mode 100644 index d1d91f2..0000000 --- a/fdraw/FDRAW.TABLES.S +++ /dev/null @@ -1,339 +0,0 @@ -******************************** -* * -* Fast Apple II Graphics * -* By Andy McFadden * -* Version 0.3, Aug 2015 * -* * -* Pre-computed data and * -* large internal buffers. * -* (Included by FDRAW.S) * -* * -* Developed with Merlin-16 * -* * -******************************** - -* Expected layout with alignment: -* -* P1 ylooklo, misc tables -* P2 ylookhi, colorline -* P3 rastx0l -* P4 rastx0h -* P5 rastx1l -* P6 rastx1h, div7hi, mod7hi -* P7 div7lo -* P8 mod7lo -* P9 rast_unroll, rastunidx -* -* Tables should be just under $900 bytes. - - PG_ALIGN - -* Hi-res Y lookup, low part (192 bytes). -ylooklo HEX 0000000000000000 - HEX 8080808080808080 - HEX 0000000000000000 - HEX 8080808080808080 - HEX 0000000000000000 - HEX 8080808080808080 - HEX 0000000000000000 - HEX 8080808080808080 - HEX 2828282828282828 - HEX a8a8a8a8a8a8a8a8 - HEX 2828282828282828 - HEX a8a8a8a8a8a8a8a8 - HEX 2828282828282828 - HEX a8a8a8a8a8a8a8a8 - HEX 2828282828282828 - HEX a8a8a8a8a8a8a8a8 - HEX 5050505050505050 - HEX d0d0d0d0d0d0d0d0 - HEX 5050505050505050 - HEX d0d0d0d0d0d0d0d0 - HEX 5050505050505050 - HEX d0d0d0d0d0d0d0d0 - HEX 5050505050505050 - HEX d0d0d0d0d0d0d0d0 - -* Color masks for odd/even bytes, colors 0-7. -evencolor dfb $00,$2a,$55,$7f,$80,$aa,$d5,$ff -oddcolor dfb $00,$55,$2a,$7f,$80,$d5,$aa,$ff - -* XOR mask for colors 0-7 - non-BW flip on odd/even. -xormask dfb $00,$7f,$7f,$00,$00,$7f,$7f,$00 - -* AND mask for the 7 pixel positions, high bit set -* for the color shift. -andmask dfb $81,$82,$84,$88,$90,$a0,$c0 - -* These are pixel AND masks, used with the modulo 7 -* result. Entry #2 in leftmask means we're touching -* the rightmost 5 pixels, and entry #2 in rightmask -* means we're touching the 3 leftmost pixels. -* -* The high bit is always set, because we want to -* keep the color's high bit. -leftmask dfb $ff,$fe,$fc,$f8,$f0,$e0,$c0 -rightmask dfb $81,$83,$87,$8f,$9f,$bf,$ff - - PG_ALIGN - -* Hi-res Y lookup, high part (192 bytes). -* OR with $20 or $40. -ylookhi HEX 0004080c1014181c - HEX 0004080c1014181c - HEX 0105090d1115191d - HEX 0105090d1115191d - HEX 02060a0e12161a1e - HEX 02060a0e12161a1e - HEX 03070b0f13171b1f - HEX 03070b0f13171b1f - HEX 0004080c1014181c - HEX 0004080c1014181c - HEX 0105090d1115191d - HEX 0105090d1115191d - HEX 02060a0e12161a1e - HEX 02060a0e12161a1e - HEX 03070b0f13171b1f - HEX 03070b0f13171b1f - HEX 0004080c1014181c - HEX 0004080c1014181c - HEX 0105090d1115191d - HEX 0105090d1115191d - HEX 02060a0e12161a1e - HEX 02060a0e12161a1e - HEX 03070b0f13171b1f - HEX 03070b0f13171b1f - -* Masks for current color (even/odd), e.g. 55 2a 55 2a ... -* Updated whenever the color changes. -colorline ds 40 - - PG_ALIGN -rastx0l ds NUM_ROWS - PG_ALIGN -rastx0h ds NUM_ROWS - ds 1 ;repeat mode can overstep - PG_ALIGN -rastx1l ds NUM_ROWS - PG_ALIGN -rastx1h ds NUM_ROWS - -* Lookup tables for dividing 0-279 by 7. The "hi" -* parts are 24 bytes each, so they fit inside -* the previous 192-byte entry. The "lo" parts -* each fill a page. -div7hi HEX 2424242525252525 - HEX 2525262626262626 - HEX 2627272727272727 -mod7hi HEX 0405060001020304 - HEX 0506000102030405 - HEX 0600010203040506 - - PG_ALIGN - -div7lo HEX 0000000000000001 - HEX 0101010101010202 - HEX 0202020202030303 - HEX 0303030304040404 - HEX 0404040505050505 - HEX 0505060606060606 - HEX 0607070707070707 - HEX 0808080808080809 - HEX 0909090909090a0a - HEX 0a0a0a0a0a0b0b0b - HEX 0b0b0b0b0c0c0c0c - HEX 0c0c0c0d0d0d0d0d - HEX 0d0d0e0e0e0e0e0e - HEX 0e0f0f0f0f0f0f0f - HEX 1010101010101011 - HEX 1111111111111212 - HEX 1212121212131313 - HEX 1313131314141414 - HEX 1414141515151515 - HEX 1515161616161616 - HEX 1617171717171717 - HEX 1818181818181819 - HEX 1919191919191a1a - HEX 1a1a1a1a1a1b1b1b - HEX 1b1b1b1b1c1c1c1c - HEX 1c1c1c1d1d1d1d1d - HEX 1d1d1e1e1e1e1e1e - HEX 1e1f1f1f1f1f1f1f - HEX 2020202020202021 - HEX 2121212121212222 - HEX 2222222222232323 - HEX 2323232324242424 -mod7lo HEX 0001020304050600 - HEX 0102030405060001 - HEX 0203040506000102 - HEX 0304050600010203 - HEX 0405060001020304 - HEX 0506000102030405 - HEX 0600010203040506 - HEX 0001020304050600 - HEX 0102030405060001 - HEX 0203040506000102 - HEX 0304050600010203 - HEX 0405060001020304 - HEX 0506000102030405 - HEX 0600010203040506 - HEX 0001020304050600 - HEX 0102030405060001 - HEX 0203040506000102 - HEX 0304050600010203 - HEX 0405060001020304 - HEX 0506000102030405 - HEX 0600010203040506 - HEX 0001020304050600 - HEX 0102030405060001 - HEX 0203040506000102 - HEX 0304050600010203 - HEX 0405060001020304 - HEX 0506000102030405 - HEX 0600010203040506 - HEX 0001020304050600 - HEX 0102030405060001 - HEX 0203040506000102 - HEX 0304050600010203 - - -* RastFill unrolled loop. At each step we store the current -* color value, XOR it to flip the bits if needed, and advance. -* The caller needs to set the appropriate initial value based -* on whether the address is odd or even. -* -* We can use a 3-cycle "EOR dp" or a 2-cycle "EOR imm". The -* former is one cycle slower, the latter requires us to -* self-mod 40 instructions when the color changes. -* -* This must be page-aligned so that we can take the value -* from the rastunidx table and self-mod a JMP without having -* to do a 16-bit add. We have just enough room for the -* unrolled loop (40*5+3) and x5 table (41) = 244 bytes, fits -* on a single page. - - do USE_FAST ;***** - ds \ -]hbasl equ zptr0 ;must match FillRaster -rast_unroll equ * - lst off - lup BYTES_PER_ROW - sta (]hbasl),y ;6 - eor #$00 ;2 - iny ;2 10 cycles, 5 bytes - --^ - jmp rastlinedone - -* Index into rast_unroll. If we need to output N bytes, -* we want to jump to (rast_unroll + (40 - N) * 5) (where -* 5 is the number of bytes per iteration). -rastunidx -]offset = BYTES_PER_ROW*5 - lup BYTES_PER_ROW+1 ;0-40 - dfb ]offset -]offset = ]offset-5 - --^ - - fin ;***** - - -******************************** -* -* Code used to generate tables above. If you want to -* decrease load size, use these functions to generate -* the data into empty memory, then discard the code. -* (Maybe use a negative DS and overlap with rastx0l?) -* -******************************** - DO 0 ;***** - -init_ylook -]hbasl equ zptr1 -]hbash equ zptr1+1 - -* Initialize Y-lookup table. We just call the bascalc -* function. - ldx #NUM_ROWS - ldy #NUM_ROWS-1 -]loop tya - jsr bascalc - lda hbasl - sta ylooklo,y - lda hbash - ora #$20 ;remove for $0000 base - sta ylookhi,y - dey - dex - bne ]loop - rts - -* Hi-res base address calculation. This is based on the -* HPOSN routine at $F411. -* -* Call with the line in A. The results are placed into -* zptr1. X and Y are not disturbed. -* -* The value is in the $0000-1fff range, so you must OR -* the desired hi-res page in. -* -bascalc - pha - and #$c0 - sta ]hbasl - lsr - lsr - ora ]hbasl - sta ]hbasl - pla - sta ]hbash - asl - asl - asl - rol ]hbash - asl - rol ]hbash - asl - ror ]hbasl - lda ]hbash - and #$1f - sta ]hbash - rts - -* -* Create divide-by-7 tables. -* -mkdivtab -]val equ zloc0 - - ldy #0 - sty ]val - ldx #0 -]loop lda ]val - sta div7lo,y - txa - sta mod7lo,y - inx - iny - beq :lodone - cpx #7 - bne ]loop - inc ]val - ldx #0 - beq ]loop ;always -:lodone ;safe to ignore ]va update -]loop lda ]val - sta div7hi,y - txa - sta mod7hi,y - iny - cpy #280-256 - beq :hidone - inx - cpx #7 - bne ]loop - inc ]val - ldx #0 - beq ]loop ;always -:hidone rts - - FIN ;***** diff --git a/fdraw/fdraw.circle.s b/fdraw/fdraw.circle.s new file mode 100644 index 0000000..daf9b44 --- /dev/null +++ b/fdraw/fdraw.circle.s @@ -0,0 +1,754 @@ +******************************** +* * +* Fast Apple II Graphics * +* By Andy McFadden * +* Version 0.3, Aug 2015 * +* * +* Circle rendering * +* (Included by FDRAW.S) * +* * +* Developed with Merlin-16 * +* * +******************************** + +* TODO: if USE_FAST is 0, replace the outline circle +* plot code with calls to DrawPoint (or maybe a +* common sub-function so we don't trash the input +* parameters). Saves a little space. + + +******************************** +* +* Draw a circle. The radius is in in_rad, and +* the center is at in_x0l+in_x0h,in_y0. +* +******************************** +DrawCircle + lda #$20 ;JSR + cmp _cp08 ;configured for outline? + beq :okay + jsr fixcplot +:okay + jmp calc_circle + + +******************************** +* +* Draw filled circle. +* +******************************** +FillCircle + lda #$2c ;BIT + cmp _cp08 ;configured for fill? + beq :okay + jsr fixcplot +:okay + jsr calc_circle + jmp FillRaster + + +* Calculate a circle, using Bresenham's algorithm. The +* results are placed into the rasterization buffers. +* +* in_rad must be from 0 to 255. The x/y center +* coordinates must be on the screen, but the circle +* can extend off the edge. +* +* The computed values are stored in the rasterization +* tables. For an outline circle, we also plot the +* points immediately. + + do USE_FAST ;***** +* local storage -- not used often enough to merit DP +circ_8bit ds 1 +circ_clip ds 1 + fin ;***** + +calc_circle +max_fast_rad equ 41 +]cxl equ zloc0 +]cxh equ zloc1 +]cy equ zloc2 +]dlo equ zloc3 +]dhi equ zloc4 +]xsav equ zloc5 +]ysav equ zloc6 +]min_x equ zloc7 ;min/max offsets from center +]max_x equ zloc8 ;(min is above center, max +]min_y equ zloc9 ; is below) +]max_y equ zloc10 +]hitmp equ zloc11 +* only used by hplot for outline circles +]hbasl equ zptr0 +]andmask equ zloc11 ;overlaps with ]hitmp +]savxreg equ zloc12 +]savyreg equ zloc13 + +* Special-case radius=0. It removes an annoying +* edge case (first y-- becomes 0xff, but 6502 cmp +* is unsigned). + lda in_rad + bne :notzero + ldy in_y0 + sty rast_top + sty rast_bottom + lda in_x0l + sta rastx0l,y + sta rastx1l,y + lda in_x0h + sta rastx0h,y + sta rastx1h,y + rts + +* Use different version of function for small +* circles, because we can do it all in 8 bits. +:notzero + do USE_FAST ;***** + ldy #$01 + cmp #max_fast_rad ;in_rad in Acc + blt :use_fast + dey +:use_fast sty circ_8bit + fin ;***** + + lda in_x0l ;copy center to DP for speed + sta ]cxl + lda in_x0h + sta ]cxh + lda in_y0 + sta ]cy + +* Compute min/max values, based on offset from center. +* These are compared against offset-from-center x/y. +* We need tight bounds on Y because we use it to +* compute the rast_render top/bottom. Getting tight +* bounds on X is not so important, but we still need +* it for the no-clip optimization. + ldx #$04 ;count edges needing clip + + lda #NUM_ROWS-1 ;191 + sec + sbc ]cy ;maxY = 191-cy + cmp in_rad + blt :ylimok + lda in_rad ;clamp to radius + dex +:ylimok sta ]max_y ;maxY = 191-cy + + lda ]cy ;minY = cy + cmp in_rad + blt :ylimok2 + lda in_rad ;clamp to radius + dex +:ylimok2 sta ]min_y + + lda ]cxh + beq :xlimlo +* Examples (note # bad, must use rad +* cx=24, 23-24=255 + carry clear --> ok, chk rad +* cx=255, 23-255=24 + carry clear --> ok, chk rad +:xlimlo + lda # 255) ? + cmp in_rad + blt :xlimok2 + lda in_rad ;clamp to radius + dex +:xlimok2 sta ]min_x + +:xlimdone + + do USE_FAST ;***** + stx circ_clip + fin ;***** + +* set top/bottom rows for rasterizer + lda ]cy + clc + adc ]max_y + sta rast_bottom + lda ]cy + sec + sbc ]min_y + sta rast_top + + DO 0 ;debug debug debug + LDA ]min_x ;save a copy where the + STA $0380 ; monitor won't trash it + LDA ]max_x + STA $0381 + LDA ]min_y + STA $0382 + LDA ]max_y + STA $0383 + FIN + +* Set initial conditions for Bresenham. + ldx #0 ;:x = 0 + stx ]xsav + ldy in_rad ;:y = rad + sty ]ysav + lda #1 ;:d = 1 - rad + sec + sbc ]ysav ;in_rad + sta ]dlo + bcs :hizero ;C==1 if in_rad<=1 + ldx #$ff ;C was 0, make neg +:hizero stx ]dhi + +* +* Outer loop -- plot 8 points, then update values. +* +circ_loop + + do USE_FAST ;***** + lda circ_clip + beq ncypy + jmp with_clip + +* Quick version, no clipping required +* row cy+y: cx-x and cx+x +ncypy + lda ]ysav + clc + adc ]cy + tay ;y-coord in Y-reg + + lda ]cxl + sec + sbc ]xsav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp00 jsr cplotl + + lda ]cxl + clc + adc ]xsav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp01 jsr cplotrn + +* row cy-y: cx-x and cx+x +ncymy + lda ]cy + sec + sbc ]ysav + tay ;y-coord in Y-reg + + lda ]cxl + sec + sbc ]xsav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp02 jsr cplotl + + lda ]cxl + clc + adc ]xsav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp03 jsr cplotrn + +* row cy+x: cx-y and cx+y +ncypx + lda ]xsav ;off bottom? + clc + adc ]cy + tay ;y-coord in Y-reg + + lda ]cxl + sec + sbc ]ysav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp04 jsr cplotl + + lda ]cxl + clc + adc ]ysav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp05 jsr cplotrn + +* row cy-x: cx-y and cx+y +ncymx + lda ]cy + sec + sbc ]xsav + tay ;y-coord in Y-reg + + lda ]cxl + sec + sbc ]ysav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp06 jsr cplotl + + lda ]cxl + clc + adc ]ysav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp07 jsr cplotrn + +* CLICK + jmp circ_plot_done + + fin ;***** (USE_FAST) + +* +* Same thing, but this time clipping edges. +* +with_clip + +* row cy+y: cx-x and cx+x +ccypy + lda ]ysav ;off bottom? + cmp ]max_y + beq :cypy_ok + bge cypy_skip ;completely off screen +:cypy_ok clc + adc ]cy + tay ;y-coord in Y-reg + + ldx ]xsav ;handle cx-x + cpx ]min_x + blt :cxmx_ok + beq :cxmx_ok + lda #0 ;clip at 0 + sta rastx0l,y + sta rastx0h,y + beq cxmx_done0 ;always + BREAK +:cxmx_ok lda ]cxl + sec + sbc ]xsav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp08 jsr cplotl +cxmx_done0 + + cpx ]max_x ;handle cx+x + blt :cxpx_ok + beq :cxpx_ok + lda #NUM_COLS-1 + sta rastx1h,y + bne cxpx_done0 ;always + BREAK +:cxpx_ok lda ]cxl + clc + adc ]xsav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp09 jsr cplotr +cxpx_done0 +cypy_skip + +* row cy-y: cx-x and cx+x +ccymy + lda ]ysav ;off top? + cmp ]min_y + beq :cymy_ok + bge cymy_skip +:cymy_ok lda ]cy + sec + sbc ]ysav + tay ;y-coord in Y-reg + + ldx ]xsav ;handle cx-x + cpx ]min_x + blt :cxmx_ok + beq :cxmx_ok + lda #0 ;clip at 0 + sta rastx0l,y + sta rastx0h,y + beq cxmx_done1 ;always + BREAK +:cxmx_ok lda ]cxl + sec + sbc ]xsav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp10 jsr cplotl +cxmx_done1 + + cpx ]max_x ;handle cx+x + blt :cxpx_ok + beq :cxpx_ok + lda #NUM_COLS-1 + sta rastx1h,y + bne cxpx_done1 ;always + BREAK +:cxpx_ok lda ]cxl + clc + adc ]xsav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp11 jsr cplotr +cxpx_done1 +cymy_skip + +* row cy+x: cx-y and cx+y +ccypx + lda ]xsav ;off bottom? + cmp ]max_y + beq :cypx_ok + bge cypx_skip +:cypx_ok clc + adc ]cy + tay ;y-coord in Y-reg + + ldx ]ysav ;handle cx-y + cpx ]min_x + blt :cxmy_ok + beq :cxmy_ok + lda #0 ;clip at 0 + sta rastx0l,y + sta rastx0h,y + beq cxmy_done2 ;always + BREAK +:cxmy_ok lda ]cxl + sec + sbc ]ysav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp12 jsr cplotl +cxmy_done2 + + cpx ]max_x ;handle cx+y + blt :cxpy_ok + beq :cxpy_ok + lda #NUM_COLS-1 + sta rastx1h,y + bne cxpy_done2 ;always + BREAK +:cxpy_ok lda ]cxl + clc + adc ]ysav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp13 jsr cplotr +cxpy_done2 +cypx_skip + +* row cy-x: cx-y and cx+y +ccymx + lda ]xsav ;off top? + cmp ]min_y + beq :cymx_ok + bge cymx_skip +:cymx_ok lda ]cy + sec + sbc ]xsav + tay ;y-coord in Y-reg + + ldx ]ysav ;handle cx-y + cpx ]min_x + blt :cxmy_ok + beq :cxmy_ok + lda #0 ;clip at 0 + sta rastx0l,y + sta rastx0h,y + beq cxmy_done3 ;always + BREAK +:cxmy_ok lda ]cxl + sec + sbc ]ysav + sta rastx0l,y + lda ]cxh + sbc #$00 + sta rastx0h,y +_cp14 jsr cplotl +cxmy_done3 + + cpx ]max_x ;handle cx+y + blt :cxpy_ok + beq :cxpy_ok + lda #NUM_COLS-1 + sta rastx1h,y + bne cxpy_done3 ;always + BREAK +:cxpy_ok lda ]cxl + clc + adc ]ysav + sta rastx1l,y + lda ]cxh + adc #$00 + sta rastx1h,y +_cp15 jsr cplotr +cxpy_done3 +cymx_skip + +circ_plot_done +* Update X/Y/D. Up to about radius=41 we can maintain +* 'd' in an 8-bit register. + do USE_FAST ;***** + lda circ_8bit + beq circ_slow + +* +* Bresenham update, with 8-bit 'd'. +* + ldx ]xsav + lda ]dlo + bmi :dneg + txa ;:d = d + ((x-y)*4) +5 + sec + sbc ]ysav ;x <= y, may be neg or 0 + asl + asl + clc ;can't know carry + adc #5 + clc ;still don't want carry + adc ]dlo + sta ]dlo + dec ]ysav ;:y-- + jmp :loopbot +:dneg txa ;:d = d + (x*4) +3 + asl + asl ;x always pos, C=0 + DO 0 + BCC :TEST ;debug + BREAK ;debug +:TEST ;debug + FIN + adc #3 + adc ]dlo + sta ]dlo +:loopbot + inx ;:x++ + stx ]xsav + cpx ]ysav + beq :again + bge circ_done +:again jmp circ_loop + + fin ;***** + +* +* Bresenham update, with 16-bit 'd' +* +circ_slow + CLICK + ldx ]xsav + lda ]dhi + bmi :dneg + lda ]dlo + clc + adc #5 + sta ]dlo + bcc :noinc + inc ]dhi +:noinc + txa ;:d = d + ((x-y)*4) +5 + ldy #$00 + sty ]hitmp + sec + sbc ]ysav ;x <= y, may be neg or 0 + beq :xeqy ;if x==y, nothing to add + ldy #$ff + sty ]hitmp + asl + rol ]hitmp + asl + rol ]hitmp + clc + adc ]dlo + sta ]dlo + lda ]dhi + adc ]hitmp + sta ]dhi +:xeqy + dec ]ysav ;:y-- + jmp :loopbot + +:dneg lda ]dlo ;:d = d + (x*4) + 3 + clc + adc #3 + sta ]dlo + bcc :noinc2 + inc ]dhi +:noinc2 txa + ldy #0 ;x always positive + sty ]hitmp + asl + rol ]hitmp + asl + rol ]hitmp + clc ;not needed? + adc ]dlo + sta ]dlo + lda ]dhi + adc ]hitmp + sta ]dhi +:loopbot + inx ;:x++ + stx ]xsav + cpx ]ysav + beq :again + bge circ_done +:again jmp circ_loop + + +circ_done rts + + +* Plot a point for outline circle rendering. +* +* X and Y must be preserved. Y holds the current line +* number. +* +* Most DP locations are in use -- see the variable +* declarations at the start of the circle function. + +* cplotl is the entry point for the leftmost point. +cplotl + stx ]savxreg + sty ]savyreg + + lda ylooklo,y + sta ]hbasl + lda ylookhi,y +_pg_or2 ora #$20 + sta ]hbasl+1 + +* Convert the X coordinate into byte/bit. + ldx rastx0l,y ;x coord, lo + lda rastx0h,y ;>= 256? + beq :lotabl ;no, use the low table + ldy div7hi,x + lda mod7hi,x + bpl cplotcom ;always + BREAK ;debug +:lotabl ldy div7lo,x + lda mod7lo,x + jmp cplotcom + +* cplotr is the entry point for the rightmost point. +* We use rastx1 instead of rastx0. +cplotr + lda ylooklo,y + sta ]hbasl + lda ylookhi,y +_pg_or3 ora #$20 + sta ]hbasl+1 + +* If we just plotted the left point on the same line, +* we can skip the Y-lookup by jumping here. +cplotrn + stx ]savxreg + sty ]savyreg + + ldx rastx1l,y ;x coord, lo + lda rastx1h,y ;>= 256? + beq :lotabl ;no, use the low table + ldy div7hi,x + lda mod7hi,x + bpl cplotcom ;always + BREAK ;debug +:lotabl ldy div7lo,x + lda mod7lo,x + +* Plot the point. The byte offset (0-39) is in Y, +* the bit offset (0-6) is in A. +cplotcom + tax + lda colorline,y ;start with color pattern + eor (]hbasl),y ;flip all bits + and andmask,x ;clear other bits + eor (]hbasl),y ;restore ours, set theirs + sta (]hbasl),y + + ldx ]savxreg + ldy ]savyreg + rts + +* Reconfigure calc_circle to either JSR to cplotl/r, +* or just BIT the address (a 4-cycle no-op). The +* desired instruction is in A. +fixcplot + do USE_FAST ;***** + sta _cp00 + sta _cp01 + sta _cp02 + sta _cp03 + sta _cp04 + sta _cp05 + sta _cp06 + sta _cp07 + fin ;***** + sta _cp08 + sta _cp09 + sta _cp10 + sta _cp11 + sta _cp12 + sta _cp13 + sta _cp14 + sta _cp15 + rts + + diff --git a/fdraw/fdraw.line.s b/fdraw/fdraw.line.s new file mode 100644 index 0000000..10a454d --- /dev/null +++ b/fdraw/fdraw.line.s @@ -0,0 +1,590 @@ +******************************** +* * +* Fast Apple II Graphics * +* By Andy McFadden * +* Version 0.3, Aug 2015 * +* * +* Point and line functions * +* (Included by FDRAW.S) * +* * +* Developed with Merlin-16 * +* * +******************************** + + +******************************** +* +* Draw a single point in the current color. +* +******************************** +DrawPoint +]hbasl equ zptr0 + + ldy in_y0 + lda ylooklo,y + sta ]hbasl + lda ylookhi,y + ora g_page + sta ]hbasl+1 + + ldx in_x0l ;x coord, lo + lda in_x0h ;>= 256? + beq :lotabl ;no, use the low table + ldy div7hi,x + lda mod7hi,x + bpl :plotit ;always + BREAK ;debug +:lotabl ldy div7lo,x + lda mod7lo,x + +* Plot the point. The byte offset (0-39) is in Y, +* the bit offset (0-6) is in A. +:plotit + tax + lda colorline,y ;start with color pattern + eor (]hbasl),y ;flip all bits + and andmask,x ;clear other bits + eor (]hbasl),y ;restore ours, set theirs + sta (]hbasl),y + rts + + +******************************** +* +* Draw a line between two points. +* +******************************** +DrawLine + +]hbasl equ zptr0 +]xposl equ zloc0 ;always left edge +]xposh equ zloc1 +]ypos equ zloc2 ;top or bottom +]deltaxl equ zloc3 +]deltaxh equ zloc4 +]deltay equ zloc5 +]count equ zloc6 +]counth equ zloc7 +]diff equ zloc8 +]diffh equ zloc9 +]andmask equ zloc10 +]wideflag equ zloc11 ;doesn't really need DP + +* We use a traditional Bresenham run-length approach. +* Run-slicing is possible, but the code is larger +* and the increased cost means it's only valuable +* for longer lines. An optimal solution would switch +* approaches based on line length. +* +* Start by identifying where x0 or x1 is on the +* left. To make life simpler we always work from +* left to right, flipping the coordinates if +* needed. +* +* We also need to figure out if the line is more +* than 255 pixels long -- which, because of +* inclusive coordinates, means abs(x0-x1) > 254. + lda in_x1l ;assume x0 on left + sec + sbc in_x0l + tax + beq checkvert ;low bytes even, check hi + lda in_x1h + sbc in_x0h + bcs lx0left + +* x1 is on the left, so the values are negative +* (hi byte in A, lo byte in X) +lx0right eor #$ff ;invert hi + sta ]deltaxh ;store + txa + eor #$ff ;invert lo + sta ]deltaxl + inc ]deltaxl ;add one for 2s complement + bne :noinchi ;rolled into high byte? + inc ]deltaxh ;yes +:noinchi lda in_x1l ;start with x1 + sta ]xposl + lda in_x1h + sta ]xposh + lda in_y1 + sta ]ypos + sec + sbc in_y0 ;compute deltay + jmp lncommon + +checkvert + lda in_x1h ;diff high bytes + sbc in_x0h ;(carry still set) + blt lx0right ;width=256, x0 right + bne lx0left ;width=256, x0 left + jmp vertline ;all zero, go vert + +* (branch back from below) +* This is a purely horizontal line. We farm the job +* out to the raster fill code for speed. (There's +* no problem with the line code handling it; its just +* more efficient to let the raster code do it.) +phorizontal + ldy ]ypos + sty rast_top + sty rast_bottom + lda ]xposl + sta rastx0l,y + clc + adc ]deltaxl ;easier to add delta back + sta rastx1l,y ; in than sort out which + lda ]xposh ; arg is left vs. right + sta rastx0h,y + adc ]deltaxh + sta rastx1h,y + jmp FillRaster + +* x0 is on the left, so the values are positive +lx0left stx ]deltaxl + sta ]deltaxh + lda in_x0l ;start with x0 + sta ]xposl + lda in_x0h + sta ]xposh + lda in_y0 ;and y0 + sta ]ypos + sec + sbc in_y1 ;compute deltay + +* Value of (starty - endy) is in A, flags still set. +lncommon + bcs :posy + eor #$ff ;negative, invert + adc #$01 + sta ]deltay + lda #$e8 ;INX + bne gotdy +:posy +_lmb beq phorizontal + sta ]deltay + lda #$ca ;DEX +gotdy sta _hmody + sta _vmody + sta _wmody + + do 0 ;***** for regression test + ldx #$01 + lda ]deltaxh + bne :iswide + lda ]deltaxl + cmp #$ff ;== 255? + beq :iswide + ldx #$00 ;notwide +:iswide stx $300 + lda ]xposl + sta $301 + lda ]xposh + sta $302 + lda ]ypos + sta $303 + ldx ]deltaxl + stx $304 + ldx ]deltaxh + stx $305 + ldx ]deltay + stx $306 + lda _hmody + and #$20 ;nonzero means inc, + sta $307 ; zero means dec + fin ;***** + +* At this point we have the initial X position in +* ]startxl/h, the initial Y position in ]starty, +* deltax in ]deltaxl, deltay in ]deltay, and we've +* tweaked the Y-update instructions to either INC or +* DEC depending on the direction of movement. +* +* The next step is to decide whether the line is +* horizontal-dominant or vertical-dominant, and +* branch to the appropriate handler. +* +* The core loops for horiz and vert take about +* 80 cycles when moving diagonally, and about +* 20 fewer when moving in the primary direction. +* The wide-horiz is a bit slower. + ldy #$01 ;set "wide" flag to 1 + lda ]deltaxl + ldx ]deltaxh + bne horzdom ;width >= 256 + cmp #$ff ;width == 255 + beq horzdom + dey ;not wide + cmp ]deltay + bge horzdom ; for diagonal lines + jmp vertdom + +* We could special-case pure-diagonal lines here +* (just BEQ a couple lines up). It does +* represent our worst case. I'm not convinced +* we'll see them often enough to make it worthwhile. + + +* horizontal-dominant +horzdom + sty ]wideflag + sta ]count ;:count = deltax + 1 + inc ]count + lsr ;:diff = deltax / 2 + sta ]diff + +* set Y to the byte offset in the line +* load the AND mask into ]andmask + ldx ]xposl + lda ]xposh ;>= 256? + beq :lotabl ;no, use the low table + ldy div7hi,x + lda mod7hi,x + bpl :gottab ;always +* BREAK ;debug +:lotabl ldy div7lo,x + lda mod7lo,x +:gottab + tax + lda andmask,x + sta ]andmask + +* Set initial value for line address. + ldx ]ypos + lda ylooklo,x + sta ]hbasl + lda ylookhi,x + ora g_page + sta ]hbasl+1 + + lda ]wideflag ;is this a "wide" line? + beq :notwide ;nope, stay local + jmp widedom + +:notwide lda colorline,y ;set initial color mask + sta _hlcolor+1 + jmp horzloop + +hrts rts + +* bottom of loop, essentially +hnoroll sta ]diff ;3 +hdecc dec ]count ;5 :count-- + beq hrts ;2 :while (count != 0) + ;= 7 or 10 + +* We keep the byte offset in the line in Y, and the +* line index in X, for the entire loop. +horzloop +_hlcolor lda #$00 ;2 start with color pattern +_lmdh eor (]hbasl),y ;5 flip all bits + and ]andmask ;3 clear other bits + eor (]hbasl),y ;5 restore ours, set theirs + sta (]hbasl),y ;6 = 21 + +* Move right. We shift the bit mask that determines +* the pixel. When we shift into bit 7, we know it's +* time to advance another byte. +* +* If this is a shallow line we would benefit from +* keeping the index in X and just doing a 4-cycle +* indexed load to get the mask. Not having the +* line number in X makes the line calc more +* expensive for steeper lines though. + lda ]andmask ;3 + asl ;2 shift, losing hi bit + eor #$80 ;2 set the hi bit + bne :noh8 ;3 cleared hi bit? +* We could BEQ away and branch back in, but this +* happens every 7 iterations, so on average it's +* a very small improvement. If we happen to branch +* across a page boundary the double-branch adds +* two more cycles and we lose. + iny ;2 advance to next byte + lda colorline,y ;4 update color mask + sta _hlcolor+1 ;4 + lda #$81 ;2 reset +:noh8 sta ]andmask ;3 = 13 + ((12-1)/7) = 14 + +* Update error diff. + lda ]diff ;3 + sec ;2 + sbc ]deltay ;3 :diff -= deltay + bcs hnoroll ;2+ :if (diff < 0) ... + ;= 11 level, 10 up/down + adc ]deltaxl ;3 : diff += deltax + sta ]diff ;3 +_hmody inx ;2 : ypos++ (or --) + lda ylooklo,x ;4 update hbasl after line + sta ]hbasl ;3 change + lda ylookhi,x ;4 +_pg_or4 ora #$20 ;2 + sta ]hbasl+1 ;3 + bne hdecc ;3 = +27 this path -> 37 + BREAK +* horizontal: 10+21+14+11=56 cycles/pixel +* diagonal: 7+21+14+37=79 cycles/pixel + + +* Vertical-dominant line. Could go up or down. +vertdom + ldx in_y0 + cpx ]ypos ;starting at y0? + bne :endy0 ;yup + ldx in_y1 ;nope +:endy0 stx _vchk+1 ;end condition + + lda ]deltay + lsr + sta ]diff ;:diff = deltay / 2 + +* set Y to the byte offset in the line +* load the AND mask into ]andmask + ldx ]xposl + lda ]xposh ;>= 256? + beq :lotabl ;no, use the low table + ldy div7hi,x + lda mod7hi,x + bpl :gottab ;always + BREAK ;debug +:lotabl ldy div7lo,x + lda mod7lo,x +:gottab + tax + lda andmask,x ;initial pixel mask + sta ]andmask + + lda colorline,y ;initial color mask + sta _vlcolor+1 + + ldx ]ypos + jmp vertloop + +* We keep the byte offset in the line in Y, and the +* line index in X, for the entire loop. + +* Bottom of loop, essentially. +vnoroll sta ]diff ;3 + +vertloop + lda ylooklo,x ;4 + sta ]hbasl ;3 + lda ylookhi,x ;4 +_pg_or5 ora #$20 ;2 + sta ]hbasl+1 ;3 = 16 + +_vlcolor lda #$00 ;2 start with color pattern +_lmdv eor (]hbasl),y ;5 flip all bits + and ]andmask ;3 clear other bits + eor (]hbasl),y ;5 restore ours, set theirs + sta (]hbasl),y ;6 = 21 + +_vchk cpx #$00 ;2 was this last line? + beq vrts ;2 yes, done +_vmody inx ;2 :ypos++ (or --) + +* Update error diff. + lda ]diff ;3 + sec ;2 + sbc ]deltaxl ;3 :diff -= deltax + bcs vnoroll ;2 :if (diff < 0) ... + ;= 10 vert, 9 move right + + adc ]deltay ;3 : diff += deltay + sta ]diff ;3 +* Move right. We shift the bit mask that determines +* the pixel. When we shift into bit 7, we know it's +* time to advance another byte. + lda ]andmask ;3 + asl ;2 shift, losing hi bit + eor #$80 ;2 set the hi bit + beq :is8 ;2+ goes to zero on 8th bit + sta ]andmask ;3 + bne vertloop ;3 = 21 + (18/7) = 24 + BREAK + +:is8 iny ;2 advance to next byte + lda colorline,y ;4 update color + sta _vlcolor+1 ;4 + lda #$81 ;2 reset + sta ]andmask ;3 + bne vertloop ;3 = 18 + BREAK +vrts rts +* vertical: 3 + 16 + 21 + 6 + 10 = 56 cycles +* diagonal: 16 + 21 + 6 + 9 + 24 = 76 cycles + + +* "Wide" horizontally-dominant loop. We have to +* maintain error-diff and deltax as 16-bit values. +* Most of the setup from the "narrow" version carried +* over, but we have to re-do the count and diff. +* +* Normally we set count to (deltax + 1) and decrement +* to zero, but it's actually easier to set it equal +* to deltax and check for -1. +widedom + lda ]deltaxh ;:count = deltax + sta ]counth + ldx ]deltaxl + stx ]count + stx ]diff + lsr ;:diff = deltax / 2 + ror ]diff + sta ]diffh + ldx ]ypos + + lda colorline,y ;set initial color mask + sta _wlcolor+1 + +* We keep the byte offset in the line in Y, and the +* line index in X, for the entire loop. +wideloop +_wlcolor lda #$00 ;2 start with color pattern +_lmdw eor (]hbasl),y ;5 flip all bits + and ]andmask ;3 clear other bits + eor (]hbasl),y ;5 restore ours, set theirs + sta (]hbasl),y ;6 = 21 + +* Move right. We shift the bit mask that determines +* the pixel. When we shift into bit 7, we know it's +* time to advance another byte. + lda ]andmask ;3 + asl ;2 shift, losing hi bit + eor #$80 ;2 set the hi bit + bne :not7 ;3 goes to zero on 8th bit + iny ; 2 advance to next byte + lda colorline,y ; 4 update color mask + sta _hlcolor+1 ; 4 + lda #$81 ; 2 reset +:not7 sta ]andmask ;3 = 13 usually, 25 every 7 + +* Update error diff, which is a positive number. If +* it goes negative ("if (diff < 0)") we act. + lda ]diff + sec + sbc ]deltay ;:diff -= deltay + bcs wnoroll ;didn't even roll low byte + dec ]diffh ;check hi byte + bpl wnoroll ;went 1->0, keep going + + adc ]deltaxl ;: diff += deltax + sta ]diff + lda ]diffh + adc ]deltaxh + sta ]diffh +_wmody inx ;: ypos++ (or --) + lda ylooklo,x ;update hbasl after line + sta ]hbasl ; change + lda ylookhi,x +_pg_or6 ora #$20 + sta ]hbasl+1 + bne wdecc + BREAK + +wnoroll sta ]diff + +wdecc dec ]count ;5 :count-- + lda ]count ;3 + cmp #$ff ;2 + bne wideloop ;3 :while (count > -1) + dec ]counth ;low rolled, decr high + beq wideloop ;went 1->0, keep going + rts + + +* Pure-vertical line. These are common in certain +* applications, and checking for it only adds two +* cycles to the general case. +vertline + ldx in_y0 + ldy in_y1 + cpx in_y1 ;y0 < y1? + blt :usey0 ;yes, go from y0 to y1 + txa ;swap X/A + tay + ldx in_y1 +:usey0 stx ]ypos + iny + sty _pvytest+1 + + ldx in_x0l ;xc lo + lda in_x0h ;>= 256? + beq :lotabl + ldy div7hi,x + lda mod7hi,x + bpl :gotit ;always +:lotabl ldy div7lo,x + lda mod7lo,x + +* Byte offset is in Y, mod-7 value is in A. +:gotit tax + lda andmask,x + sta _pvand+1 ;this doesn't change + + lda colorline,y + sta _pvcolor+1 ;nor does this + + ldx ]ypos ;top line + +* There's a trick where, when (linenum & 0x07) is +* nonzero, you just add 4 to hbasl+1 instead of +* re-doing the lookup. However, TXA+AND+BEQ +* followed by LDA+CLC+ADC+STA is 16 cycles, the same +* as our self-modified lookup, so it's not a win. +* (And if we used a second ylookhi and self-modded +* the table address, we could shave off another 2.) + +* Main pure-vertical loop +pverloop + lda ylooklo,x ;4 + sta ]hbasl ;3 + lda ylookhi,x ;4 +_pg_or7 ora #$20 ;2 + sta ]hbasl+1 ;3 (= 16) + +_pvcolor lda #$00 ;2 start with color pattern +_lmdpv eor (]hbasl),y ;5 flip all bits +_pvand and #$00 ;2 clear other bits + eor (]hbasl),y ;5 + sta (]hbasl),y ;6 (= 20) + + inx ;2 +_pvytest cpx #$00 ;2 done? + bne pverloop ;3 = 7 + rts +* 43 cycles/pixel + + +******************************** +* +* Set the line mode according to in_arg +* +* A slightly silly feature to get xdraw lines +* without really working for it. +* +******************************** +SetLineMode + lda in_arg + beq :standard + +* configure for xdraw + lda #$24 ;BIT dp + sta _lmb + sta _lmdh + sta _lmdv + sta _lmdw + sta _lmdpv + rts + +* configure for standard drawing +:standard lda #$f0 ;BEQ + sta _lmb + lda #$51 ;EOR (dp),y + sta _lmdh + sta _lmdv + sta _lmdw + sta _lmdpv + rts + + diff --git a/fdraw/fdraw.s b/fdraw/fdraw.s new file mode 100644 index 0000000..968436d --- /dev/null +++ b/fdraw/fdraw.s @@ -0,0 +1,807 @@ +******************************** +* * +* Fast Apple II Graphics * +* By Andy McFadden * +* Version 0.3, Aug 2015 * +* * +* Main source file * +* * +* Developed with Merlin-16 * +* * +******************************** + +* Set to 1 to build FDRAW.FAST, set to zero to +* build FDRAW.SMALL. +USE_FAST equ 1 + +* Set to 1 to turn on beeps/clicks for debugging. +NOISE_ON equ 0 + + + lst off + org $9400 ;;; CUSTOMIZED FOR APPLECORN + +* +* Macros. +* +spkr equ $c030 +bell equ $ff3a + +* If enabled, click the speaker (changes flags only). +CLICK mac + do NOISE_ON + bit spkr + fin + <<< +* If enabled, beep the speaker (scrambles regs). +BEEP mac + do NOISE_ON + jsr bell + fin + <<< +* If enabled, insert a BRK. +BREAK mac + do NOISE_ON + brk $99 + fin + <<< + +* In "fast" mode, we align tables on page boundaries so we +* don't take a 1-cycle hit when the indexing crosses a page. +* In "small" mode, we skip the alignment. +PG_ALIGN mac + do USE_FAST + ds \ + fin + <<< + +* +* Hi-res screen constants. +* +BYTES_PER_ROW = 40 +NUM_ROWS = 192 +NUM_COLS = 280 + +* +* Variable storage. We assign generic names to +* zero-page scratch locations, then assign variables +* with real names to these. +* +* 06-09 are unused (except by SWEET-16) +* 1a-1d are Applesoft hi-res scratch +* cc-cf are only used by INTBASIC +* eb-ef and ff appear totally unused by ROM routines +* +zptr0 equ $1a ;2b +zloc0 equ $06 +zloc1 equ $07 +zloc2 equ $08 +zloc3 equ $09 +zloc4 equ $1c +zloc5 equ $1d +zloc6 equ $cc +zloc7 equ $cd +zloc8 equ $ce +zloc9 equ $cf +zloc10 equ $eb +zloc11 equ $ec +zloc12 equ $ed +zloc13 equ $ee + + +******************************** +* +* Entry points for external programs. +* +******************************** +Entry + jmp Init ;initialize data tables + dfb 0,3 ;version number + +* +* Parameters passed from external programs. +* +in_arg ds 1 ;generic argument +in_x0l ds 1 ;X coordinate 0, low part +in_x0h ds 1 ;X coordinate 0, high part +in_y0 ds 1 ;Y coordinate 0 +in_x1l ds 1 +in_x1h ds 1 +in_y1 ds 1 +in_rad ds 1 ;radius for circles + + ds 3 ;pad to 16 bytes + + jmp SetColor + jmp SetPage + jmp Clear + jmp DrawPoint + jmp DrawLine + jmp DrawRect + jmp FillRect + jmp DrawCircle + jmp FillCircle + jmp SetLineMode + jmp noimpl ;reserved2 + jmp FillRaster + +* Raster fill values. Top, bottom, and pointers to tables +* for the benefit of external callers. +rast_top ds 1 +rast_bottom ds 1 + da rastx0l + da rastx0h + da rastx1l + da rastx1h + +noimpl rts + + +******************************** +* +* Global variables. +* +******************************** + +g_inited dfb 0 ;initialized? +g_color dfb 0 ;hi-res color (0-7) +g_page dfb $20 ;hi-res page ($20 or $40) + + +******************************** +* +* Initialize. +* +******************************** +Init + lda #$00 + sta in_arg + jsr SetColor ;set color to zero + jsr SetLineMode ;set normal lines + lda #$20 + sta in_arg + sta g_inited + jmp SetPage ;set hi-res page 1 + + +******************************** +* +* Set the color. +* +******************************** +SetColor + lda in_arg + cmp g_color ;same as the old color? + beq :done + + and #$07 ;safety first + sta g_color + +* Update the "colorline" table, which provides a quick color +* lookup for odd/even bytes. We could also have one table +* per color and self-mod the "LDA addr,y" instructions to +* point to the current one, but that uses a bunch of memory +* and is kind of ugly. Takes 16 + (12 * 40) = 496 cycles. + tax ;2 + lda xormask,x ;4 + sta :_xormsk+1 ;4 + + lda oddcolor,x ;4 + ldy #BYTES_PER_ROW-1 ;2 +]loop sta colorline,y ;5 +:_xormsk eor #$00 ;2 + dey ;2 + bpl ]loop ;3 + +:done rts + + +******************************** +* +* Set the page. +* +******************************** +SetPage + lda g_inited ;let's just check this + beq noinit ; (not called too often) + + lda in_arg + cmp #$20 + beq :good + cmp #$40 + beq :good + jmp bell +:good + sta g_page + + do 0 ;***** + cmp ylookhi + beq :tabok +* Check to see if the values currently in the Y-lookup table +* match our current page setting. If they don't, we need to +* adjust the code that does lookups. + +* This approach modifies the table itself, paying a large +* cost now so we don't have to pay it on every lookup. +* However, this costs 2+(16*192)=3074 cycles, while an +* "ORA imm" only adds two to each lookup, so we'd have +* to do a lot of drawing to make this worthwhile. +* (Note: assumes ylookhi is based at $2000 not $0000) + ldy #NUM_ROWS ;2 +]loop lda ylookhi-1,y ;4 + eor #$60 ;2 $20 <--> $40 + sta ylookhi-1,y ;5 + dey ;2 + bne ]loop ;3 + + else ;***** + +* This approach uses self-modifying code to update the +* relevant instructions. It's a bit messy to have it +* here, but it saves us from having to do it on +* every call. +* +* We could also have a second y-lookup table and +* use this to update the pointers. That would let +* us drop the "ORA imm" entirely, without the cost +* of the rewrite above, but eating up another 192 bytes. + sta _pg_or1+1 ;rastfill + sta _pg_or2+1 ;circle hplot + sta _pg_or3+1 ;circle hplot + sta _pg_or4+1 ;drawline + sta _pg_or5+1 ;drawline + sta _pg_or6+1 ;drawline + sta _pg_or7+1 ;drawline + + fin ;***** + +:tabok rts + +noinit ldy #$00 +]loop lda :initmsg,y + beq :done + jsr $fded ;cout + iny + bne ]loop +:done rts + +:initmsg asc "FDRAW NOT INITIALIZED",87,87,00 + + +******************************** +* +* Clear the screen to the current color. +* +******************************** +Clear + + do USE_FAST ;***** +* This performs a "visually linear" clear, erasing the screen +* from left to right and top to bottom. To reduce the amount +* of code required we erase in thirds (top/middle/bottom). +* +* Compare to a "venetian blind" clear, which is what you get +* if you erase memory linearly. +* +* The docs discuss different approaches. This version +* requires ((2 + 5*64 + 11) * 40 + 14) * 3 = 40002 cycles. +* If we didn't divide it into thirds to keep the top-down +* look, we'd need (5*64 + 9) * 120 = 39480 cycles, so +* we're spending 522 cycles to avoid the venetian look. + lda :clrloop+2 + cmp g_page + beq :pageok + +* We're on the wrong hi-res page. Flip to the other one. +* 4 + (20*64) = 1284 cycles to do the flip (+ a few more +* because we're probably crossing a page boundary). + BEEP + ldy #NUM_ROWS ;2 +]loop lda :clrloop-3+2,y ;4 + eor #$60 ;2 + sta :clrloop-3+2,y ;5 + dey ;2 + dey ;2 + dey ;2 + bne ]loop ;3 + +:pageok ldx g_color ;grab the current color + lda xormask,x + sta :_xormsk+1 + lda evencolor,x + + ldy #0 + jsr :clearthird + ldy #BYTES_PER_ROW + jsr :clearthird + ldy #BYTES_PER_ROW*2 +* fall through into :clearthird for final pass + +:clearthird + ldx #BYTES_PER_ROW-1 ;2 +:clrloop sta $2000,y ;5 (* 64) + sta $2400,y ;this could probably be + sta $2800,y ; done with LUP math + sta $2c00,y + sta $3000,y + sta $3400,y + sta $3800,y + sta $3c00,y + sta $2080,y + sta $2480,y + sta $2880,y + sta $2c80,y + sta $3080,y + sta $3480,y + sta $3880,y + sta $3c80,y + sta $2100,y + sta $2500,y + sta $2900,y + sta $2d00,y + sta $3100,y + sta $3500,y + sta $3900,y + sta $3d00,y + sta $2180,y + sta $2580,y + sta $2980,y + sta $2d80,y + sta $3180,y + sta $3580,y + sta $3980,y + sta $3d80,y + sta $2200,y + sta $2600,y + sta $2a00,y + sta $2e00,y + sta $3200,y + sta $3600,y + sta $3a00,y + sta $3e00,y + sta $2280,y + sta $2680,y + sta $2a80,y + sta $2e80,y + sta $3280,y + sta $3680,y + sta $3a80,y + sta $3e80,y + sta $2300,y + sta $2700,y + sta $2b00,y + sta $2f00,y + sta $3300,y + sta $3700,y + sta $3b00,y + sta $3f00,y + sta $2380,y + sta $2780,y + sta $2b80,y + sta $2f80,y + sta $3380,y + sta $3780,y + sta $3b80,y + sta $3f80,y +:_xormsk eor #$00 ;2 flip odd/even bits + iny ;2 + dex ;2 + bmi :done ;2 + jmp :clrloop ;3 +:done rts + + else ;***** not USE_FAST + +* This version was suggested by Marcus Heuser on +* comp.sys.apple2.programmer. It does a "venetian blind" +* clear, and takes (5 * 32 + 7) * 248 = 41416 cycles. +* It overwrites half of the screen holes. + lda :clrloop+5 + cmp g_page + beq :pageok + +* We're on the wrong hi-res page. Flip to the other one. +* 12 + (20*31) = 632 cycles to do the flip. We have to +* single out the first entry because it's $1f not $20. + BEEP + lda :clrloop+2 ;4 + eor #$20 ;2 $1f <-> $3f + sta :clrloop+2 ;4 + ldy #31*3 ;2 +]loop lda :clrloop+2,y ;4 + eor #$60 ;2 $20 <-> $40 + sta :clrloop+2,y ;5 + dey ;2 + dey ;2 + dey ;2 + bne ]loop ;3 + +:pageok ldx g_color + lda xormask,x + sta :_xormsk+1 + lda oddcolor,x + ldy #248 ;120 + 8 + 120 +:clrloop +]addr = $1fff + lup 32 ;begin a loop in assembler + sta ]addr,y ;5 +]addr = ]addr+$100 ;sta 20ff,21ff,... + --^ +:_xormsk eor #$00 ;2 + dey ;2 + bne :clrloop ;3 + rts + + fin ;***** not USE_FAST + + +******************************** +* +* Draw rectangle outline. +* +******************************** +DrawRect +* We could just issue 4 line draw calls here, maybe +* adjusting the vertical lines by 1 pixel up/down to +* avoid overdraw. But if the user wanted 4 lines, +* they could just draw 4 lines. Instead, we're going +* to draw a double line on each edge to ensure that +* the outline rectangle always has the correct color. +* +* Rather than draw two vertical lines, we draw a +* two-pixel-wide filled rectangle on each side. +* +* We don't want to double-up if the rect is only one +* pixel wide, so we have to check for that. +* +* If the rect is one pixel high, it's just a line. +* If it's two pixels high, we don't need to draw +* the left/right edges, just the top/bottom lines. +* If it's more than two tall, we don't need to draw +* the left/right edges on the top and bottom lines, +* so we save a few cycles by skipping those. + + lda in_y1 ;copy top/bottom to local + sta rast_bottom + dec rast_bottom ;move up one + sec + sbc in_y0 + beq :isline ;1 pixel high, just draw line + cmp #1 + beq :twolines ;2 pixels high, lines only + ldy in_y0 + iny ;start down a line + sty rast_top + + lda in_x0h ;check to see if left/right + cmp in_x1h ; coords are the same; if + bne :notline ; so, going +1/-1 at edge + lda in_x0l ; will overdraw. + cmp in_x1l + bne :notlin1 + +:isline jmp DrawLine ;just treat like line + +* Set up left edge. Top line is in Y. +:notline lda in_x0l +:notlin1 sta rastx0l,y + clc + adc #1 + sta rastx1l,y + lda in_x0h + ora #$80 ;"repeat" flag + sta rastx0h,y + and #$7f + adc #0 + sta rastx1h,y + jsr FillRaster + + ldy rast_top + lda in_x1l ;now set up right edge + sta rastx1l,y + sec + sbc #1 + sta rastx0l,y + lda in_x1h + sta rastx1h,y + sbc #0 + ora #$80 ;"repeat" flag + sta rastx0h,y + jsr FillRaster + +* Now the top/bottom lines. +:twolines + ldy in_y0 + jsr :drawline + ldy in_y1 + +:drawline + sty rast_top + sty rast_bottom + lda in_x0l ;copy left/right to the + sta rastx0l,y ; table entry for the + lda in_x0h ; appropriate line + sta rastx0h,y + lda in_x1l + sta rastx1l,y + lda in_x1h + sta rastx1h,y + jmp FillRaster + + +******************************** +* +* Draw filled rectangle. +* +******************************** +FillRect +* Just fill out the raster table and call the fill routine. +* We require y0=top, y1=bottom, x0=left, x1=right. + ldy in_y0 + sty rast_top + lda in_y1 + sta rast_bottom + + lda in_x0l + sta rastx0l,y + lda in_x0h + ora #$80 ;"repeat" flag + sta rastx0h,y + lda in_x1l + sta rastx1l,y + lda in_x1h + sta rastx1h,y + + jmp FillRaster + + +******************************** +* +* Fill an area defined by the raster tables. +* +******************************** +FillRaster + +* Render rasterized output. The left and right edges +* are stored in the rastx0/rastx1 tables, and the top +* and bottom-most pixels are in rast_top/rast_bottom. +* +* This can be used to render an arbitrary convex +* polygon after it has been rasterized. +* +* If the high bit of the high byte of X0 is set, we +* go into "repeat" mode, where we just repeat the +* previous line. This saves about 40 cycles of +* overhead per line when drawing rectangles, plus +* what we would have to spend to populate multiple +* lines of the raster table. It only increases the +* general per-line cost by 3 cycles. +* +* We could use the "repeat" flag to use this code to +* draw vertical lines, though that's mostly of value +* to an external caller who knows ahead of time that +* the line is vertical. The DrawLine code is pretty +* good with vertical lines, and adding additional +* setup time to every vertical-dominant line to +* decide if it should call here seems like a +* losing proposition. + +]hbasl equ zptr0 +]hbash equ zptr0+1 +]lftbyte equ zloc0 +]lftbit equ zloc1 +]rgtbyte equ zloc2 +]rgtbit equ zloc3 +]line equ zloc4 +]andmask equ zloc5 +]cur_line equ zloc6 +]repting equ zloc7 + + ldx g_color ;configure color XOR byte + lda xormask,x + do USE_FAST ;***** + cmp rast_unroll+3 ;already configured? + beq :goodmask + jsr fixrastxor +:goodmask + else + sta _xorcolor+1 + fin ;***** + + lda #$00 + sta ]repting + + ldy rast_top + +* Main rasterization loop. Y holds the line number. +rastloop + sty ]cur_line ;3 + ldx ylooklo,y ;4 + stx ]hbasl ;3 + lda ylookhi,y ;4 +_pg_or1 ora #$20 ;2 will be $20 or $40 + sta ]hbash ;3 = 19 cycles + do USE_FAST-1 ;***** i.e. not USE_FAST + stx _wrhires+1 + sta _wrhires+2 + fin ;***** + +* divide left edge by 7 + ldx rastx0l,y ;4 line num in Y + lda rastx0h,y ;4 + bpl :noflag ;2 + sta rastx0h+1,y ;4 propagate + lda ]repting ;3 first time through? + beq :firstre ;2 yup, finish calculations + lda ]rgtbyte ;3 need this in A + bpl :repeat ;3 always +:firstre lda rastx0h,y ;reload + sta ]repting ;any nonzero will do + and #$7f ;strip repeat flag +:noflag beq :lotabl + lda mod7hi,x + sta ]lftbit + lda div7hi,x + sta ]lftbyte + bpl :gotlft ;always + BREAK ;debug +:lotabl lda mod7lo,x + sta ]lftbit + lda div7lo,x + sta ]lftbyte +:gotlft + +* divide right edge by 7 + ldx rastx1l,y ;4 line num in Y + lda rastx1h,y ;4 + beq :lotabr ;3 + lda mod7hi,x + sta ]rgtbit + lda div7hi,x + sta ]rgtbyte + bpl :gotrgt ;always + BREAK ;debug +:lotabr lda mod7lo,x ;4 + sta ]rgtbit ;3 + lda div7lo,x ;4 + sta ]rgtbyte ;3 = 25 for X1 < 256 +:gotrgt + +:repeat + cmp ]lftbyte ;3 + bne :not1byte ;3 + +* The left and right edges are in the same byte. We +* need to set up the mask differently, so we deal with +* it as a special case. + ldy ]lftbit + lda leftmask,y ;create the AND mask + ldx ]rgtbit + and rightmask,x ;strip out bits on right + sta ]andmask + + ldy ]lftbyte + lda colorline,y ;get color bits + eor (]hbasl),y ;combine w/screen + and ]andmask ;remove not-ours + eor (]hbasl),y ;combine again + sta (]hbasl),y + jmp rastlinedone + +* This is the more general case. We special-case the +* left and right edges, then byte-stomp the middle. +* On entry, ]rgtbyte is in A +:not1byte + sec ;2 compute number of full + sbc ]lftbyte ;3 and partial bytes to + tax ;2 draw + inx ;2 + + ldy ]rgtbit ;3 + cpy #6 ;2 + beq :rgtnospcl ;3 + lda rightmask,y ;handle partial-byte right + sta ]andmask + ldy ]rgtbyte + lda colorline,y + eor (]hbasl),y + and ]andmask + eor (]hbasl),y + sta (]hbasl),y + dex ;adjust count +:rgtnospcl + + ldy ]lftbit ;3 check left for partial + beq :lftnospcl ;3 + lda leftmask,y ;handle partial-byte left + sta ]andmask + ldy ]lftbyte + lda colorline,y + eor (]hbasl),y + and ]andmask + eor (]hbasl),y + sta (]hbasl),y + dex ;adjust count + beq rastlinedone ;bail if all done + iny ;advance start position + bne :liny ;always + BREAK +:lftnospcl + + ldy ]lftbyte ;3 +:liny + + do USE_FAST ;***** "fast" loop +* Instead of looping, jump into an unrolled loop. +* Cost is 10 cycles per byte with an extra 14 cycles +* of overhead, so we start to win at 4 bytes. + lda rastunidx,x ;4 + sta :_rastun+1 ;4 + lda colorline,y ;4 get odd/even color val +:_rastun jmp rast_unroll ;3 + + else ;***** "slow" loop +* Inner loop of the renderer. This runs 0-40x. +* Cost is 14 cycles/byte. + lda colorline,y ;get appropriate odd/even val +_wrhires sta $2000,y ;5 replaced with line addr +_xorcolor eor #$00 ;2 replaced with $00/$7f + iny ;2 + dex ;2 + bne _wrhires ;3 + + fin ;***** + +rastlinedone + ldy ]cur_line ;3 more lines to go? + cpy rast_bottom ;4 + bge :done ;2 + iny ;2 + jmp rastloop ;3 must have line in Y + +:done rts + +fixrastxor + do USE_FAST ;***** +* Update the EOR statements in the unrolled rastfill code. +* Doing this with a loop takes ~600 cycles, doing it with +* unrolled stores takes 160. We only do this when we +* need to, so changing the color from green to blue won't +* cause this to run. +* +* Call with the XOR value in A. +]offset = 0 + lup BYTES_PER_ROW + sta rast_unroll+3+]offset +]offset = ]offset+5 + --^ + BEEP + rts + fin ;***** + + +* include the line functions + put FDRAW.LINE + +* include the circle functions + put FDRAW.CIRCLE + + lst on +CODE_END equ * ;end of code section + lst off + +* include the data tables + put FDRAW.TABLES + + lst on +DAT_END equ * ;end of data / BSS + lst off + +* Save the appropriate object file. + do USE_FAST + sav FDRAW.FAST + else + sav FDRAW.SMALL + fin + + diff --git a/fdraw/fdraw.tables.s b/fdraw/fdraw.tables.s new file mode 100644 index 0000000..4e47c66 --- /dev/null +++ b/fdraw/fdraw.tables.s @@ -0,0 +1,341 @@ +******************************** +* * +* Fast Apple II Graphics * +* By Andy McFadden * +* Version 0.3, Aug 2015 * +* * +* Pre-computed data and * +* large internal buffers. * +* (Included by FDRAW.S) * +* * +* Developed with Merlin-16 * +* * +******************************** + +* Expected layout with alignment: +* +* P1 ylooklo, misc tables +* P2 ylookhi, colorline +* P3 rastx0l +* P4 rastx0h +* P5 rastx1l +* P6 rastx1h, div7hi, mod7hi +* P7 div7lo +* P8 mod7lo +* P9 rast_unroll, rastunidx +* +* Tables should be just under $900 bytes. + + PG_ALIGN + +* Hi-res Y lookup, low part (192 bytes). +ylooklo HEX 0000000000000000 + HEX 8080808080808080 + HEX 0000000000000000 + HEX 8080808080808080 + HEX 0000000000000000 + HEX 8080808080808080 + HEX 0000000000000000 + HEX 8080808080808080 + HEX 2828282828282828 + HEX a8a8a8a8a8a8a8a8 + HEX 2828282828282828 + HEX a8a8a8a8a8a8a8a8 + HEX 2828282828282828 + HEX a8a8a8a8a8a8a8a8 + HEX 2828282828282828 + HEX a8a8a8a8a8a8a8a8 + HEX 5050505050505050 + HEX d0d0d0d0d0d0d0d0 + HEX 5050505050505050 + HEX d0d0d0d0d0d0d0d0 + HEX 5050505050505050 + HEX d0d0d0d0d0d0d0d0 + HEX 5050505050505050 + HEX d0d0d0d0d0d0d0d0 + +* Color masks for odd/even bytes, colors 0-7. +evencolor dfb $00,$2a,$55,$7f,$80,$aa,$d5,$ff +oddcolor dfb $00,$55,$2a,$7f,$80,$d5,$aa,$ff + +* XOR mask for colors 0-7 - non-BW flip on odd/even. +xormask dfb $00,$7f,$7f,$00,$00,$7f,$7f,$00 + +* AND mask for the 7 pixel positions, high bit set +* for the color shift. +andmask dfb $81,$82,$84,$88,$90,$a0,$c0 + +* These are pixel AND masks, used with the modulo 7 +* result. Entry #2 in leftmask means we're touching +* the rightmost 5 pixels, and entry #2 in rightmask +* means we're touching the 3 leftmost pixels. +* +* The high bit is always set, because we want to +* keep the color's high bit. +leftmask dfb $ff,$fe,$fc,$f8,$f0,$e0,$c0 +rightmask dfb $81,$83,$87,$8f,$9f,$bf,$ff + + PG_ALIGN + +* Hi-res Y lookup, high part (192 bytes). +* OR with $20 or $40. +ylookhi HEX 0004080c1014181c + HEX 0004080c1014181c + HEX 0105090d1115191d + HEX 0105090d1115191d + HEX 02060a0e12161a1e + HEX 02060a0e12161a1e + HEX 03070b0f13171b1f + HEX 03070b0f13171b1f + HEX 0004080c1014181c + HEX 0004080c1014181c + HEX 0105090d1115191d + HEX 0105090d1115191d + HEX 02060a0e12161a1e + HEX 02060a0e12161a1e + HEX 03070b0f13171b1f + HEX 03070b0f13171b1f + HEX 0004080c1014181c + HEX 0004080c1014181c + HEX 0105090d1115191d + HEX 0105090d1115191d + HEX 02060a0e12161a1e + HEX 02060a0e12161a1e + HEX 03070b0f13171b1f + HEX 03070b0f13171b1f + +* Masks for current color (even/odd), e.g. 55 2a 55 2a ... +* Updated whenever the color changes. +colorline ds 40 + + PG_ALIGN +rastx0l ds NUM_ROWS + PG_ALIGN +rastx0h ds NUM_ROWS + ds 1 ;repeat mode can overstep + PG_ALIGN +rastx1l ds NUM_ROWS + PG_ALIGN +rastx1h ds NUM_ROWS + +* Lookup tables for dividing 0-279 by 7. The "hi" +* parts are 24 bytes each, so they fit inside +* the previous 192-byte entry. The "lo" parts +* each fill a page. +div7hi HEX 2424242525252525 + HEX 2525262626262626 + HEX 2627272727272727 +mod7hi HEX 0405060001020304 + HEX 0506000102030405 + HEX 0600010203040506 + + PG_ALIGN + +div7lo HEX 0000000000000001 + HEX 0101010101010202 + HEX 0202020202030303 + HEX 0303030304040404 + HEX 0404040505050505 + HEX 0505060606060606 + HEX 0607070707070707 + HEX 0808080808080809 + HEX 0909090909090a0a + HEX 0a0a0a0a0a0b0b0b + HEX 0b0b0b0b0c0c0c0c + HEX 0c0c0c0d0d0d0d0d + HEX 0d0d0e0e0e0e0e0e + HEX 0e0f0f0f0f0f0f0f + HEX 1010101010101011 + HEX 1111111111111212 + HEX 1212121212131313 + HEX 1313131314141414 + HEX 1414141515151515 + HEX 1515161616161616 + HEX 1617171717171717 + HEX 1818181818181819 + HEX 1919191919191a1a + HEX 1a1a1a1a1a1b1b1b + HEX 1b1b1b1b1c1c1c1c + HEX 1c1c1c1d1d1d1d1d + HEX 1d1d1e1e1e1e1e1e + HEX 1e1f1f1f1f1f1f1f + HEX 2020202020202021 + HEX 2121212121212222 + HEX 2222222222232323 + HEX 2323232324242424 +mod7lo HEX 0001020304050600 + HEX 0102030405060001 + HEX 0203040506000102 + HEX 0304050600010203 + HEX 0405060001020304 + HEX 0506000102030405 + HEX 0600010203040506 + HEX 0001020304050600 + HEX 0102030405060001 + HEX 0203040506000102 + HEX 0304050600010203 + HEX 0405060001020304 + HEX 0506000102030405 + HEX 0600010203040506 + HEX 0001020304050600 + HEX 0102030405060001 + HEX 0203040506000102 + HEX 0304050600010203 + HEX 0405060001020304 + HEX 0506000102030405 + HEX 0600010203040506 + HEX 0001020304050600 + HEX 0102030405060001 + HEX 0203040506000102 + HEX 0304050600010203 + HEX 0405060001020304 + HEX 0506000102030405 + HEX 0600010203040506 + HEX 0001020304050600 + HEX 0102030405060001 + HEX 0203040506000102 + HEX 0304050600010203 + + +* RastFill unrolled loop. At each step we store the current +* color value, XOR it to flip the bits if needed, and advance. +* The caller needs to set the appropriate initial value based +* on whether the address is odd or even. +* +* We can use a 3-cycle "EOR dp" or a 2-cycle "EOR imm". The +* former is one cycle slower, the latter requires us to +* self-mod 40 instructions when the color changes. +* +* This must be page-aligned so that we can take the value +* from the rastunidx table and self-mod a JMP without having +* to do a 16-bit add. We have just enough room for the +* unrolled loop (40*5+3) and x5 table (41) = 244 bytes, fits +* on a single page. + + do USE_FAST ;***** + ds \ +]hbasl equ zptr0 ;must match FillRaster +rast_unroll equ * + lst off + lup BYTES_PER_ROW + sta (]hbasl),y ;6 + eor #$00 ;2 + iny ;2 10 cycles, 5 bytes + --^ + jmp rastlinedone + +* Index into rast_unroll. If we need to output N bytes, +* we want to jump to (rast_unroll + (40 - N) * 5) (where +* 5 is the number of bytes per iteration). +rastunidx +]offset = BYTES_PER_ROW*5 + lup BYTES_PER_ROW+1 ;0-40 + dfb ]offset +]offset = ]offset-5 + --^ + + fin ;***** + + +******************************** +* +* Code used to generate tables above. If you want to +* decrease load size, use these functions to generate +* the data into empty memory, then discard the code. +* (Maybe use a negative DS and overlap with rastx0l?) +* +******************************** + DO 0 ;***** + +init_ylook +]hbasl equ zptr1 +]hbash equ zptr1+1 + +* Initialize Y-lookup table. We just call the bascalc +* function. + ldx #NUM_ROWS + ldy #NUM_ROWS-1 +]loop tya + jsr bascalc + lda hbasl + sta ylooklo,y + lda hbash + ora #$20 ;remove for $0000 base + sta ylookhi,y + dey + dex + bne ]loop + rts + +* Hi-res base address calculation. This is based on the +* HPOSN routine at $F411. +* +* Call with the line in A. The results are placed into +* zptr1. X and Y are not disturbed. +* +* The value is in the $0000-1fff range, so you must OR +* the desired hi-res page in. +* +bascalc + pha + and #$c0 + sta ]hbasl + lsr + lsr + ora ]hbasl + sta ]hbasl + pla + sta ]hbash + asl + asl + asl + rol ]hbash + asl + rol ]hbash + asl + ror ]hbasl + lda ]hbash + and #$1f + sta ]hbash + rts + +* +* Create divide-by-7 tables. +* +mkdivtab +]val equ zloc0 + + ldy #0 + sty ]val + ldx #0 +]loop lda ]val + sta div7lo,y + txa + sta mod7lo,y + inx + iny + beq :lodone + cpx #7 + bne ]loop + inc ]val + ldx #0 + beq ]loop ;always +:lodone ;safe to ignore ]va update +]loop lda ]val + sta div7hi,y + txa + sta mod7hi,y + iny + cpy #280-256 + beq :hidone + inx + cpx #7 + bne ]loop + inc ]val + ldx #0 + beq ]loop ;always +:hidone rts + + FIN ;***** + + diff --git a/mainmem.fsequ.s b/mainmem.fsequ.s index 87c6725..6aaa364 100644 --- a/mainmem.fsequ.s +++ b/mainmem.fsequ.s @@ -63,4 +63,6 @@ GEOFCMD EQU $D1 + + diff --git a/mainmem.init.s b/mainmem.init.s index 5bda82e..dedcbdf 100644 --- a/mainmem.init.s +++ b/mainmem.init.s @@ -107,6 +107,8 @@ RESET TSX + + diff --git a/mainmem.ldr.s b/mainmem.ldr.s index 37c9c57..0edea07 100644 --- a/mainmem.ldr.s +++ b/mainmem.ldr.s @@ -141,10 +141,12 @@ LOADCODE PHP ; Save carry flag JSR CROUT PLP RTS -:ADDRL DB $00 ; Destination address (LSB) -:ADDRH DB $00 ; Destination address (MSB) -:BLOCKS DB $00 ; Counter for blocks read -:LEN DB $00 ; Length of filename +:ADDRL DB $00 ; Destination address (LSB) +:ADDRH DB $00 ; Destination address (MSB) +:BLOCKS DB $00 ; Counter for blocks read +:LEN DB $00 ; Length of filename :CANTOPEN ASC "Unable to open " DB $00 + + diff --git a/mainmem.lists.s b/mainmem.lists.s index f6e2fab..aa1f91d 100644 --- a/mainmem.lists.s +++ b/mainmem.lists.s @@ -127,4 +127,6 @@ QUITPL HEX 04 ; Number of parameters + + diff --git a/mainmem.menu.s b/mainmem.menu.s index dd11e58..7187806 100644 --- a/mainmem.menu.s +++ b/mainmem.menu.s @@ -142,6 +142,8 @@ ROM8 STR "USERROM2.ROM" + + diff --git a/mainmem.misc.s b/mainmem.misc.s index 84fd62b..e9e235e 100644 --- a/mainmem.misc.s +++ b/mainmem.misc.s @@ -211,6 +211,8 @@ FILEREFS DB $00,$00,$00,$00 + + diff --git a/mainmem.path.s b/mainmem.path.s index 0d82de4..5197ca3 100644 --- a/mainmem.path.s +++ b/mainmem.path.s @@ -308,4 +308,6 @@ PREFIX DS 65 ; Buffer for ProDOS prefix + + diff --git a/mainmem.svc.s b/mainmem.svc.s index 91e4723..014c75e 100644 --- a/mainmem.svc.s +++ b/mainmem.svc.s @@ -1061,16 +1061,16 @@ MAINRDEXIT >>> XF2AUX,NULLRTS ; Back to an RTS CLRHGR >>> ENTMAIN LDA BGCOLOR STA FDRAWADDR+5 - JSR FDRAWADDR+16 ; FDRAW: SetColor - JSR FDRAWADDR+22 ; FDRAW: Clear + JSR FDRAWADDR+16 ; FDRAW: SetColor + JSR FDRAWADDR+22 ; FDRAW: Clear LDA FGCOLOR STA FDRAWADDR+5 - JSR FDRAWADDR+16 ; FDRAW: SetColor + JSR FDRAWADDR+16 ; FDRAW: SetColor >>> XF2AUX,VDU16RET * Call FDraw SetLineMode routine SETLINE >>> ENTMAIN - JSR FDRAWADDR+43 ; FDRAW: SetLineMode + JSR FDRAWADDR+43 ; FDRAW: SetLineMode >>> XF2AUX,VDU18RET1 * Call FDraw DrawLine routine @@ -1089,8 +1089,8 @@ DRAWLINE >>> ENTMAIN BRA :SETCOLOR :S2 LDA BGCOLOR ; Draw in background colour :SETCOLOR STA FDRAWADDR+5 - JSR FDRAWADDR+16 ; FDRAW: SetColor - JSR FDRAWADDR+28 ; FDRAW: DrawLine + JSR FDRAWADDR+16 ; FDRAW: SetColor + JSR FDRAWADDR+28 ; FDRAW: DrawLine >>> XF2AUX,VDU25RET * Call FDraw DrawPoint routine @@ -1109,24 +1109,24 @@ DRAWPNT >>> ENTMAIN BRA :SETCOLOR :S2 LDA BGCOLOR ; Draw in background colour :SETCOLOR STA FDRAWADDR+5 - JSR FDRAWADDR+16 ; FDRAW: SetColor - JSR FDRAWADDR+25 ; FDRAW: DrawPoint + JSR FDRAWADDR+16 ; FDRAW: SetColor + JSR FDRAWADDR+25 ; FDRAW: DrawPoint >>> XF2AUX,VDU25RET * Reset colours and linetype -GFXINIT JSR FDRAWADDR+0 ; Initialize FDRAW library +GFXINIT JSR FDRAWADDR+0 ; Initialize FDRAW library LDA #$20 STA FDRAWADDR+5 - JSR FDRAWADDR+19 ; FDRAW: Set page $2000 + JSR FDRAWADDR+19 ; FDRAW: Set page $2000 STZ LINETYPE STZ FDRAWADDR+5 - JSR FDRAWADDR+43 ; FDRAW: SetLineMode + JSR FDRAWADDR+43 ; FDRAW: SetLineMode LDA #$07 STA FGCOLOR STA FDRAWADDR+5 - JSR FDRAWADDR+16 ; FDRAW: SetColor + JSR FDRAWADDR+16 ; FDRAW: SetColor STZ BGCOLOR - JSR FDRAWADDR+22 ; FDRAW: clear HGR screen + JSR FDRAWADDR+22 ; FDRAW: clear HGR screen RTS FGCOLOR DB $00 ; Foreground colour @@ -1136,3 +1136,5 @@ PLOTMODE DB $00 ; K value for PLOT K,X,Y + + diff --git a/mainmem.wild.s b/mainmem.wild.s index 8e5f5b1..2c52624 100644 --- a/mainmem.wild.s +++ b/mainmem.wild.s @@ -386,3 +386,5 @@ MATCHBUF DS 65 ; For storing match results (Pascal str) + + diff --git a/memmap.txt b/memmap.txt index 5b56aee..c363d79 100644 --- a/memmap.txt +++ b/memmap.txt @@ -1,4 +1,4 @@ -* Memory layout in main memory +* Memory layout in main memory (Apple environment) * * ; $0000-$00FF Zero page * ; $0100-$01FF Stack @@ -40,27 +40,46 @@ MOSFILE2 EQU $0341 ; $0341 length * * EQU $0400 ; $0400- Can't use as ProDOS uses 'hidden' bytes * ; -$07FF within screen for workspace -SCREEN EQU $0800 ; $0800-$0BFF half 80-col screen or 40-col screen +SCREEN EQU $0800 ; $0800-$0BFF Half 80-col screen or 40-col screen IOBUF0 EQU $0C00 ; $0C00-$0FFF For loading ROM, OSFILE, *. IOBUF1 EQU $1000 ; $1000-$13FF Four open files for langs IOBUF2 EQU $1400 ; $1400-$17FF IOBUF3 EQU $1800 ; $1800-$1BFF IOBUF4 EQU $1C00 ; $1C00-$1FFF -* ; $2000- Code, to do: make code move itself -* -$4FFF -BLKBUF EQU $5000 ; $5000-$53FF 512-byte buffer plus channel data -BLKBUFEND EQU $5200 - - -* To do later: * ; $2000-$3FFF Hi-Res screen 1 -* ; $4000-$5FFF Hi-Res screen 2 -* ; $6000- available -* ; -$95FF available +* ; $4000- Code, to do: make code move itself +* -$6FFF +BLKBUF EQU $7000 ; $7000-$73FF 512-byte buffer plus channel data +BLKBUFEND EQU $7200 +* * ; $9600-$BDFF ProDOS buffers * ; $BE00-$BEFF MLI Global workspace * ; $BF00-$BFFF MLI API interface -I think $0300-$03DF can be usefully used as filing system workspace, -the mainmem copies of the filename and control block, MOSNAME and CBFILE, -and later for OSGBPB. + +Memory layout in aux memory (Acorn environment) +* ; $0000-$00FF Zero page +* ; $00-$8F Language workspace +* ; $90-$9F Network workspace +* ; $A0-$A7 NMI workspace +* ; $A8-$AF Non-MOS *command workspace +* ; $B0-$BF Temporary filing system workspace +* ; $C0-$CF Persistant filing system workspace +* ; $D0-$DF VDU driver workspace +* ; $E0-$EE Internal MOS workspace +* ; $EF-$FF MOS API workspace +* ; $0100-$01FF Stack +* ; $0200-$02FF Kernel vectors and workspace +* ; $0200-$0235 Vectors +* ; $0236-$028F OSBYTE variables +* ; $0290-$02ED +* ; $02EE-$02FF MOS control block +* ; $0300-$03FF +* ; $0300- +* ; $03E0-$03EF XFER workspace +* ; $03F0-$03FF +* ; $0400-$07FF Language workspace +* ; $0800-$0BFF Screen memory +* ; $0C00-$0DFF --> use as transient command buffer +* ; $0E00 Default PAGE +