Jump to content
IGNORED

Why does Stella TIA debugger show 2 bitmaps for each Player?


lucienEn

Recommended Posts

Hi, I have a couple of questions on the TIA debugger in Stella which doesn't work as I would expect. Anyone knows how this works:

 

1) Why do the P0/P1 bitmaps not get updated right after updating GRP0/1? See below where I would have expected GRP0 = Y = 00010000. Instead it shows 01001110. UPDATE: just noticed at bottom of page it says 'Queued Writes'. Why is it queued and how long does it take to take effect?

2) Why are the 2 bitmaps shown for P0 and P1? I know there is some caching for delaying drawing but not sure how this works here since I thought it would only delay the position, but seems it's also the bitmaps

 

image.thumb.jpeg.0db2934c3cf409a8c785f74e7b397fa1.jpeg

 

Thanks!

Lucien

Edited by lucienEn
Link to comment
Share on other sites

I discovered it's indeed that GRP registers are rather delayed when using VDELP. Would have been nice to see the VDELP0/1 settings in the debugger but from the queued writes I think it can be derived.

 

This seems to be a required technique to be able to draw longer text on 1 line. I do see in Circus Convoy a trick it appears to alternate drawing different character per line for the scrolling text but still this is pretty complex for something seemingly basic:-).

Edited by lucienEn
Link to comment
Share on other sites

6 minutes ago, lucienEn said:

Would have been nice to see the VDELP0/1 settings in the debugger but from the queued writes I think it can be derived.

If you look to the right of the orange outline you drew in the screenshot, you will see the 2 "VDEL" settings displayed (one for P0 and P1).

  • Like 1
Link to comment
Share on other sites

Yes just noticed those. Looking at Stella doc I noticed there is also a VDELBL. I need to further analyze how this works with the '3 copies' but seems this is required to be able to write longer lines of text.

 

Also interesting here is that both are set to be delayed. My guess is that you always have to write to both in pairs. Second it seems this only takes effect after the next statement but not right at the GRP write. The 'Queued Writes' says something like '1 clk, shuffle GRP1'. Not sure what that means exactly yet.

 

Still not completely clear what the red outlines mean around each player bit and what the 2 lines of bitmaps represent. I would think it's cached & current but not yet seeing that correspond to what I'm debugging.

Edited by lucienEn
  • Like 1
Link to comment
Share on other sites

1 hour ago, lucienEn said:

I need to further analyze how this works with the '3 copies' but seems this is required to be able to write longer lines of text.

 

VDEL was originally designed for smooth line-by-line vertical movement when using 2 Line Kernels.  You might like to check out my tutorial, Collect, which covers the writing a 2K game from scratch.  Step 4 covers the 2 Line Kernels. Later on they realized it could be used with both players set to 3 copies to draw 48 pixels, often used for a 6 digit display but also for things like the cars in Dragster

 

1 hour ago, lucienEn said:

Still not completely clear what the red outlines mean around each player bit and what the 2 lines of bitmaps represent.

 

From Stella Debugger documentation:

Quote

The debugger tracks changes to the CPU, TIA and RIOT registers and RAM by displaying changed locations or registers with a red background after each step, trace, scanLine, or frame advance. This sounds simple, and it is, but it's also amazingly useful.

 

 

Link to comment
Share on other sites

2 hours ago, lucienEn said:

The 'Queued Writes' says something like '1 clk, shuffle GRP1'. Not sure what that means exactly yet.

That means that the copying of GRP1 from the shadow buffer into the visible buffer is delayed by one pixel clock. These tiny delays can make a difference in tight kernels.

Link to comment
Share on other sites

1 hour ago, SpiceWare said:

 

VDEL was originally designed for smooth line-by-line vertical movement when using 2 Line Kernels.  You might like to check out my tutorial, Collect, which covers the writing a 2K game from scratch.  Step 4 covers the 2 Line Kernels. Later on they realized it could be used with both players set to 3 copies to draw 48 pixels, often used for a 6 digit display but also for things like the cars in Dragster

 

 

From Stella Debugger documentation:

 

 

Yes I checked earlier the Collect tutorial and it is great! Didn't go through all steps yet (but went through all of the 2600 programming book which I also have and 'Racing the Beam Explained' youtube video which is visually really helpful).

 

I was curious about the exact code used to multi-character lines in Circus Convoy etc. That's where I noticed the delays and 2 bitmap patterns in the debugger. But the debugger help itself doesn't go into any details. It seems upper line is buffer.

 

loop:
  sta WSYNC
  dec ram_84    ; next line to draw
  ldy ram_84    ; current line
  bmi exit

  lda (ram_E5),y     ; base: FA3F
  sta GRP0             ; pixels 1..8
  lda (ram_E7),y    
  sta GRP1             ; pixels 9..16
  lda (ram_E9),y    
  sta GRP0             ; pixels 17..24
  lda (ram_EF),y
  sta ram_82       
  lda (ram_ED),y
  tax
  lda (ram_EB),y
  ldy ram_82
  sta GRP1              ; pixels 25..32
  stx GRP0              ; pixels 33..40
  sty GRP1              ; pixels 41..48
  sta GRP0              ; why does this copy same pattern a P1?
  jmp loop

Link to comment
Share on other sites

1 hour ago, Thomas Jentzsch said:

That means that the copying of GRP1 from the shadow buffer into the visible buffer is delayed by one pixel clock. These tiny delays can make a difference in tight kernels.

Thanks. I'm getting to understand the code above and I wonder what it means if have both VDEL0 and VDEL1 set. Unless that got nothing to do what's in the player bitmaps bit more when the drawing occurs. In this case when GRP0 is written it will say:

Queued Writes:

1) 1 clk, $00 -> GRP0

2) 1 clk, shuffle GRP1

 

I think 'shuffle' means then copy from current shadow buffer since GRP0 triggered the write also to GRP1.

 

Now if GRP1 is written it will put 3 things in Queued writes:

 

1) 1 clk, $00 -> GRP1

2) 1 clk, shuffle GRP0

3) 1 clk, shuffle ENABL (not sure what this refers too, the ball object enable?)

Edited by lucienEn
Link to comment
Share on other sites

Thanks everyone to help explaining including the 48px link:-). Makes sense now how this works and I created something to visualize how Circus Convoy does the timing. To summarize:

 

Stella TIA Debugger explanation:

 

- Upper bitmap: shadow cache (also called 'new')

- Lower bitmap: current GRP bitmap

- Queues writes: shuffle: take current shadow and copy to GRP, otherwise straight value in 'new' register cache

- Red rectangle: change from previous state (for 1 instruction).

 

 

timing drawing chars.jpg

Edited by lucienEn
Fixed diagram
Link to comment
Share on other sites

In the TIA schematics, the two registers are called "new" (the upper one in the debugger) and "old" (the lower one). The Stella programmer's guide calls the "new" one simply as "GRP0/1" and the "old" one as "GRP0/1 delay" register. You can only directly write to the "new" registers. The "old" ones are updated by the TIA itself.

The Stella guide uses this diagram to show how, when the address of one of the GRPx registers appears on the address bus during a write operation, two writes actually occur: one to the destination "new" register, using the bits on the data bus, the other one to the other player "old" register, using the data from the corresponding "new" one.

VDEL.thumb.png.f5548684982239177b713622c7d0072b.png


So, when you write to GRP0, the value is stored into GRP0 "new", while at the same time the TIA automatically copies GRP1 "new" into GRP1 "old".

VDEL_GRP0.thumb.png.c77d7ced4d9936f8b66110538940aed0.png
In the same way, when you write to GRP1, you're writing into GRP1 "new", while the TIA copies GRP0 "new" into GRP0 "old"

.VDEL_GRP1.thumb.png.f85b9af08b17de35c1917f81a937f404.png

 

The above mechanism is always in place, no matter if VDELP0/VDELP1 are set or not.

 

The only thing that VDELxx does is to select which one between the "new" or "old" register will be used to draw the screen. If VDELxx is set, the "old" register is used, else the "new" one is. (In the diagram VDELxx is represented as a switch, selecting one of the two registers for the output). E.g.:

 

VDEL_bits.thumb.png.c9ad0c3c95c3dd351e41bd0cd2770108.png

Not shown in the diagram, the Ball also has a "new" and "old" ENABL registers. (there's just one bit, so the Ball is either on or off, and hence the name. But you can think of the ENABL register as a single pixel  "GRBL" register). ENABL "new" is copied into ENABL "old" whenever GRP1 is written to. Writing to ENABL sets the "new" register for the ball, but doesn't have any other effect.

VDELBL selects if the "new" or "old" ENABL value is used for the output to the screen.

 

Edited by alex_79
  • Like 3
  • Thanks 1
Link to comment
Share on other sites

Thanks very much, great explanation as I didn't find that explained in Stella reference. I did see 'old' and 'new' but ambiguous terms incl. 'shuffle' used in Stella debugger. I fixed my diagram above.

 

So my understanding of terminology used in Stella debugger for 'Queued writes':

 

Shuffle: copy from 'new' to 'old' (lower)

Direct 1 clock delayed write: write new value to 'new' register (not drawn)

Edited by lucienEn
Link to comment
Share on other sites

17 minutes ago, Thomas Jentzsch said:

AFAIK there is no official term for the "shuffle". Would make things easier.

'Cache' and 'active' register names would have been clear to me, but I know that's not the terminology originally used (e.g. 'new' and 'old').

But now I know and perhaps Stella could have used this instead but now I understand the meaning:-):

 

Write to GRP0 (with delays set):

 

1 clk, $0c -> GRP0 (new)

1 clk, GRP1 (new) -> GRP1 (old)

 

Or:

 

1 clk, $0c -> GRP0 (cache)

1 clk, GRP1 (cache) -> GRP1 (active)

Edited by lucienEn
Link to comment
Share on other sites

39 minutes ago, lucienEn said:

1 clk, $0c -> GRP0 (cache)

1 clk, GRP1 (cache) -> GRP1 (active)

That doesn't work quite well, as "cache" and "active" don't uniquely refer to a specific register. The "new" register would be the "cache" one if VDEL is set, or the "active" one if VDEL is not set. The "old" register would be the "active" one when VDEL is set, and you'd need to find another term to indicate it when VDEL is not set, as the "shuffle" would still take place in that case. I think that would be confusing.

 

The terms "new" and "old" are used in the Stella debugger documentation (you should be able to open the relative section of the manual if you have the TIA tab selected in the debugger and you press "F1" in Windows and Linux). The TIA Tab is already quite cramped, especially when using low resolutions, so adding labels to the registers and/or more verbose output in the "Queued Writes" area might not be a good idea.
Anyway, it would be useful to mention in the manual that "shuffle" indicates the copy of "new" register into the "old" one performed internally by the TIA.

 

 

 

Link to comment
Share on other sites

22 minutes ago, alex_79 said:

That doesn't work quite well, as "cache" and "active" don't uniquely refer to a specific register. The "new" register would be the "cache" one if VDEL is set, or the "active" one if VDEL is not set. The "old" register would be the "active" one when VDEL is set, and you'd need to find another term to indicate it when VDEL is not set, as the "shuffle" would still take place in that case. I think that would be confusing.

 

The terms "new" and "old" are used in the Stella debugger documentation (you should be able to open the relative section of the manual if you have the TIA tab selected in the debugger and you press "F1" in Windows and Linux). The TIA Tab is already quite cramped, especially when using low resolutions, so adding labels to the registers and/or more verbose output in the "Queued Writes" area might not be a good idea.
Anyway, it would be useful to mention in the manual that "shuffle" indicates the copy of "new" register into the "old" one performed internally by the TIA.

 

 

 

Got it, so in case of VDel set, the 'old ' value is being used to render, and otherwise the 'new' register (and 'old' is unused).

Not sure how I missed it when I checked debugger F1 help, but it's indeed described what is displayed. Shuffle isn't but I can't fault this excellent debugger and once you know it's pretty clear what's going on.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...