Re: [stella] TIA latch timing
Subject: Re: [stella] TIA latch timing|
From: Kevin Horton <khorton@xxxxxxxxxxx>
Date: Thu, 18 Oct 2001 04:00:04 -0500
At 08:31 10/17/01 -0400, you wrote:
Thanks Kevin, I was wondering how tthe PF would work under the covers to
provide the results Glen was describing. Do the player graphics work in
the same way? It looks like HBLANK time is gold since it's the only time
some of these registers can be updated safely.
You refer to a schematic of the PF, where can I find this? Does it include
other parts of the TIA?
I have the complete TIA schematic. It's on 5 sheets of paper so it's not
conducive to posting yet. Was thinking about scanning it or taking
pictures with my digicam. I've been adding "notes" to the schematic as I
go, commenting what certain parts do.
As for the player graphics, they are done differently. They have a 3 bit
binary counter (haven't checked to see if it's an up or down counter) and
use the Q outputs (non-inverted) and /Q (inverted) outputs and run 'em thru
a selector. The reflect player bit controls if the Q or /Q outputs get
passed. The Q outputs scan from 0 thru 7 while the /Q outputs scan from 7
to 0. This inverting trick to count backwards/forwards with 1 counter is
useful elsewhere. I've used it a number of times to make "oscillating"
counters that count up from 0 to 127, then 127 back to 0, then 0 to 127,
etc. See end for this.
These then run through an AND matrix which decodes the 8 states to select a
single bit from the player registers.
Here is where it gets really tricky! This is possibly new information on
how the players work. Each player register is really a *two byte*
register, instead of a single byte register.
The two bytes are termed "new" graphics data and "old" graphics data. The
bytes are "stacked" side by side, and act as a 2 byte deep buffer. When
the graphics data is written to, it goes into the "new" register. When you
write to the OTHER player graphics data register, it latches the contents
of the "new" graphics register into the "old" graphics register.
i.e. If I write to P0GF, the contents go into the "new" register of
P0GF. Whatever happened to be on P1GF's "new" register will be latched in
P1GF's "old" register.
It works both ways. Likewise, if I write a byte into P1GF, it will go into
P1GF's "new" register (P1GF's "old" register is not modified at all during
this). Then P0GF's "new" register contents get latched into P0GF's "old"
register. That is what makes the 6 sprite per line trick possible.
The player vertical delay selects the "new" or "old" graphics register for
The rest of the position circuitry is quite complex, and at the heart is an
LFSR with some decoded states. Remember that LFSR's were used in place of
normal binary counters, since they required less logic/transistors, and
they were truly syncronous (i.e. all outputs changed at the exact same
time; no "ripple delay" from chained binary counters (called a "ripple
counter" due to the "rippling" effect of the carry propagation down the
Oscillating counter code example:
do_osc: inc osc_ctr ;inc our counter
lda osc_ctr ;get oscillator counter
bpl no_inv ;if 0-127, don't invert
eor #0ffh ;invert every bit including D7 :-)
no_inv: rts ;end of code
"osc_ctr" counts from 0-255d. However, the accumulator will only return
0-127d. It does so in an "oscillating" fashion, however. 0-127, 127-0,
0-127, etc. The XOR 0ffh inverts all the bits. D7 is always set when this
inversion occurs, so making sure our XOR has its 7th bit set will ensure D7
remains clear after the XOR (1 XOR 1 = 0). The remaining 7 bits then get
flipped around and returned.
Archives (includes files) at http://www.biglist.com/lists/stella/archives/
Unsub & more at http://www.biglist.com/lists/stella/