YINYANG h DSK (ü˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙˙YIN-ASM €2]P2"YIN-EA3 € ˘P T€*6* Generates a Bitmap Yin/Yang on the TI-99/4A Computer** Matthew Hagerty - March 2006** This code is Public Domain* DEF YIN* VDP MEMORY MAP*/VDPRD EQU >8800 VDP RAM READ DATA,VDPSTA EQU >8802 VDP RAM STATUS˙0VDPWD EQU >8C00 VDP RAM WRITE DATA8VDPWA EQU >8C02 VDP RAM READ/WRITE ADDRESSMVR1CPY EQU >83D4 COPY OF VDP REGISTER 1 - SEE E/A MANUAL PG. 248 * WORKSPACES*˙9WRKSP0 EQU >8300 WORKSPACE 0 FOR PROGRAM USEFWRKSP1 EQU >8320 WORKSPACE 1 FOR VDP AND RELATED ROUTINES5W1R0LB EQU WRKSP1+1 WORKSPACE 1 R0 LOW BYTE * EQUATES*SIZE EQU 192TWELVE EQU SIZE/12HALF EQU SIZE/2˙QTR EQU SIZE/4QTR3 EQU SIZE/4*3GREAT EQU HALF*HALFHEAD EQU QTR*QTREYE EQU TWELVE*TWELVE* DATA** Pixel Look Up Table#PLUT DATA >8040,>2010,>0804,>0201* Set up bitmap mode.*0YIN LIMI 0 DISABLE INTERRUPTS˙1 LWPI WRKSP1 USE VDP WORKSPACE 14 LI R0,>0002 SET BIT 6 OF VDP REG 0 BL @VWTR> LI R0,>0206 MOVE SCREEN IMAGE TABLE TO >1800 BL @VWTR˙7 LI R0,>03FF MOVE COLOR TABLE TO >2000 BL @VWTR? LI R0,>0403 PATTERN DESCRIPTOR TABLE TO >0000 BL @VWTRA LI R0,>0536 MOVE SPRITE ATTRIBUTE LIST TO >1B00 BL @VWTR˙4 LI R0,>1B00 DISABLE UNUSED SPRITES) LI R1,>D000 ALL SPRITES BL @VSBWF* WRITE 0 - 255 THREE TIMES. USE AN INLINE VSBW FOR FASTER OPERATION.*> LI R0,>1800 SCREEN IMAGE TABLE START ADDRESS˙D MOVB @W1R0LB,@VDPWA SEND LOW BYTE OF VDP RAM WRITE ADDRESSI ORI R0,>4000 SET READ/WRITE BITS 14 AND 15 TO WRITE (01)E MOVB R0,@VDPWA SEND HIGH BYTE OF VDP RAM WRITE ADDRESS˙+ CLR R1 START AT ZEROE LI R2,3 NUMBER OF TIMES TO LOOP 0 - 255 PATTERN3INIT1 MOVB R1,@VDPWD WRITE BYTE TO VDP RAM4 AI R1,>0100 INC THE VALUE TO WRITE˙; JNE INIT1 CHECK IF DONE WRITING PATTERN- DEC R2 PATTERN COUNTER+ JNE INIT1 CHECK IF DONE * CLEAR PATTERN DESCRIPTOR TABLE*2 CLR R0 ADDRESS OF PDT >0000˙7 CLR R1 VALUE TO WRITE - ALL ZERO; LI R2,>1800 NUMBER OF TIMES TO WRITE ZERO BL @VSMW* CLEAR COLOR TABLE*: LI R0,>2000 ADDRESS OF COLOR TABLE >2000˙< LI R1,>FE00 DEFAULT COLOR IS WHITE ON GRAY: LI R2,>1800 NUMER OF TIMES TO WRITE ZERO BL @VSMW* INITIALIZE THE YING YANG*6 LI R0,32 START ADDRESS X CENTERED˙) CLR R1 BIT PATTERN= CLR R3 CURRENT PIXEL FROM LEFT IN BYTE) CLR R4 X START = 0) CLR R5 Y START = 0˙I CLR R10 IF NOT 0, THEN HOLDS COLOR FOR CURRENT BYTEG* THIS IS USED IN EVERY CHECK, SO CALCULATE IT ONCE INSTEAD OF POSSIBLY * FOUR TIMES.* ((HALF - X) * (HALF - X))*MAINLP LI R6,HALF& S R4,R6 HALF - X˙4 MPY R6,R6 R7 = (HALF-X)*(HALF-X)%* TEST IF OUTSIDE OF THE GREAT CIRCLE?* ((HALF - X) * (HALF - X)) + ((HALF - Y) * (HALF - Y)) > GREAT* LI R8,HALF& S R5,R8 HALF - Y˙4 MPY R8,R8 R9 = (HALF-Y)*(HALF-Y) A R7,R9 CI R9,GREAT= JLE NEXT0 IN GREAT CIRCLE, FIND OUT WHEREH CI R4,HALF SEE WHICH SIDE OF THE BACKGROUND WE ARE IN˙; JHE XLOOP ON THE LIGHT SIDE, DO NOTHING@ SOCB @PLUT(R3),R1 ON DARK SIDE, SET BACKGROUND PIXELD LI R10,>E100 SET THIS BYTE TO HAVE GRAY/BLACK COLOR JMP XLOOP˙=* CHECK IF IN UPPER HALF OF GREAT CIRCLE, AND WITHIN THE EYE.<* ((HALF - X) * (HALF - X)) + ((QTR - Y) * (QTR - Y)) <= EYE*NEXT0 LI R8,QTR% S R5,R8 QTR - Y2 MPY R8,R8 R9 = (QTR-Y)*(QTR-Y) A R7,R9˙ CI R9,EYE( JGT NEXT1 NOT IN EYEA LI R10,>F100 IN BLACK EYE, SET COLOR WHITE/BLACK JMP XLOOP>* CHECK IF IN UPPER HALF OF GREAT CIRCLE, AND WITHIN THE HEAD.˙=* ((HALF - X) * (HALF - X)) + ((QTR - Y) * (QTR - Y)) <= HEAD*NEXT1 CI R9,HEAD) JGT NEXT2 NOT IN HEAD' SOCB @PLUT(R3),R1 SET PIXEL JMP XLOOP=* CHECK IF IN LOWER HALF OF GREAT CIRCLE, AND WITHIN THE EYE.˙>* ((HALF - X) * (HALF - X)) + ((QTR3 - Y) * (QTR3 - Y)) <= EYE*NEXT2 LI R8,QTR3& S R5,R8 QTR3 - Y4 MPY R8,R8 R9 = (QTR3-Y)*(QTR3-Y) A R7,R9 CI R9,EYE˙( JGT NEXT3 NOT IN EYE' SOCB @PLUT(R3),R1 SET PIXELA LI R10,>F100 IN WHITE EYE, SET COLOR WHITE/BLACK JMP XLOOP>* CHECK IF IN LOWER HALF OF GREAT CIRCLE, AND WITHIN THE HEAD.˙?* ((HALF - X) * (HALF - X)) + ((QTR3 - Y) * (QTR3 - Y)) <= HEAD*NEXT3 CI R9,HEAD) JGT NEXT4 NOT IN HEAD> CI R10,0 IF COLOR IS ALREADY SET, SKIP IT JNE XLOOP˙D LI R10,>F100 IN DARK HEAD, SET COLOR TO WHITE/BLACK JMP XLOOP* IN A TAIL, WHICH ONE?*NEXT4 CI R4,HALF+ JHE NEXT5 IN LIGHT TAIL> CI R10,0 IF COLOR IS ALREADY SET, SKIP IT˙ JNE XLOOPD LI R10,>F100 IN DARK TAIL, SET COLOR TO WHITE/BLACK JMP XLOOP'NEXT5 SOCB @PLUT(R3),R1 SET PIXELA* DONE WITH THIS PIXEL. IF THIS IS THE LAST PIXEL IN THE CURRENT* BYTE, WRITE TO THE VDP.*˙2000 ADDRESS OF BYTE IN COLOR TABLE- MOV R10,R1 NEW COLOR VALUE. BL @VSBW WRITE COLOR BYTE˙= AI R0,->2000 ADJUST BYTE ADDRESS BACK TO PDT/ CLR R10 RESET COLOR VALUEGXLOOP0 AI R0,8 ADDRESS OF NEXT BYTE IN CURRENT PIXEL ROW/ CLR R1 RESET BIT PATTERN˙7 CLR R3 RESET CURRENT PIXEL COUNT*XLOOP1 INC R4 NEXT X PIXEL CI R4,SIZE JHE YLOOP JMP MAINLPYLOOP INC R5 CI R5,SIZE JHE DONE˙@ LI R4,32 TEMPORARY X LOCATION FOR CENTERING< BL @PXADDR CALCULATE THE NEW BYTE ADDRESS) CLR R3 RESET PIXEL% CLR R4 RESET X JMP MAINLP˙/DONE LIMI 2 ENABLE INTERRUPTSQUIT JMP QUIT**** * SUBROUTINES***** PIXEL OFFSET ADDRESS*C* Calculate a byte and bit offset in bitmap mode. The register useC* is such that when done R0 contains the address offset for reading˙D* the existing byte from the pattern descriptor table into R1. Then@* set the correct pixel and write back to the pattern descriptor* table.** R4 = Column (X), R5 = Row (Y)&* R0 = Byte Offset, R3 = Bit to Change*˙'PXADDR MOV R5,R0 ROW TO R09 SLA R0,5 DIV ROW BY 8 AND MUL BY 2565 SOC R5,R0 ADD REMAINDER TO OFFSET1 ANDI R0,>FF07 ADJUST FOR DIVISION' MOV R4,R3 COL TO R3˙* ANDI R3,7 COL MODULO 8/ A R4,R0 ADD COL TO OFFSET5 S R3,R0 ADJUST BY COL REMAINDER RT*** VDP ROUTINES**0* Uses a dedicated workspace in fast 16-bit RAM.*˙* General register use is: * R0 VDP RAM starting address.J* R1 MSB contains the value to write or to receive a value when reading.F* For multipe byte reads/writes, contains the CPU buffer address.˙7* R2 Counter (counts down) for multiple reads/writes.** WRITING VDP DATA*4* VDP SINGLE BYTE WRITE - SINGLE BYTE MULTIPLE WRITE*<* Writes the value in the most-significant byte of R1 to the˙=* VDP RAM address indicated in R0. For VSMW, the value in R2<* determines how many times to write the byte. This is very>* useful when initializing large amounts of VDP RAM for things8* such as clearing the screen or setting up bitmap mode.*˙MVSBW LI R2,1 FORCE THE BYTE COUNT TO 1 FOR SINGLE BYTE WRITEDVSMW MOVB @W1R0LB,@VDPWA SEND LOW BYTE OF VDP RAM WRITE ADDRESSI ORI R0,>4000 SET READ/WRITE BITS 14 AND 15 TO WRITE (01)˙E MOVB R0,@VDPWA SEND HIGH BYTE OF VDP RAM WRITE ADDRESS= ANDI R0,>3FFF WAIT FOR THE VDP AND RESTORE R03VSMWLP MOVB R1,@VDPWD WRITE BYTE TO VDP RAM* DEC R2 BYTE COUNTER˙+ JNE VSMWLP CHECK IF DONE RT* VDP MULTIPLE BYTE WRITE*=* Writes the number of bytes indicated in R2 from the CPU RAM<* starting at the address indicated by R1 and places them in˙6* the VDP RAM starting at the address indicated by R0.*DVMBW MOVB @W1R0LB,@VDPWA SEND LOW BYTE OF VDP RAM WRITE ADDRESSI ORI R0,>4000 SET READ/WRITE BITS 14 AND 15 TO WRITE (01)˙E MOVB R0,@VDPWA SEND HIGH BYTE OF VDP RAM WRITE ADDRESS= ANDI R0,>3FFF WAIT FOR THE VDP AND RESTORE R03VMBWLP MOVB *R1+,@VDPWD WRITE BYTE TO VDP RAM* DEC R2 BYTE COUNTER˙+ JNE VMBWLP CHECK IF DONE RT** READING VDP DATA** VDP SINGLE BYTE READ*>* Reads a byte from VDP RAM address indicated in R0 and places(* it in the most-significate byte of R1.*˙DVSBR MOVB @W1R0LB,@VDPWA SEND LOW BYTE OF VDP RAM WRITE ADDRESSH ANDI R0,>3FFF SET READ/WRITE BITS 14 AND 15 TO READ (00)E MOVB R0,@VDPWA SEND HIGH BYTE OF VDP RAM WRITE ADDRESS˙. NOP WAIT FOR THE VDP4 MOVB @VDPRD,R1 READ BYTE FROM VDP RAM RT* VDP MULTIPLE BYTE READ*<* Reads the number of bytes indicated in R2 from the VDP RAM˙<* starting at the address indicated by R0 and places them in6* the CPU RAM starting at the address indicated by R1.*DVMBR MOVB @W1R0LB,@VDPWA SEND LOW BYTE OF VDP RAM WRITE ADDRESS˙H ANDI R0,>3FFF SET READ/WRITE BITS 14 AND 15 TO READ (00)E MOVB R0,@VDPWA SEND HIGH BYTE OF VDP RAM WRITE ADDRESS. NOP WAIT FOR THE VDP4VMBRLP MOVB @VDPRD,*R1+ READ BYTE FROM VDP RAM˙* DEC R2 BYTE COUNTER/ JNE VMBRLP CHECK IF FINISHED RT** VDP REGISTERS** VDP WRITE TO REGISTER*A* Writes the value in the least-significant byte of R0 to the VDP˙8* register indicated in the most-significate byte of R0.*LVWTR MOVB @W1R0LB,@VDPWA SEND LOW BYTE (VALUE) TO WRITE TO VDP REGISTERC ORI R0,>8000 SET UP A VDP REGISTER WRITE OPERATION˙F MOVB R0,@VDPWA SEND HIGH BYTE (ADDRESS) OF VDP REGISTER RT ENDP00202 A0000B8040B2010B0804B0201B0300B0000B02E0B8320B02007F37BF 0001PA0012B0002B06A0C01F2B0200B0206B06A0C01F2B0200B03FFB06A0C01F27F2DFF 0002PA0028B0200B0403B06A0C01F2B0200B0536B06A0C01F2B0200B1B00B02017F315F 0003˙PA003EBD000B06A0C0186B0200B1800BD820B8321B8C02B0260B4000BD8007F2E3F 0004PA0054B8C02B04C1B0202B0003BD801B8C00B0221B0100B16FBB0602B16F97F2D2F 0005PA006AB04C0B04C1B0202B1800B06A0C018AB0200B2000B0201BFE00B02027F2F7F 0006˙PA0080B1800B06A0C018AB0200B0020B04C1B04C3B04C4B04C5B04CAB02067F2D2F 0007PA0096B0060B6184B3986B0208B0060B6205B3A08BA247B0289B2400B12087F2F5F 0008PA00ACB0284B0060B1437BF063C0000B020ABE100B1032B0208B0030B62057F302F 0009˙PA00C2B3A08BA247B0289B0100B1503B020ABF100B1027B0289B0900B15037F2EDF 0010PA00D8BF063C0000B1021B0208B0090B6205B3A08BA247B0289B0100B15057F2F9F 0011PA00EEBF063C0000B020ABF100B1014B0289B0900B1506B028AB0000B160E7F2D9F 0012˙PA0104B020ABF100B100BB0284B0060B1406B028AB0000B1605B020ABF1007F300F 0013PA011AB1002BF063C0000B0583B0283B0008B1611B06A0C0186B028AB00007F30CF 0014PA0130B1308B0220B2000BC04AB06A0C0186B0220BE000B04CAB0220B00087F300F 0015˙PA0146B04C1B04C3B0584B0284B00C0B1401B10A0B0585B0285B00C0B14077F2EBF 0016PA015CB0204B0020B06A0C0170B04C3B04C4B1095B0300B0002B10FFBC0057F2E3F 0017PA0172B0A50BE005B0240BFF07BC0C4B0243B0007BA004B6003B045BB02027F2C8F 0018˙PA0188B0001BD820B8321B8C02B0260B4000BD800B8C02B0240B3FFFBD8017F2AAF 0019PA019EB8C00B0602B16FCB045BBD820B8321B8C02B0260B4000BD800B8C027F297F 0020PA01B4B0240B3FFFBD831B8C00B0602B16FCB045BBD820B8321B8C02B02407F273F 0021˙PA01CAB3FFFBD800B8C02B1000BD060B8800B045BBD820B8321B8C02B02407F27AF 0022PA01E0B3FFFBD800B8C02B1000BDC60B8800B0602B16FCB045BBD820B83217F261F 0023PA01F6B8C02B0260B8000BD800B8C02B045B7F81EF 0024˙P50008YIN 7FD7CF 0025P:Asm994a TMS99000 Assembler - v3.007 0026