Re: [stella] TIA latch timing

Subject: Re: [stella] TIA latch timing
From: "B. Watson" <urchlay@xxxxxxxxxxxxxxxx>
Date: Tue, 16 Oct 2001 15:53:30 -0400 (EDT)

On Tue, 16 Oct 2001, Eric Ball/Markham/IBM wrote:

> Is there a list somewhere which indicates the number of cycles after WSYNC
> when each TIA register is latched?  e.g. I believe the playfield registers
> are latched on color cycles 68 and 148 (left edge and middle of screen), so
> any updates to those registers need to be completed by CPU cycle 22 and 49.
> Also, are any registers not latched, so can only be updated during

Disclaimer: This is based on observed behavior, not actual knowledge of how
the hardware works...

I'm not sure they're latched, in the way you mean... if you change a TIA
register (PF0, say) while it's in the middle of being displayed, you will
actually see part of the old data and part of the new data.

Using PF0 as an example... PF0 is 4 playfield pixels, 16 color clocks wide.
Suppose that, on the previous scanline, you had stored $F0 into PF0 (only
the top 4 bits are used). If you don't update PF0 on this scanline, it'll
still have $F0. If you update PF0 before it starts getting drawn (cycle
22 or less), you'll see only new data. This much, you already knew.

Now, if you update PF0 at cycle 25, you're writing to PF0 while it's being
drawn. You're at color clock 75, or the 7th visible one on the scanline. The
TIA has already started drawing the old data from the previous scanline, now
you write $00 into it (it had $F0 before). You'll actually see something like
2 `on' pixels and 2 `off' pixels displayed on the TV.

Someone more hardware-oriented than I can probably explain what the TIA is
doing there... but I've observed this behavior on a real 2600 (by accident,
I had written an asymmetrical playfield routine that worked in xstella but
not on The Real Thing.)

For the playfield, it's not too hard to calculate at what cycle the data starts
being drawn. You take the color clock where the first pixel starts and convert
to CPU cycles, like so:

(layout for non-reflected playfields):

0   1       2       0   1       2       

(layout for reflected playfields):

0   1       2       2       1       0   

each dash is one PF pixel (you need to be looking at this with a fixed
font), and the numbers are at the pixel where each PF register starts
being displayed.

Each PF pixel is 4 clocks wide, so you want to multiply the pixel
position (0 to 39) by 4, then add 68 clocks for the HBLANK period,
then divide the whole mess by 3 for the CPU cycle, discarding any
fractional part of a cycle.

You end up with a table something like:

      Repeated PF                  Reflected PF
copy reg PFpixel CPUclock    copy reg PFpixel CPUclock
 1   PF0   0       22         1   PF0   0       22
 1   PF1   4       28         1   PF1   4       28
 1   PF2  12       38         1   PF2  12       38
 2   PF0  20       49         2   PF2  20       49
 2   PF1  24       54         2   PF1  28       60
 2   PF2  32       65         2   PF0  36       70

That CPU clock value tells you the last possible cycle when your
STA PF? instruction can end, if you want to update the register
before it gets displayed. Also, these numbers were arrived at by
calculation, but you may have to play with them some in practice.

For the color registers, I'm not sure how often the TIA samples
them but it's definitely possible to change colors in mid-scanline.

For the player & missile stuff, well, you're the one who times the
horizontal positioning, so you know at what color clock they start
getting drawn. If you're modifying GRP0/1 to draw a sprite, you just
have to make sure the data gets written before the TIA starts
displaying the player. If your players can be positioned anywhere
horizontally, this means you have to update GRP0/1 during the HBLANK,
or else you'll get sprites that appear to shift down one scanline
when they get too far to the left. This applies to ENAM0/1 and
ENABL too (the missiles and ball).

The HMOVE has to be written to right after a STA WSYNC, not sure what
the effects of breaking this rule are.

The HMP0/1 HMM0/1 HMBL registers aren't supposed to be written to until
24 CPU cycles after the last STA HMOVE (this applies to HMCLR too).
Again, I'm not sure what happens when you break this rule, but I think
I've read on this list that it's one of the few differences between
the original 2600 and the 2600jr (they respond differently when this
rule gets broken. Anyone care to elaborate?)

I'm not sure about the effects of messing with CTRLPF in mid-scanline.

The collision registers don't care when you reset them, but if you're
resetting them in mid-display, you should be doing it during the HBLANK

I'm at work right now (procrastinating, not working) so I can't
mess with my 2600, but this should give you a good starting point.

Hope this helps, and hope it doesn't contain too many errors...


Archives (includes files) at
Unsub & more at

Current Thread