Re: [stella] single digit scoring...

Subject: Re: [stella] single digit scoring...
From: Erik Mooney <erik@xxxxxxxxxx>
Date: Sun, 24 Aug 2003 20:22:28 -0400
On 24 Aug 2003 22:31:14 -0000, you wrote:

>Score0Graphic
>        .byte #%00111100
>        .byte #%01000010
>        .byte #%01000010
>        .byte #%01000010
>        .byte #%00111100
>Score1Graphic
>        .byte #%00111110
>        .byte #%00001000
>        .byte #%00001000
>        .byte #%00101000
>        .byte #%00011000
>
>I know 5 is kind of an odd number,
>I tried for 4 but couldn't make it look good, and it seems wasteful
>to pad it to 8

If you have ROM but need CPU cycles for the kernel, then padding it to 8
would be the right thing to do.  Especially if you can stick other data in
the 3 unused bytes between each digit.  But let's solve the case for 5...


>I think the basic idea is pretty simple:
>for each scanline, the piece of score to display is at
>
>Y (holding scanline) + (5 * playerscore) + startofscoresinmemory
>
>(hmm, actually maybe I should compute
>(5 * playerscore) + startofscoresinmemory
>during the VBLANK and then just add the scanline to that?
>
>Anyway, this is the bit I came up with:
>
>ScoreDisplayLoop
>	LDA p0score ;accumulator = score
>	ROL ;accumulator = score * 2
>	ROL ;accumulator = score * 4
>	CLC
>	ADC p0score  ;accumulator = (score * 4) + score = score * 5
>	CLC
>	ADC Score0Graphic
>	STA GRP0
>
>;...P1 etc goes here, along with two WSYNCs
>
>	DEY		
>	BNE ScoreDisplayLoop	

OK.  Here's the deal: on the 6502, you don't load an entire ROM address
into a register.  That would take 16 bits, and our registers are only 8
bits wide.  What you do is calculate an 8-bit offset from the start of a
table, load it into the X or Y register, and do LDA Table, X where Table
is a 16-bit (hardcoded, not variable) address.

But, to iterate through a score digit would require indexing with both
registers at once: Score0Graphic + X (the index to the start of the digit)
+ Y (the index within a digit.)  You can't do that.  You could add both
indexes and load them into Y, then in the loop, decrement Y until it
equals X (which you can't do directly - you'd have to STX Temp / CPY
Temp).  But that gets a bit ugly.

The better way to do this on the 6502 is to use indirect indexed
addressing.  That works like this:

LDA ($90), Y

Suppose memory location $90 contains $20, and location $91 contains $FF.
That makes the 16-bit value $FF20.  That instruction will load the value
at offset $FF20 + Y into the accumulator.

So, let's create a 16-bit value in memory that is the offset to the start
of your digit.  After you've multiplied A by 5:

	ADC p0score  ;accumulator = (score * 4) + score = score * 5
	STA TempPointer
	LDA #>Score0Graphic 
	STA TempPointer+1

Now we have created a 16-bit pointer in the memory location called
TempPointer that points to your digit.  That odd-looking LDA means "load
the high byte of the 16-bit hardcoded value Score0Graphic".  All of this
you only need to do once, not for every line of the score.  From here it's
simple:

	LDY #5
Loop
	STA WSYNC
	LDA (TempPointer), Y
	STA GRP0
	DEY
	BNE Loop

I hope this made sense, and that my 6502 isn't too rusty (I'm sure someone
will correct something that I got wrong :) )


----------------------------------------------------------------------------------------------
Archives (includes files) at http://www.biglist.com/lists/stella/archives/
Unsub & more at http://www.biglist.com/lists/stella/


Current Thread