Jump to content
IGNORED

Changing GRP0/1 during a single scanline


Recommended Posts

Hi all! I hope I haven't picked a dull or oft-asked question for my first post. Here goes:

 

Is there a document or forum post that explains exactly how and when the GRP0/1 registers are latched and used during the course of a scanline?

 

In particular, I'm trying to understand how the title graphics of the game E.T. are rendered. Each line of E.T.'s face comprises six sprite instances--three of player 0, three of player 1--that are interleaved to create a row of 48 pixels. I understand how NUSIZ0/1 are used to make each sprite appear three times, however the timing of the writes to GRP0/1 that permit all 48 pixels to be unique is more of a mystery.

 

Suggestions for further reading?

 

Kindest regards,

Aaron

Edited by jaholmes
Link to comment
Share on other sites

The short answer is that GRP0 and GRP1 are written to 3 times per scanline each. Each write needs to occur in the time between the respective sprite being rendered. So GRP1 is written to while GRP0 is being drawn on the screen and vice versa.

 

You should be able to search around the forum for lots of topics related to 48/96pixel kernels. Just keep in mind that these sort of techniques require timed code. In other words, you have to worry about how long each instruction takes to execute in addition to what it's doing. If you feel this is something you're ready for I would suggest starting with just a Player0 duplicate wide sprite and trying to get different graphics to be displayed on each copy. Also, make sure you lookup how to make use of the debugging facilities in stella.

Link to comment
Share on other sites

You should be able to search around the forum for lots of topics related to 48/96pixel kernels.

<snip>

If you feel this is something you're ready for I would suggest starting with just a Player0 duplicate wide sprite and trying to get different graphics to be displayed.

 

Thanks! I will certainly do that. I was hoping there'd be a timing diagram floating around--in fact, I'd almost swear I saw one, but now I've lost track of it--but I suppose a bit of experimenting could derive a practical one fairly quickly if I start simply enough. I'll give it a go.

 

"Ready for"? Probably not, heheh. :) I have a tendency--for better or worse!--to take a depth-first approach to learning these things.

 

Thanks again,

Aaron

Link to comment
Share on other sites

 

"Ready for"? Probably not, heheh. :) I have a tendency--for better or worse!--to take a depth-first approach to learning these things.

Isn't that the only way?

 

Don't forget that the TIA runs 3 times the clock rate of the 6507. That 8 pixel window to perform the write is only 2.66 CPU cycles. Storing a value to ZeroPage takes 3 CPU cycles. The reason the 48pixel is possible is because it starts ahead of the beam and just barely stays ahead of it. GRP0/1 can be set to the first graphic prior to the time sensitive section. The A, X, and Y registers can all be preloaded as well. That way during the time sensitive section all that needs to be done are writes.

 

Btw, I recently posted a demo that is similar to what you're asking about here: http://atariage.com/forums/topic/237574-demo-3-sprites-without-flicker/ Reviewing how that works might give you some further insight.

Link to comment
Share on other sites

The A, X, and Y registers can all be preloaded as well. That way during the time sensitive section all that needs to be done are writes.

 

Yes, in fact that's exactly what I see in the E.T. disassembly I have in front of me. I suppose, given the very limited number of CPU cycles available and the costly indirect+index addressing used to fetch the bitmaps--that's almost half the available cycles right there!--the number of different ways to do this particular maneuver is somewhat limited.

 

 

Btw, I recently posted a demo that is similar to what you're asking about here: http://atariage.com/forums/topic/237574-demo-3-sprites-without-flicker/ Reviewing how that works might give you some further insight.

 

That's pretty slick. Definitely will bookmark this as an example. Thanks!

Aaron

Link to comment
Share on other sites

You need to enable VDELP0 and VDELP1. This lets you write the graphics values for the first three sprites early in the loop, leaving just three more that will need to be written with rapid timing. Then read the graphics values for the last three sprites into A, X, and Y. Finally, write A, X, and Y one after the other into GRP0 and GRP1; you'll need to include an extra write so the last sprite will be changed.

Link to comment
Share on other sites

Head over to MiniDig. You'll find lots of useful info there. For your question, check out 48 pixel sprite and VDEL explained.

 

I've also done up a blog series, Collect, which covers the development of a 2K game. While I don't cover 48 pixel sprites in it, you may find it helpful for other things.

Link to comment
Share on other sites

Thanks guys! I really appreciate all the helpful responses I'm getting.

 

Finally, write A, X, and Y one after the other into GRP0 and GRP1; you'll need to include an extra write so the last sprite will be changed.

 

For your question, check out <snip> VDEL explained.

 

Perfect! I get it now. :) I couldn't figure out why I was seen eight writes for 48 pixels. Looking back at the Stella guide, I sort of get what it's saying now, but the practical implications are much less clear from its wording.

 

Thanks again,

Aaron

 

Link to comment
Share on other sites

I couldn't figure out why I was seen eight writes for 48 pixels.

 

You don't need eight writes, just seven:

 

(1) Write GRP0-- with VDELP0 enabled, this updates the "new" copy of P0 but the "old" copy is still displayed onscreen.

(2) Write GRP1-- with VDELP1 enabled, this updates the "new" copy of P1 but the "old" copy is still displayed; and with VDELP0 enabled, this also updates the "old" copy of P0 from its "new" copy.

(3) Write GRP0-- this updates the "new" copy of P0, and also updates the "old" copy of P1 from its "new" copy.

 

These first three writes let you set up the first three sprites ahead of time (i.e., early on in the scan line, or possibly even during the latter part of the previous scan line depending on the horizontal positions of the sprites), but the data for the third sprite is "held in reserve" for the time being. Then you load A, X, and Y with the data for the last three sprites-- which takes a little juggling, since you're also using Y as an index into the graphics tables-- and time the last four writes so they occur neither too early nor too late:

 

(4) Write GRP1-- this updates the "new" copy of P1, and also updates the "old" copy of P0 from its "new" copy; so this write must finish executing sometime after the first sprite has finished being drawn but before the third sprite needs to start being drawn.

(5) Write GRP0-- this updates the "new" copy of P0, and also updates the "old" copy of P1 from its "new" copy; so this write must finish executing sometime after the second sprite has finished being drawn but before the fourth sprite needs to start being drawn.

(6) Write GRP1-- this updates the "new" copy of P1, and also updates the "old" copy of P0 from its "new" copy; so this write must finish executing sometime after the third sprite has finished being drawn but before the fifth sprite needs to start being drawn.

(7) Write GRP0-- this updates the "new" copy of P0, and also updates the "old" copy of P1 from its "new" copy; so this write must finish executing sometime after the fourth sprite has finished being drawn but before the sixth sprite needs to start being drawn.

 

It doesn't matter whether you write A, X, or Y to GRP0 in the last step, because the "new" copy of P0 won't be displayed anyway-- this extra write is strictly to ensure that the sixth sprite displays the correct graphics.

 

It also doesn't matter whether you arrange the sprites as P0-P1-P0-P1-P0- P1 or as P1-P0-P1-P0-P1-P0, although if you decide to position P1 first then you'll need to change the order of the writes to P1-P0-P1-P0-P1-P0-P1.

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

 

You don't need eight writes, just seven:

 

(detailed explanation of write ordering)

 

Thanks a ton for this, SeaGtGruff. Fiddling with it in DASM+Stella right now.

 

(And about to pull the trigger on a Harmony so that I can test my timing on the Real Thing when the time comes...)

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...