Tile draw code optimization help

Basic and Machine Language

Moderator: Moderators

Post Reply
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Tile draw code optimization help

Post by KingTrode »

Hi All

Below is my take on a tile draw routine for the text screen, try not to be too harsh on lil old novice me :wink: .

The tiles are 2x2 characters in size and are all drawn using the same colour.

I was hoping to get some feedback/possible speed optimization suggestions before I put this to use in my projects, maybe there's a better way to store the data that would facilitate faster processing of it by a modified draw routine etc.

At the moment his code can draw approx. 5,120 tiles per second using some pretty slack loop code.


Cheers


KingTrode / Jim

Code: Select all

; ******************************************
; *  Commodore VIC-20 2x2 Tile Draw Test   *
; *  By Richard Croskell (KingTrode) 2013  *
; *                                        *
; *  Requires no RAM Expansion             *
; *                                        *
; *  Source Code Format: 64TASS Assembler  *
; ******************************************
	.cpu 6502
	
	.include "..\Include\colours.asm"
	.include "..\Include\macros.asm"
	
; *******************************
; *  Zero Page Address Storage  *
; *******************************
TileAddrLo	= $F9
TileAddrHi	= $FA
ScrAddrLo		=	$FB
ScrAddrHi		=	$FC
ClrAddrLo		=	$FD
ClrAddrHi		=	$FE

; ***********************************
; *  Non Zero Page Address Storage  *
; ***********************************
PenColour		= $0286
VicRegs			= $9000
ColourBase	= $9600
ScreenBase	= $1E00
CharRom			= $8000
GetIn				=	$FFE4

; *************************
; *  Some Useful Equates  *
; *************************

; ***************************
; *  ORG Directive options  *
; ***************************
; *= $0401 ; 3k VIC
; *= $1001 ; Unexpanded VIC
; *= $1201 ; 8k+ VIC

	*= $1001													; 0k VIC-20 

	.word	NextLine										; BASIC pointer to next line
	.word	2013												; BASIC line number = 2013
	.byte	$9E													; BASIC token code for "SYS" command
	.byte	$30 + ((SysAddr/1000)//10)	; Calculate 2nd digit of SYS_ADDRESS
	.byte	$30 + ((SysAddr/100)//10)		; Calculate 3rd digit of SYS_ADDRESS
	.byte	$30 + ((SysAddr/10)//10)		; Calculate 4th digit of SYS_ADDRESS
	.byte	$30 + (SysAddr//10)					; Calculate 5th digit of SYS_ADDRESS
	.byte	$00													; BASIC end of line marker
NextLine
	.word	$0000											; BASIC end of program 

; ******************************
; *  Start of executable code  *
; ******************************
SysAddr
	lda #3
	ldx #20
	ldy #21
	jsr DrawTile ; Draw Tile #3 @ 20,21
	
	rts	; Return to Caller
	
; *****************************
; *  Draw 2x2 Tile on screen  *
; *  A = Tile Number          *
; *  X = Column 0-20          *
; *  Y = Row 0-21             *
; *****************************
DrawTile
	pha	
	jsr CalcXYAddr ; Setup screen / colour pointers	
	pla
	
	tay	
	lda TileAddrTabLo,y
	sta TileAddrLo
	lda TileAddrTabHi,y
	sta TileAddrHi ; Setup Tile Definition pointer
	
	lda TileClrTab,y
	pha ; Get tile colour and save
	
	jsr DrawTileRow ; Draw top row of Tile

	clc	
	lda ScrAddrLo
	adc #22
	sta ScrAddrLo
	sta ClrAddrLo
	bcc DrawTileSkip1
	inc ScrAddrHi
	inc ClrAddrHi ; Point to next screen row

DrawTileSkip1
	clc
	lda TileAddrLo
	adc #2
	sta TileAddrLo
	bcc DrawTileSkip2
	inc TileAddrHi ; Point to next Tile row

DrawTileSkip2	
	pla
	jsr DrawTileRow	; Draw bottom row of tile	
	rts
	
DrawTileRow
	ldy #0
	sta (ClrAddrLo),y
	iny
	sta (ClrAddrLo),y ; Set Tile colour left/right cells
	dey
	lda (TileAddrLo),y
	sta (ScrAddrLo),y
	iny
	lda (TileAddrLo),y
	sta (ScrAddrLo),y ; Draw Left/Right chars	
	rts

; *************************************************************
; *  Calculate screen/colour address from .X (Col) / .Y (Row) *
; *************************************************************	
CalcXYAddr
	txa
	clc
	adc ScrAddrTabLo,Y
	sta ScrAddrLo
	sta ClrAddrLo
	lda ScrAddrTabHi,Y
	adc #$00
	sta ScrAddrHi
	clc
	adc #$78
	sta ClrAddrHi
	rts
		
; **********************************************
; *  Screen Lo Byte address rows offset table  *
; **********************************************
ScrAddrTabLo
	.byte $00,$16,$2c,$42,$58,$6e,$84,$9a,$b0,$c6,$dc,$f2
	.byte $08,$1e,$34,$4a,$60,$76,$8c,$a2,$b8,$ce,$e4

; **********************************************
; *  Screen Hi Byte address rows offset table  *
; **********************************************
ScrAddrTabHi
	.byte $1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e,$1e
	.byte $1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f,$1f

; ********************************
; *  Tile Lo Byte address table  *
; ********************************
TileAddrTabLo
	.byte <Tile00,<Tile01,<Tile02,<Tile03,<Tile04,<Tile05
	
; ********************************
; *  Tile Lo Byte address table  *
; ********************************
TileAddrTabHi
	.byte >Tile00,>Tile01,>Tile02,>Tile03,>Tile04,>Tile05

; ***********************
; *  Tile Colour Table  *
; ***********************
TileClrTab
	.byte Yellow,Red,Blue,Black,Green,Purple
	
; *****************************
; *  Tile Definitions (2x2)   *
; *                           *
; *  0 = Top Left Char Code   *
; *  1 = Top Right Char Cod   *
; *  2 = Bot Left Char Code   *
; *  3 = Bot Right Char Code  *
; *****************************	
Tile00
	.byte $00,$01,$02,$03
Tile01
	.byte $04,$05,$06,$07
Tile02
	.byte $08,$09,$0a,$0b
Tile03
	.byte $0c,$0d,$0e,$0f
Tile04
	.byte $10,$11,$12,$13
Tile05
	.byte $14,$15,$16,$17
User avatar
Mike
Herr VC
Posts: 4830
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

Not much faster, and untested, but you might try out this one instead:

Code: Select all

; ***************************** 
; *  Draw 2x2 Tile on screen  * 
; *  A = Tile Number          * 
; *  X = Column 0-20          * 
; *  Y = Row 0-21             * 
; ***************************** 

 STA tile_ptr
 LDA #0
 ASL tile_ptr:ROL A
 ASL tile_ptr:ROL A
 STA tile_ptr+1
 CLC
 LDA #tile_base MOD 256:ADC tile_ptr  :STA tile_ptr
 LDA #tile_base DIV 256:ADC tile_ptr+1:STA tile_ptr+1

 CLC
 TXA   :ADC line_table_lo,Y:STA scrn_ptr  :STA col_ptr
 LDA #0:ADC line_table_hi,Y:STA scrn_ptr+1:ADC #(col_base-scrn_base)DIV256:STA col_ptr+1

 LDY #0:LDA (tile_ptr),Y:        STA (scrn_ptr),Y:LDA #0:STA (col_ptr),Y
 INY   :LDA (tile_ptr),Y:        STA (scrn_ptr),Y:LDA #0:STA (col_ptr),Y
 INY   :LDA (tile_ptr),Y:LDY #22:STA (scrn_ptr),Y:LDA #0:STA (col_ptr),Y
 LDY #3:LDA (tile_ptr),Y:LDY #23:STA (scrn_ptr),Y:LDA #0:STA (col_ptr),Y
 RTS
It does not use yet another set of address tables to point to the tiles, rather the tile_ptr is directly calcuted from tile_base+tile_number*4.

Including the JSR + RTS call sequence, this needs 168 cycles per tile (if my cycle counts are correct) plus some cycles extra if page boundaries are crossed. This would correspond to ~6500 tiles per second.

If you initialise the colour RAM beforehand, you gain a few cycles of course.
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Post by KingTrode »

Thanks for the reply Mike, I shall try your method later.

One thing I didn't state very clearly in my original post when I wrote "The tiles are 2x2 characters in size and are all drawn using the same colour. ", what I meant was all the four chars that make up the tile are the same colour, each tile can be a different colour.

The following part of your code:

Code: Select all

LDA #0:STA (col_ptr),Y


has fallen foul of my poor explanation?



Cheers


KingTrode / Jim
User avatar
Mike
Herr VC
Posts: 4830
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Post by Mike »

KingTrode wrote:what I meant was all the four chars that make up the tile are the same colour, each tile can be a different colour.
I missed that somehow.

You can fetch the tile colour from another table and then put it into another ZP address, changing:

Code: Select all

 STA tile_ptr
 LDA #0
to

Code: Select all

 STA tile_ptr
 STA tile_colour
 LDA #0
inserting this after the scrn_ptr calculation:

Code: Select all

 LDX tile_colour:LDA tile_colour_table,X:STA tile_colour
and replacing all instances of

Code: Select all

 LDA #0:STA (col_ptr),Y
with

Code: Select all

 LDA tile_colour:STA (col_ptr),Y
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Post by KingTrode »

Hi Mike

Reporting back with some results :D

The test I ran was drawing 121 tiles (11x11 almost a full screen ) to the screen 256 times, withing the 256 loop the tile number was cycled from 0 to 5 and back to 0...

My original took approx 7.2 seconds and yours unsurprisingly took approx 6.4 secs (timed with a stopwatch :roll: )

So a big thanks for your feedback on this Mike, your time and effort is always greatly appreciated !


Cheers

KingTrode / Jim
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Post by KingTrode »

After doing some reading I had a play with the tile draw code and tried a few things out.

After running it through the same benchmark test as the previous two I got a time of 5.5 secs (will only support 64 Tiles max) :shock:

Note: I edited the previous post as it read 144 tiles 12x12 when it should of been 121 Tiles 11x11.

Here's the new code, though I have yet to fully test it outside of the benchmark and it could be flawed :oops:


KingTrode / Jim

Code: Select all

; *****************************
; *  Draw 2x2 Tile on screen  *
; *  A = Tile Number          *
; *  X = Column 0-20          *
; *  Y = Row 0-21             *
; *****************************
DrawTile
	pha
	
	clc 
	txa
	adc ScrAddrTabLo,y
	sta ScrAddrLo
	sta ClrAddrLo
	lda #0
	adc ScrAddrTabHi,y
	sta ScrAddrHi
	adc #$78
	sta ClrAddrHi
	
	pla
	tax
	asl
	asl
	pha
	lda TileClrTab,x
	sta TileClr
	pla
	
   tax
	ldy #0
	lda TileTab,x
	sta (ScrAddrLo),y
	lda TileClr
	sta (ClrAddrLo),y
	
	inx
	iny
	lda TileTab,x
	sta (ScrAddrLo),y
	lda TileClr
	sta (ClrAddrLo),y
	
	inx
	lda TileTab,x
	ldy #22
	sta (ScrAddrLo),y
	lda TileClr
	sta (ClrAddrLo),y
	
	inx
	iny
	lda TileTab,x
	sta (ScrAddrLo),y
	lda TileClr
	sta (ClrAddrLo),y		
	rts
wimoos
Vic 20 Afficionado
Posts: 345
Joined: Tue Apr 14, 2009 8:15 am
Website: http://wimbasic.webs.com
Location: Netherlands
Occupation: farmer

Some memory savers

Post by wimoos »

This tip will not speed things up, but will save you memory: 44 bytes to be exact.

The table at SrcAddrTabLo is available in ROM at $EDFD
The table at SrcAddrTabHi can be derived from the table at $D9 when masking off bit7 (LDA $D9,Y / AND #$7F)

Regards,

Wim.
VICE; selfwritten 65asmgen; tasm; maintainer of WimBasic
KingTrode
Vic 20 Hobbyist
Posts: 133
Joined: Tue Apr 13, 2010 2:32 am

Re: Some memory savers

Post by KingTrode »

wimoos wrote:This tip will not speed things up, but will save you memory: 44 bytes to be exact.

The table at SrcAddrTabLo is available in ROM at $EDFD
The table at SrcAddrTabHi can be derived from the table at $D9 when masking off bit7 (LDA $D9,Y / AND #$7F)

Regards,

Wim.
Thanks for the tip Wim, could come in very handy for those Unexpanded projects that are real tight on RAM usage.


KingTrode / Jim
User avatar
Mike
Herr VC
Posts: 4830
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Some memory savers

Post by Mike »

wimoos wrote:LDA $D9,Y
The zeropage-indexed-Y addressing mode is only supported by LDX and STX. LDA $00D9,Y works, though.
Post Reply