lucienEn Posted December 18, 2022 Share Posted December 18, 2022 (edited) 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 Thanks! Lucien Edited December 18, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 18, 2022 Author Share Posted December 18, 2022 (edited) 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 December 18, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
+splendidnut Posted December 18, 2022 Share Posted December 18, 2022 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). 1 Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 18, 2022 Author Share Posted December 18, 2022 (edited) 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 December 18, 2022 by lucienEn 1 Quote Link to comment Share on other sites More sharing options...
+SpiceWare Posted December 18, 2022 Share Posted December 18, 2022 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. Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted December 18, 2022 Share Posted December 18, 2022 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. Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 18, 2022 Author Share Posted December 18, 2022 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 Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 18, 2022 Author Share Posted December 18, 2022 (edited) 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 December 18, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
glurk Posted December 18, 2022 Share Posted December 18, 2022 You should read about (and understand) how the 48px kernel idea works. It's explained in various places, but I find this page to be a good explanation: https://bumbershootsoft.wordpress.com/2018/09/24/atari-2600-a-48px-kernel/ It explains how the VDELs work and why they are used (they serve as 'extra' registers) 1 Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted December 18, 2022 Share Posted December 18, 2022 1 hour ago, lucienEn said: 3) 1 clk, shuffle ENABL (not sure what this refers too, the ball object enable?) Yes. The ball can be "VDELed" too. And there the write to ENABL is delayed until one writes to GRP1. Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 18, 2022 Author Share Posted December 18, 2022 (edited) 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). Edited December 19, 2022 by lucienEn Fixed diagram Quote Link to comment Share on other sites More sharing options...
alex_79 Posted December 19, 2022 Share Posted December 19, 2022 (edited) 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. 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". In the same way, when you write to GRP1, you're writing into GRP1 "new", while the TIA copies GRP0 "new" into GRP0 "old" . 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.: 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 December 19, 2022 by alex_79 3 1 Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 19, 2022 Author Share Posted December 19, 2022 (edited) 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 December 19, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted December 19, 2022 Share Posted December 19, 2022 3 minutes ago, lucienEn said: I did see 'old' and 'new' but ambiguous terms incl. 'shuffle' used in Stella debugger. AFAIK there is no official term for the "shuffle". Would make things easier. Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 19, 2022 Author Share Posted December 19, 2022 (edited) 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 December 19, 2022 by lucienEn Quote Link to comment Share on other sites More sharing options...
alex_79 Posted December 19, 2022 Share Posted December 19, 2022 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. Quote Link to comment Share on other sites More sharing options...
lucienEn Posted December 19, 2022 Author Share Posted December 19, 2022 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.