Jump to content
IGNORED

Sprite Positioning: Timing Confusion


Recommended Posts

*Accidentally didn't post this in the right sub-forum.  Hello, Atari VCS programmers.  I am confused with regards to the exercise for Chapter 9 on 8bitworkshop.com.  I've been following along with the companion book, "Making Games for the Atari 2600" and I'm finding discrepancies between the Javatari and Stella debugger.  Using both debuggers, I set a breakpoint at the blue highlighted line (included at end of post).  When I step past the first sta WSYNC instruction, the Javatari debugger shows 62 lines of the horizontal blank remaining, while Stella shows 68.  The Stella one made sense to me since my understanding is that the instruction pauses the 6507's execution until the start of the next scanline, and then you have a fresh 68 color clocks of horizontal blank to work with.  Is this incorrect?  Are the 3 cycles required for the instruction consumed on the previous scanline or the next scanline?  Both emulators display the same image, however, when the programs are executed.  

 

Also, when using the HMxx register, I have noticed some sources show a table like so:

image.png.7cb91dee315a37e34200b68f4ebbc5d3.png

 

while other sources (Stella programmer's guide) say it goes from -8 to +7 and the values are reversed.  Which one is it?  Using the table shown above and assuming there are only 62 lines left in the horizontal blank, the sprite position makes sense for the Javatari program, but the 62 doesn't make sense.  I appreciate any help you guys can provide to clear this confusion. 

 

 

; Instead of representing the horizontal position in CPU clocks,
; we're going to use TIA clocks.

    lda counter    ; load the counter as horizontal position
    and #$7f    ; force range to (0-127)
    
; We're going to divide the horizontal position by 15.
; The easy way on the 6502 is to subtract in a loop.
; Note that this also conveniently adds 5 CPU cycles
; (15 TIA clocks) per iteration.
    sta WSYNC    ; 35th line
    sta HMCLR    ; reset the old horizontal position
DivideLoop
    sbc #15        ; subtract 15
    bcs DivideLoop    ; branch until negative
; A now contains (the remainder - 15).
; We'll convert that into a fine adjustment, which has
; the range -8 to +7.
    eor #7
    asl        ; HMOVE only uses the top 4 bits, so shift by 4
    asl
    asl
    asl
; The fine offset goes into HMP0
    sta HMP0
; Now let's fix the coarse position of the player, which as you
; remember is solely based on timing. If you rearrange any of the
; previous instructions, position 0 won't be exactly on the left side.
    sta RESP0
; Finally we'll do a WSYNC followed by HMOVE to apply the fine offset.
    sta WSYNC    ; 36th line
    sta HMOVE    ; apply offset

Link to comment
Share on other sites

Regarding your WSYNC question: Stella's debugger is behaving correctly. After writing WSYNC, the TIA will pull RDY low until the beginning of the next HBLANK phase, which will stop the 6502 at the beginning of the next read cycle. Once the TIA enters HBLANK, RDY is pulled high again, and the CPU resumes with the read cycle in which it was suspended. So, after WSYNC, the CPU will continue loading and executing the next instruction (STA HMCLR in your case), and there will be 68 color clocks of HBLANK remaining for this and for the subsequent instructions.

 

Both types of tables that you quote are correct --- the programmer's guide talks about left shifts, while the source that you quote seems to refer to right shifts. In order to understand the assignment, consider how HMOVE actually works. All sprites (Missiles, Players, Ball) are essentially counters that go from 0 to 159 and that receive a pulse during every visible color clock. If HMOVE is strobed, HBLANK is extended by eight more color clocks during which the counters don't receive any pulses, which amounts  to an effective shift by eight pixels to the right. In addition, the TIA sends a bunch of extra pulses to the counters during HBLANK, the number of which is determined by the high nibble of HMP0 & friends, with the highest bit inverted.

 

A value of $80 means "no extra clocks at all", which amounts to a right shift of 8 pixels. $90 means one extra clock, which gives a right shift of 7 pixels.  A value of $60 means 14 extra clocks, which is a left shift of 6 pixels (eight pixels to the right and 14 to the left), and $70 means 15 extra clocks = 7 pixels left shift. Cleverly, this is equivalent to interpreting the hight nibble as a four bit signed integer:

 

  • $8 = -8 -> -8 pixels shift to the left
  • $9 = -7 -> -7 pixels shift to the left
  • ...
  • $F = -1 -> -1 pixels shift to the left
  • $0 = 0 -> no shift at all
  • $1 = 1 -> 1 pixels shift to the left
  • ...
  • $7 = 7 -> 7 pixels shift to the left

BTW, the details of HMOVE are also the reason for the strict timing requirements quoted by the programmer's guide: the TIA needs enough HBLANK time to send all extra pulses for HMOVE to work properly, so it should be strobed at the very beginning of HBLANK.

Edited by DirtyHairy
  • Like 3
Link to comment
Share on other sites

DirtyHairy, thank you for the response!  You showed me that the table confusion boiled down to a frame of reference problem that took me a while to wrap my head around.

 

I'm still a bit confused on the point you bring up regarding the technical details surrounding HMOVE.  You say to regard the sprites as counters from 0 to 159 that receive a pulse during every visible color clock.  Are these pulses only sent during the parts of the screen when the sprites are visible, or do they receive 159 pulses regardless of visibility?  You say visible color clock, so I assume the former.  I'm guessing the tia needs to know how many pulses to send during the HBLANK, before HMOVE is strobed? 

 

To confirm my understanding, the 8 extra color clocks added to HBLANK provide a buffer that allows the positioning of the sprites to be fine tuned since it could "draw" from the 8 tia clocks provided and return to "zero" position.  But it could also consume more than the added tia clocks during this period if you wanted to move the sprite positive pixels to the left, and these are the extra pulses that need to be accounted for and the reason why HMOVE is strobed at the beginning of HBLANK?  So in theory, say you only used the player 0 sprite, and wanted either a no shift, or negative shifts to the left (right movement).  Then could HMOVE not be strobed until tia color clock 68, since it would only pull from the now extended 8 clock HBLANK buffer of 76?  Or are there other technical reasons besides accounting for the extra pulses that enforce the strict timing requirement?  

Edited by DigitalAnthony
Link to comment
Share on other sites

Close, but not quite :) I skipped a bit of detail.

 

When I say that the sprites are counters that receive clocks during the visible part of the line, what I meant was outside of hblank, irrespective of whether they are visible or not. For each counter, there is a decode matrix, and when the counter reaches a particular value, the TIA starts to draw the sprite. Visibility just controls whether the drawn sprite actually ends up on screen.

 

If you strobe HMOVE, hblank is extended by eight clocks (this gives rise to the HMOVE bars on left edge of the screen). The consequence is that the sprite only receives 152 clocks on this line, and it will take eight more color clocks to reach the decode value and draw to the screen. This amounts to a right shift of 8 pixels.

 

Once HMOVE is strobed, there is a delay of 6 clocks, after which the TIA starts sending extra clocks to the sprites. An extra clock is sent every four color clocks. HMP0 and friends control the number of clocks sent to the corresponding sprite. If HMOVE starts with a "STA HMOVE", then it will take 9 color clocks until the 6502 writes to the register, and another 6 color clocks until the TIA will start sending extra clocks. It will take 15 * 4 = 60 color clocks to send all extra pulses so, all in all, doing a left shift by 7 pixels takes 75 clocks to complete. As hblank is extended by 8 color clocks during HMOVE, this fits, but just barely.

 

Hope this explanation helps ;)

Edited by DirtyHairy
  • Like 1
  • Thanks 2
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...