The article describing this program appears on a separate page.
STARS3D.ASM is available in ATASCII format.
0100 ; ***********************
0110 ; * STARS 3D DEMO *
0120 ; * BY CRAIG PATCHETT *
0130 ; ***********************
0140 ;
0150 ; System equates
0160 ;
0170 SDMCTL = $022F
0180 NMIEN = $D40E
0190 RANDOM = $D20A
0200 WSYNC = $D40A
0210 SDLSTL = $0230
0220 VDSLST = $0200
0230 COLPF0 = $D016
0240 COLOR4 = $02C8
0250 SETVBV = $E45C
0260 XITVBL = $E462
0270 ;
0280 ; Zero-page equate
0290 ;
0300 INDRCT = $CC ; for indirect addressing
0310 ;
0320 *= $3800
0330 ;
0340 ; Get things going
0350 ;
0360 INITIL
0370 JSR STRINI ; set up stars
0380 JSR DLSINI ; set up display list
0390 LDA #0 ; set background color
0400 STA COLOR4
0410 LDA #7 ; set up VBLANK
0420 LDX #VBLANK/256
0430 LDY #VBLANK&255
0440 JSR SETVBV
0450 LDA #DLI&255 ; get DLIs going
0460 STA VDSLST
0470 LDA #DLI/256
0480 STA VDSLST+1
0490 LDA #192
0500 STA NMIEN
0510 ALLDON
0520 JMP ALLDON ; let things run
0530 ;
0540 ; VBLANK routine
0550 ;
0560 VBLANK
0570 JSR CNTDWN ; take care of star movement
0580 LDA #0 ; reset index
0590 STA INDEX
0600 JMP XITVBL ; back to system
0610 ;
0620 ; Initialize stars
0630 ;
0640 STRINI
0650 LDA #STRLIN&255 ; set up STRTPL/H arrays
0660 STA STRTPL
0670 LDA #STRLIN/256
0680 STA STRTPH
0690 LDX #0
0700 STX STRPOS
0710 INX
0720 STRBR1
0730 LDA STRTPL-1,X ; make each address a screen
0740 CLC ; width more than the one
0750 ADC #48 ; before
0760 STA STRTPL,X
0770 LDA STRTPH-1,X
0780 ADC #0
0790 STA STRTPH,X
0800 LDA #0
0810 STA STRPOS,X
0820 INX
0830 CPX #16
0840 BNE STRBR1
0850 LDA #STRLIN&255 ; clear star memory
0860 STA INDRCT
0870 LDA #STRLIN/256
0880 STA INDRCT+1
0890 LDY #255
0900 LDX #3
0910 LDA #0
0920 STRBR2
0930 STA (INDRCT),Y
0940 DEY
0950 CPY #255
0960 BNE STRBR2
0970 DEX
0980 BEQ STRBR3
0990 INC INDRCT+1
1000 JMP STRBR2
1010 STRBR3
1020 LDX #0 ; give each line a star
1030 STRBR4
1040 LDA STRTPL,X
1050 STA INDRCT
1060 LDA STRTPH,X
1070 STA INDRCT+1
1080 LDA #64
1090 LDY #0
1100 STA (INDRCT),Y
1110 INX
1120 CPX #16
1130 BNE STRBR4
1140 RTS
1150 ;
1160 ; Initialize display list
1170 ;
1180 DLSINI
1190 LDA #DLIST&255 ; set up for indirect
1200 STA INDRCT ; addressing
1210 LDA #DLIST/256
1220 STA INDRCT+1
1230 LDA #0 ; get index ready
1240 STA INDEX
1250 LDY #3
1260 DLSBR4
1270 LDA #$CE ; ANTIC 14, DLI, LMS line
1280 STA (INDRCT),Y
1290 INY
1300 BNE DLSBR1
1310 INC INDRCT+1
1320 DLSBR1
1330 LDA RANDOM ; pick star type
1340 AND #7
1350 PHA
1360 TAX
1370 LDA MANCOL,X ; tell STRCOL what color
1380 LDX INDEX ; this line is
1390 STA STRCOL,X
1400 PLA
1410 INC INDEX
1420 ASL A ; times two so we skip over
1430 TAX ; two screen widths...
1440 DLSBR2
1450 LDA RANDOM ; pick random offset into
1460 AND #63 ; line
1470 CMP #48 ; make sure it's less than
1480 BCS DLSBR2 ; a screen width
1490 CLC
1500 ADC STRTPL,X ; ...here instead of one
1510 STA (INDRCT),Y ; put it into display list
1520 INY
1530 BNE DLSBR5
1540 INC INDRCT+1
1550 DLSBR5
1560 LDA STRTPH,X
1570 ADC #0
1580 STA (INDRCT),Y
1590 INY
1600 BNE DLSBR6
1610 INC INDRCT+1
1620 DLSBR6
1630 CPY #67 ; 192 lines done, finish up
1640 BNE DLSBR4
1650 LDA #$41
1660 STA (INDRCT),Y
1670 INY
1680 LDA #DLIST&255
1690 STA (INDRCT),Y
1700 STA SDLSTL
1710 INY
1720 LDA #DLIST/256
1730 STA (INDRCT),Y
1740 STA SDLSTL+1
1750 LDA #$23 ; give us a wide screen
1760 STA SDMCTL
1770 RTS
1780 ;
1790 ; Display list interrupt routine
1800 ;
1810 DLI
1820 LDX INDEX ; what line are we on?
1830 LDA STRCOL,X ; load this line's color
1840 STA WSYNC ; wait for end of last line
1850 STA COLPF0 ; store color
1860 INC INDEX ; get ready for next line
1870 RTI
1880 ;
1890 ; Timer routine
1900 ;
1910 CNTDWN
1920 LDX #13 ; move fastest star
1930 JSR SCROLL
1940 JSR SCROLL
1950 LDX #12 ; and its twin
1960 JSR SCROLL
1970 JSR SCROLL
1980 CNTBR1
1990 DEX ; for the rest...
2000 BMI CNTRET
2010 DEC TIMER,X ; ...countdown timer
2020 BNE CNTBR1
2030 JSR SCROLL ; scroll if ready
2040 LDA TIMARY,X ; and reset timer
2050 STA TIMER,X
2060 JMP CNTBR1
2070 CNTRET
2080 RTS
2090 ;
2100 ; Star scroll routine
2110 ;
2120 SCROLL
2130 LDA STRTPL,X ; set up for indirect addressing
2140 STA INDRCT
2150 LDA STRTPH,X
2160 STA INDRCT+1
2170 LDY STRPOS,X ; get star position
2180 LDA (INDRCT),Y ; get byte with star in it
2190 ASL A ; shift star left one
2200 ASL A
2210 STA (INDRCT),Y ; put it back
2220 BCC SCRBR1 ; did it fall off byte?
2230 LDA #1 ; if so, put it in next one
2240 DEY
2250 CPY #255 ; did it fall off screen?
2260 BNE SCRBR2
2270 LDY #47 ; if so, put it on other end
2280 SCRBR2
2290 STA (INDRCT),Y
2300 TYA
2310 STA STRPOS,X ; remember where it is now
2320 SCRBR1
2330 RTS
2340 ;
2350 TIMER
2360 .BYTE 8,8,6,6,4,4 ; timers for scrolling
2370 .BYTE 3,3,2,2,1,1
2380 TIMARY
2390 .BYTE 8,8,6,6,4,4 ; values to reset timers
2400 .BYTE 3,3,2,2,1,1
2410 MANCOL
2420 .BYTE $22,$24,$26 ; star colors
2430 .BYTE $28,$2A,$2C
2440 .BYTE $2E,$22
2450 ;
2460 DLIST
2470 .BYTE $70,$70,$F0 ; display list
2480 *= *+579
2490 STRLIN
2500 *= *+768 ; star (screen) memory
2510 STRTPL
2520 *= *+16 ; addresses of beginning of
2530 STRTPH
2540 *= *+16 ; each star line
2550 STRPOS
2560 *= *+16 ; position of star on line
2570 STRCOL
2580 *= *+192 ; color of each line
2590 INDEX
2600 *= *+1 ; used to index into STRCOL