
===================================================================
Atari 2600 TIA Hardware Notes
===================================================================

v1.0 6-March-2003
by Andrew Towers
mariofrog@bigpond.com


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ TIA Hardware Notes (a Small Opus on the TIA)

Following is a whole bunch of notes on the TIA I made while I
was trying to work out how the whole thing is put together.
You'll need a copy of the TIA schematics to understand the more
complicated bits of this since I was looking at them when I
wrote it. According to my copy they were scanned in by Mark De
Smet. They are now available for download from AtariAge at:
http://www.atariage.com/2600/archives/schematics_tia/index.html

I started out searching through the stella archives for any info
on triggering the players more than once per scanline (at the
time I wanted to draw more than the 12 copies possible by flicker
and 3-repeat) - and I came across Eckhard Stolberg's 'grid2' demo
from Oct 1998, followed by a long series of threads over several
months discussing how the technique actually manages to work =)
From all the articles it looked like a complete black art and
no-one had a theory that would explain it fully.

Then I came across the TIA-1A schematics, and proceeded to spend
the next 3-4 days solid drinking copious amounts of coffee and
taking very little sleep while I tried to figure the whole mess
out from the gate level up. (hey, the 2600 is a new hobby, I can
splurge ;) In the end I found that as usual writing a 'few quick
notes' turned into 'writing a tutorial' or, 'a small opus on the
TIA'. So, here we go.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Polynomial Counters, what the heck is this?

Almost all of the timing and counting within the TIA is implemented
in the form of "polynomial counters", so this seems a good place to
start. If you've never come across these before (I hadn't) they
seem a really obscure way to go about counting things, but they're
very small and simple to implement and therefore cheap on silicon.
They also have the useful property that 'adding 1' takes linear
time (unlike a ripple-carry adder/counter) - as long as you don't
want to know where you're up to in traditional binary numeric form,
they're perfect ;)

Actually, as the TIA designers pointed out, you can use a small
lookup table to convert from one to the other, and you can compare
two counter states to see if you're up to the same count without
knowing the numeric values. But this is getting off track and
hand-wavery. If you want to know the maths behind polynomial
counters I suggest you look elsewhere, I'm no mathematician ;)
These things seem to be used as pseudo-random number generators or
noise generators (see the TIA sound generator, ditto for the GBA)
more than anything else.

A polynomial counter (actually a form of "Linear Feedback Shift
Register") consists of a shift register, as the name suggests,
with some sort of feedback logic - in this case a single two-
input XNOR gate obfuscated in NOR logic. They have the property
that they will step through up to (2^n)-1 unique states when
optimally wired up, from any starting state except for the illegal
state (and of course it's possible to power-up in the illegal
state =) so for a 6-bit shift register there can be at most 63
valid states.

The TIA uses the same polynomial counter circuit for all of its
horizontal counters - there is a HSync counter, two Player
Position and two Missile Position counters, and the Ball Position
counter. The sound generator has a more complex design involving
another polynomial counter or two - I haven't delved into the
workings of this one yet.

Beside each counter there is a two-phase clock generator. This
takes the incoming 3.58 MHz colour clock (CLK) and divides by
4 using a couple of flip-flops. Two AND gates are then used to
generate two independent clock signals thusly:
 __          __          __
_| |_________| |_________| |_________  PHASE-1 (H@1)
       __          __          __
_______| |_________| |_________| |___  PHASE-2 (H@2)

You'll need a thingo, fixed-spacing font, to make sense of that.
The two clock lines are used to perform a two-step increment
of the counter, as well as being used independently to move
data through the supporting clocked logic.

This concept seems to come up a -lot- in the TIA, I think it's
some sort of Zen NMOS thing, it seems to go hand and hand with
storing data in back of inverters all over the place (a * is used
in the TIA schematics to denote this), and building bit-shifting
chains into your data storage so you don't need addressing ;p
If you've ever wondered why the Playfield bit order is so obscure,
now you know.

Each counter has a wired-AND counter state decode matrix (woo..)
connected in parallel with the shift register. In every case,
the top line of the decoder on the schematics checks for '111111'
and forces a Reset if it is encountered. This is to prevent the
counter getting stuck in the illegal state when it powers up as
mentioned earlier.

Also in every case, the next decoder line is the 'wrap-around'
value - when this state comes up, the counter does a self-reset
to 000000 on the next phase-2 clock, and usually does something
useful like generating a START signal for graphics output.

The rest of the counter decodes depend entirely on which counter
we're looking at, set let's get into 'em.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Horizontal Sync Counter

The HSync counter counts from 0 to 56 once for every TV scan-line
before wrapping around, a period of 57 counts at 1/4 CLK (57*4=228
CLK). The counter decodes shown below provide all the horizontal
timing for the control lines used to construct a valid TV signal.

This table shows the elapsed number of CLK, CPU cycles, Playfield
(PF) bits and Playfield pixels at the start of each counter state
(ie when the counter changes to this state on the rising edge of
the H@2 clock). The decoded control lines are usually clocked into
other logic blocks during the next H@1-H@2 cycle (within 4 CLK).

Value	HCount	CLK	CPU	PF	Pixel	Control

000000	0	0	0
100000	1	4	1.3
110000	2	8	2.6
111000	3	12	4
111100	4	16	5.3			Set H-SYNC [SHS]
111110	5	20	6.6
011111	6	24	8
101111	7	28	9.3
110111	8	32	10.6			Reset H-SYNC [RHS]
111011	9	36	12
111101	10	40	13.3
011110	11	44	14.6
001111	12	48	16			ColourBurst [RCB]
100111	13	52	17.3
110011	14	56	18.6
111001	15	60	20
011100	16	64	21.3			Reset H-BLANK [RHB]
101110	17	68	22.6	0	0
010111	18	72	24	1	4	Late RHB [LRHB]
101011	19	76	25.3	2	8
110101	20	80	26.6	3	12
011010	21	84	28	4	16
001101	22	88	29.3	5	20
000110	23	92	30.6	6	24
000011	24	96	32	7	28
100001	25	100	33.3	8	32
010000	26	104	34.6	9	36
101000	27	108	36	10	40
110100	28	112	37.3	11	44
111010	29	116	38.6	12	48
011101	30	120	40	13	52
001110	31	124	41.3	14	56
000111	32	128	42.6	15	60
100011	33	132	44	16	64
110001	34	136	45.3	17	68
011000	35	140	46.6	18	72
101100	36	144	48	19	76	Center [CNT]
110110	37	148	49.3	20	80
011011	38	152	50.6	21	84
101101	39	156	52	22	88
010110	40	160	53.3	23	92
001011	41	164	54.6	24	96
100101	42	168	56	25	100
010010	43	172	57.3	26	104
001001	44	176	58.6	27	108
000100	45	180	60	28	112
100010	46	184	61.3	29	116
010001	47	188	62.6	30	120
001000	48	192	64	31	124
100100	49	196	65.3	32	128
110010	50	200	66.6	33	132
011001	51	204	68	34	136
001100	52	208	69.3	35	140
100110	53	212	70.6	36	144
010011	54	216	72	37	148
101001	55	220	73.3	38	152	
010100	56	224	74.6	39	156	RESET, HBLANK [SHB]
101010	57	(228)	(76)	(40)	(160)	(already at 000000)
010101	58	232	-	-	-
001010	59	236	-	-	-
000101	60	240	-	-	-
000010	61	244	-	-	-
000001	62	248	-	-	-
000000	0	0	-	-	-	(cycle)
111111	-	-	-	-	-	ERROR (Reset to 000000)

Key:
SHS   Turn on the TV HSYNC signal to start Horizontal flyback.
RHS   Turn off the HSYNC signal, delayed 4 CLK.
RCB   Reset Colour Burst, delayed 4 CLK latching [CB].
RHB   Reset HBlank (enable output), delayed 4 CLK latching [HB].
LRHB  Late RHB, used instead of RHB when [HMOVE] latch is set.
CNT   Center screen, start copy/reflect PF, delayed 4 CLK for [CNTD].
SHB   Start HBlank (disable output), Reset HCount to 000000.

The HSync counter resets itself after 57 counts; the decode on
HCount=56 performs a reset to 000000 delayed by 4 CLK, so
HCount=57 becomes HCount=0. This gives a period of 57 counts
or 228 CLK.

Playfield pixels start on the [RHB] control line at CLK=64, but
the first visible pixel won't appear until CLK=68 due to the
clocking on its output. The [CNT] control line either starts the
Playfield again as normal, or starts a reverse-shifted copy when
reflect-playfield [REF] is enabled.

RSYNC resets the two-phase clock for the HSync counter to the
H@1 rising edge when strobed. It looks like this could be used
to move the HSync counter into phase with the CPU on any cycle
(although there is some auto-synchronisation between the two-phase
clock and the div-by-3 counter for the CPU clock, I haven't looked
into this yet.) A full H@1-H@2 cycle after RSYNC is strobed, the
HSync counter is also reset to 000000 and HBlank is turned on.
This one requires more investigation.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Player 0 and Player 1 Horizontal Position Counters

There are two independent Player Horizontal Position Counters, one
each for player 0 and player 1. The counters are identical; only
one is drawn in the schematics. This section describes only the
player 0 counter.

The player position counter controls the position of the player
graphics object (P0) on each scanline. The player counter counts
from 0 to 39 and then wraps around, giving a period of 40 counts
at 1/4 CLK (160 CLK) - also the number of visible pixels on a
scanline.

This table shows the elapsed number of CLK and CPU cycles at the
beginning of each counter state (the CPU column isn't particularly
relevant). Each START decode is delayed by 4 CLK in decoding, plus
a further 1 CLK to latch the STARTat the graphics scan counter.
The START decodes are ANDed with flags from the NUSIZ register
before being latched, to determine whether to draw that copy.
Actual graphics output is shown in parentheses for non-stretched
copies of the player.

Value	PCount	CPU	CLK	Event

000000	0	0	0	(draw -012)
100000	1	1.3	4	(draw 3456)
110000	2	2.6	8	(draw 7---)
111000	3	4	12	START DRAWING (NUSIZ=001,011)
111100	4	5.3	16	(draw -012)
111110	5	6.6	20	(draw 3456)
011111	6	8	24	(draw 7---)
101111	7	9.3	28	START DRAWING (NUSIZ=011,010,110)
110111	8	10.6	32	(draw -012)
111011	9	12	36	(draw 3456)
111101	10	13.3	40	(draw 7---)
011110	11	14.6	44
001111	12	16	48
100111	13	17.3	52
110011	14	18.6	56
111001	15	20	60	START DRAWING (NUSIZ=100,110)
011100	16	21.3	64	(draw -012)
101110	17	22.6	68	(draw 3456)
010111	18	24	72	(draw 7---)
101011	19	25.3	76
110101	20	26.6	80
011010	21	28	84
001101	22	29.3	88
000110	23	30.6	92
000011	24	32	96
100001	25	33.3	100
010000	26	34.6	104
101000	27	36	108
110100	28	37.3	112
111010	29	38.6	116
011101	30	40	120
001110	31	41.3	124
000111	32	42.6	128
100011	33	44	132
110001	34	45.3	136
011000	35	46.6	140
101100	36	48	144
110110	37	49.3	148
011011	38	50.6	152
101101	39	52	156	RESET, START DRAWING (always)
010110	40	53.3	160	(already at 000000)
001011	41	54.6	
100101	42	56	
010010	43	57.3	
001001	44	58.6	
000100	45	60	
100010	46	61.3	
010001	47	62.6	
001000	48	64	
100100	49	65.3	
110010	50	66.6	
011001	51	68	
001100	52	69.3	
100110	53	70.6	
010011	54	72	
101001	55	73.3	
010100	56	74.6	
101010	57	76	
010101	58	-
001010	59	-
000101	60	-
000010	61	-
000001	62	-
000000	0	-		(cycle)
111111	-	-		ERROR (Reset to 000000)

The graphics output for players contains some extra clocking
logic not present for the Playfield or other screen objects.
It takes 1 additional CLK to latch the player START signal.
The rest of the clocking logic is in common with the other
grahpics objects; therefore we can say that player grahpics
are delayed by 1 CLK (this is why the leftmost possible start
position for a RESP0 is pixel 1, not pixel 0. You can HMOVE
the player further left though, if necessary.)

The most important thing to note about the player counter is
that it only receives CLK signals during the visible part of
each scanline, when HBlank is off; exactly 160 CLK per scanline
(except during HMOVE). During the other 68 CLK per line, the
counter lies dormant on the exact 1/4 phase it was up to.
The [MOTCK] (motion clock?) line supplies the CLK signals
for all movable graphics objects during the visible part of
the scanline. It is an inverted (out of phase) CLK signal.

This arrangement means that resetting the player counter on any
visible pixel will cause the main copy of the player to appear
at that same pixel position on the next and subsequent scanlines.
There are 5 CLK worth of clocking/latching to take into account,
so the actual position ends up 5 pixels to the right of the
reset pixel (approx. 9 pixels after the start of STA RESP0).

For better or worse, the manual 'reset' signal (RESP0) does not
generate a START signal for graphics output. This means that
you must always do a 'reset' then wait for the counter to
wrap around (160 CLK later) before the main copy of the player
will appear. However, if you have any of the 'close', 'medium'
or 'far' copies of the player enabled in NUSIZ, these will be
drawn on the current and subsequent scanlines as the appropriate
decodes are reached and generate their START signals.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Player 0 and Player 1 Graphics Scan Counters

The Player Graphics Scan Counters are 3-bit binary ripple counters
attached to the player objects, used to determine which pixel
of the player is currently being drawn by generating a 3-bit
source pixel address. These are the only binary ripple counters
in the TIA.

The Scan Counters are never reset, so once the counter receives
the Start signal it will count fully from 0 to 7. Counting is
only performed during the visible part of the scanline since
it is driven by the [MOTCK] line used to advance the Player
Position Counter. This gives rise to "sprite wrapping" whereby
a player positioned so it ends past the righthand side of the
screen will finish drawing at the beginning of the next scanline.
Note that a HMOVE can gobble up the wrapped player graphics -
see below.

The count frequency is determined by the NUSIZ register for that
player; this is used to selectively mask off the clock signals to
the Graphics Scan Counter. Depending on the player stretch mode,
one clock signal is allowed through every 1, 2 or 4 graphics CLK.
The stretched modes are derived from the two-phase clock; the H@2
phase allows 1 in 4 CLK through (4x stretch), both phases ORed
together allow 1 in 2 CLK through (2x stretch).

The NUSIZ register can be changed at any time in order to alter
the counting frequency, since it is read every graphics CLK.
This should allow possible player graphics warp effects etc.

Player Reflect bit - this is read every time a pixel is generated,
and used to conditionally invert the bits of the source pixel
address. This has the effect of flipping the player image drawn.
This flag could potentially be changed during the rendering of
the player, for example this might be used to draw bits 01233210.

Player graphics registers - there are four 8-bit registers in the
TIA for storing Player graphics, two for each player. Only two
of these are ever directly accessible; these are labelled the
"new" player graphics registers on the schematics. Unless the
Player Vertical Delay (VDELPn) is set, the "new" registers are
always drawn.

Writes to GRP0 always modify the "new" P0 value, and the
contents of the "new" P0 are copied into "old" P0 whenever
GRP1 is written. (Likewise, writes to GRP1 always modify the
"new" P1 value, and the contents of the "new" P1 are copied
into "old" P1 whenever GRP0 is written). It is safe to modify
GRPn at any time, with immediate effect.

Vertical Delay bit - this is also read every time a pixel is
generated and used to select which of the "new" (0) or "old" (1)
Player Graphics registers is used to generate the pixel. (ie
the pixel is retrieved from both registers in parallel, and
this flag used to choose between them at the graphics output).
It is safe to modify VDELPn at any time, with immediate effect.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Missile 0 and Missile 1 Horizontal Position Counters

There are also two individual Horizontal Position Counters for
missile 0 and missile 1. The counters are independent and identical.

These counters use exactly the same counter decodes as the players,
but without the extra 1 CLK delay to start writing out graphics.

Missiles use the same control lines as the player from the NUISZ
register to determine the number of copies drawn, although they
ignore the player scaling options (you'll just get a single copy
for the scaled player modes).

Missile width is implemented in the same way as the ball width; it
appears to be exactly the same gate arrangement (see below).

The Missile-to-player reset is implemented by resetting the M0
counter when the P0 graphics scan counter is at %100 (in the middle
of drawing the player graphics) AND the main copy of P0 is being
drawn (ie the missile counter will not be reset when a subsequent
copy is drawn, if any). This second condition is generated from a
latch outputting [FSTOB] that is reset when the P0 counter wraps
around, and set when the START signal is decoded for a 'close',
'medium' or 'far' copy of P0.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Ball Horizontal Position Counter

The ball position counter controls the position of the ball
graphics object (BL) on each scanline. The ball counter counts
from 0 to 39 and then wraps around, giving a period of 40 counts
at 1/4 CLK (160 CLK).

Ball width is given by combining clock signals of different widths
based on the state of the two size bits (the gates form an AND ->
OR -> AND -> OR -> out arrangement, with a hanger-on AND gate).
See notes later for all the messy details ;p

It seems a shame to have a whole polynomial counter for the ball, and
no special effects aside from its size - except for one small detail.

If you look closely at the START signal for the ball, unlike all
the other position counters - the ball reset RESBL does send a START
signal for graphics output! This makes the ball incredibly useful
since you can trigger it as many times as you like across the same
scanline and it will start drawing immediately each time :)

So it's good for cutting holes in things, drawing background details,
clipping the edges off things, etc. It can even be used to draw simple
sprites, or used as the background colour (because it's behind
everything else) for a two-colour sprite.

Actually on my 2600jr (long rainbow), setting the ball size to 8
pixels results in solid colour when it's reset every 9 pixels
(this might just be colour bleeding, I'm not sure).

Value	BCount	CPU	CLK	Event

000000	0	0	0	(draw 0123)
100000	1	1.3	4	(draw 4567)
110000	2	2.6	8
111000	3	4	12
111100	4	5.3	16
111110	5	6.6	20
011111	6	8	24
101111	7	9.3	28
110111	8	10.6	32
111011	9	12	36
111101	10	13.3	40
011110	11	14.6	44
001111	12	16	48
100111	13	17.3	52
110011	14	18.6	56
111001	15	20	60
011100	16	21.3	64
101110	17	22.6	68
010111	18	24	72
101011	19	25.3	76
110101	20	26.6	80
011010	21	28	84
001101	22	29.3	88
000110	23	30.6	92
000011	24	32	96
100001	25	33.3	100
010000	26	34.6	104
101000	27	36	108
110100	28	37.3	112
111010	29	38.6	116
011101	30	40	120
001110	31	41.3	124
000111	32	42.6	128
100011	33	44	132
110001	34	45.3	136
011000	35	46.6	140
101100	36	48	144
110110	37	49.3	148
011011	38	50.6	152
101101	39	52	156	RESET, START DRAWING
010110	40	53.3
001011	41	54.6	
100101	42	56	
010010	43	57.3	
001001	44	58.6	
000100	45	60	
100010	46	61.3	
010001	47	62.6	
001000	48	64	
100100	49	65.3	
110010	50	66.6	
011001	51	68	
001100	52	69.3	
100110	53	70.6	
010011	54	72	
101001	55	73.3	
010100	56	74.6	
101010	57	76	
010101	58	-
001010	59	-
000101	60	-
000010	61	-
000001	62	-
000000	0	-		(cycle)
111111	-	-		ERROR (Reset to 000000)

Vertical Delay bit - the VDELBL control bit works in the same
manner as the player VDEL bits; the state of VDELBL is used
every CLK to determine which of the "new" (0) or "old" (1)
ENABL values to use at the graphics output. Writes to ENABL
always modify the "new" value, and whenever GRP1 is written
the "new" value is copied into the "old". It is safe to
modify VDELBL and ENABL at any time, with immediate effects.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Using the Horizontal Position Counters

The documented way to use a player position counter is to reset
it with RESPn on any CPU cycle divisible by 5 during the visible
scanline (5 is a convenient number for DEX-BNE loops), set up
HMPn to adjust the position by +7 (left) to -8 (right) pixels,
and hit HMOVE immediately after the next WSYNC. Then configure
NUSIZn for the number and spacing of copies required, and let
the hardware go about its business. Once this is set up, you
can just change the grpahics in GRPn every scanline to get one,
two or three copies at fixed spacing.

In fact the hardware has hard-wired requirements for almost none
of the above =) The fixed spacing between copies is hard-wired
and HMOVE is largely not negotiable, but the rest is complete
tosh.

The TIA renders each movable graphics object according to
independent position counters running at 1/4 CLK with a period
of 40 increments, and synchronised to the last RESPn/RESMn/RESBL
strobe. Each and every time a counter wraps around, the 'main'
copy of the object starts to draw. Since it takes 4 CLK to reset
the counter to zero and 4 CLK to increment the counter, the image
can be expected to appear after exactly 40 full counts, or 160 CLK.

The counters are normally only running during the 'visible' part
of a scanline, unless you're doing a HMOVE. Since the scanline
has 160 visible pixels, this yields the documented behavior that
a RESPn/etc sets the position for the next scanline. It's out
by 5 pixels when you set it, but who's counting?

Due to extra clocking logic for Player graphics output, the first
player pixel won't appear until 1 CLK later than for any other
grahpics object once rendering 'starts'. See the HSync/Player
Counter info above for an explanation of this.

During the horizontal blank (see the Horizontal Counter info
above) the Player, Missile and Ball counters stop receiving
CLK signals, so they pause on the exact 1/4 CLK they're up to
and resume where they left off at the first visible pixel on
the next scanline. This gives rise to the 'wrap around' effect,
to the point of splitting a copy of the player image in half
because it happened to start too near the right edge of the
screen ;)

The object counters are running at the same 1/4 CLK rate as the
HSync counter, but you can set them out of phase with the HSync
counter (and therefore the Playfield) by resetting any of them
on a CPU cycle that isn't divisible by 4. (If this were not the
case, there would only be 40 possible positions along the
scanline and we could all go home early). You can also use the
HMOVE command, which is described below.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Playing with the HMOVE registers

In principle the operation of HMOVE is quite straight-forward;
if a HMOVE is initiated immediately after HBlank starts, which
is the case when HMOVE is used as documented, the [HMOVE] signal
is latched and used to delay the end of the HBlank by exactly
8 CLK, or two counts of the HSync Counter. This is achieved in
the TIA by resetting the HB (HBlank) latch on the [LRHB] (Late
Reset H-Blank) counter decode rather than the normal [RHB] (Reset
H-Blank) decode.

The extra HBlank time shifts everything except the Playfield
right by 8 pixels, because the position counters will now
resume counting 8 CLK later than they would have without the
HMOVE. This is also the source of the HMOVE 'comb' effect;
the extended HBlank hides the normal playfield output for the
first 8 pixels of the line.

In order to move less than 8 pixels right the TIA performs
'clock stuffing' on the Player, Missile and Ball position
counters, whereby a number of clock pulses between 0 and 15
are sent to the counters during HMOVE. Each extra clock pulse
eats up 1/4 count in the object's horizontal position counter,
and thereby moves the object left one pixel. This must be done
during HBlank because it is sending these extra clock pulses
down the same clock lines that usually receive [MOTCK] pulses
during the visible part of the scanline.

The Stella Programmer's Guide states that "the motion registers
should not be modified for at least 24 machine cycles after an
HMOVE command". This is indeed for internal hardware
considerations, although perhaps not entirely mysterious.
After several attempts, I finally got my head around the
heavily obfuscated logic in the schematics. It turns out to
be fairly simple, and quite elegant :)

The HMOVE values set by the programmer are stored in a matrix
of 4-bit data latches with built-in comparators - each latch
effectively contains a wired-XOR gate, and the 4 latches for
a given HMxx register are arranged in a wired-NOR formation
to give a 4-bit comparator.

Beside the matrix of HMxx latches is a 4-bit binary ripple
counter. It begins at 15 and decrements down to zero during
the HMOVE at a rate of 1 decrement every 4 CLK (it's built
from 2-phase clocked logic). The counter is wired in parallel
to the comparators in all 5 HMxx registers.

At the beginning of the HMOVE, a latch is set for each movable
object to indicate that it requires more motion to the left.
When the comparator for a given object detects that none of
the 4 bits match the bits in the counter state, it clears this
latch (a clever exercise in reverse logic!) Until this time,
the output of the latch is sent through to the movable object
once every 4 CLK (on every H@1 signal from the HSync two-phase
clock) as an extra "stuffed" clock signal.

Since one extra CLK pulse is sent every 4 CLK, this takes at
most 4*16=64 CLK (including counter reset at the end), or
64/3=21 CPU cycles. It takes 3 CLK after the HMOVE command
is received to decode the [SEC] signal (at most 6 CLK depending
on the timing of STA HMOVE) and a further 4 CLK to set the
"more movement required" latches. So we need to wait at least
71/3=23.66 CPU cycles before the HMOVE operation is complete.
For a normal HMOVE after WSYNC, it might be safe by cycle 23
(this has not been tested).

The first compare (against 15) will be sampled 15 CLK after STA
HMOVE begins and every 4 CLK thereafter. The first counter
decrement will happen at CLK 17, and every 4 CLK thereafter.

You may have noticed that the above discussion ignores the
fact that HMxx values are specified in the range +7 to -8.
In an odd twist, this was done purely for the convenience
of the programmer! The comparator for D7 in each HMxx latch
is wired up in reverse, costing nothing in silicon and
effectively inverting this bit so that the value can be
treated as a simple 0-15 count for movement left. It might
be easier to think of this as having D7 inverted when it
is stored in the first place.

In theory then the side effects of modifying the HMxx registers
during HMOVE should be quite straight-forward. If the internal
counter has not yet reached the value in HMxx, a new value greater
than this (in 0-15 terms) will work normally. Conversely, if
the counter has already reached the value in HMxx, new values
will have no effect because the latch will have been cleared.

Much more interesting is this: if the counter has not yet
reached the value in HMxx (or has reached it but not yet
commited the comparison) and a value with at least one bit
in common with all remaining internal counter states is
written (zeros or ones), the stopping condition will never be
reached and the object will be moved a full 15 pixels left.
In addition to this, the HMOVE will complete without clearing
the "more movement required" latch, and so will continue to send
an additional clock signal every 4 CLK (during visible and
non-visible parts of the scanline) until another HMOVE operation
clears the latch. The HMCLR command does not reset these latches.

The Cosmic Ark stars effect achieved this by writing the value
$60 to HMM0, 21 cycles after HMOVE starts. See this message in
the archives:
http://www.biglist.com/lists/stella/archives/199705/msg00024.html

Following is how I believe it works: at 21 cycles in, the internal
counter has just decremented to %0000 and is about to test this
against the HMxx registers (2 CLK from now, if my timings are
correct). If we flip the top bit of $60 as described above,
we have the binary pattern %1110. This pattern has at least one
bit in common with the final remaining state (the bottom zero
bit), and also has bits in common with the default counter state
%1111 which will arise when the counter resets. This means the
compare will pass now and forever more :) For this to work, I
expect that they must have set HMM0 to $70 before using the trick
(binary %0111, or %1111 with the bit flipped), but after a cursory
glance at Thomas' commented Cosmic Ark code I haven't found this.

Looking at the archives relating to Cosmic Arc and Rabbit Transit
tricks, I also notice that a HMCLR 20 cycles in has the same effect.
In this case it will be resetting HMxx to %1000 (bit-flipped)
which also obeys the rules for bypassing the stopping condition.


Also of note, the HMOVE latch used to extend the HBlank time
is cleared when the HSync Counter wraps around. This fact is
exploited by the trick that invloves hitting HMOVE on the 74th
CPU cycle of the scanline; the CLK stuffing will still take
place during the HBlank and the HSYNC latch will be set just
before the counter wraps around. It will then be cleared again
immediately (and therefore ignored) when the counter wraps,
preventing the HMOVE comb effect. Since the extended HBlank
is needed to move all objects right 8 pixels, this has the
limitation that objects can only be moved left, and the normal
HMOVE numbering no longer applies. Instead the HMOVE value is
interpreted as (8 + value) pixels to the left, ie:

    -8 = 0    -4 = 4	0 = 8     4 = 12
    -7 = 1    -3 = 5	1 = 9	  5 = 13
    -6 = 2    -2 = 6	2 = 10	  6 = 14
    -5 = 3    -1 = 7	3 = 11	  7 = 15

This means that all objects will be moved 8 pixels left unless
you set their HMxx value to -8 for zero movement.

I've recently found a post in the Stella mailing list archives
that gave these results by exhaustive testing, posted by Brad Mott:
http://www.biglist.com/lists/stella/archives/199804/msg00198.html


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Graphics Scan Counters during HMOVE

Since the Graphics Scan Counters are never reset, player
graphics output can wrap around as mentioned above.

A HMOVE 8 pixels right (-8 << 4), has no effect on the scan
counter since it will perform no "clock stuffing" of the
player counters for that player (the extended HBlank time
moves everything right 8 pixels).

Any other HMOVE value will gobble up at least one pixel,
or more proportional to the HMOVE value. Since a HMOVE
value really represents a count from 0 (for -8) to 15
(for +7) with the top bit inverted, this is the number
of player pixels that will be gobbled up by the HMOVE.

This means that a HMOVE of 0 will gobble up all remaining
wrapped output for the non-stretched player modes, since it
sends 8 extra clocks to the player. (Note that this is only
true if HMOVE was actually strobed for the scanline,
otherwise the configured HMxx registers never have any
effect). For the stretched player modes there could be some
output left - it takes 16 stuffed clocks to eat up a full
2X player, and 32 clocks to eat up a full 4X player.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ HMOVE during the visible scanline.

I mentioned above that HMOVE sends extra clock pulses down
the same clock lines that are usually used during the visible
part of the scanline. In theory this means that performing a
HMOVE during the visible part of the scanline should have no
effect. However, looking at how the various clock signals
interact, I suspect it is possible. I did some preliminary
experiments (on a 2600 Jr) at some point, and I seem to
remember having some success.

In this case the extra HMOVE clock pulses act to perform
'plugging' instead of the normal 'stuffing'; by this I mean
that the extra pulses plug up the gaps in the normal [MOTCK]
pulses, preventing them from counting as clock pulses. This
only works because the extra HMOVE pulses are derived from
the two-phase clock on the HSync counter, which is itself
derived from CLK (the TIA colour clock input), whereas
[MOTCK] is an inverted CLK signal - so they are more or less
precisely out of phase :)

I'm not sure how universal (or reliable!) this might turn out
to be, but I haven't seen it mentioned before. Also of note,
this technique can only be used to effect a move to the right,
at a rate of 1 pixel every 4 CLK (since this is the rate that
HMOVE generates the extra clock pulses).


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ The Re-trigger Trick, and all that jazz

I've read some theories suggesting that re-triggering is a
hack, possibly dependent on chip revision, where you trick
the TIA into rendering more than three copies by hitting
RESP0/RESP1 during the rendering of a 'legitimate' copy, or
some other method to confuse the poor chip. Through extensive
coffee consumption, I have determined that this is not the
case. Perhaps peering at the TIA schematics for countless
hours on end, until I fell asleep (two days in a row), may
have helped also.

The behaviour of the TIA positioning registers is quite
predictable and completely independent from its graphics
output logic, as documented above. What remains are issues
involving the timing of RESPn commands, given that the TIA
counts things at 1/4 clock and the CPU runs at 1/3 CLK =)

Following is a table of the cycle decodes for the Player
counters, starting from CLK=0 when the counter resets. This
is an excerpt from the Player Counter table listed elsewhere
in the document (I recomment you go have a look, the spacing
between events should look oddly familiar ;)

Value	PCount	CPU	CLK	Event

111000	3	4	12	START DRAWING (NUSIZ=001,011)	Close
101111	7	9.3	28	START DRAWING (011,010,110)	Medium
111001	15	20	60	START DRAWING (100,110)		Far
101101	39	52	156	RESET, START DRAWING (always)	Main

The columns from the left are: the polynomial counter state,
(see notes above), the decimal value that the player counter
is up to, the number of CPU cycles since the counter reset,
and the number of CLKs elapsed since the counter reset.

You'll notice I'm now talking about everything relative to
RESPn on the current scanline, rather than the beginning of
the scanline. This is because this is all that matters.
You should understand the following point:

  If you hit RESPn at least twice on every scanline,
  you will never see the 'main' copy of that player,
  ever, on any scanline.

This is because the counter will always be reset before it
manages to complete a full 40 counts (160 CLK), and so the
'main' copy will never start drawing.

This is tricky to test, especially if you don't reset a few
things when you stop (eg, for VSync) - whenever you stop
hiting RESPn, you will start to get the normal output on the
next and subsequent scanlines, including the 'main' copy.
The very top visible scanline is a perfectly valid
'subsequent scanline' after the very bottom visible scanline,
once you get past the first frame ;)

If you've set up NUSIZn for 3 copies close (011), you'll be
getting four copies on every scanline on which you hit RESPn
twice, as long as they are far enough apart. This works because
it doesn't take a counter wrap-around to get to the 'close' and
'medium' copies as shown in the table above. They will appear
4+12+1=17 and 4+28+1=33 pixels after each RESPn CLK arrives
in the TIA (it takes 4 extra CLK to reset the counter, and 1
extra CLK to start the graphics output).

It's important to note, that as long as the second RESPn on
the line causes a reset after the 'start' signal has been
generated for the 'medium' copy of the first RESPn, you will
get four copies regardless of how far apart the RESPn hits
are. If you do the second RESPn too soon you'll end up with
only three copies - the 'close' from the first RESPn, followed
by the the 'close' and the 'medium' from the second RESPn.
If you do the second RESPn before the first 'close' copy,
you'll only end up with the 'close' and 'medium' from the
second RESPn.

From this it follows that if you set NUSIZ0 to 011, hit RESPn
and wait until the 'medium' copy has started, then change NUSIZ0
to 100 or 110, you will get all of 'close', 'medium' and 'far'.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Re-triggering after exactly 18, 33, 66 or 162 cycles

These are special cases only because resetting a Position Counter
(RSPn, RESMn, RESBL) also resets the two-phase clock attached
to it, and this in turn affects the clocked logic on the output
of the counter decodes.

For the player counters, this affects the four decodes that
produce the Start signal for copies of the player graphics.
These are generated 12, 28, 60, and 160 CLK after the Position
Counter has been reset, in order to trigger the 'close', 'medium',
'far' and 'main' copies.

These decodes pass through a block of logic that requires a full
cycle of the two-phase clock (hence the normal 4 CLK delay before
graphics output common to all movable graphics objects). If the
Position Counter and therefore the two-phase clock are reset
during this decoding process, the Start signal will either be
lost or delayed up to 3 CLK depending on exact timing.

This effect is most evident when attempting to re-trigger the
player graphics over and over again. For example, examine this
retriggering technique:

        STA     RESP0   ;3 reset P0, call this 0 CLK.
        CMP     $EA     ;3 nop
        STA     RESP0   ;3 reset P0 again, after 18 CLK.
        CMP     $EA     ;3 nop
        STA     RESP0   ;3 reset P0 again, after 18 CLK.

The visible result of this will be a 'close' copy of P0 shifted
right by two pixels from the expected position, followed by a
second 'close' copy shifted right by two pixels, and finally a
third 'close' copy, not shifted right. There will be an 18 pixel
gap between the first two copies of P0, and only a 16 pixel gap
before the third copy.

In order to fix up the spacing of the final copy, it is necessary
to trigger P0 yet again exactly 18 CLK later, but clear GRP0 in
the mean time so nothing is drawn.

If the retriggering will be continuing onto the next line there is
no need to do this; just ensure that the first re-trigger on the
next line happens 18 visible pixels after the last RESP0 on the
previous line (ie 18 CLK later, minus HBlank time).


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Notes on the Ball/Missile width enclockifier

Just to reiterate, ball width is given by combining clock signals
of different widths based on the state of the two size bits (the
gates form an AND -> OR -> AND -> OR -> out arrangement, with a
hanger-on AND gate).

The Enable (output) signal is built in two halves, arranged back-
to-back at the final OR gate.

The first half comes from one of three sources combined through
the earlier OR gate and then AND-ed with the Start signal:

(1) If D4 and D5 are both clear, one of the two-phase clock signals
(active 1 in 4 colour CLK) yields a single pixel of output.
(2) If D4 is set, a line active 2 in every 4 colour CLK is borrowed
from the two-phase clock generator (this yields 2 pixels).
(3) Finally D5 itself is used directly - the Start signal is active
for 4 CLK so this generates 4 pixels.

The second half is added if both D4 and D5 are set; a delayed copy
of the Start signal (4 colour CLK wide again) is OR-ed into the
Enable signal at the final OR gate.

I hope someone had as much fun building this little circuit as I
had pulling it apart again ;p


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ CPU Clock to Player Pixel Table

The Player Position Counter can be reset to zero (with RESP0/1) on
any CPU cycle as shown below, and copies will appear at the pixel
positions listed for 'close', 'medium' and/or 'far' depending on
the flags in NUSIZ; 1, 2, 3 or (if you change NUSIZ at the right
time) 4 copies at hard-wired positions after the reset. If the
counter is allowed to wrap around, the 'main' copy will appear
on the next line.

Resetting the counter takes 4 CLK, decoding the 'start drawing' signal
takes 4 CLK, latching the 'start' takes a further 1 CLK giving a
total 9 CLK delay after a RESP0/1. Since the playfield takes 4 CLK
to start drawing the player is visibly delayed by exactly 5 CLK -
hence the magic '5' :)

NOTE: The player counter can be safely reset 18 CLK after the previous
reset and the previous copy will still be drawn. BUT the 'start' signal
for the previous copy will be delayed a further 2 CLK due to the 2-
phase clock being reset before the 'start' signal has been clocked
through to the 'start' latch.

CPU	CLK	Pixel	Main	Close	Medium	Far	PF

0	0	-	1	17	33	65	-
...
22	66	-	1	17	33	65	-
22.6 --------------------------------------------------------
23	69	1	6	22	38	70	0.25
24	72	4	9	25	41	73	1
25	75	7	12	28	44	76	1.75
26	78	10	15	31	47	79	2.5
27	81	13	18	34	50	82	3.25
28	84	16	21	37	53	85	3
29	87	19	24	40	56	88	
30	90	22	27	43	59	91	
31	93	25	30	46	62	94	
32	96	28	33	49	65	97	
33	99	31	36	52	68	100	
34	102	34	39	55	71	103	
35	105	37	42	58	74	106	
36	108	40	45	61	77	109	
37	111	43	48	64	80	112	
38	114	46	51	67	83	115	
39	117	49	54	70	86	118	
40	120	52	57	73	89	121	
41	123	55	60	76	92	124	
42	126	58	63	79	95	127	
43	129	61	66	82	98	130	
44	132	64	69	85	101	133	
45	135	67	72	88	104	136	
46	138	70	75	91	107	139	
47	141	73	78	94	110	142	
48	144	76	81	97	113	145	
49	147	79	84	100	116	148	
50	150	82	87	103	119	151	
51	153	85	90	106	122	154	
52	156	88	93	109	125	157	
53	159	91	96	112	128	0	
54	162	94	99	115	131	3	
55	165	97	102	118	134	6	
56	168	100	105	121	137	9	
57	171	103	108	124	140	12	
58	174	106	111	127	143	15	
59	177	109	114	130	146	18	
60	180	112	117	133	149	21	
61	183	115	120	136	152	24	
62	186	118	123	139	155	27	
63	189	121	126	142	158	30	
64	192	124	129	145	1	33	
65	195	127	132	148	4	36	
66	198	130	135	151	7	39	
67	201	133	138	154	10	42	
68	204	136	141	157	13	45	
69	207	139	144	0	16	48	
70	210	142	147	3	19	51	
71	213	145	150	6	22	54	
72	216	148	153	9	25	57	
73	219	151	156	12	28	60	
74	222	154	159	15	31	63	
75	225	157	2	18	34	66	
76	228	0	5	21	37	69	
----------------------------------------------------- Start HBLANK

Also note that hitting RESP0 before HBLANK has finished will reset
the counter immediately, but it will only start counting again when
HBLANK goes off. Due to output clocking, this will produce player
graphics at playfield pixel 1.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ The Venerable 6-digit Score Trick

The 6-digit score trick involves putting both players into 3-repeat
mode (011 or 110 in NUSIZ0/1) and resetting them such that all the
player 2 images are positioned exactly between all the player 1
images, ergo:

  P1  P2
  v   v
  1   2   1   2   1   2

Then you need to set the graphics up (GRP0/1) for the first two
digits, and write some very precise timing code to wait until the
scan-line is just about to start drawing the first copy of P1.
While you're waiting, get the rest of the graphics loaded into
the registers (A, X, and Y).

At this point you need to start storing all the graphics you've
loaded into GRP0 and GRP1 as fast as you can - it will look like
this because there's only one way to do it fast enough:

  STA GRP0  ; 3
  STX GRP1  ; 3
  STY GRP0  ; 3
  ST? GRP1  ; 3   we've run out of registers!

Notice that each one takes 3 cycles to execute (which is 9 pixels)
and makes the change on the -end- of the 3rd cycle. We could use
the stack pointer register (S) for the last one and do a TSX, but
that would take 5 cycles (that's 15 pixels) which is too long.

To get it working you need to turn on VDELP0/1 (vertical delay)
which allows you to set up the first 3 digits in the TIA's
graphics registers before the beginning of the scanline, and
requires only the 3 remaining registers to hold the last 3 digits.

I've found a post in the Stellar archives that explains this
technique in great detail, so I'll stop here.

http://www.biglist.com/lists/stella/archives/199704/msg00137.html


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++ Fine Print

Please note that these notes are my own, and are made available
without any warranties of any kind. They may include errors,
omissions and much that is apocryphal; use at your own risk.

Please let me know if you spot anything that is blatantly wrong
and I'll update the document. I'm also happy to answer any
questions about this stuff.

Copyright (C) Andrew Towers 2003


