Hi!
I think I have found a bug in Christian Bauer's explanation of sprites
and $D017. I have found it quite a long time ago, and I hoped I could
investigate further to find what the correct explanation is, but there
has not been enough time so far.
To make it short, try the following program by Andreas Boose:
begin 644 sp.prg
M`,!XJ7^-#=RM#=RI4XT4`ZG`C14#J1N-$="I8XT2T*D!C1K0K1G0C1G0HC^I
M59W``\H0^JD/C?@'J8B-`-"I9HT!T*D`C1#0C1S0J0&-%]"-%=!88,X9T.X1
GT,X1T"3_HC'*T/VI`(T7T*D!C1?0H@G*T/VI`(T7T*D!C1?03#'J
`
end
Here is the assembly listing:
C000 SEI
C001 LDA #$7F
C003 STA $DC0D
C006 LDA $DC0D
C009 LDA #$53
C00B STA $0314
C00E LDA #$C0
C010 STA $0315
C013 LDA #$1B
C015 STA $D011
C018 LDA #$63
C01A STA $D012
C01D LDA #$01
C01F STA $D01A
C022 LDA $D019
C025 STA $D019
C028 LDX #$3F
C02A LDA #$55
C02C STA $03C0,X
C02F DEX
C030 BPL $C02C
C032 LDA #$0F
C034 STA $07F8
C037 LDA #$88
C039 STA $D000
C03C LDA #$66
C03E STA $D001
C041 LDA #$00
C043 STA $D010
C046 STA $D01C
C049 LDA #$01
C04B STA $D017
C04E STA $D015
C051 CLI
C052 RTS
C053 DEC $D019
C056 INC $D011
C059 DEC $D011
C05C BIT $FF
C05E LDX #$31
C060 DEX
C061 BNE $C060
C063 LDA #$00
C065 STA $D017 ; first $D017 write
C068 LDA #$01
C06A STA $D017 ; second $D017 write
C06D LDX #$09
C06F DEX
C070 BNE $C06F
C072 LDA #$00
C074 STA $D017 ; third $D017 write
C077 LDA #$01
C079 STA $D017 ; fourth $D017 write
C07C JMP $EA31
Basically, this code activates an y-expanded sprite starting at line
$67; then, using an IRQ, it writes $01 to $D017 at cycle 15 and $00 at
cycle 21, once at line $69 and once at line $6a.
According to the "VIC article",
1. The expansion flip flip is set as long as the bit in MxYE in
register $d017 corresponding to the sprite is cleared.
(so the flip flop is always 1 if the sprite is not y-expanded)
3. In the first phases of cycle 55 and 56, the VIC checks for every
sprite if the corresponding MxE bit in register $d015 is set and the
Y coordinate of the sprite (odd registers $d001-$d00f) match the
lower 8 bits of RASTER. If this is the case and the DMA for the
sprite is still off, the DMA is switched on, MCBASE is cleared, and
if the MxYE bit is set the expansion flip flip is reset.
(so the flip flop is always 0 on the first line of an y-expanded
sprite)
I have checked "sp.prg" on my 64C at home. I have figured out which
memory locations are displayed in which pixels, and it looks like
there is really something wrong with this description.
+-----+-----+-----+
| 0 | 1 | 2 |
+-----+-----+-----+
| 0 | 1 | 2 |
+-----+-----+-----+
| 3 | 4 | 5 | <- First $D017 write
+-----+-----+-----+
| 7 | 8 | 9 | <- Third $D017 write
+-----+-----+-----+
| 7 | 8 | 9 |
+-----+-----+-----+
| 7 | 8 | 9 |
+-----+-----+-----+
| 10 | 11 | 12 |
+-----+-----+-----+
| 10 | 11 | 12 |
+-----+-----+-----+
: : : :
Each rectangle represents 8 pixels, and the number represents the
offset of the memory location that contains the bitmap for those 8
pixels, relative to the start of the sprite (in this case, $03C0).
The $D017 writes are the ones "sp.prg" makes at cycle 15 and 21, after
the `DEX' loop. The flip flop before the first write is 0 (because
the sprite starts expanded), and writing 0 to the register should
(according to the article) set the flip flop to 1. As the write
happens at cycle 15, the memory pointer should be incremented by 1
instead of 3 (as explained in 3.14.7). As "sp.prg" also writes 0 into
$D017 afterwards, at cycle 54 the flip flop would be inverted (3.8.1,
rule 2), so its value would be zero before the third $D017 write,
which thus should cause another 1-byte shift in the memory pointer.
So the beginning of the map would be like this:
+-----+-----+-----+
| 0 | 1 | 2 |
+-----+-----+-----+
| 0 | 1 | 2 |
+-----+-----+-----+
| 3 | 4 | 5 | <- First $D017 write
+-----+-----+-----+
| 4 | 5 | 6 | <- Third $D017 write
+-----+-----+-----+
| 5 | 6 | 7 |
+-----+-----+-----+
| 5 | 6 | 7 |
+-----+-----+-----+
| 8 | 9 | 10 |
+-----+-----+-----+
| 11 | 12 | 13 |
+-----+-----+-----+
: : : :
That's what FrodoSC does, indeed, but it is clearly not correct.
VICE does this right instead. This happens because the "Xayne's
Birthday Party" disk by Crest contains a routine showing this effect,
and even a table of the values that should be added to the sprite
memory pointer when this effect is used; I have just copied it and
implemented things accordingly. The table looks like the following
(grabbed from `src/c64/sprcrunch.h'):
static const int sprite_crunch_table[64] = {
1, 4, 3, /* 0 */
4, 1, 0, /* 3 */
-1, 0, 1, /* 6 */
4, 3, 4, /* 9 */
1, 8, 7, /* 12 */
8, 1, 4, /* 15 */
3, 4, 1, /* 18 */
0, -1, 0, /* 21 */
1, 4, 3, /* 24 */
4, 1, -8, /* 27 */
-9, -8, 1, /* 30 */
4, 3, 4, /* 33 */
1, 0, -1, /* 36 */
0, 1, 4, /* 39 */
3, 4, 1, /* 42 */
8, 7, 8, /* 45 */
1, 4, 3, /* 48 */
4, 1, 0, /* 51 */
-1, 0, 1, /* 54 */
4, 3, 4, /* 57 */
1, -40, -41, /* 60 */
0
};
Using this table is quite straightforward: whenever $D017 is written
to I do the following (I just include the C source here, as I think
it's clearer than words):
sprites[i].y_expanded = value & (1 << i) ? 1 : 0;
if (!sprites[i].y_expanded && !sprites[i].exp_flag) {
/* Sprite crunch! */
if (cycle == 15)
sprites[i].memptr_inc = sprite_crunch_table[sprites[i].memptr];
else if (cycle < 15)
sprites[i].memptr_inc = 3;
sprites[i].exp_flag = 1;
}
`value' is the value being written to $D017, `i' is the number of the
sprite, `exp_flag' is the status of the expansion flip flop, and
`memptr_inc' is the value that is being added to the sprite memory
pointer on this line, after the DMA is done. Of course this is done
for every sprite.
Now, this has no theoretical foundations; I have no explanation for
those values, that actually look like black magic. Is there anybody
who has tried to explain this effect?
Another problem is that I am pretty sure there is still something
wrong with this. I have at least two demos that do not behave
correctly yet. Maybe trying to explain the internals could help, but
so far we have not had the time to investigate this further. Is there
anybody out there who could help?
Btw, CCS64 does that right. Too bad it does not come with source
code. :-)
Bye
Ettore.
-
This message was sent through the cbm-hackers mailing list.
To unsubscribe: echo unsubscribe | mail cbm-hackers-request@dot.tcm.hut.fi.
Archive generated by hypermail 2.1.1.