; REMARK: Due to self program update Draw/Erase, ABSDX, ABSDY, VY, etc., this program doesn't run on the ROM. ; Needs to be on the RAM. EXPORT LINEDDAM_INPUTADDR EXPORT LINEDDAM EXPORT LINEDDA_VRAMADDR EXPORT LINEDDA_BYTE_PER_LINE EXPORT LINEDDA_OP EXPORT LINEDDA_X0 EXPORT LINEDDA_Y0 EXPORT LINEDDA_X1 EXPORT LINEDDA_Y1 EXPORT LINEDDA ; Line drawing by DDA by Soji Yamakawa 10/26/2017 ; All input must come from an array. ; LINEDDA_INPUT must have the address. ; 2 PTR VRAM ADDRESS ; 1 UCHAR BYTES PER LINE ; Should be 80 to use for FM-7 VRAM ; (640 pixels, 8 pixels per byte) ; 1 UCHAR Must be 1 ; 1 UCHAR # LINES ; 2 UINT X0 ; 1 UINT Y0 ; 2 UINT X1 ; 1 UINT Y1 ; : ; : ; : ; Multiple lines LINEDDAM_INPUTADDR RZB 2 LINEDDAM PSHS A,B,X,Y,U LINEDDAM_VRAMACCESSON NOP ; Will be made BITA $D409 for Sub-CPU NOP NOP LDU LINEDDAM_INPUTADDR,PCR LDD ,U++ STD LINEDDA_VRAMADDR,PCR LDD ,U++ STD LINEDDA_BYTE_PER_LINE,PCR LDB ,U+ BEQ LINEDDAM_LOOP_END LINEDDAM_LOOP LDX ,U++ STX LINEDDA_X0,PCR LDA ,U+ STA LINEDDA_Y0,PCR LDX ,U++ STX LINEDDA_X1,PCR LDA ,U+ STA LINEDDA_Y1,PCR BSR LINEDDA DECB BNE LINEDDAM_LOOP LINEDDAM_LOOP_END LINEDDAM_VRAMACCESSOFF NOP ; Will be made STA $D409 for Sub-CPU NOP ; See INSTALL_LINEDDA_IN_SUBCPU function NOP PULS A,B,X,Y,U,PC ; Save one RTS by pulling PC together ; RTS ; Single line ; (X0,Y0), (X1,Y1) must be within the VRAM location. ; It doesn't clip. ; Input (X0,Y0),(X1,Y1) may be swapped after this function. LINEDDA_VRAMADDR RZB 2 LINEDDA_BYTE_PER_LINE RZB 1 LINEDDA_OP RZB 1 ; 1 UCHAR 1=Draw LINEDDA_X0 RZB 2 LINEDDA_Y0 RZB 1 LINEDDA_X1 RZB 2 LINEDDA_Y1 RZB 1 ; EXEC &H578A LINEDDA PSHS A,B,X,Y,U LDA LINEDDA_OP,PCR DECA LBNE LINEDDA_END ; Must be 1 for now. ; Always X0<=X1 LDD LINEDDA_X1,PCR SUBD LINEDDA_X0,PCR STD LINEDDA_ABSDX,PCR BPL LINEDDA_DX_MADE_POSI COMA COMB ADDD #1 STD LINEDDA_ABSDX,PCR ; Swap P0 and P1 LDD LINEDDA_X0,PCR LDX LINEDDA_X1,PCR STD LINEDDA_X1,PCR STX LINEDDA_X0,PCR LDA LINEDDA_Y0,PCR LDB LINEDDA_Y1,PCR STA LINEDDA_Y1,PCR STB LINEDDA_Y0,PCR LINEDDA_DX_MADE_POSI ; X0,Y0 is fixed at this point. ; Ready to calculate current address and bit. LDA LINEDDA_Y0,PCR LDB LINEDDA_BYTE_PER_LINE,PCR MUL ADDD LINEDDA_VRAMADDR,PCR STD LINEDDA_CURADDR,PCR LDB LINEDDA_X0+1,PCR LDA #$80 ANDB #7 BEQ LINEDDA_X0Y0ADDR_SETBIT LINEDDA_X0Y0ADDR_SHIFT LSRA DECB BNE LINEDDA_X0Y0ADDR_SHIFT LINEDDA_X0Y0ADDR_SETBIT STA LINEDDA_CURBIT,PCR LDD LINEDDA_X0,PCR LSRA RORB LSRA RORB LSRA RORB ADDD LINEDDA_CURADDR,PCR STD LINEDDA_CURADDR,PCR ; Also ready to calculate VY LDB LINEDDA_BYTE_PER_LINE,PCR LDA LINEDDA_Y1,PCR CMPA LINEDDA_Y0,PCR BHI LINEDDA_SETVY ; Make sure to use unsigned comparison NEGB LINEDDA_SETVY SEX STD LINEDDA_VY,PCR LDB LINEDDA_Y1,PCR SUBB LINEDDA_Y0,PCR BHI LINEDDA_DY_MADE_POSI NEGB LINEDDA_DY_MADE_POSI CLRA STD LINEDDA_ABSDY,PCR LDU LINEDDA_CURADDR,PCR ; U will be current VRAM address ; D=ABSDY CMPD LINEDDA_ABSDX,PCR ; Therefore, D=ABSDY at LINEDDA_DYGREATER LBHI LINEDDA_DYGREATER ; At this line, ABSDX is either greater or equal than ABSDY ; If ABSDX is zero, it means ABSDY is also zero. LDD LINEDDA_ABSDX,PCR LBEQ LINEDDA_ZERO LINEDDA_DXGREATER ; D is ABSDX SUBD LINEDDA_ABSDY,PCR STD LINEDDA_CURBALANCE,PCR LDX LINEDDA_ABSDX,PCR ; Step count LEAX 1,X ; Conservative method >> ;LINEDDA_DXG_LOOP ; LDA LINEDDA_CURBIT,PCR ; ORA ,U ; STA ,U ; ; LDA LINEDDA_CURBIT,PCR ; LSRA ; BCC LINEDDA_DXG_XMOVED ; RORA ; LEAU 1,U ;LINEDDA_DXG_XMOVED STA LINEDDA_CURBIT,PCR ; ; ; LDD LINEDDA_CURBALANCE,PCR ; SUBD LINEDDA_ABSDY,PCR ; STD LINEDDA_CURBALANCE,PCR ; BGE LINEDDA_DXG_YMOVED ; ADDD LINEDDA_ABSDX,PCR ; STD LINEDDA_CURBALANCE,PCR ; ; LDD LINEDDA_VY,PCR ; LEAU D,U ;LINEDDA_DXG_YMOVED ; LEAX -1,X ; Memo LEAU doesn't set zero flag. LEAX does. ; BNE LINEDDA_DXG_LOOP ; Conservative method << ; Self Program Update >> ; Updating the program >> LDD LINEDDA_ABSDX,PCR STD LINEDDA_DXG_ABSDX7+2,PCR STD LINEDDA_DXG_ABSDX6+2,PCR STD LINEDDA_DXG_ABSDX5+2,PCR STD LINEDDA_DXG_ABSDX4+2,PCR STD LINEDDA_DXG_ABSDX3+2,PCR STD LINEDDA_DXG_ABSDX2+2,PCR STD LINEDDA_DXG_ABSDX1+2,PCR STD LINEDDA_DXG_ABSDX0+2,PCR STD LINEDDA_DXG_ABSDX_+2,PCR CLRA CLRB SUBD LINEDDA_ABSDY,PCR STD LINEDDA_DXG_ABSDY7+2,PCR STD LINEDDA_DXG_ABSDY6+2,PCR STD LINEDDA_DXG_ABSDY5+2,PCR STD LINEDDA_DXG_ABSDY4+2,PCR STD LINEDDA_DXG_ABSDY3+2,PCR STD LINEDDA_DXG_ABSDY2+2,PCR STD LINEDDA_DXG_ABSDY1+2,PCR STD LINEDDA_DXG_ABSDY0+2,PCR STD LINEDDA_DXG_ABSDY_+2,PCR LDD LINEDDA_VY,PCR ; In the expanded loop, B is free and used as VY STD LINEDDA_DXG_VY_+2,PCR LDY LINEDDA_CURBALANCE,PCR LDB LINEDDA_CURBIT,PCR ; Updating the program << ; In self-programming loop, ; X is for balance, and ; Y is for the counter. ; It saves 1 cycle per pixel. ; 5 bytes in total. EXG X,Y CMPY #8 LBLO LINEDDA_DXG_LOOP_ CLRA ; Needed for middle start ASLB ; CMPB #$40 & BEQ BMI LINEDDA_DXG_ENTERLOOP6 ASLB ; CMPB #$20 & BEQ BMI LINEDDA_DXG_ENTERLOOP5 ASLB ; CMPB #$10 & BEQ BMI LINEDDA_DXG_ENTERLOOP4 ASLB ; CMPB #$08 & BEQ BMI LINEDDA_DXG_ENTERLOOP3 ASLB ; CMPB #$04 & BEQ BMI LINEDDA_DXG_ENTERLOOP2 ASLB ; CMPB #$02 & BEQ BMI LINEDDA_DXG_ENTERLOOP1 ASLB ; CMPB #$01 & BEQ BMI LINEDDA_DXG_ENTERLOOP0 BRA LINEDDA_DXG_ENTERLOOP7 ; B is free in the expanded loop. Use it as VY LINEDDA_DXG_ENTERLOOP6 LDB LINEDDA_VY+1,PCR LEAY 1,Y ; Will skip one y-. To match up with y-=8. BRA LINEDDA_DXG_LOOP6 LINEDDA_DXG_ENTERLOOP5 LDB LINEDDA_VY+1,PCR LEAY 2,Y ; Will skip two y-. To match up with y-=8. BRA LINEDDA_DXG_LOOP5 LINEDDA_DXG_ENTERLOOP4 LDB LINEDDA_VY+1,PCR LEAY 3,Y ; Will skip three y-. To match up with y-=8. BRA LINEDDA_DXG_LOOP4 LINEDDA_DXG_ENTERLOOP3 LDB LINEDDA_VY+1,PCR LEAY 4,Y ; Will skip four y-. To match up with y-=8. BRA LINEDDA_DXG_LOOP3 LINEDDA_DXG_ENTERLOOP2 LDB LINEDDA_VY+1,PCR LEAY 5,Y ; Will skip five y-. To match up with y-=8. LBRA LINEDDA_DXG_LOOP2 LINEDDA_DXG_ENTERLOOP1 LDB LINEDDA_VY+1,PCR LEAY 6,Y ; Will skip six y-. To match up with y-=8. LBRA LINEDDA_DXG_LOOP1 LINEDDA_DXG_ENTERLOOP0 LDB LINEDDA_VY+1,PCR LEAY 7,Y ; Will skip seven y-. To match up with y-=8. LBRA LINEDDA_DXG_LOOP0 ; Let me say again, B is free in the expanded loop. Use it as VY LINEDDA_DXG_ENTERLOOP7 LDB LINEDDA_VY+1,PCR LINEDDA_DXG_LOOP7 LDA #$80 LINEDDA_DXG_ABSDY7 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED7 LINEDDA_DXG_ABSDX7 LEAX $7FFF,X ; Using Self Program Update ORA ,U STA ,U CLRA LEAU B,U LINEDDA_DXG_YMOVED7 LINEDDA_DXG_LOOP6 ORA #$40 LINEDDA_DXG_ABSDY6 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED6 LINEDDA_DXG_ABSDX6 LEAX $7FFF,X ; Using Self Program Update ORA ,U STA ,U CLRA LEAU B,U LINEDDA_DXG_YMOVED6 LINEDDA_DXG_LOOP5 ORA #$20 LINEDDA_DXG_ABSDY5 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED5 LINEDDA_DXG_ABSDX5 LEAX $7FFF,X ; Using Self Program Update ORA ,U STA ,U CLRA LEAU B,U LINEDDA_DXG_YMOVED5 LINEDDA_DXG_LOOP4 ORA #$10 LINEDDA_DXG_ABSDY4 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED4 LINEDDA_DXG_ABSDX4 LEAX $7FFF,X ; Using Self Program Update ORA ,U STA ,U CLRA LEAU B,U LINEDDA_DXG_YMOVED4 LINEDDA_DXG_LOOP3 ORA #$08 LINEDDA_DXG_ABSDY3 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED3 LINEDDA_DXG_ABSDX3 LEAX $7FFF,X ; Using Self Program Update ORA ,U STA ,U CLRA LEAU B,U LINEDDA_DXG_YMOVED3 LINEDDA_DXG_LOOP2 ORA #$04 LINEDDA_DXG_ABSDY2 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED2 LINEDDA_DXG_ABSDX2 LEAX $7FFF,X ; Using Self Program Update ORA ,U STA ,U CLRA LEAU B,U LINEDDA_DXG_YMOVED2 LINEDDA_DXG_LOOP1 ORA #$02 LINEDDA_DXG_ABSDY1 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED1 LINEDDA_DXG_ABSDX1 LEAX $7FFF,X ; Using Self Program Update ORA ,U STA ,U CLRA LEAU B,U LINEDDA_DXG_YMOVED1 LINEDDA_DXG_LOOP0 ORA #$01 ORA ,U STA ,U+ LINEDDA_DXG_ABSDY0 LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED0 LINEDDA_DXG_ABSDX0 LEAX $7FFF,X ; Using Self Program Update LEAU B,U LINEDDA_DXG_YMOVED0 LEAY -8,Y ; Memo LEAU doesn't set zero flag. LEAX does. CMPY #8 LBCC LINEDDA_DXG_LOOP7 CMPY #0 BEQ LINEDDA_END LDB #$80 LINEDDA_DXG_LOOP_ TFR B,A ORA ,U STA ,U LSRB BCC LINEDDA_DXG_XMOVED_ RORB LEAU 1,U LINEDDA_DXG_XMOVED_ LINEDDA_DXG_ABSDY_ LEAX $7FFF,X ; Using Self Program Update CMPX #0 BGE LINEDDA_DXG_YMOVED_ LINEDDA_DXG_ABSDX_ LEAX $7FFF,X ; Using Self Program Update LINEDDA_DXG_VY_ LEAU $7FFF,U ; Using Self Program Update LINEDDA_DXG_YMOVED_ LEAY -1,Y ; Memo LEAU doesn't set zero flag. LEAX does. BNE LINEDDA_DXG_LOOP_ ; Remember X,Y usage is flipped in DY>DX case. ; Self Program Update << BRA LINEDDA_END LINEDDA_DYGREATER ; See comments above. D is already ABSDY ; LDD LINEDDA_ABSDY,PCR SUBD LINEDDA_ABSDX,PCR STD LINEDDA_CURBALANCE,PCR LDX LINEDDA_ABSDY,PCR ; Step count LEAX 1,X ; Conservative method >> ;LINEDDA_DYG_LOOP ; LDA LINEDDA_CURBIT,PCR ; ORA ,U ; STA ,U ; LDD LINEDDA_VY,PCR ; LEAU D,U ; ; LDD LINEDDA_CURBALANCE,PCR ; SUBD LINEDDA_ABSDX,PCR ; STD LINEDDA_CURBALANCE,PCR ; BGE LINEDDA_DYG_NEXT ; ADDD LINEDDA_ABSDY,PCR ; STD LINEDDA_CURBALANCE,PCR ; ; LDA LINEDDA_CURBIT,PCR ; LSRA ; BCC LINEDDA_DYG_XMOVED ; RORA ; LEAU 1,U ;LINEDDA_DYG_XMOVED STA LINEDDA_CURBIT,PCR ;LINEDDA_DYG_NEXT ; Conservative method << ; Using Self-Program Update >> ; Updating the program >> CLRA CLRB SUBD LINEDDA_ABSDX,PCR STD LINEDDA_DYG_ABSDX+2,PCR LDD LINEDDA_ABSDY,PCR STD LINEDDA_DYG_ABSDY+2,PCR LDD LINEDDA_VY,PCR STD LINEDDA_DYG_VY+2,PCR LDY LINEDDA_CURBALANCE,PCR LDB LINEDDA_CURBIT,PCR ; Updating the program << LINEDDA_DYG_LOOP TFR B,A ORA ,U STA ,U LINEDDA_DYG_VY LEAU $7FFF,U ; Using Self-Program Update LINEDDA_DYG_ABSDX LEAY $7FFF,Y ; Using Self-Program Update CMPY #0 BGE LINEDDA_DYG_NEXT LINEDDA_DYG_ABSDY LEAY $7FFF,Y ; Using Self-Program Update LSRB BCC LINEDDA_DYG_NEXT RORB LEAU 1,U LINEDDA_DYG_NEXT ; Using Self-Program Update >> LEAX -1,X ; Memo LEAU doesn't set zero flag. LEAX does. BNE LINEDDA_DYG_LOOP BRA LINEDDA_END LINEDDA_ZERO LDA LINEDDA_CURBIT,PCR LINEDDA_ZERO_SETPIXEL ORA ,U STA ,U LINEDDA_END PULS A,B,X,Y,U,PC ; Save 1 RTS by pulling PC together. ; RTS LINEDDA_ABSDX RZB 2 LINEDDA_ABSDY RZB 2 LINEDDA_CURADDR RZB 2 ; Maybe just use X register? LINEDDA_CURBALANCE RZB 2 LINEDDA_VY RZB 2 LINEDDA_CURBIT RZB 1 LINEDDA_LASTADDR ; Better be after LINEDDA_LASTADDR because these bytes don't need to be copied to Sub-CPU RAM. LINEDDA_BITA_D409 BITA $D409 ; Sub-CPU VRAM Access Flag On LINEDDA_STA_D409 STA $D409 ; Sub-CPU VRAM Access Flag Clear LINEDDA_LINEBUF_PTR FDB 0 ; Input buffer address ; VRAM Address taken from LINEDDA_VRAMADDR ; Bytes-Per-Line taken from LINEDDA_BYTE_PER_LINE LINEDDA_LINECOUNT_PTR FDB 0 ; Output Byte_ptr line-count address LINEDDA_NEXTLINE_PTR FDB 0 ; Output next line address LINEDDA_INIT_LINEBUF PSHS A,B,U LDU LINEDDA_LINEBUF_PTR,PCR LDD LINEDDA_VRAMADDR,PCR STD ,U++ LDA LINEDDA_BYTE_PER_LINE,PCR STA ,U+ ; 80 bytes per line LDA #1 STA ,U+ ; Needs to be one. STU LINEDDA_LINECOUNT_PTR,PCR CLR ,U+ ; Number of lines STU LINEDDA_NEXTLINE_PTR,PCR PULS A,B,U,PC ; LINEDDA_LINEBUF_PTR Input ; LINEDDA_LINECOUNT_PTR Output Byte_ptr line-count address ; LINEDDA_NEXTLINE_PTR Output next line address LINEDDA_GET_LINECOUNT_AND_NEXTLINE_PTR PSHS A,B,U LDU LINEDDA_LINEBUF_PTR,PCR LEAU 4,U STU LINEDDA_LINECOUNT_PTR,PCR CLRA LDB ,U+ LSLB ROLA LEAU D,U ; +2N LSLB ROLA LEAU D,U ; +4N : Total +6N STU LINEDDA_NEXTLINE_PTR,PCR PULS A,B,U,PC