From 613cb2ff77c55f37712c88bf834ee335a739e341 Mon Sep 17 00:00:00 2001 From: cuz Date: Sun, 7 Jul 2002 11:12:16 +0000 Subject: [PATCH] Add TGI driver git-svn-id: svn://svn.cc65.org/cc65/trunk@1335 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- libsrc/Makefile | 10 +- libsrc/c64/.cvsignore | 1 + libsrc/c64/Makefile | 36 +- libsrc/c64/c64-320-200-2.s | 1206 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1234 insertions(+), 19 deletions(-) create mode 100644 libsrc/c64/.cvsignore create mode 100644 libsrc/c64/c64-320-200-2.s diff --git a/libsrc/Makefile b/libsrc/Makefile index 1a0a49478..b6f3152d8 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -6,9 +6,10 @@ # Defines for executables. The first two are passed to the submakes and are # relative to the subdirectories, the last one is used directly. -CC = ../../src/cc65/cc65 AS = ../../src/ca65/ca65 AR = ../src/ar65/ar65 +CC = ../../src/cc65/cc65 +LD = ../../src/ld65/ld65 # List of all targets ALLTARGETS = apple2lib \ @@ -28,7 +29,7 @@ all: for tgt in $(ALLTARGETS); do \ $(MAKE) clean $$tgt || exit 1; \ done - + #----------------------------------------------------------------------------- # Apple ][ @@ -82,10 +83,11 @@ atmoslib: c64lib: for i in c64 cbm common runtime conio dbg tgi; do \ - CC=$(CC) \ AS=$(AS) \ - CFLAGS="-Osir -g -T -t c64 -I../../include" \ + CC=$(CC) \ + LD=$(LD) \ AFLAGS="-t c64 -I../../asminc" \ + CFLAGS="-Osir -g -T -t c64 -I../../include" \ $(MAKE) -C $$i || exit 1; \ done mv c64/crt0.o c64.o diff --git a/libsrc/c64/.cvsignore b/libsrc/c64/.cvsignore new file mode 100644 index 000000000..a19e3c8e1 --- /dev/null +++ b/libsrc/c64/.cvsignore @@ -0,0 +1 @@ +*.tgi diff --git a/libsrc/c64/Makefile b/libsrc/c64/Makefile index e451f7eba..d19c7cd81 100644 --- a/libsrc/c64/Makefile +++ b/libsrc/c64/Makefile @@ -11,23 +11,29 @@ %.o: %.s @$(AS) -g -o $@ $(AFLAGS) $< -OBJS = _scrsize.o \ - break.o \ - crt0.o \ - cgetc.o \ - clrscr.o \ - color.o \ - conio.o \ - cputc.o \ - kbhit.o \ - mouse.o \ - readjoy.o \ - rs232.o \ - tgi_mode_table.o\ +%.tgi: %.o + @$(LD) -t module -o $@ $< ../runtime/zeropage.o + +OBJS = _scrsize.o \ + break.o \ + crt0.o \ + cgetc.o \ + clrscr.o \ + color.o \ + conio.o \ + cputc.o \ + kbhit.o \ + mouse.o \ + readjoy.o \ + rs232.o \ + tgi_mode_table.o \ write.o -all: $(OBJS) +TGIS = c64-320-200-2.tgi + + +all: $(OBJS) $(TGIS) clean: - @rm -f $(OBJS) + @rm -f $(OBJS) $(TGIS:.tgi=.o) diff --git a/libsrc/c64/c64-320-200-2.s b/libsrc/c64/c64-320-200-2.s new file mode 100644 index 000000000..8872d2515 --- /dev/null +++ b/libsrc/c64/c64-320-200-2.s @@ -0,0 +1,1206 @@ +; +; Graphics driver for the 320x200x2 mode on the C64. +; +; Based on Stephen L. Judds GRLIB code +; + + .include "zeropage.inc" + + .include "tgi-kernel.inc" + .include "tgi-mode.inc" + .include "tgi-error.inc" + + + .macpack generic + + +; ------------------------------------------------------------------------ +; Header. Includes jump table and constants. + +.segment "JUMPTABLE" + +; First part of the header is a structure that has a magic and defines the +; capabilities of the driver + + .byte $74, $67, $69 ; "tgi" + .byte $00 ; TGI version number + .word 320 ; X resolution + .word 200 ; Y resolution + .byte 2 ; Number of drawing colors + .byte 1 ; Number of screens available + .res 6, $00 ; Reserved for future extensions + +; Next comes the jump table. Currently all entries must be valid and may point +; to an RTS for test versions (function not implemented). A future version may +; allow for emulation: In this case the vector will be zero. Emulation means +; that the graphics kernel will emulate the function by using lower level +; primitives - for example ploting a line by using calls to SETPIXEL. + + .word INSTALL + .word DEINSTALL + .word INIT + .word DONE + .word GETERROR + .word CONTROL + .word CLEAR + .word SETVIEWPAGE + .word SETDRAWPAGE + .word SETCOLOR + .word SETPALETTE + .word GETPALETTE + .word GETDEFPALETTE + .word SETPIXEL + .word GETPIXEL + .word HORLINE + .word LINE + .word 0 ; BAR + .word CIRCLE + + +; ------------------------------------------------------------------------ +; Data. + +; Variables mapped to the zero page segment variables. Some of these are +; used for passing parameters to the driver. + +X1 = ptr1 +Y1 = ptr2 +X2 = ptr3 +Y2 = ptr4 +RADIUS = tmp1 + +ROW = tmp2 ; Bitmap row... +COL = tmp3 ; ...and column, both set by PLOT +TEMP = tmp4 +TEMP2 = sreg +POINT = regsave + +CHUNK = X2 ; Used in the line routine +OLDCHUNK = X2+1 ; Dito + +; Absolute variables used in the code + +.bss + +ERROR: .res 1 ; Error code +PALETTE: .res 2 ; The current palette + +BITMASK: .res 1 ; $00 = clear, $FF = set pixels + +; INIT/DONE +OLDD018: .res 1 ; Old register value + +; PLOT variables +INRANGE: .res 1 ; $00 = coordinates in range + +; Line routine stuff +DX: .res 2 +DY: .res 2 + +; Circle routine stuff +CURX: .res 1 +CURY: .res 1 +BROW: .res 1 ; Bottom row +TROW: .res 1 ; Top row +LCOL: .res 1 ; Left column +RCOL: .res 1 ; Right column +CHUNK1: .res 1 +OLDCH1: .res 1 +CHUNK2: .res 1 +OLDCH2: .res 1 + +; Constants and tables + +.rodata + +DEFPALETTE: .byte $00, $01 ; White on black +PALETTESIZE = * - DEFPALETTE + +BITTAB: .byte $80,$40,$20,$10,$08,$04,$02,$01 +BITCHUNK: .byte $FF,$7F,$3F,$1F,$0F,$07,$03,$01 + +VBASE = $E000 ; Video memory base address +CBASE = $D000 ; Color memory base address + + +.code + +; ------------------------------------------------------------------------ +; INSTALL routine. Is called after the driver is loaded into memory. May +; initialize anything that has to be done just once. Is probably empty +; most of the time. +; +; Must set an error code: NO +; + +INSTALL: + rts + + +; ------------------------------------------------------------------------ +; DEINSTALL routine. Is called before the driver is removed from memory. May +; clean up anything done by INSTALL but is probably empty most of the time. +; +; Must set an error code: NO +; + +DEINSTALL: + rts + + +; ------------------------------------------------------------------------ +; INIT: Changes an already installed device from text mode to graphics +; mode. The number of the graphics mode is passed to the function in A. +; Note that INIT/DONE may be called multiple times while the driver +; is loaded, while INSTALL is only called once, so any code that is needed +; to initializes variables and so on must go here. Setting palette and +; clearing the screen is not needed because this is called by the graphics +; kernel later. +; The graphics kernel will never call INIT when a graphics mode is already +; active, so there is no need to protect against that. +; +; Must set an error code: YES +; + +INIT: cmp #TGI_MODE_320_200_2 ; Correct mode? + beq @L1 ; Jump if yes + lda #TGI_ERR_INV_MODE ; ## Error + bne @L9 + +; Initialize variables + +@L1: ldx #$FF + stx BITMASK + +; Switch into graphics mode + + lda $DD02 ; Set the data direction regs + ora #3 + sta $DD02 + lda $DD00 + and #$FC ; Switch to bank 3 + sta $DD00 + + lda $D018 + sta OLDD018 + lda #$48 ; Set color map to $D000, screen to $E000 + sta $D018 + + lda $D011 ; And turn on bitmap + ora #$20 + sta $D011 + +; Done, reset the error code + + lda #TGI_ERR_OK +@L9: sta ERROR + rts + +; ------------------------------------------------------------------------ +; DONE: Will be called to switch the graphics device back into text mode. +; The graphics kernel will never call DONE when no graphics mode is active, +; so there is no need to protect against that. +; +; Must set an error code: YES +; + +DONE: lda $DD02 ; Set the data direction regs + ora #3 + sta $DD02 + lda $DD00 + ora #$03 ; Bank 0 + sta $DD00 + + lda OLDD018 ; Screen mem --> $0400 + sta $D018 + + lda $D011 + and #<~$20 + sta $D011 + rts + +; ------------------------------------------------------------------------ +; GETERROR: Return the error code in A and clear it. + +GETERROR: + ldx #TGI_ERR_OK + lda ERROR + stx ERROR + rts + +; ------------------------------------------------------------------------ +; CONTROL: Platform/driver specific entry point. +; +; Must set an error code: YES +; + +CONTROL: + lda #TGI_ERR_INV_FUNC + sta ERROR + rts + +; ------------------------------------------------------------------------ +; CLEAR: Clears the screen. +; +; Must set an error code: NO +; + +CLEAR: ldy #$00 + tya +@L1: sta VBASE+$0000,y + sta VBASE+$0100,y + sta VBASE+$0200,y + sta VBASE+$0300,y + sta VBASE+$0400,y + sta VBASE+$0500,y + sta VBASE+$0600,y + sta VBASE+$0700,y + sta VBASE+$0800,y + sta VBASE+$0900,y + sta VBASE+$0A00,y + sta VBASE+$0B00,y + sta VBASE+$0C00,y + sta VBASE+$0D00,y + sta VBASE+$0E00,y + sta VBASE+$0F00,y + sta VBASE+$1000,y + sta VBASE+$1100,y + sta VBASE+$1200,y + sta VBASE+$1300,y + sta VBASE+$1400,y + sta VBASE+$1500,y + sta VBASE+$1600,y + sta VBASE+$1700,y + sta VBASE+$1800,y + sta VBASE+$1900,y + sta VBASE+$1A00,y + sta VBASE+$1B00,y + sta VBASE+$1C00,y + sta VBASE+$1D00,y + sta VBASE+$1E00,y + sta VBASE+$1F00,y + iny + bne @L1 + rts + +; ------------------------------------------------------------------------ +; SETVIEWPAGE: Set the visible page. Called with the new page in A (0..n). +; The page number is already checked to be valid by the graphics kernel. +; +; Must set an error code: NO (will only be called if page ok) +; + +SETVIEWPAGE: + rts + +; ------------------------------------------------------------------------ +; SETDRAWPAGE: Set the drawable page. Called with the new page in A (0..n). +; The page number is already checked to be valid by the graphics kernel. +; +; Must set an error code: NO (will only be called if page ok) +; + +SETDRAWPAGE: + rts + +; ------------------------------------------------------------------------ +; SETCOLOR: Set the drawing color (in A). The new color is already checked +; to be in a valid range (0..maxcolor-1). +; +; Must set an error code: NO (will only be called if color ok) +; + +SETCOLOR: + tax + beq @L1 + lda #$FF +@L1: sta BITMASK + rts + +; ------------------------------------------------------------------------ +; SETPALETTE: Set the palette (not available with all drivers/hardware). +; A pointer to the palette is passed in ptr1. Must set an error if palettes +; are not supported +; +; Must set an error code: YES +; + +SETPALETTE: + ldy #PALETTESIZE - 1 +@L1: lda (ptr1),y ; Copy the palette + and #$0F ; Make a valid color + sta PALETTE,y + dey + bpl @L1 + +; Get the color entries from the palette + + lda PALETTE+1 ; Foreground color + asl a + asl a + asl a + asl a + ora PALETTE ; Background color + tax + +; Initialize the color map with the new color settings (it is below the +; I/O area) + + ldy #$00 + sei + lda $01 ; Get ROM config + pha ; Save it + and #%11111100 ; Clear bit 0 and 1 + sta $01 + txa ; Load color code +@L2: sta CBASE+$0000,y + sta CBASE+$0100,y + sta CBASE+$0200,y + sta CBASE+$0300,y + iny + bne @L2 + pla + sta $01 + cli + +; Done + + rts + +; ------------------------------------------------------------------------ +; GETPALETTE: Return the current palette in A/X. Must return NULL and set an +; error if palettes are not supported. +; +; Must set an error code: YES +; + +GETPALETTE: + lda #PALETTE + rts + +; ------------------------------------------------------------------------ +; GETDEFPALETTE: Return the default palette for the driver in A/X. Must +; return NULL and set an error of palettes are not supported. +; +; Must set an error code: YES +; + +GETDEFPALETTE: + lda #DEFPALETTE + rts + +; ------------------------------------------------------------------------ +; SETPIXEL: Draw one pixel at X1/Y1 = ptr1/ptr2 with the current drawing +; color. The coordinates passed to this function are never outside the +; visible screen area, so there is no need for clipping inside this function. +; +; Must set an error code: NO +; + +SETPIXEL: + jsr CALC ; Calculate coordinates + + sei ; Get underneath ROM + lda $01 + pha + lda #$34 + sta $01 + + lda (POINT),Y + eor BITMASK + and BITTAB,X + eor (POINT),Y + sta (POINT),Y + + pla + sta $01 + cli + +@L9: rts + +; ------------------------------------------------------------------------ +; GETPIXEL: Read the color value of a pixel and return it in A/X. The +; coordinates passed to this function are never outside the visible screen +; area, so there is no need for clipping inside this function. + + +GETPIXEL: + jsr CALC ; Calculate coordinates + + sei ; Get underneath ROM + lda $01 + pha + lda #$34 + sta $01 + + lda (POINT),Y + ldy #$00 + and BITTAB,X + beq @L1 + iny + +@L1: pla + sta $01 + cli + + tya ; Get color value into A + ldx #$00 ; Clear high byte + rts + +; ------------------------------------------------------------------------ +; HORLINE: Draw a horizontal line from X1/Y to X2/Y, where X1 = ptr1, +; Y = ptr2 and X2 = ptr3, using the current drawing color. +; +; This is a special line drawing entry used when the line is know to be +; horizontal, for example by the BAR emulation routine. If the driver does +; not have special code for horizontal lines, it may just copy Y to Y2 and +; proceed with the generic line drawing code. +; +; Note: Line coordinates will always be sorted (Y1 <= X2) and clipped. +; +; Must set an error code: NO +; + +HORLINE: + lda ptr2 + sta ptr4 + lda ptr2+1 + sta ptr4+1 +; jmp LINE + +; ------------------------------------------------------------------------ +; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and +; X2/Y2 = ptr3/ptr4 using the current drawing color. +; +; To deal with off-screen coordinates, the current row +; and column (40x25) is kept track of. These are set +; negative when the point is off the screen, and made +; positive when the point is within the visible screen. +; +; X1,X2 etc. are set up above (x2=LINNUM in particular) +; Format is LINE x2,y2,x1,y1 +; +; Must set an error code: NO +; + +LINE: + +@CHECK: lda X2 ;Make sure x1=y1? + lda Y1 ;Otherwise dy=y1-y2 + sec + sbc Y2 + tay + ldx #$88 ;DEY + +@DYPOS: sty DY ; 8-bit DY -- FIX ME? + stx YINCDEC + stx XINCDEC + + jsr CALC ; Set up .X,.Y,POINT, and INRANGE + lda BITCHUNK,X + sta OLDCHUNK + sta CHUNK + + sei ; Get underneath ROM + lda #$34 + sta $01 + + ldx DY + cpx DX ;Who's bigger: dy or dx? + bcc STEPINX ;If dx, then... + lda DX+1 + bne STEPINX + +; +; Big steps in Y +; +; To simplify my life, just use PLOT to plot points. +; +; No more! +; Added special plotting routine -- cool! +; +; X is now counter, Y is y-coordinate +; +; On entry, X=DY=number of loop iterations, and Y= +; Y1 AND #$07 +STEPINY: + lda #00 + sta OLDCHUNK ;So plotting routine will work right + lda CHUNK + lsr ;Strip the bit + eor CHUNK + sta CHUNK + txa + bne @CONT ;If dy=0 it's just a point + inx +@CONT: lsr ;Init counter to dy/2 +; +; Main loop +; +YLOOP: sta TEMP + + lda INRANGE ;Range check + bne @SKIP + + lda (POINT),y ;Otherwise plot + eor BITMASK + and CHUNK + eor (POINT),y + sta (POINT),y +@SKIP: +YINCDEC: + iny ;Advance Y coordinate + cpy #8 + bcc @CONT ;No prob if Y=0..7 + jsr FIXY +@CONT: lda TEMP ;Restore A + sec + sbc DX + bcc YFIXX +YCONT: dex ;X is counter + bne YLOOP +YCONT2: lda (POINT),y ;Plot endpoint + eor BITMASK + and CHUNK + eor (POINT),y + sta (POINT),y +YDONE: lda #$37 + sta $01 + cli + rts + +YFIXX: ;x=x+1 + adc DY + lsr CHUNK + bne YCONT ;If we pass a column boundary... + ror CHUNK ;then reset CHUNK to $80 + sta TEMP2 + lda COL + bmi @C1 ;Skip if column is negative + cmp #39 ;End if move past end of screen + bcs YDONE +@C1: lda POINT ;And add 8 to POINT + adc #8 + sta POINT + bcc @CONT + inc POINT+1 +@CONT: inc COL ;Increment column + bne @C2 + lda ROW ;Range check + cmp #25 + bcs @C2 + lda #00 ;Passed into col 0 + sta INRANGE +@C2: lda TEMP2 + dex + bne YLOOP + beq YCONT2 + +; +; Big steps in X direction +; +; On entry, X=DY=number of loop iterations, and Y= +; Y1 AND #$07 + +.bss +COUNTHI: + .byte $00 ;Temporary counter + ;only used once +.code +STEPINX: + ldx DX + lda DX+1 + sta COUNTHI + cmp #$80 + ror ;Need bit for initialization + sta Y1 ;High byte of counter + txa + bne @CONT ;Could be $100 + dec COUNTHI +@CONT: ror +; +; Main loop +; +XLOOP: lsr CHUNK + beq XFIXC ;If we pass a column boundary... +XCONT1: sbc DY + bcc XFIXY ;Time to step in Y? +XCONT2: dex + bne XLOOP + dec COUNTHI ;High bits set? + bpl XLOOP + +XDONE: lsr CHUNK ;Advance to last point + jsr LINEPLOT ;Plot the last chunk +EXIT: lda #$37 + sta $01 + cli + rts +; +; CHUNK has passed a column, so plot and increment pointer +; and fix up CHUNK, OLDCHUNK. +; +XFIXC: sta TEMP + jsr LINEPLOT + lda #$FF + sta CHUNK + sta OLDCHUNK + lda COL + bmi @C1 ;Skip if column is negative + cmp #39 ;End if move past end of screen + bcs EXIT +@C1: lda POINT + adc #8 + sta POINT + bcc @CONT + inc POINT+1 +@CONT: inc COL + bne @C2 + lda ROW + cmp #25 + bcs @C2 + lda #00 + sta INRANGE +@C2: lda TEMP + sec + bcs XCONT1 +; +; Check to make sure there isn't a high bit, plot chunk, +; and update Y-coordinate. +; +XFIXY: dec Y1 ;Maybe high bit set + bpl XCONT2 + adc DX + sta TEMP + lda DX+1 + adc #$FF ;Hi byte + sta Y1 + + jsr LINEPLOT ;Plot chunk + lda CHUNK + sta OLDCHUNK + + lda TEMP +XINCDEC: + iny ;Y-coord + cpy #8 ;0..7 is ok + bcc XCONT2 + sta TEMP + jsr FIXY + lda TEMP + jmp XCONT2 + +; +; Subroutine to plot chunks/points (to save a little +; room, gray hair, etc.) +; +LINEPLOT: ; Plot the line chunk + lda INRANGE + bne @SKIP + + lda (POINT),Y ; Otherwise plot + eor BITMASK + ora CHUNK + and OLDCHUNK + eor CHUNK + eor (POINT),Y + sta (POINT),Y +@SKIP: rts + +; +; Subroutine to fix up pointer when Y decreases through +; zero or increases through 7. +; +FIXY: cpy #255 ;Y=255 or Y=8 + beq @DECPTR +@INCPTR: ;Add 320 to pointer + ldy #0 ;Y increased through 7 + lda ROW + bmi @C1 ;If negative, then don't update + cmp #24 + bcs @TOAST ;If at bottom of screen then quit +@C1: lda POINT + adc #<320 + sta POINT + lda POINT+1 + adc #>320 + sta POINT+1 +@CONT1: inc ROW + bne @DONE + lda COL + bmi @DONE + lda #00 + sta INRANGE +@DONE: rts + +@DECPTR: ;Okay, subtract 320 then + ldy #7 ;Y decreased through 0 + lda POINT + sec + sbc #<320 + sta POINT + lda POINT+1 + sbc #>320 + sta POINT+1 +@CONT2: dec ROW + bmi @TOAST + lda ROW + cmp #24 + bne @DONE + lda COL + bmi @DONE + lda #00 + sta INRANGE + rts +@TOAST: pla ;Remove old return address + pla + jmp EXIT ;Restore interrupts, etc. + +; ------------------------------------------------------------------------ +; BAR: Draw a filled rectangle with the corners X1/Y1, X2/Y2, where +; X1/Y1 = ptr1/ptr2 and X2/Y2 = ptr3/ptr4 using the current drawing color. +; Contrary to most other functions, the graphics kernel will sort and clip +; the coordinates before calling the driver, so on entry the following +; conditions are valid: +; X1 <= X2 +; Y1 <= Y2 +; (X1 >= 0) && (X1 < XRES) +; (X2 >= 0) && (X2 < XRES) +; (Y1 >= 0) && (Y1 < YRES) +; (Y2 >= 0) && (Y2 < YRES) +; +; Must set an error code: NO +; + +BAR: rts + +; ------------------------------------------------------------------------ +; CIRCLE: Draw a circle around the center X1/Y1 (= ptr1/ptr2) with the +; radius in tmp1 and the current drawing color. +; +; Must set an error code: NO +; + +CIRCLE: lda RADIUS + sta CURY + bne @L1 + jmp SETPIXEL ; Plot as a point + +@L1: clc + adc Y1 + sta Y1 + bcc @L2 + inc Y1+1 +@L2: jsr CALC ; Compute XC, YC+R + + lda ROW + sta BROW + lda COL + sta LCOL + sta RCOL + + sty Y2 ; Y AND 07 + lda BITCHUNK,X + sta CHUNK1 ; Forwards chunk + sta OLDCH1 + lsr + eor #$FF + sta CHUNK2 ; Backwards chunk + sta OLDCH2 + lda POINT + sta TEMP2 ; TEMP2 = forwards high pointer + sta X2 ; X2 = backwards high pointer + lda POINT+1 + sta TEMP2+1 + sta X2+1 + +; Next compute CY-R + + lda Y1 + sec + sbc RADIUS + bcs @C3 + dec Y1+1 + sec +@C3: sbc RADIUS + bcs @C4 + dec Y1+1 +@C4: sta Y1 + + jsr CALC ; Compute new coords + sty Y1 + lda POINT + sta X1 ; X1 will be the backwards + lda POINT+1 ; low-pointer + sta X1+1 ; POINT will be forwards + lda ROW + sta TROW + + sei ; Get underneath ROM + lda #$34 + sta $01 + + lda RADIUS + lsr ; A=r/2 + ldx #00 + stx CURX ; y=0 + +; Main loop + +@LOOP: inc CURX ; x=x+1 + + lsr CHUNK1 ; Right chunk + bne @CONT1 + jsr UPCHUNK1 ; Update if we move past a column +@CONT1: asl CHUNK2 + bne @CONT2 + jsr UPCHUNK2 +@CONT2: sec + sbc CURX ; a=a-x + bcs @LOOP + + adc CURY ;if a<0 then a=a+y; y=y-1 + tax + jsr PCHUNK1 + jsr PCHUNK2 + lda CHUNK1 + sta OLDCH1 + lda CHUNK2 + sta OLDCH2 + txa + + dec CURY ;(y=y-1) + + dec Y2 ;Decrement y-offest for upper + bpl @CONT3 ;points + jsr DECYOFF +@CONT3: ldy Y1 + iny + sty Y1 + cpy #8 + bcc @CONT4 + jsr INCYOFF +@CONT4: ldy CURX + cpy CURY ;if y<=x then punt + bcc @LOOP ;Now draw the other half +; +; Draw the other half of the circle by exactly reversing +; the above! +; +NEXTHALF: + lsr OLDCH1 ;Only plot a bit at a time + asl OLDCH2 + lda RADIUS ;A=-R/2-1 + lsr + eor #$FF +@LOOP: + tax + jsr PCHUNK1 ;Plot points + jsr PCHUNK2 + txa + dec Y2 ;Y2=bottom + bpl @CONT1 + jsr DECYOFF +@CONT1: inc Y1 + ldy Y1 + cpy #8 + bcc @CONT2 + jsr INCYOFF +@CONT2: ldx CURY + beq @DONE + clc + adc CURY ;a=a+y + dec CURY ;y=y-1 + bcc @LOOP + + inc CURX + sbc CURX ;if a<0 then x=x+1; a=a+x + lsr CHUNK1 + bne @CONT3 + tax + jsr UPCH1 ;Upchunk, but no plot +@CONT3: lsr OLDCH1 ;Only the bits... + asl CHUNK2 ;Fix chunks + bne @CONT4 + tax + jsr UPCH2 +@CONT4: asl OLDCH2 + bcs @LOOP +@DONE: +CIRCEXIT: ;Restore interrupts + lda #$37 + sta $01 + cli + rts +; +; Decrement lower pointers +; +DECYOFF: + tay + lda #7 + sta Y2 + + lda X2 ;If we pass through zero, then + sec + sbc #<320 ;subtract 320 + sta X2 + lda X2+1 + sbc #>320 + sta X2+1 + lda TEMP2 + sec + sbc #<320 + sta TEMP2 + lda TEMP2+1 + sbc #>320 + sta TEMP2+1 + + tya + dec BROW + bmi EXIT2 + rts +EXIT2: pla ;Grab return address + pla + jmp CIRCEXIT ;Restore interrupts, etc. + +; Increment upper pointers +INCYOFF: + tay + lda #00 + sta Y1 + lda X1 + clc + adc #<320 + sta X1 + lda X1+1 + adc #>320 + sta X1+1 + lda POINT + clc + adc #<320 + sta POINT + lda POINT+1 + adc #>320 + sta POINT+1 +@ISKIP: inc TROW + bmi @DONE + lda TROW + cmp #25 + bcs EXIT2 +@DONE: tya + rts + +; +; UPCHUNK1 -- Update right-moving chunk pointers +; Due to passing through a column +; +UPCHUNK1: + tax + jsr PCHUNK1 +UPCH1: lda #$FF ;Alternative entry point + sta CHUNK1 + sta OLDCH1 + lda TEMP2 + clc + adc #8 + sta TEMP2 + bcc @CONT + inc TEMP2+1 + clc +@CONT: lda POINT + adc #8 + sta POINT + bcc @DONE + inc POINT+1 +@DONE: txa + inc RCOL + rts + +; +; UPCHUNK2 -- Update left-moving chunk pointers +; +UPCHUNK2: + tax + jsr PCHUNK2 +UPCH2: lda #$FF + sta CHUNK2 + sta OLDCH2 + lda X2 + sec + sbc #8 + sta X2 + bcs @CONT + dec X2+1 + sec +@CONT: lda X1 + sbc #8 + sta X1 + bcs @DONE + dec X1+1 +@DONE: txa + dec LCOL + rts +; +; Plot right-moving chunk pairs for circle routine +; +PCHUNK1: + + lda RCOL ;Make sure we're in range + cmp #40 + bcs @SKIP2 + lda CHUNK1 ;Otherwise plot + eor OLDCH1 + sta TEMP + lda TROW ;Check for underflow + bmi @SKIP + ldy Y1 + lda (POINT),y + eor BITMASK + and TEMP + eor (POINT),y + sta (POINT),y + +@SKIP: lda BROW ;If CY+Y >= 200... + cmp #25 + bcs @SKIP2 + ldy Y2 + lda (TEMP2),y + eor BITMASK + and TEMP + eor (TEMP2),y + sta (TEMP2),y +@SKIP2: rts + +; +; Plot left-moving chunk pairs for circle routine +; + +PCHUNK2: + lda LCOL ;Range check in X + cmp #40 + bcs EXIT3 + lda CHUNK2 ;Otherwise plot + eor OLDCH2 + sta TEMP + lda TROW ;Check for underflow + bmi @SKIP + ldy Y1 + lda (X1),y + eor BITMASK + and TEMP + eor (X1),y + sta (X1),y + +@SKIP: lda BROW ;If CY+Y >= 200... + cmp #25 + bcs EXIT3 + ldy Y2 + lda (X2),y + eor BITMASK + and TEMP + eor (X2),y + sta (X2),y +EXIT3: rts + +; ------------------------------------------------------------------------ +; Calculate all variables to plot the pixel at X1/Y1. If the point is out +; of range, a carry is returned and INRANGE is set to a value !0 zero. If +; the coordinates are valid, INRANGE is zero and the carry clear. + +CALC: lda Y1 + sta ROW + and #7 + tay + lda Y1+1 + lsr ; Neg is possible + ror ROW + lsr + ror ROW + lsr + ror ROW + + lda #00 + sta POINT + lda ROW + cmp #$80 + ror + ror POINT + cmp #$80 + ror + ror POINT ; row*64 + adc ROW ; +row*256 + clc + adc #>VBASE ; +bitmap base + sta POINT+1 + + lda X1 + tax + sta COL + lda X1+1 + lsr + ror COL + lsr + ror COL + lsr + ror COL + + txa + and #$F8 + clc + adc POINT ; +(X AND #$F8) + sta POINT + lda X1+1 + adc POINT+1 + sta POINT+1 + txa + and #7 + tax + + lda ROW + cmp #25 + bcs @L9 + lda COL + cmp #40 + bcs @L9 + lda #00 +@L9: sta INRANGE + rts + + -- 2.39.5