Re: [stella] 6 Digit Routine Cont.

Subject: Re: [stella] 6 Digit Routine Cont.
From: Christopher Tumber <christophertumber@xxxxxxxxxx>
Date: Wed, 10 Sep 2003 11:52:26 -0400
This may be dead obvious, but I'll point it out anyway.

You actually understand the 6 digit display routine.

This routine does a couple other things besides just a "simple" 6 digit display.

- Skips scanlines so text is displayed at correct vertical position (bottom of screen?)
- Sets the colours based on the current level
- Sets up the pointers for use in the 6 digit display based on a string-like structure
- Draws the 6 digit display

In effect, you're actually dealing with four distinct routines. They are:

Skip a certain number of scanlines (based on level?)

>    ldy     MsgDelayTab-1,x
>    beq     .skipWait
>.loopWait:
>    sta     WSYNC
>    dey                         ; 2
>    bne     .loopWait           ; 2³
> 
>^ Simple Enough
>
>.skipWait:

Set colours:

>    lda     Planet
>    and     #~PLANETMASK
>    bne     .NTSCMsgCol
>    lda     MsgColTab_PAL,x     ; 4
>    bne     .contMsgCol
>    DEBUG_BRK
>.NTSCMsgCol:
>    lda     MsgColTab,x         ; 4
>.contMsgCol:
>    sta     COLUP0              ; 3
>    sta     COLUP1              ; 3 = 10 <-- When I count, I get much more than 10?

Set up pointers:

 ldy     MsgTab,x            ; 4
>^??????? Totally lost here |Load height of graphic?
> 
>    lda     LetterPtrTab,y      ; 4
>    sta     digitPtr            ; 3
>^LetterPtrTab,Y = Address of first 8x8 Graphic?
> 
>    lda     LetterPtrTab+1,y    ; 4
>^Here is where I get lost? I don't understand how this gets compiled
>^If LetterPtrTab = $1200 and Y is $05, then this returns $1200 + 1 + 5? ($1206)???
>^Shouldn't this get the last byte of the second graphic? I'm confused how it does this?
> 
>    sta     digitPtr+2          ; 3
>^digitPtr is in Zero Page... So the graphic data is loaded into RAM...
>
>    lda     LetterPtrTab+2,y    ; 4
>    sta     digitPtr+4          ; 3
>    lda     LetterPtrTab+3,y    ; 4
>    sta     digitPtr+6          ; 3
>    lda     LetterPtrTab+4,y    ; 4
>    sta     digitPtr+8          ; 3
>    lda     LetterPtrTab+5,y    ; 4
>    sta     digitPtr+10         ; 3 = 46

6 digit display:

>    ldy     #5                  ; 2
>;    ldy     MsgHeightTab-1,x
>    txa                         ; 2         don't change C!
>    eor     #MSG_C_2000         ; 2
>    bne     .msgLoop            ; 2³
>    ldy     #7                  ; 2 = 7/8
>.msgLoop:
> 
>^ All graphics are 5 height, except Copyright which is 7...
>^ These are all wasted cycles for me... in order for this to work for me however, 
>^ I have to get this exact cycle count?
>
>    dey                         ; 2     61
>    sty     tmpVar              ; 3     64
>    lda     (digitPtr+$8),y     ; 5     69
>    tax                         ; 2     71
>    sta     WSYNC               ; 3 --- 76 ---
>    lda     (digitPtr),y        ; 5      5
>    sta     GRP0                ; 3      8
>    lda     (digitPtr+$2),y     ; 5     13
>    sta     GRP1                ; 3     16
>    lda     (digitPtr+$4),y     ; 5     21
>    sta     GRP0                ; 3     24
>    lda     (digitPtr+$6),y     ; 5     29
>    sta     tmpVar2             ; 3     32
>    lda     (digitPtr+$a),y     ; 5     37
>    ldy.w   tmpVar2             ; 4     41
>    sty     GRP1                ; 3     44
>    stx     GRP0                ; 3     47
>    sta     GRP1                ; 3     50
>    sta     GRP0                ; 3     53
>    ldy     tmpVar              ; 3     56
>    bne     .msgLoop            ; 2³    59
> 
>^This all makes sense
> 
>    sty     GRP0
>    sty     GRP1
>    sty     GRP0
>^Why is GRP0 cleared twice?
>    rts 


The part of the routine you seem to actually be having a problem with is the use of pointers, not really the display routine itself (Though I will also point out that the timing is  only critical during the actual display part of the routine, the timing in other parts - particularly in the skip lines part (which you asked about) is not critical). And you didn't include the tables in the code you posted. MsgTab and LetterPtrTab are tables of offsets to the graphics data. So you need to consider and understand those tables if you're going to understand what's going on.

To simplify things, I'm just going to consider the first digit being displayed and ignore the other 5 digits.

To set up the first digit, we need to put a pointer to it's graphics data into digitPtr

If we want to setup digitPtr to point to the first letter in our alphabet (presumably a 0 or A but you didn't include the tables so I'm guessing and I'm not going to go hunting for the source..) we would:

lda #0*HeightOfLetters
sta digitPtr             ;digitPtr+1 has been pre-set to point to the top of the graphics table at $FF00 or $FE00 or etc

If we want to setup digitPtr to point to the second letter in our alphabet (presumably a 1 or B but you didn't include the tables so I'm guessing and I'm not going to go hunting for the source..) we would:

lda #1*HeightOfLetters
sta digitPtr ;digitPtr+1 has been pre-set to point to the top of the graphics table at $FF00 or $FE00 or etc

And so on...

However, in this example Thomas has abstracted things a little to allow the routine to display different strings. So instead of loading the character values directly, he's using a pointer to some strings:

lda     LetterPtrTab,y      ; 4
sta     digitPtr            ; 3

LetterPtrTab is a table of strings, if each string is (probably) 6 letters wide, then to put the first letter of the first string into digitPtr

lda     #0
lda     LetterPtrTab,y      ; 4
sta     digitPtr            ; 3

To put the first letter of the second string in digitPtr

lda     #6
lda     LetterPtrTab,y      ; 4
sta     digitPtr            ; 3

But that's not particularly usefull unless you turn that #0 and #6 into a variable. Thomas could have used a simple variable like:

 ldy      MsgOffset
 lda     LetterPtrTab,y      ; 4
 sta     digitPtr            ; 3

Which would be fine if you only have a couple different messages to display, and they're all the same width. However, given many different messages to display it's convenient to put it all into a table:

 ldy     MsgTab,x            ; 4
 lda     LetterPtrTab,y      ; 4
 sta     digitPtr            ; 3

So, to display the first message (string):

 ldx   #0
 ldy     MsgTab,x            ; 4
 lda     LetterPtrTab,y      ; 4
 sta     digitPtr            ; 3

So, to display the second message (string):

 ldx   #1
 ldy     MsgTab,x            ; 4
 lda     LetterPtrTab,y      ; 4
 sta     digitPtr            ; 3


If  this still doesn't make any sense to you, it may not matter. If you just want to use the 6 digit display to display a score or a specific static text then you don't need all these extra abstractions that are desinged to handle a variety of different strings. All you really need is that 4th section of the code, and set up digitPtr et al to suit your own purposes.


Chris...



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


Current Thread