Jump to content
IGNORED

RESP0 while pixel position is negative/low


louisg

Recommended Posts

I've been trying to get my own horizontal positioning code working, and have noticed something strange that I can't quite figure out. My demo program works when I pop in code by vdub bobby that I got from another thread. This code does STA RESP0 when the pixel position is -11, and the resulting coarse positioning of P0 is 6. My code, on the other hand, does STA RESP0 when the pixel position is 1 or -17 and I get the resulting coarse position of 3 in either case.

 

What exactly is going on here? And if I want to position an object at X=0, do I absolutely need my routine to map that as coarse=6 and fine=6-to-the-left ?

Link to comment
Share on other sites

I've been trying to get my own horizontal positioning code working, and have noticed something strange that I can't quite figure out. My demo program works when I pop in code by vdub bobby that I got from another thread. This code does STA RESP0 when the pixel position is -11, and the resulting coarse positioning of P0 is 6. My code, on the other hand, does STA RESP0 when the pixel position is 1 or -17 and I get the resulting coarse position of 3 in either case.

 

What exactly is going on here? And if I want to position an object at X=0, do I absolutely need my routine to map that as coarse=6 and fine=6-to-the-left ?

If you do a STA RESP0 at cycle 0 through cycle 22, you should get player 0 at screen position 3.

 

If you do a STA RESP0 at cycle 23, you should get player 0 at screen position 6.

 

Note that the cycle numbers mentioned actually refer to the cycle that comes immediately *after* the instruction, due to the way cycles are counted. That is, suppose you do a STA WSYNC and then a STA RESP0. The cycles would typically be counted as follows:

 

  STA WSYNC ; +3 ; 0
  STA RESP0 ; +3 ; 3

 

Of course, different programmers may use different notation, but I do it as shown above. The first number shows how many cycles the instruction takes, and the second number shows how many cycles have elapsed on the current scan line. In this example we can't tell which cycle the STA WSYNC instruction begins on, but we know that STA WSYNC will pause the CPU and it won't start processing again until cycle 0. That means the STA RESP0 instruction will begin at cycle 0 and end at cycle 2-- i.e., since it takes 3 cycles to execute, it will span cycles 0, 1, and 2. Thus, the next cycle *after* the STA RESP0 instruction will be cycle 3, which is also equal to the total number of cycles that have elapsed on the current scan line. Following the naming convention used when referring to HMOVE-- e.g., a "cycle 73 HMOVE" or a "cycle 74 HMOVE"-- this would be called a "cycle 3 RESP0" because the instruction takes effect at cycle 3. Actually, there's a lag between the end of the STA RESP0 instruction and player 0's new position, due to the way the TIA works, but the repositioning process starts as soon as the instruction ends. The amount of the lag depends on a few things, but the shortest lag for the two players is 5 color clocks.

 

I haven't seen your code or the code you're using from vdub bobby, but the only thing that comes to mind is that you might be referring to the color clock where the instruction *starts* rather than the color clock that comes after the instruction has completed. And it's possible you're using either absolute addressing or zero-page,X addressing or zero-page,Y addressing (which take 4 cycles) rather than zero-page addressing (which takes 3 cycles). Most positioning routines do use zero-page,X or zero-page,Y addressing, where the X or Y register is used to offest the target address so the same routine can be used for positioning any of the five sprites. So if that's what you're doing, the STA RESP0,X instruction takes 4 cycles or 12 color clocks. Hence if it starts at color clock 57 (or pixel -11), that would be cycle 19. But it spans cycles 19, 20, 21, and 22, therefore it doesn't take effect until cycle 23, which would produce a new player 0 position at pixel 6:

 

  STA RESP0,X ; +4 ; -11 ; 057 ; 19-22 ; 23 ; 069 ; 001 ; 006

 

The numbers given above are an expansion of the way I normally count cycles-- they show the number of cycles used by the instruction, the screen position the instruction starts on, the corresponding color clock, the cycles that the instruction spans, the cycle immediately following the instruction, the corresponding color clock, the corresponding screen position, and the new position of the sprite. Normally I would notate this as shown below (omitting the starting values and the cycles spanned by the instruction), but I gave the additional numbers above to help illustrate what I think may be going on.

 

  STA RESP0,X ; +4 ; 23 ; 069 ; 001 ; 006

 

If you did STA RESP0,X a cycle earlier, you would get the results you expected:

 

  STA RESP0,X ; +4 ; 22 ; 066 ; -02 ; 003

Edited by SeaGtGruff
Link to comment
Share on other sites

Hmm, it looks like sta RESP0 at cycle 23 gives me $F for the screen position. If I sta RESP0 exactly 20 cycles in, though, it gives me 6 for the position! I think this code is going to work. It's not as efficient as the one I found on the forum (I waste 5 cycles), but it's mine :)

 

And now I can see why the author of this positioning code I was looking at wanted to hit 6-- it so happens that this is the left-most position in my fine-tuning table, and since fine-tune is only 16 values signed, it's slim pickings! I think the only alternative may be to have a special case for the left-most values, or to just offset everything (maybe by using sprite wrapping on the right-most side..?)

 

I investigated the Air-Sea Battle code for a bit, and it looks like that one doesn't let sprites go all the way to the left (I think x=3 may have been the minimum..?). It's a fascinating system where getting full-range motion for sprites is considered a breakthrough!

 

So is it documented somewhere what X position you can expect when strobing the RESP0 register at various times? I'm assuming it's a constant lag time once the beam moves onto the visible screen (from "pixel position" 0 onward), but it seems unpredictable as long as the pixel position is negative, giving 3 for the majority of the time. I wonder if Atari programmers were armed with this knowledge, or if they were just winging it? I'm guessing when you're coding Atari games 8+ hours a day, you have the luxury of being able to experiment :)

 

BTW when I say pixel position, I'm thinking the counter in the Stella debugger.

 

Thanks so much for your help!

Link to comment
Share on other sites

It's easy enough to figure out.

 

(1) Take the number of the cycle that comes right after the RESxx completes.

(2) Multiply by 3 to get the equivalent color clock number.

(3) Add 4 if you're repositioning the ball or a missile, else add 5 if you're repositioning a player.

(4) Subtract 68 to convert the resulting (adjusted) color clock number into a screen (pixel) position.

 

If the final result is positive, that's the new position. If the final result is negative (i.e., inside the horizontal blanking area), the new position will generally be 2 for the missiles or ball, or 3 for the players-- those being the first values that fall within the active (visible) area.

 

However, if you strobe RESxx right after doing a standard HMOVE it seems to throw the repositioning off by 1, making the new positions 3 for the missiles or ball, or 4 for the players. But I'm not sure of the details-- i.e., whether it's anytime while HMOVE is feeding extra clocks to the position counters, or if there's some specific time frame involved-- so it's probably best to use trial and error to find the exact position if HMOVE is also involved.

 

Here's an example: Suppose you do a 3-cycle STA RESP0 that begins at cycle 25 and therefore spans cycles 25, 26, and 27. The next cycle is 28, so multiply by 3 (28*3=84), add 5 since a player is involved (84+5=89), and subtract 68 (89-68=21). So the new position will be at pixel 21.

Link to comment
Share on other sites

OK, so strobing at CPU cycles=20 isn't an anomaly then? Adding in the time the STA RESP0 takes, I get ((23*3)-68) + 5 = 6. Interesting! So the question isn't whether the pixel position is negative before RESP0, it's whether it's still negative *after* RESP0!

 

But this doesn't hold up for hitting X=0: If I do RESP0 starting at cycle 18, that gives me ((21*3)-68) + 5 = 0, but I wind up with X=3, exactly as if I had triggered it any time it's still negative. I guess the +5-pixel lag for P0 has to happen when the pixel position is past the horizontal blanking period or it always places it at X=3. This would mean the earliest it'll place P0 is at X=5 (triggering RESP0 exactly as the horizontal blanking period ends), not counting triggering it inside of horizontal blanking.

 

Is my understanding correct?

Edited by louisg
Link to comment
Share on other sites

I guess I messed up when I said "if the final result is positive." Here's a slightly modified set of steps that are more accurate:

 

(1) Take the number of the cycle that comes right after the RESxx completes.

(2) Multiply by 3 to get the equivalent color clock number.

(3) Add 4 to get the adjusted color clock number.

(4) Subtract 68 to convert the adjusted color clock number into a pixel position.

(5) If the result is negative, keep adding 3 to it until you get a positive value.

(6) If you're repositioning a player, add 1 more pixel.

 

The thing is, even though you have to add 5 instead of 4 to get the player's position, the TIA behaves as though the player starts 1 pixel earlier and is 9 pixels wide, but the leftmost pixel is always blank. You can read about the technical reasons for this in a document called "Atari 2600 TIA Hardware Notes" by Andrew Tower. So in the example you gave, it's actually ((21 * 3) + 4) - 68 = -1, which is negative, so you have to keep adding 3 until you get a positive number, or -1 + 3 = 2. Then you have to add 1 more because you're repositioning a player, so you end up with 2 + 1 = 3.

 

But there's an exception at the right edge of the screen. If you strobe RESxx such that the next cycle after the instruction ends is cycle 75, you get ((75 * 3) + 4) - 68 = (225 + 4) - 68 = 229 - 68 = 161. The color clocks go up to only 227 (i.e., color clock 228 = color clock 0), so that's actually 229 - 68 = (229 - 228) - 68 = 1 - 68 = -67, which is negative. However, the next cycle after the RESxx instruction ends is still within the active portion of the scan line, so the TIA is still clocking the sprite position counters, and the sprite's new position ends up at pixel 1, or at pixel 2 if it's a player. That's because the sprite position counters stop during the horizontal blank, which is why a sprite wraps around the screen if its left edge is near the right edge of the screen (i.e., the left side of the player is at the right side of the screen and the rest of the player gets drawn at the left side of the screen). So essentially the new position is 161 as computed the first time. Subtract 160 for the wraparound behavior, giving 161 - 160 = 1 for the ball or a missile. Then add 1 if you're repositioning a player.

 

As I mentioned before, it appears that repositioning a sprite while HMOVE is doing its thing causes the sprite to end up 1 pixel further to the right than expected, but I'm not sure of the specifics of that behavior.

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