Re: [stella] 13 chars C64-style

Subject: Re: [stella] 13 chars C64-style
From: Andrew Towers <mariofrog@xxxxxxxxxxx>
Date: Wed, 10 Dec 2003 02:12:00 +1100
Thomas wrote:
Paul wrote:
> And it shows that there's going to have to be a lot of optimizing done
> to get those lines closer together.

That is really a problem, but I suppose Rob's code does have the same.
Optimizing looks difficult too, even with even more roll unrolling.

I haven't done any VCS stuff for a while so I thought playing with this might be a good way to get back into things.. besides which, I couldn't resist giving it a try ;)

I've rewritten the routine that builds the display graphics in zero
page using two copies of the font as Paul suggested; this eliminates
a lot of the space but it still takes about as long to generate the
line of text as it does to display it. The decoding loop could be
unrolled again but there's no point unless it will eliminate another
whole scanline. As it is the decoding only takes up 85 bytes (but
doesn't use indirection for the text lookup, which would be necessary
in a real game).

The two copies of the font take up 144 bytes each, a bit over a page
in total including a couple of symbol characters. To put this in
perspective, that block of uncompressed text takes up 182 bytes on
its own!

The rest of the code is basically left alone, I didn't attempt to roll
up the rendering code.. well I did but I couldn't make it work so I
left it alone for now ;)

Regards,
Andrew.

Attachment: 13ch2.bin
Description: Binary data

;---------------------------------------------------------------------------
;
; Generic 2600 Game
;
;---------------------------------------------------------------------------

	processor 6502	
	include vcs.h	


;---------------------------------------------------------------------------
; Constants
;---------------------------------------------------------------------------

;---------------------------------------------------------------------------
; RAM Variables 
;---------------------------------------------------------------------------

chara equ $81
charb equ $86
charc equ $8b
chard equ $90
chare equ $95
charf equ $9a
charg equ $9f
chars equ $a3

temp  equ $a4
line  equ $a5
count equ $a6
textptr equ $a7
savesp equ $a8


	MAC TEXTDISP
	lda charg+{1}	;3
	sta ENAM0	;3
	lsr		;2
	sta ENAM1	;3
	lsr		;2
	sta ENABL	;3
	lda charf+{1} 	;3
	sta GRP0	;3
	lda chare+{1}	;3
	sta.w GRP1	;3
	ldx #$26+{2}	;2
	nop		;2
	nop		;2
	stx COLUP0	;3
	stx COLUP1	;3
	lda chard+{1}	;3
	sta GRP0	;3
	lda charc+{1}	;3
	ldy charb+{1}	;3
	stx COLUPF	;3
	ldx chara+{1}	;3
	sta GRP1	;3
	sty GRP0	;3
	stx GRP1	;3
	sta GRP0	;3
	lda #$20	;2
	sta COLUPF	;3
	ENDM



;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
	org $F000
;---------------------------------------------------------------------------
;---------------------------------------------------------------------------
				
;---------------------------------------------------------------------------
; Start of Program
;---------------------------------------------------------------------------
; Clear memory, locate character graphics positions and such,
; initialize key memory values, start GameLoop.
;-------------------------------------------------------------
Start
	sei  	
	cld  		
	ldx #$FF
	txs  		
	lda #0
clear   
	sta 0,x
	dex
	bne clear	

;---------------------------------------------------------------------------
; Initialize variables / registers
;---------------------------------------------------------------------------

	lda #$48
	sta COLUP0
	lda #$99
	sta COLUP1
	lda #255
	sta PF0
	sta PF1
	lda #0
	sta PF2

	lda #%00000101
	sta WSYNC
	sta CTRLPF
	sta GRP0
	sta GRP1
	lda #$03           ; set both players to 3 copies
	sta NUSIZ0
	sta NUSIZ1
	lda #$01           ; set vertical delay on for both players
	sta VDELP0
	sta $2d    ; nop
	sta RESM0
	sta RESM1
	sta VDELP1
	sta RESBL
	sta RESP0
	sta RESP1
	lda #%11110000
	sta HMP1
	lda #%11100000
	sta HMP0
	lda #%10000000
	sta HMBL
	lda #%10110000
	sta HMM0
	lda #%01010000
	sta HMM1
	sta WSYNC
	sta HMOVE


;--------------------------------------------------------------------------
; GameLoop
;--------------------------------------------------------------------------
GameLoop
	jsr VSync 	;start vertical retrace

	jsr VBlank    	; spare time during screen blank
	jsr Picture	; draw one screen
	jsr overscan	; do overscan

	jmp GameLoop    ;back to top

;--------------------------------------------------------------------------
; VSync
;--------------------------------------------------------------------------
VSync
	lda #2		;bit 1 needs to be 1 to start retrace
	sta VSYNC	;start retrace
	sta WSYNC 	;wait a few lines
	sta WSYNC 
	lda #44		;prepare timer to exit blank period (44)
	sta TIM64T	;turn it on
	sta WSYNC 	;wait one more
	sta VSYNC 	;done with retrace, write 0 to bit 1

	rts ; VSync



;--------------------------------------------------------------------------
; VBlank
;--------------------------------------------------------------------------
; Game Logic
;--------------------------------------------------------------------------
VBlank

	rts ; VBlank



;--------------------------------------------------------------------------
; Overscan
;--------------------------------------------------------------------------
; More Game Logic
;--------------------------------------------------------------------------
overscan

	sta WSYNC	

	lda #$00
	sta COLUBK

	lda #36		; Use the timer to make sure overscan takes (34)
	sta TIM64T	; 30 scan lines.  29 scan lines * 76 = 2204 / 64 = 34.4

endOS	
	lda INTIM	; We finished, but wait for timer
	bne endOS	; by looping till zero
	
	sta WSYNC	; End last scanline

	lda #$82
	sta VBLANK
	lda #$02
	sta VBLANK

	rts	; overscan



;--------------------------------------------------------------------------
; Draw TV Pictures
;--------------------------------------------------------------------------
;
;--------------------------------------------------------------------------


Picture

pictureLoop
	lda INTIM	;check timer for end of VBLANK period
	bne pictureLoop	;loop until it reaches 0

	sta WSYNC
	lda #$80
	sta VBLANK  	;end screen blank

	; Set playfield color
	lda #$20
	sta COLUPF
	
	lda #14
	sta line
	
	lda #0
	sta textptr
	
	tsx
	stx savesp

	sta WSYNC
	jmp mainTextLoop	;3
	
; render the line of text
; place the code here so we can branch before rendering,
; when we have the cycles to spare!

renderTextLine

	lda #255	;2
	sta GRP0	;3
	sta GRP1	;3 [59]

	TEXTDISP 0,0
	TEXTDISP 1,2
	TEXTDISP 2,4
	TEXTDISP 3,6
	TEXTDISP 4,8

	lda #0		;2
	sta COLUP0	;3
	sta COLUP1	;3
	;sta GRP0
	;sta GRP1
	;sta GRP0
	;sta ENAM0
	;sta ENAM1
	sta ENABL	;3

	nop		;2
	nop		;2
	dec $2d		;5

mainTextLoop

; set up the stack for building screen data

	ldx #chars	;2
	txs		;2

; load the first text character

	ldx textptr	;3
	ldy text,x	;4
	inx		;2

; build screen data for first character

	lda fontlo,y	;4
	pha		;3
	lda fontlo+1,y	;4
	pha		;3
	lda fontlo+2,y	;4
	pha		;3
	lda fontlo+3,y	;4
	pha		;3
	lda fontlo+4,y	;4
	pha		;3

; loop through the remaining 6 character pairs

	lda #6		;2
	sta count	;3

textLineLoop

; load the next two text characters

	ldy text,x	;4
	lda text+1,x	;4
	inx		;2
	inx		;2
	stx textptr	;3
	tax		;2

; build screen data for next two characters

	lda fonthi,y	;4
	ora fontlo,x	;4
	pha		;3
	lda fonthi+1,y	;4
	ora fontlo+1,x	;4
	pha		;3
	lda fonthi+2,y	;4
	ora fontlo+2,x	;4
	pha		;3
	lda fonthi+3,y	;4
	ora fontlo+3,x	;4
	pha		;3
	lda fonthi+4,y	;4
	ora fontlo+4,x	;4
	pha		;3

; next character pair

	ldx textptr	 ;3
	dec count	 ;5
	bne textLineLoop ;2

; now render it asap

	;;sta WSYNC
	
	dec $2d		;5 nop
	dec $2d		;5 nop
	dec $2d		;5 nop

;	ldx #3		;2 (was 10)
;dly
;	dex		;2
;	bne dly		;3/2 -> +24 (was 49)

	dec line		;5
	bmi quitTextLoop	;2
	jmp renderTextLine	;3
quitTextLoop

	;------------------------------------------------------------------
	;------------------------------------------------------------------
endText
	lda #0
	sta GRP0
	sta GRP1
	sta GRP0
	sta GRP1
	sta ENAM0
	sta ENAM1
	sta ENABL

; restore stack pointer

	ldx savesp
	txs


	ldx #1

ScanLoop	
	sta WSYNC	
	dex
	bne ScanLoop

	sta COLUPF
	
	rts	; Picture




;---------------------------------------------------------------------------
; note: dasm doesn't like using x or y as a label!

	align 256
text
	byte t,h,i,r,t,e,e,n,c,h,a,r,s
	byte _,_,ast,_,d,e,m,o,_,ast,_,_,_
	byte eq,eq,eq,eq,eq,eq,eq,eq,eq,eq,eq,eq,eq
	byte t,h,i,s,_,i,s,_,a,_,_,_,_
	byte w,h,o,l,e,_,b,u,n,c,h,_,_
	byte o,f,_,s,t,u,f,f,_,i,_,a,m
	byte w,r,i,t,i,n,g,_,t,o,_,_,_
	byte t,e,s,t,_,t,h,e,_,n,e,w,_
	byte t,e,xx,t,_,r,o,u,t,i,n,e,_
	byte i,s,_,i,t,_,n,o,t,_,_,_,_
	byte ast,ast,v,e,r,yy,_,c,o,o,l,ast,ast
	byte yy,e,s,_,i,t,_,i,s,_,_,_,_
	byte a,c,t,u,a,l,l,yy,_,_,_,_,_
	byte eq,eq,eq,eq,eq,eq,eq,eq,eq,eq,eq,eq,eq



;---------------------------------------------------------------------------

	align 256
fonthi
_
	byte %00000000
	byte %00000000
	byte %00000000
	byte %00000000
	byte %00000000
a
	byte %10100000
	byte %10100000
	byte %11100000
	byte %10100000
	byte %01000000
b
	byte %11000000
	byte %10100000
	byte %11000000
	byte %10100000
	byte %11000000
c
	byte %01100000
	byte %10000000
	byte %10000000
	byte %10000000
	byte %01100000
d
	byte %11000000
	byte %10100000
	byte %10100000
	byte %10100000
	byte %11000000
e
	byte %11100000
	byte %10000000
	byte %11000000
	byte %10000000
	byte %11100000
f
	byte %10000000
	byte %10000000
	byte %11000000
	byte %10000000
	byte %11100000
g
	byte %01100000
	byte %10100000
	byte %10100000
	byte %10000000
	byte %01100000
h
	byte %10100000
	byte %10100000
	byte %11100000
	byte %10100000
	byte %10100000
i
	byte %01000000
	byte %01000000
	byte %01000000
	byte %01000000
	byte %01000000
j
	byte %10000000
	byte %01000000
	byte %01000000
	byte %01000000
	byte %11100000
k
	byte %10100000
	byte %10100000
	byte %11000000
	byte %10100000
	byte %10000000
l
	byte %11100000
	byte %10000000
	byte %10000000
	byte %10000000
	byte %10000000
m
	byte %10100000
	byte %10100000
	byte %10100000
	byte %11100000
	byte %10100000
n
	byte %10100000
	byte %10100000
	byte %10100000
	byte %10100000
	byte %11100000
o
	byte %01000000
	byte %10100000
	byte %10100000
	byte %10100000
	byte %01000000
p
	byte %10000000
	byte %10000000
	byte %11000000
	byte %10100000
	byte %11000000
q
	byte %01100000
	byte %11100000
	byte %10100000
	byte %10100000
	byte %01000000
r
	byte %10100000
	byte %10100000
	byte %11000000
	byte %10100000
	byte %11000000
s
	byte %11000000
	byte %00100000
	byte %01000000
	byte %10000000
	byte %01100000
t
	byte %01000000
	byte %01000000
	byte %01000000
	byte %01000000
	byte %11100000
u
	byte %01100000
	byte %10100000
	byte %10100000
	byte %10100000
	byte %10100000
v
	byte %01000000
	byte %01000000
	byte %10100000
	byte %10100000
	byte %10100000
w
	byte %10100000
	byte %11100000
	byte %10100000
	byte %10100000
	byte %10100000
xx
	byte %10100000
	byte %10100000
	byte %01000000
	byte %10100000
	byte %10100000
yy
	byte %01000000
	byte %01000000
	byte %01000000
	byte %10100000
	byte %10100000
z
	byte %11100000
	byte %10000000
	byte %01000000
	byte %00100000
	byte %11100000
ast
	byte %10100000
	byte %01000000
	byte %11100000
	byte %01000000
	byte %10100000
eq
	byte %00000000
	byte %11100000
	byte %00000000
	byte %11100000
	byte %00000000


	align 256
fontlo
;_
	byte %00000000
	byte %00000000
	byte %00000000
	byte %00000000
	byte %00000000
;a
	byte %00001010
	byte %00001010
	byte %00001110
	byte %00001010
	byte %00000100
;b
	byte %00001100
	byte %00001010
	byte %00001100
	byte %00001010
	byte %00001100
;c
	byte %00000110
	byte %00001000
	byte %00001000
	byte %00001000
	byte %00000110
;d
	byte %00001100
	byte %00001010
	byte %00001010
	byte %00001010
	byte %00001100
;e
	byte %00001110
	byte %00001000
	byte %00001100
	byte %00001000
	byte %00001110
;f
	byte %00001000
	byte %00001000
	byte %00001100
	byte %00001000
	byte %00001110
;g
	byte %00000110
	byte %00001010
	byte %00001010
	byte %00001000
	byte %00000110
;h
	byte %00001010
	byte %00001010
	byte %00001110
	byte %00001010
	byte %00001010
;i
	byte %00000100
	byte %00000100
	byte %00000100
	byte %00000100
	byte %00000100
;j
	byte %00001000
	byte %00000100
	byte %00000100
	byte %00000100
	byte %00001110
;k
	byte %00001010
	byte %00001010
	byte %00001100
	byte %00001010
	byte %00001000
;l
	byte %00001110
	byte %00001000
	byte %00001000
	byte %00001000
	byte %00001000
;m
	byte %00001010
	byte %00001010
	byte %00001010
	byte %00001110
	byte %00001010
;n
	byte %00001010
	byte %00001010
	byte %00001010
	byte %00001010
	byte %00001110
;o
	byte %00000100
	byte %00001010
	byte %00001010
	byte %00001010
	byte %00000100
;p
	byte %00001000
	byte %00001000
	byte %00001100
	byte %00001010
	byte %00001100
;q
	byte %00000110
	byte %00001110
	byte %00001010
	byte %00001010
	byte %00000100
;r
	byte %00001010
	byte %00001010
	byte %00001100
	byte %00001010
	byte %00001100
;s
	byte %00001100
	byte %00000010
	byte %00000100
	byte %00001000
	byte %00000110
;t
	byte %00000100
	byte %00000100
	byte %00000100
	byte %00000100
	byte %00001110
;u
	byte %00000110
	byte %00001010
	byte %00001010
	byte %00001010
	byte %00001010
;v
	byte %00000100
	byte %00000100
	byte %00001010
	byte %00001010
	byte %00001010
;w
	byte %00001010
	byte %00001110
	byte %00001010
	byte %00001010
	byte %00001010
;xx
	byte %00001010
	byte %00001010
	byte %00000100
	byte %00001010
	byte %00001010
;yy
	byte %00000100
	byte %00000100
	byte %00000100
	byte %00001010
	byte %00001010
;z
	byte %00001110
	byte %00001000
	byte %00000100
	byte %00000010
	byte %00001110
;ast
	byte %00001010
	byte %00000100
	byte %00001110
	byte %00000100
	byte %00001010
;eq
	byte %00000000
	byte %00001110
	byte %00000000
	byte %00001110
	byte %00000000


;---------------------------------------------------------------------------
; Program Startup
;---------------------------------------------------------------------------
	org $FFFC
	.word Start
	.word Start

Current Thread