Assembler routine to both write and delete sprites to screen memory

Discuss all aspects of programming here. From 8-bit through to modern architectures.
Andrew_Waite
Posts: 34
Joined: Tue Aug 30, 2016 2:58 pm

Assembler routine to both write and delete sprites to screen memory

Postby Andrew_Waite » Thu May 11, 2017 2:02 am

I have written a short assembler routine for BBC/Electron MODE1 to both write and delete 16x16 pixel sprites from screen memory, shown below. As my first attempt to write a such a routine in assembler, I thought I would share it as I am sure that it is possible to optimize it further and also it maybe of interest to others.

The routine uses the EOR technique to first write the sprite to the screen by EORing it with with the contents of screen memory, then writing the result to screen memory. A second EOR step deletes the sprite by returning the contents of the screen memory to their original state.

The memory locations of the bitmap source and destination are passed to assembler by setting resident integer variables K% and N%. The BASIC in the code allows the sprites to be moved by up and down by pressing the 'Z' and 'X' keys.

I have commented the BASIC but ran out of memory trying to properly comment the assembler! The assembler routine is complicated by the need to increment the pointer to the destination memory location by (640-8)bytes every eighth row of pixels in MODE1 which is a real pain. The way bits are mapped to memory for MODE1 is shown in Appendix 'C' of the Electron Advanced User Guide.

The assembler routine contains a loop which is executed eight times, copying the nth and (n+8)th 16x1 row of pixels of the 16x16 bitmap on each pass of the loop. The two byte memory location of the source of each 16x1 row of pixels is stored in zero page at &70+&71 and &74+&75 with the memory location of the destination of these pixels at &72+&73 and &76+&77. These are copied from resident integer variables K% and N% by lines 910-950

Line 960 sets the 'Y' register to 0 which will be used as the loop counter. The loop counter is moved to the 'X' register by line 980.

Lines 1000 to 1100 first load bitmap source bytes, EOR them with the contents of the destination memory bytes, then write the result to the destination memory.

The awkward business of determining if the destination memory location of the (m+1) row of 16x1 pixels is 1byte or (640-8)bytes below the memory location of the current row of pixels is done by line 1130 with the addition being performed by lines 1140 and 1150. The loop is concluded by line 1180.

The sprites do flicker a bit when the code is run in BEEBEM but I suspect this flicker is minimal with a computer connected to a 1980s TV or CRT monitor.

Any feedback would be appreciated...


Code: Select all

   10 REM Soft sprite blit routine using EOR technique with vertical pixel resolution
   20 REM By Andrew Waite
   30 :
   40 REM This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   50 REM the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   60 REM For a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
   70 :
   80 REM Pass memory location of sprite source from BASIC to machine code via resident integer variable K%
   90 REM And sprite target memory location via N%
  100 REM Resident integer variables stored in memory between &400 and &468
  110 REM Zero page memory between &70 and &8F available for user
  120 :
  130 X1%=128:REM X-coordinate of first sprite
  140 Y1%=512:REM Y-coordinate of first sprite
  150 REM Origin in top left of screen, compared to bottom left for BBC Basic graphics
  160 Z1_New%=&C000:REM Target memory location for first sprite (first time sprite written to memory is a dummy write a location in ROM)
  170 :
  180 X2%=256:REM Second sprite
  190 Y2%=512
  200 Z2_New%=&C000
  210 :
  220 X3%=384:REM Third sprite
  230 Y3%=512
  240 Z3_New%=&C000
  250 :
  260 X4%=512:REM Fourth sprite
  270 Y4%=512
  280 Z4_New%=&C000
  290 :
  300 MODE 1
  310 HIMEM=&2B00:REM Lower HIMEM for space to store machine code
  320 PROCassem
  330 PRINT'"MACHINE CODE ENTRY POINT FOR 'CALL' :"
  340 PRINT'"blit16x16 : &";~blit16x16
  350 PRINT'"PRESS 'Z' to move sprites up, 'X' for down"
  360 PRINT'"PRESS <SPACE> TO START"
  370 REPEAT UNTIL GET=32:CLS
  380 :
  390 A1$="YOUR__SPRITE"
  400 A2$="BITMAPS_HERE":REM Experiment changing these lines or overwrite with UDGs!
  410 FOR L%=1 TO LEN(A1$)
  420   COLOUR (L%MOD3)+1
  430   PRINT TAB(L%-1,0);MID$(A1$,L%,1)
  440   PRINT TAB(L%-1,1);MID$(A2$,L%,1)
  450 NEXT
  460 :
  470 X1%=X1%DIV2:X2%=X2%DIV2:X3%=X3%DIV2:X4%=X4%DIV2:REM Divide x-coordinate by 2 to simplify calc. of Z1_New%
  480 :
  490 REPEAT
  500   :
  510   IF INKEY(-98) Y1%=Y1%+4:Y2%=Y2%+8:Y3%=Y3%+4:Y4%=Y4%+8:REM Determine new y co-ordinates for each sprite upon key presses
  520   IF INKEY(-67) Y1%=Y1%-4:Y2%=Y2%-8:Y3%=Y3%-4:Y4%=Y4%-8
  530   IF Y1%>896 Y1%=896
  540   IF Y1%<128 Y1%=128
  550   IF Y2%>896 Y2%=896
  560   IF Y2%<128 Y2%=128
  570   IF Y3%>896 Y3%=896
  580   IF Y3%<128 Y3%=128
  590   IF Y4%>896 Y4%=896
  600   IF Y4%<128 Y4%=128
  610   :
  620   Z1_Old%=Z1_New%:REM store old sprite target location so that it can be deleted next time around the loop
  630   Z1_New%=((Y1%AND2016)*20)+((Y1%AND31)DIV4)+(X1%AND2032)+&3000:REM Convert x and y co-ordinates to a memory location
  640   K%=&3000:N%=Z1_Old%:CALL blit16x16:REM Delete old sprite. Sprite source is at memory location K%, old image for deletion at memory location N%
  650   K%=&3000:N%=Z1_New%:CALL blit16x16:REM New sprite location is at N%, change K% for animated sprite
  660   :
  670   Z2_Old%=Z2_New%
  680   Z2_New%=((Y2%AND2016)*20)+((Y2%AND31)DIV4)+(X2%AND2032)+&3000
  690   K%=&3020:N%=Z2_Old%:CALL blit16x16
  700   K%=&3020:N%=Z2_New%:CALL blit16x16
  710   :
  720   Z3_Old%=Z3_New%
  730   Z3_New%=((Y3%AND2016)*20)+((Y3%AND31)DIV4)+(X3%AND2032)+&3000
  740   K%=&3040:N%=Z3_Old%:CALL blit16x16
  750   K%=&3040:N%=Z3_New%:CALL blit16x16
  760   :
  770   Z4_Old%=Z4_New%
  780   Z4_New%=((Y4%AND2016)*20)+((Y4%AND31)DIV4)+(X4%AND2032)+&3000
  790   K%=&3060:N%=Z4_Old%:CALL blit16x16
  800   K%=&3060:N%=Z4_New%:CALL blit16x16
  810   :
  820 UNTIL FALSE
  830 END
  840 :
  850 DEF PROCassem
  860 FOR I%=0 TO 3 STEP 3
  870   P%=&2B00
  880   [OPT I%
  890   .blit16x16
  900   \
  910   LDA &438:STA &72:CLC:ADC #128:STA &76
  920   LDA &439:STA &73:ADC #2:STA &77
  930   \
  940   LDA &42C:STA &70:CLC:ADC #128:STA &74
  950   LDA &42D:STA &71:ADC #2:STA &75
  960   LDY #0
  970   .blit16_loop_EOR
  980   TYA:TAX
  990   \
 1000   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1010   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1020   INY:INY:INY:INY:INY:INY:INY:INY
 1030   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1040   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1050   INY:INY:INY:INY:INY:INY:INY:INY
 1060   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1070   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1080   INY:INY:INY:INY:INY:INY:INY:INY
 1090   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1100   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1110   TXA:TAY:INY
 1120   \
 1130   TYA:CLC:ADC &72:AND #8:BEQ blit16_loop_jump
 1140   LDA &72:CLC:ADC #120:STA &72:LDA &73:ADC #2:STA &73
 1150   LDA &76:CLC:ADC #120:STA &76:LDA &77:ADC #2:STA &77
 1160   .blit16_loop_jump
 1170   \
 1180   TYA:CMP #8:BNE blit16_loop_EOR
 1190   RTS
 1200   ]
 1210 NEXT
 1220 ENDPROC

dp11
Posts: 670
Joined: Sun Aug 12, 2012 8:47 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby dp11 » Thu May 11, 2017 6:44 am

A few suggestions . I've only had a very quick look through the code . In general decrement loop counters as checking for zero or minus one is often free.

I suspect tya:clc:adc#8:Tay is quicker than 8 iny

I suspect with a bit of thought the 8 inys can be optimised away by rearranging the loop.

User avatar
tricky
Posts: 1811
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Assembler routine to both write and delete sprites to screen memory

Postby tricky » Thu May 11, 2017 12:59 pm

That's a great start, looks like the sort of thing I started writing and then slowly moved everything from BASIC to assembler, except the floating point maths at the time ;)

I recently put together a little demo drawing some sprites in modes 4 and 5, it uses EOR like yours, but is basically cut'n'pasted from one of my games.

http://stardot.org.uk/forums/viewtopic.php?f=53&t=12565&p=161767&hilit=sprites%23#p161873

The Sprites.zip has the beebasm source code, which has lots of short cuts in it, but might be interesting as you add optimisations to yours.

Andrew_Waite
Posts: 34
Joined: Tue Aug 30, 2016 2:58 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby Andrew_Waite » Thu May 11, 2017 3:09 pm

dp11 wrote:I suspect tya:clc:adc#8:Tay is quicker than 8 iny


Thank you for the suggestions!

For the NMOS 6502 :
INY takes 2 cycles, so 8*INY takes 16 cycles
TYA + CLC + ADC#8 + TAY = 2+2+2+2 = 8 cycles

I changed my code, and now save 3*8=24 clock cycles each time this particular loop is executed.

Next step is to look at decrement loop counters...

User avatar
tricky
Posts: 1811
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Assembler routine to both write and delete sprites to screen memory

Postby tricky » Thu May 11, 2017 4:26 pm

Some times it is easier not to store the sprite in the same order as the screen.

Andrew_Waite
Posts: 34
Joined: Tue Aug 30, 2016 2:58 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby Andrew_Waite » Thu May 11, 2017 5:17 pm

Thank you for your feedback!

I have modified the code to replace the 8*INY lines and simplified the loop counting by using the X-register instead of the Y-register as the loop counter.

I have a couple of ideas for further speed improvements in addition to decrement loop counting...

New code posted below...



Code: Select all

   10 REM Soft sprite blit routine using EOR technique with vertical pixel resolution
   20 REM By Andrew Waite
   30 :
   40 REM This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   50 REM the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   60 REM For a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
   70 :
   80 REM Pass memory location of sprite source from BASIC to machine code via resident integer variable K%
   90 REM And sprite target memory location via N%
  100 REM Resident integer variables stored in memory between &400 and &468
  110 REM Zero page memory between &70 and &8F available for user
  120 :
  130 X1%=128:REM X-coordinate of first sprite
  140 Y1%=512:REM Y-coordinate of first sprite
  150 REM Origin in top left of screen, compared to bottom left for BBC Basic graphics
  160 Z1_New%=&C000:REM Target memory location for first sprite (first time sprite written to memory is a dummy write a location in ROM)
  170 :
  180 X2%=256:REM Second sprite
  190 Y2%=512
  200 Z2_New%=&C000
  210 :
  220 X3%=384:REM Third sprite
  230 Y3%=512
  240 Z3_New%=&C000
  250 :
  260 X4%=512:REM Fourth sprite
  270 Y4%=512
  280 Z4_New%=&C000
  290 :
  300 MODE 1
  310 HIMEM=&2B00:REM Lower HIMEM for space to store machine code
  320 PROCassem
  330 PRINT'"MACHINE CODE ENTRY POINT FOR 'CALL' :"
  340 PRINT'"blit16x16 : &";~blit16x16
  350 PRINT'"PRESS 'Z' to move sprites up, 'X' for down"
  360 PRINT'"PRESS <SPACE> TO START"
  370 REPEAT UNTIL GET=32:CLS
  380 :
  390 A1$="YOUR__SPRITE"
  400 A2$="BITMAPS_HERE":REM Experiment changing these lines or overwrite with UDGs!
  410 FOR L%=1 TO LEN(A1$)
  420   COLOUR (L%MOD3)+1
  430   PRINT TAB(L%-1,0);MID$(A1$,L%,1)
  440   PRINT TAB(L%-1,1);MID$(A2$,L%,1)
  450 NEXT
  460 :
  470 X1%=X1%DIV2:X2%=X2%DIV2:X3%=X3%DIV2:X4%=X4%DIV2:REM Divide x-coordinate by 2 to simplify calc. of Z1_New%
  480 :
  490 REPEAT
  500   :
  510   IF INKEY(-98) Y1%=Y1%+4:Y2%=Y2%+8:Y3%=Y3%+4:Y4%=Y4%+8:REM Determine new y co-ordinates for each sprite upon key presses
  520   IF INKEY(-67) Y1%=Y1%-4:Y2%=Y2%-8:Y3%=Y3%-4:Y4%=Y4%-8
  530   IF Y1%>896 Y1%=896
  540   IF Y1%<128 Y1%=128
  550   IF Y2%>896 Y2%=896
  560   IF Y2%<128 Y2%=128
  570   IF Y3%>896 Y3%=896
  580   IF Y3%<128 Y3%=128
  590   IF Y4%>896 Y4%=896
  600   IF Y4%<128 Y4%=128
  610   :
  620   Z1_Old%=Z1_New%:REM store old sprite target location so that it can be deleted next time around the loop
  630   Z1_New%=((Y1%AND2016)*20)+((Y1%AND31)DIV4)+(X1%AND2032)+&3000:REM Convert x and y co-ordinates to a memory location
  640   K%=&3000:N%=Z1_Old%:CALL blit16x16:REM Delete old sprite. Sprite source is at memory location K%, old image for deletion at memory location N%
  650   K%=&3000:N%=Z1_New%:CALL blit16x16:REM New sprite location is at N%, change K% for animated sprite
  660   :
  670   Z2_Old%=Z2_New%
  680   Z2_New%=((Y2%AND2016)*20)+((Y2%AND31)DIV4)+(X2%AND2032)+&3000
  690   K%=&3020:N%=Z2_Old%:CALL blit16x16
  700   K%=&3020:N%=Z2_New%:CALL blit16x16
  710   :
  720   Z3_Old%=Z3_New%
  730   Z3_New%=((Y3%AND2016)*20)+((Y3%AND31)DIV4)+(X3%AND2032)+&3000
  740   K%=&3040:N%=Z3_Old%:CALL blit16x16
  750   K%=&3040:N%=Z3_New%:CALL blit16x16
  760   :
  770   Z4_Old%=Z4_New%
  780   Z4_New%=((Y4%AND2016)*20)+((Y4%AND31)DIV4)+(X4%AND2032)+&3000
  790   K%=&3060:N%=Z4_Old%:CALL blit16x16
  800   K%=&3060:N%=Z4_New%:CALL blit16x16
  810   :
  820 UNTIL FALSE
  830 END
  840 :
  850 DEF PROCassem
  860 FOR I%=0 TO 3 STEP 3
  870   P%=&2B00
  880   [OPT I%
  890   .blit16x16
  900   \
  910   LDA &438:STA &72:CLC:ADC #128:STA &76
  920   LDA &439:STA &73:ADC #2:STA &77
  930   \
  940   LDA &42C:STA &70:CLC:ADC #128:STA &74
  950   LDA &42D:STA &71:ADC #2:STA &75
  960   LDX #0:LDY #0
  970   \
  980   .blit16_loop
  990   \
 1000   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1010   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1020   TYA:CLC:ADC#8:TAY
 1030   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1040   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1050   TYA:CLC:ADC#8:TAY
 1060   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1070   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1080   TYA:CLC:ADC#8:TAY
 1090   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1100   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1110   INX:TXA:TAY
 1120   \
 1130   CLC:ADC &72:AND #8:BEQ blit16_jump
 1140   LDA &72:CLC:ADC #120:STA &72:LDA &73:ADC #2:STA &73
 1150   LDA &76:CLC:ADC #120:STA &76:LDA &77:ADC #2:STA &77
 1160   .blit16_jump
 1170   \
 1180   TYA:CMP #8:BNE blit16_loop
 1190   RTS
 1200   ]
 1210 NEXT
 1220 ENDPROC
Last edited by Andrew_Waite on Thu May 11, 2017 7:59 pm, edited 1 time in total.

dp11
Posts: 670
Joined: Sun Aug 12, 2012 8:47 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby dp11 » Thu May 11, 2017 5:24 pm

Have a think about having 8 sprite plotting routines depending on which row the sprite is going to be plotted. You might find the add 8s can be made to disappear.

User avatar
davidb
Posts: 1824
Joined: Sun Nov 11, 2007 10:11 pm
Contact:

Re: Assembler routine to both write and delete sprites to screen memory

Postby davidb » Thu May 11, 2017 5:27 pm

Andrew, if you have a GitHub account, I can invite you into the stardot organisation there and you can share your code in a repository. No pressure. :)

Andrew_Waite
Posts: 34
Joined: Tue Aug 30, 2016 2:58 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby Andrew_Waite » Fri May 12, 2017 12:46 am

I found one solution to make the 'add 8s disappear' by using three 256 byte look up tables - one each for N=N'+8, N=N'+8+8 and N=N'+8+8+8. This takes 3*256 bytes to implement so it is not a particularly elegant solution. The new code is below. Look up tales are created in BASIC by line 330, and 'read' by lines 1010, 1040 and 1070. The eight cycles needed to execute TYA:CLC:ADC#8:TAY are now replaced by a single four cycle LDA Absolute,X instruction.

Next, I am going to work on dp11's suggestion of using 8 sprite plotting routines depending on which row the sprite is going to be plotted.

Code: Select all

   10 REM Soft sprite blit routine using EOR technique with vertical pixel resolution
   20 REM By Andrew Waite
   30 :
   40 REM This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   50 REM the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
   60 REM For a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
   70 :
   80 REM Pass memory location of sprite source from BASIC to machine code via resident integer variable K%
   90 REM And sprite target memory location via N%
  100 REM Resident integer variables stored in memory between &400 and &468
  110 REM Zero page memory between &70 and &8F available for user
  120 :
  130 X1%=128:REM X-coordinate of first sprite
  140 Y1%=512:REM Y-coordinate of first sprite
  150 REM Origin in top left of screen, compared to bottom left for BBC Basic graphics
  160 Z1_New%=&C000:REM Target memory location for first sprite (first time sprite written to memory is a dummy write a location in ROM)
  170 :
  180 X2%=256:REM Second sprite
  190 Y2%=512
  200 Z2_New%=&C000
  210 :
  220 X3%=384:REM Third sprite
  230 Y3%=512
  240 Z3_New%=&C000
  250 :
  260 X4%=512:REM Fourth sprite
  270 Y4%=512
  280 Z4_New%=&C000
  290 :
  300 MODE 1
  310 HIMEM=&2B00:REM Lower HIMEM for space to store machine code
  320 PROCassem
  330 FOR N%=0 TO 255:?(&2D00+N%)=(N%+8) MOD 256:?(&2E00+N%)=(N%+16) MOD 256:?(&2F00+N%)=(N%+24) MOD 256:NEXT
  340 PRINT'"MACHINE CODE ENTRY POINT FOR 'CALL' :"
  350 PRINT'"blit16x16 : &";~blit16x16
  360 PRINT'"PRESS 'Z' to move sprites up, 'X' for down"
  370 PRINT'"PRESS <SPACE> TO START"
  380 REPEAT UNTIL GET=32:CLS
  390 :
  400 A1$="YOUR__SPRITE"
  410 A2$="BITMAPS_HERE":REM Experiment changing these lines or overwrite with UDGs!
  420 FOR L%=1 TO LEN(A1$)
  430   COLOUR (L%MOD3)+1
  440   PRINT TAB(L%-1,0);MID$(A1$,L%,1)
  450   PRINT TAB(L%-1,1);MID$(A2$,L%,1)
  460 NEXT
  470 :
  480 X1%=X1%DIV2:X2%=X2%DIV2:X3%=X3%DIV2:X4%=X4%DIV2:REM Divide x-coordinate by 2 to simplify calc. of Z1_New%
  490 :
  500 REPEAT
  510   :
  520   IF INKEY(-98) Y1%=Y1%+4:Y2%=Y2%+8:Y3%=Y3%+4:Y4%=Y4%+8:REM Determine new y co-ordinates for each sprite upon key presses
  530   IF INKEY(-67) Y1%=Y1%-4:Y2%=Y2%-8:Y3%=Y3%-4:Y4%=Y4%-8
  540   IF Y1%>896 Y1%=896
  550   IF Y1%<128 Y1%=128
  560   IF Y2%>896 Y2%=896
  570   IF Y2%<128 Y2%=128
  580   IF Y3%>896 Y3%=896
  590   IF Y3%<128 Y3%=128
  600   IF Y4%>896 Y4%=896
  610   IF Y4%<128 Y4%=128
  620   :
  630   Z1_Old%=Z1_New%:REM store old sprite target location so that it can be deleted next time around the loop
  640   Z1_New%=((Y1%AND2016)*20)+((Y1%AND31)DIV4)+(X1%AND2032)+&3000:REM Convert x and y co-ordinates to a memory location
  650   K%=&3000:N%=Z1_Old%:CALL blit16x16:REM Delete old sprite. Sprite source is at memory location K%, old image for deletion at memory location N%
  660   K%=&3000:N%=Z1_New%:CALL blit16x16:REM New sprite location is at N%, change K% for animated sprite
  670   :
  680   Z2_Old%=Z2_New%
  690   Z2_New%=((Y2%AND2016)*20)+((Y2%AND31)DIV4)+(X2%AND2032)+&3000
  700   K%=&3020:N%=Z2_Old%:CALL blit16x16
  710   K%=&3020:N%=Z2_New%:CALL blit16x16
  720   :
  730   Z3_Old%=Z3_New%
  740   Z3_New%=((Y3%AND2016)*20)+((Y3%AND31)DIV4)+(X3%AND2032)+&3000
  750   K%=&3040:N%=Z3_Old%:CALL blit16x16
  760   K%=&3040:N%=Z3_New%:CALL blit16x16
  770   :
  780   Z4_Old%=Z4_New%
  790   Z4_New%=((Y4%AND2016)*20)+((Y4%AND31)DIV4)+(X4%AND2032)+&3000
  800   K%=&3060:N%=Z4_Old%:CALL blit16x16
  810   K%=&3060:N%=Z4_New%:CALL blit16x16
  820   :
  830 UNTIL FALSE
  840 END
  850 :
  860 DEF PROCassem
  870 FOR I%=0 TO 3 STEP 3
  880   P%=&2B00
  890   [OPT I%
  900   .blit16x16
  910   \
  920   LDA &438:STA &72:CLC:ADC #128:STA &76
  930   LDA &439:STA &73:ADC #2:STA &77
  940   LDA &42C:STA &70:CLC:ADC #128:STA &74
  950   LDA &42D:STA &71:ADC #2:STA &75
  960   LDX #0:LDY #0
  970   .blit16_loop
  980   \
  990   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1000   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1010   LDY &2D00,X
 1020   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1030   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1040   LDY &2E00,X
 1050   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1060   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1070   LDY &2F00,X
 1080   LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1090   LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1100   INX:TXA:TAY:CLC:ADC &72:AND #8
 1110   BEQ blit16_jump
 1120   \
 1130   LDA &72:CLC:ADC #120:STA &72:LDA &73:ADC #2:STA &73
 1140   LDA &76:CLC:ADC #120:STA &76:LDA &77:ADC #2:STA &77
 1150   .blit16_jump
 1160   \
 1170   TYA:CMP #8:BNE blit16_loop
 1180   RTS
 1190   ]
 1200 NEXT
 1210 ENDPROC
Last edited by Andrew_Waite on Fri May 12, 2017 11:02 am, edited 1 time in total.

dp11
Posts: 670
Joined: Sun Aug 12, 2012 8:47 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby dp11 » Fri May 12, 2017 3:19 am

That's not the solution I was thinking of but an interesting one. You will be learning a lot here.

Andrew_Waite
Posts: 34
Joined: Tue Aug 30, 2016 2:58 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby Andrew_Waite » Fri May 12, 2017 5:16 pm

davidb wrote:Andrew, if you have a GitHub account, I can invite you into the stardot organisation there and you can share your code in a repository. No pressure. :)


I have posted my code in GitHub under the account name "andrewwaite1".

Please can you confirm that you are able to see it!
Last edited by Andrew_Waite on Fri May 12, 2017 5:42 pm, edited 1 time in total.

User avatar
davidb
Posts: 1824
Joined: Sun Nov 11, 2007 10:11 pm
Contact:

Re: Assembler routine to both write and delete sprites to screen memory

Postby davidb » Fri May 12, 2017 5:20 pm

I can see your repository. I have sent you an invite to the stardot organisation. :D

Andrew_Waite
Posts: 34
Joined: Tue Aug 30, 2016 2:58 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby Andrew_Waite » Mon May 15, 2017 1:22 am

Thank you all for your suggestions on improving my code. Tricky, your demos are excellent- I especially like the isometric pac-men!

I wanted to reduce the flickering of my sprites, so I reworked the BASIC code to make use of double buffering on a BBC Master by changing the ACCCON register (at &FE34) to switch the main and shadow video memory between the address space of the CPU and the video circuitry. It runs nicely under BeebEm but owning and Electron I have not been able to test it a real BBC Master - hopefully it works! The Assembler code should be unchanged since my last post. The latest code is shown below, but press <BREAK> after pressing <ESCAPE> to reset the ACCCON register else text typed into the machine may not be displayed. The screen should display "FIELD A" when video is displaying the contents of normal RAM and "FIELD B" when displaying the contents of shadow RAM.

Double buffering allows all sprites to be deleted in one go, then drawn again in their new position before flipping the video output. This allows for the next step which is to modify the 'blit16_loop' loop to delete all sprites in their old positions or to draw all sprites in their new positions with a single CALL from BASIC which should speed things up quite nicely...

Comments and feedback much appreciated...

Code: Select all

   10 :
   20 REM PRESS <BREAK> after pressing <ESCAPE> to reset ACCCON register
   30 :
   40 REM BBC MASTER soft sprite blit routine using EOR technique
   50 REM with vertical pixel resolution and double frame buffering
   60 REM By Andrew Waite
   70 :
   80 REM This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
   90 REM the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
  100 REM For a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
  110 :
  120 MODE 129:MODE 1:REM CLS BOTH VIDEO FIELDS!!!
  130 HIMEM=&2B00:REM Lower HIMEM for space to store machine code
  140 PROCassem
  150 :
  160 FOR A%=0 TO 255:?(&2D00+A%)=(A%+8) MOD 256:?(&2E00+A%)=(A%+16) MOD 256:?(&2F00+A%)=(A%+24) MOD 256:NEXT:REM Create lookup tables
  170 :
  180 X1%=128:REM X-coordinate of first sprite
  190 Y1%=512:REM Y-coordinate of first sprite
  200 REM Origin in top left of screen, compared to bottom left for BBC Basic graphics
  210 Z1_frameA%=&C000:REM Target memory location for first sprite (first time sprite written to memory is a dummy write a location in ROM)
  220 Z1_frameB%=&C000
  230 :
  240 X2%=256:REM Second sprite
  250 Y2%=512
  260 Z2_frameA%=&C000
  270 Z2_frameB%=&C000
  280 :
  290 X3%=384:REM Third sprite
  300 Y3%=512
  310 Z3_frameA%=&C000
  320 Z3_frameB%=&C000
  330 :
  340 X4%=512:REM Fourth sprite
  350 Y4%=512
  360 Z4_frameA%=&C000
  370 Z4_frameB%=&C000
  380 :
  390 PRINT'"MACHINE CODE ENTRY POINT FOR 'CALL' :"
  400 PRINT'"blit16x16 : &";~blit16x16
  410 PRINT'"PRESS 'Z/X' to move sprites up and down"
  420 PRINT'"PRESS <SPACE> TO START"
  430 REPEAT UNTIL GET=32:CLS:PRINT TAB(0,28);"This Field Normally Displayed For MODE 1";
  440 :
  450 A1$="YOUR__SPRITE"
  460 A2$="BITMAPS_HERE"
  470 FOR L%=1 TO LEN(A1$):COLOUR (L%MOD3)+1
  480 ?&FE34=?&FE34 OR 4:REM Change ACCCON (&FE34) to write to Field "B"
  490 PRINT TAB(L%-1,0);MID$(A1$,L%,1)
  500 PRINT TAB(L%-1,1);MID$(A2$,L%,1)
  510 PRINT TAB(0,7);"FIELD B"
  520 ?&FE34=?&FE34 AND 251:REM Change ACCCON (&FE34) to write to Field "A"
  530 PRINT TAB(L%-1,0);MID$(A1$,L%,1)
  540 PRINT TAB(L%-1,1);MID$(A2$,L%,1)
  550 PRINT TAB(0,5);"FIELD A"
  560 NEXT
  570 :
  580 X1%=X1%DIV2:X2%=X2%DIV2:X3%=X3%DIV2:X4%=X4%DIV2:REM Divide x-coordinate by 2 to simplify calc. of Z1_frame(A/B)%
  590 :
  600 REPEAT
  610 :
  620 PROCinput
  630 :
  640 ?&FE34=?&FE34 AND 251:?&FE34=?&FE34 OR 1:REM Enable writes to Field "A", Display FIELD "B"
  650 :
  660 K%=&3000:N%=Z1_frameA%:CALL blit16x16
  670 Z1_frameA%=((Y1%AND2016)*20)+((Y1%AND31)DIV4)+(X1%AND2032)+&3000
  680 K%=&3000:N%=Z1_frameA%:CALL blit16x16
  690 :
  700 K%=&3020:N%=Z2_frameA%:CALL blit16x16
  710 Z2_frameA%=((Y2%AND2016)*20)+((Y2%AND31)DIV4)+(X2%AND2032)+&3000
  720 K%=&3020:N%=Z2_frameA%:CALL blit16x16
  730 :
  740 K%=&3040:N%=Z3_frameA%:CALL blit16x16
  750 Z3_frameA%=((Y3%AND2016)*20)+((Y3%AND31)DIV4)+(X3%AND2032)+&3000
  760 K%=&3040:N%=Z3_frameA%:CALL blit16x16
  770 :
  780 K%=&3060:N%=Z4_frameA%:CALL blit16x16
  790 Z4_frameA%=((Y4%AND2016)*20)+((Y4%AND31)DIV4)+(X4%AND2032)+&3000
  800 K%=&3060:N%=Z4_frameA%:CALL blit16x16
  810 :
  820 PROCinput
  830 :
  840 ?&FE34=?&FE34 OR 4:?&FE34=?&FE34 AND 254:REM Enable writes to Field "B", Display FIELD "A"
  850 :
  860 K%=&3000:N%=Z1_frameB%:CALL blit16x16
  870 Z1_frameB%=((Y1%AND2016)*20)+((Y1%AND31)DIV4)+(X1%AND2032)+&3000
  880 K%=&3000:N%=Z1_frameB%:CALL blit16x16
  890 :
  900 K%=&3020:N%=Z2_frameB%:CALL blit16x16
  910 Z2_frameB%=((Y2%AND2016)*20)+((Y2%AND31)DIV4)+(X2%AND2032)+&3000
  920 K%=&3020:N%=Z2_frameB%:CALL blit16x16
  930 :
  940 K%=&3040:N%=Z3_frameB%:CALL blit16x16
  950 Z3_frameB%=((Y3%AND2016)*20)+((Y3%AND31)DIV4)+(X3%AND2032)+&3000
  960 K%=&3040:N%=Z3_frameB%:CALL blit16x16
  970 :
  980 K%=&3060:N%=Z4_frameB%:CALL blit16x16
  990 Z4_frameB%=((Y4%AND2016)*20)+((Y4%AND31)DIV4)+(X4%AND2032)+&3000
 1000 K%=&3060:N%=Z4_frameB%:CALL blit16x16
 1010 :
 1020 UNTIL FALSE
 1030 END
 1040 :
 1050 DEF PROCinput:REM Determine new y co-ordinates for each sprite upon key presses
 1060 IF INKEY(-98) Y1%=Y1%+4:Y2%=Y2%+8:Y3%=Y3%+4:Y4%=Y4%+8
 1070 IF INKEY(-67) Y1%=Y1%-4:Y2%=Y2%-8:Y3%=Y3%-4:Y4%=Y4%-8
 1080 IF Y1%>896 Y1%=896
 1090 IF Y1%<128 Y1%=128
 1100 IF Y2%>896 Y2%=896
 1110 IF Y2%<128 Y2%=128
 1120 IF Y3%>896 Y3%=896
 1130 IF Y3%<128 Y3%=128
 1140 IF Y4%>896 Y4%=896
 1150 IF Y4%<128 Y4%=128
 1160 ENDPROC
 1170 :
 1180 DEF PROCassem
 1190 FOR I%=0 TO 3 STEP 3
 1200 P%=&2B00
 1210 [OPT I%
 1220 .blit16x16
 1230 \
 1240 LDA &438:STA &72:CLC:ADC #128:STA &76
 1250 LDA &439:STA &73:ADC #2:STA &77
 1260 LDA &42C:STA &70:CLC:ADC #128:STA &74
 1270 LDA &42D:STA &71:ADC #2:STA &75
 1280 LDX #0:LDY #0
 1290 .blit16_loop
 1300 \
 1310 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1320 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1330 LDY &2D00,X
 1340 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1350 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1360 LDY &2E00,X
 1370 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1380 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1390 LDY &2F00,X
 1400 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1410 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1420 INX:TXA:TAY:CLC:ADC &72:AND #8
 1430 BEQ blit16_jump
 1440 \
 1450 LDA &72:CLC:ADC #120:STA &72:LDA &73:ADC #2:STA &73
 1460 LDA &76:CLC:ADC #120:STA &76:LDA &77:ADC #2:STA &77
 1470 .blit16_jump
 1480 \
 1490 TYA:CMP #8:BNE blit16_loop
 1500 RTS
 1510 ]
 1520 NEXT
 1530 ENDPROC

User avatar
tricky
Posts: 1811
Joined: Tue Jun 21, 2011 8:25 am
Contact:

Re: Assembler routine to both write and delete sprites to screen memory

Postby tricky » Mon May 15, 2017 6:31 am

Thanks, they are there to inspire and encourage.
I've always coded for the been, but the shadow display seems like a great way to improve the look of your game.
With eor, you could also move one at a time, it will still flicker a bit, but much less than clearing all and then redrawing all, but not as clean as your solution.

Andrew_Waite
Posts: 34
Joined: Tue Aug 30, 2016 2:58 pm

Re: Assembler routine to both write and delete sprites to screen memory

Postby Andrew_Waite » Tue May 16, 2017 1:39 am

The assembler code has now been modified so that a single CALL deletes or redraws all of the sprites in one go. I also changed the sprites to spiders. Press 'Z' or 'X' to move the spiders up and down after they have all been drawn (this process takes a few 10s seconds).

Unfortunately to squeeze the additional BASIC needed to draw and animate the spiders in MODE 1 I have had to remove all the REM statements and use multi statement lines so the BASIC code has lost much of its readability.

I think I have the sprite handling code now for the basis of a reasonable game based off my December 1986 "Santa's Sleigh" MicroUser game which was written in BASIC. The next step to try and realise this eventual goal is to reorganise the code such that assembler and bitmaps fit inside a sideways RAM bank.

Code: Select all

   10 REM BBC MASTER soft sprite blit routine
   20 REM By Andrew Waite
   30 :
   40 MODE 129:MODE 1
   50 HIMEM=&2B00
   60 PROCassem:PRINT'"ENTRY POINT ";~blit16x16;" Press <SPACE>":REPEAT UNTIL GET=32:CLS
   70 :
   80 FOR A%=0 TO 255:?(&2D00+A%)=(A%+8) MOD 256:?(&2E00+A%)=(A%+16) MOD 256:?(&2F00+A%)=(A%+24) MOD 256:NEXT
   90 X1%=128:Y1%=512:Z1frA%=&C000:I1frA%=&3000:Z1frB%=&C000:I1frB%=&3020
  100 X2%=256:Y2%=512:Z2frA%=&C000:I2frA%=&3020:Z2frB%=&C000:I2frB%=&3040
  110 X3%=384:Y3%=512:Z3frA%=&C000:I3frA%=&3040:Z3frB%=&C000:I3frB%=&3060
  120 X4%=512:Y4%=512:Z4frA%=&C000:I4frA%=&3060:Z4frB%=&C000:I4frB%=&3000
  130 :
  140 RESTORE
  150 FOR O%=0 TO 3:FOR L%=0 TO 15
  160 READ A$
  170 FOR M%=0 TO 15
  180 GCOL0,VAL(MID$(A$,M%+1,1))
  190 ?&FE34=?&FE34 OR 4:PLOT 69,(M%*4)+(O%*64),1023-(L%*4):?&FE34=?&FE34 AND 251:PLOT 69,(M%*4)+(O%*64),1023-(N%*64)-(L%*4)
  200 NEXT:NEXT:NEXT
  210 X1%=X1%DIV2:X2%=X2%DIV2:X3%=X3%DIV2:X4%=X4%DIV2
  220 :
  230 REPEAT
  240 PROCinput
  250 ?&FE34=?&FE34 AND 251:?&FE34=?&FE34 OR 1
  260 A%=I1frA%:B%=Z1frA%:C%=I2frA%:D%=Z2frA%:E%=I3frA%:F%=Z3frA%:G%=I4frA%:H%=Z4frA%
  270 CALL blit16x16
  280 Z1frA%=((Y1%AND2016)*20)+((Y1%AND31)DIV4)+(X1%AND2032)+&3000
  290 I1frA%=I1frA%+&20:IF I1frA%=&3080 I1frA%=&3000
  300 Z2frA%=((Y2%AND2016)*20)+((Y2%AND31)DIV4)+(X2%AND2032)+&3000
  310 I2frA%=I2frA%+&20:IF I2frA%=&3080 I2frA%=&3000
  320 Z3frA%=((Y3%AND2016)*20)+((Y3%AND31)DIV4)+(X3%AND2032)+&3000
  330 I3frA%=I3frA%+&20:IF I3frA%=&3080 I3frA%=&3000
  340 Z4frA%=((Y4%AND2016)*20)+((Y4%AND31)DIV4)+(X4%AND2032)+&3000
  350 I4frA%=I4frA%+&20:IF I4frA%=&3080 I4frA%=&3000
  360 A%=I1frA%:B%=Z1frA%:C%=I2frA%:D%=Z2frA%:E%=I3frA%:F%=Z3frA%:G%=I4frA%:H%=Z4frA%
  370 CALL blit16x16
  380 PROCinput
  390 ?&FE34=?&FE34 OR 4:?&FE34=?&FE34 AND 254
  400 A%=I1frB%:B%=Z1frB%:C%=I2frB%:D%=Z2frB%:E%=I3frB%:F%=Z3frB%:G%=I4frB%:H%=Z4frB%
  410 CALL blit16x16
  420 Z1frB%=((Y1%AND2016)*20)+((Y1%AND31)DIV4)+(X1%AND2032)+&3000
  430 I1frB%=I1frB%+&20:IF I1frB%=&3080 I1frB%=&3000
  440 Z2frB%=((Y2%AND2016)*20)+((Y2%AND31)DIV4)+(X2%AND2032)+&3000
  450 I2frB%=I2frB%+&20:IF I2frB%=&3080 I2frB%=&3000
  460 Z3frB%=((Y3%AND2016)*20)+((Y3%AND31)DIV4)+(X3%AND2032)+&3000
  470 I3frB%=I3frB%+&20:IF I3frB%=&3080 I3frB%=&3000
  480 Z4frB%=((Y4%AND2016)*20)+((Y4%AND31)DIV4)+(X4%AND2032)+&3000
  490 I4frB%=I4frB%+&20:IF I4frB%=&3080 I4frB%=&3000
  500 A%=I1frB%:B%=Z1frB%:C%=I2frB%:D%=Z2frB%:E%=I3frB%:F%=Z3frB%:G%=I4frB%:H%=Z4frB%
  510 CALL blit16x16
  520 UNTIL FALSE
  530 END
  540 :
  550 DEF PROCinput
  560 IF INKEY(-98) Y1%=Y1%+4:Y2%=Y2%+8:Y3%=Y3%+4:Y4%=Y4%+8
  570 IF INKEY(-67) Y1%=Y1%-4:Y2%=Y2%-8:Y3%=Y3%-4:Y4%=Y4%-8
  580 IF Y1%>896 Y1%=896
  590 IF Y1%<128 Y1%=128
  600 IF Y2%>896 Y2%=896
  610 IF Y2%<128 Y2%=128
  620 IF Y3%>896 Y3%=896
  630 IF Y3%<128 Y3%=128
  640 IF Y4%>896 Y4%=896
  650 IF Y4%<128 Y4%=128
  660 ENDPROC
  670 :
  680 DEF PROCassem
  690 FOR I%=0 TO 3 STEP 3
  700 P%=&2B00
  710 [OPT I%
  720 .blit16x16
  730 \
  740 LDA &408:STA &72:CLC:ADC #128:STA &76
  750 LDA &409:STA &73:ADC #2:STA &77
  760 LDA &404:STA &70:CLC:ADC #128:STA &74
  770 LDA &405:STA &71:ADC #2:STA &75
  780 \
  790 LDA &410:STA &7A:CLC:ADC #128:STA &7E
  800 LDA &411:STA &7B:ADC #2:STA &7F
  810 LDA &40C:STA &78:CLC:ADC #128:STA &7C
  820 LDA &40D:STA &79:ADC #2:STA &7D
  830 \
  840 LDA &418:STA &82:CLC:ADC #128:STA &86
  850 LDA &419:STA &83:ADC #2:STA &87
  860 LDA &414:STA &80:CLC:ADC #128:STA &84
  870 LDA &415:STA &81:ADC #2:STA &85
  880 \
  890 LDA &420:STA &8A:CLC:ADC #128:STA &8E
  900 LDA &421:STA &8B:ADC #2:STA &8F
  910 LDA &41C:STA &88:CLC:ADC #128:STA &8C
  920 LDA &41D:STA &89:ADC #2:STA &8D
  930 \
  940 LDX #0:LDY #0
  950 .blit16_loop
  960 \
  970 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
  980 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
  990 LDA (&78),Y:EOR (&7A),Y:STA (&7A),Y
 1000 LDA (&7C),Y:EOR (&7E),Y:STA (&7E),Y
 1010 LDA (&80),Y:EOR (&82),Y:STA (&82),Y
 1020 LDA (&84),Y:EOR (&86),Y:STA (&86),Y
 1030 LDA (&88),Y:EOR (&8A),Y:STA (&8A),Y
 1040 LDA (&8C),Y:EOR (&8E),Y:STA (&8E),Y
 1050 LDY &2D00,X
 1060 \
 1070 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1080 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1090 LDA (&78),Y:EOR (&7A),Y:STA (&7A),Y
 1100 LDA (&7C),Y:EOR (&7E),Y:STA (&7E),Y
 1110 LDA (&80),Y:EOR (&82),Y:STA (&82),Y
 1120 LDA (&84),Y:EOR (&86),Y:STA (&86),Y
 1130 LDA (&88),Y:EOR (&8A),Y:STA (&8A),Y
 1140 LDA (&8C),Y:EOR (&8E),Y:STA (&8E),Y
 1150 LDY &2E00,X
 1160 \
 1170 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1180 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1190 LDA (&78),Y:EOR (&7A),Y:STA (&7A),Y
 1200 LDA (&7C),Y:EOR (&7E),Y:STA (&7E),Y
 1210 LDA (&80),Y:EOR (&82),Y:STA (&82),Y
 1220 LDA (&84),Y:EOR (&86),Y:STA (&86),Y
 1230 LDA (&88),Y:EOR (&8A),Y:STA (&8A),Y
 1240 LDA (&8C),Y:EOR (&8E),Y:STA (&8E),Y
 1250 LDY &2F00,X
 1260 \
 1270 LDA (&70),Y:EOR (&72),Y:STA (&72),Y
 1280 LDA (&74),Y:EOR (&76),Y:STA (&76),Y
 1290 LDA (&78),Y:EOR (&7A),Y:STA (&7A),Y
 1300 LDA (&7C),Y:EOR (&7E),Y:STA (&7E),Y
 1310 LDA (&80),Y:EOR (&82),Y:STA (&82),Y
 1320 LDA (&84),Y:EOR (&86),Y:STA (&86),Y
 1330 LDA (&88),Y:EOR (&8A),Y:STA (&8A),Y
 1340 LDA (&8C),Y:EOR (&8E),Y:STA (&8E),Y
 1350 \
 1360 INX
 1370 \
 1380 TXA:CLC:ADC &72:AND #8
 1390 BEQ blit16_jumpA
 1400 LDA &72:CLC:ADC #120:STA &72:LDA &73:ADC #2:STA &73
 1410 LDA &76:CLC:ADC #120:STA &76:LDA &77:ADC #2:STA &77
 1420 .blit16_jumpA
 1430 \
 1440 TXA:CLC:ADC &7A:AND #8
 1450 BEQ blit16_jumpB
 1460 LDA &7A:CLC:ADC #120:STA &7A:LDA &7B:ADC #2:STA &7B
 1470 LDA &7E:CLC:ADC #120:STA &7E:LDA &7F:ADC #2:STA &7F
 1480 .blit16_jumpB
 1490 \
 1500 TXA:CLC:ADC &82:AND #8
 1510 BEQ blit16_jumpC
 1520 LDA &82:CLC:ADC #120:STA &82:LDA &83:ADC #2:STA &83
 1530 LDA &86:CLC:ADC #120:STA &86:LDA &87:ADC #2:STA &87
 1540 .blit16_jumpC
 1550 \
 1560 TXA:CLC:ADC &8A:AND #8
 1570 BEQ blit16_jumpD
 1580 LDA &8A:CLC:ADC #120:STA &8A:LDA &8B:ADC #2:STA &8B
 1590 LDA &8E:CLC:ADC #120:STA &8E:LDA &8F:ADC #2:STA &8F
 1600 .blit16_jumpD
 1610 \
 1620 TXA:TAY:CMP #8:BEQ blit16_rts
 1630 JMP blit16_loop
 1640 \
 1650 .blit16_rts
 1660 RTS
 1670 ]
 1680 NEXT
 1690 ENDPROC
 1700 :
 1710 DATA"0000002222000000"
 1720 DATA"0000221111220000"
 1730 DATA"0000211111120000"
 1740 DATA"0002111111112000"
 1750 DATA"2002111111112002"
 1760 DATA"2000211111120002"
 1770 DATA"0200221111220020"
 1780 DATA"0022002112002200"
 1790 DATA"2002021111202002"
 1800 DATA"0220211111120220"
 1810 DATA"0002021111202000"
 1820 DATA"0022002222002200"
 1830 DATA"2200020000200022"
 1840 DATA"0000200000020000"
 1850 DATA"0000200000020000"
 1860 DATA"0000200000020000"
 1870 DATA"0000002222000000"
 1880 DATA"0000221111220000"
 1890 DATA"0000211111120000"
 1900 DATA"0002111111112000"
 1910 DATA"0002111111112000"
 1920 DATA"2000211111120002"
 1930 DATA"0200221111220020"
 1940 DATA"0022002112002200"
 1950 DATA"0002021111202000"
 1960 DATA"2220211111120222"
 1970 DATA"0002021111202000"
 1980 DATA"0022002222002200"
 1990 DATA"0200020000200020"
 2000 DATA"2000200000020002"
 2010 DATA"0000200000020000"
 2020 DATA"0000200000020000"
 2030 DATA"0000002222000000"
 2040 DATA"0000221111220000"
 2050 DATA"0000211111120000"
 2060 DATA"0002111111112000"
 2070 DATA"0002111111112000"
 2080 DATA"0000211111120000"
 2090 DATA"2200221111220022"
 2100 DATA"0022002112002200"
 2110 DATA"0002021111202000"
 2120 DATA"0220211111120220"
 2130 DATA"2002021111202002"
 2140 DATA"0022002222002200"
 2150 DATA"0200020000200020"
 2160 DATA"0200200000020020"
 2170 DATA"0000200000020000"
 2180 DATA"0000200000020000"
 2190 DATA"0000002222000000"
 2200 DATA"0000221111220000"
 2210 DATA"0000211111120000"
 2220 DATA"0002111111112000"
 2230 DATA"0002111111112000"
 2240 DATA"2000211111120002"
 2250 DATA"0200221111220020"
 2260 DATA"0022002112002200"
 2270 DATA"0002021111202000"
 2280 DATA"2220211111120222"
 2290 DATA"0002021111202000"
 2300 DATA"0022002222002200"
 2310 DATA"0200020000200020"
 2320 DATA"2000020000200002"
 2330 DATA"0000020000200000"
 2340 DATA"0000020000200000"


Return to “programming”

Who is online

Users browsing this forum: No registered users and 3 guests