| |
Copyfault
Registered: Dec 2001 Posts: 475 |
Sprite data fetch in sideborder
I'm playing around with sprites in the sideborder. Usually the ypos for a sprite is one less than the rasterline it should actually show up, e.g. if you want to see a sprite in rasterline $33, you have to put $32 in its ypos-reg.
Now if a sprite has xpos >= $164, the sprite display is turned on in the very same line. For sprite 0, this behaviour can be exploited as the sprite data is read in the cycles directly before. This was done e.g. to get 9 sprites in one rasterline.
If we put any other sprite at this position (xpos >= $164), the display will also start immediatly on the same rasterline (not on the following one). But the sprite data that was fetched looks like a [$ff $00 $ff]-pattern.
I found out that the '$00' in the middle comes from the last byte of the active vic bank (ghostbyte) and that it can be changed accordingly.
Still not clear is the origin of the other $ff-bytes. Are they hardwired just like the $ff-bytes the vic reads as vram on fli-lines? Are they coupled to the adress/data bus somehow?
Maybe someone has already examined this and could explain the behaviour. |
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
I would assume they're equally hardwired to ff just like the char fetches prior to char dma (i.e. The fli-bug) |
| |
Oswald
Registered: Apr 2002 Posts: 5086 |
nice discovery, not even the famous VIC article mentions this behaviour IIRC.
#$ff comes from at FLI according to the VIC article: AEC is high and so the internal data bus drivers D0-D7 of the VIC are closed and as the chip is manufactured in NMOS technology, it reads the value $ff.
not sure if the same happens for sprites. why would VIC connect to the bus on/off on different cycles ? maybe its that sprite DMA is not yet turned on, CPU is not halted, and as VIC gets the bus alternatively normally, when it gets the bus it goes for the ghostbyte when it doesnt it reads $ff.
while thinking of it, ghostbyte is probably an NMOS feature aswell, undriven bus lines are pointing to $3fff (%11111111111111) ? |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Some time ago, i investigated, for fun and profit, on how to read and write RAM locations $00 and $01.
Not the CPU internal "registers", but the REAL ram.
I learned that when cpu access $00 or $01 for read or write, set up the data-bus "normally" as if it were a normal ram access, but returns or write the "internal" cpu addresses.
Then i thought that the only chip can access ram independently from cpu is vic-ii.
When VIC-II does an "uncontrolled" ram access?
During the "idle-access" that cause, in some circumstances, the display of the idle graphic pattern.
The most easy way to show idle-gfx pattern, is to open the lower border without zeroing the $3FFF location (in -normal- conditions...), so here there is a idle-ram access.
If we wait the "right moment" and read or write $00/$01, we have the "register" value written/readed in/from $00/$01, but a "pending" value on the data-bus.
To write into $00/$01 we need to store the value at vic-ii idle address ($3FFF usually) then write to the "register", but for read a value from $00/$01, we need to read from $00/$01 then, just after that, read a NOT-CONNECTED address (like $DE00 if no CRTs are used) to grab "pending" data from bus.
I think some code can explain better than 1.000 words:
.> c000 a9 7f lda #$7f
.> c002 cd 12 d0 cmp $d012
.> c005 d0 fb bne $c002
.> c007 ad 11 d0 lda $d011
.> c00a 10 fb bpl $c007
.> c00c a5 01 lda $01
.> c00e a0 e0 ldy #$e0
.> c010 8c ff 3f sty $3fff
.> c013 85 01 sta $01
.> c015 a5 01 lda $01
.> c017 ad 00 de ldx $de00
.> c01a 60 rts
This code write and read value $E0 (ending content of .X) from RAM location $01.
(Works also with Vice)
All that to say what?
Maybe other value used for sprite GFX comes from one of this 2 locations.
For eg, Vice (and also RH should) have $FF stored at RAM address $00 after a "normal" reset...
Now is up to you =P |
| |
chatGPZ
Registered: Dec 2001 Posts: 11354 |
no, the VIC doesnt access $00/$01 ... its either idle access or hardwired $ff. someone could check if it is already working properly in x64sc, and then look up what it is in the source... i'd start with this test program |
| |
tlr
Registered: Sep 2003 Posts: 1787 |
I researched this and implemented it for x64sc and it should be working properly AFAIK. I'm sure the knowledge was known by others before that.
Those $ff bytes come from whatever is on the internal VIC-II bus at the cycles when the sprite fetch should have occured.
To change the value from the default pulled up state, perform a write (or read) access that generates the desired byte on the internal bus on the right cycles. |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Groepaz, this is the result of test.prg on RH/Vice x64 2.4.5 r27742M.
From what i can see ... they are the same thing:
http://i59.tinypic.com/1zbrwar.jpg
IIRC on RH i have a ceramic VIC R1... but can be a R3, i need to check if it should be interesting... |
| |
Copyfault
Registered: Dec 2001 Posts: 475 |
Quoting tlr...
Those $ff bytes come from whatever is on the internal VIC-II bus at the cycles when the sprite fetch should have occured.
To change the value from the default pulled up state, perform a write (or read) access that generates the desired byte on the internal bus on the right cycles.
Thanks for the hint! I already tried that but I wasn't able to change the bit pattern. Maybe I have to do smth else than senseful placements of "lda #<bitpattern>"??? |
| |
chatGPZ
Registered: Dec 2001 Posts: 11354 |
making it appear on the internal bus probably needs some more fiddling :) |
| |
Oswald
Registered: Apr 2002 Posts: 5086 |
"To change the value from the default pulled up state, perform a write (or read) access that generates the desired byte on the internal bus on the right cycles."
the ghostbyte is shown between two $ff's, so I dont think thats gonna work. its probably like the FLI bug, VIC tries to read but it doesnt has the bus, cpu has it. VIC gets $ff.
the end. |
| |
Copyfault
Registered: Dec 2001 Posts: 475 |
The question is if it is possible at all to squeeze _any_ byte into the internal vic bus floating by at the correct raster cycle.
My explanation (up to now) looks like this: as the described behaviour occurs on the same rasterline as the ypos-value of the sprite, there has not been a valid sprite data fetch before during the cycles belonging to that sprite. What happend instead during those two sprite fetch cycles?
1. In the first halfcycle (with the bus connected to the vic) the sprite pointer was read
2. in the second halfcycle (now with bus connected to cpu) the next cpu cycle is executed
-> some mechanism must generate the first $ff-byte at this point
3. in the next halfcycle (now again bus connected to vic) the vic does an idle access to $3fff as the normal sprite data fetch is not active yet
4. in the last halfcycle (bus belongig to cpu again) the same should happen as in the 2nd halfcycle
Due to this first theory I was trying to put the wanted bytevalues on the bus via "lda #bytepattern", but this did not change anything. How could it be done correctly - if it can be done at all? |
| |
tlr
Registered: Sep 2003 Posts: 1787 |
Quote: Quoting tlr...
Those $ff bytes come from whatever is on the internal VIC-II bus at the cycles when the sprite fetch should have occured.
To change the value from the default pulled up state, perform a write (or read) access that generates the desired byte on the internal bus on the right cycles.
Thanks for the hint! I already tried that but I wasn't able to change the bit pattern. Maybe I have to do smth else than senseful placements of "lda #<bitpattern>"???
Placing a value on the internal bus is done by writing or reading a vic-ii register. As there is no dma going on it is possible to do this in the right spot. If you want to do this for both ff's go for a rmw instruction. Having independent arbitrary data for both ff's may prove tricky though.
One use for this is just to hide the upper bogus line even though the border is open. That's how it works in hcl's starion intro remake, intentional or not. Compare between x64 and x64sc.
Edit: arbitrary might be possible by preloading a vic register with the first byte then doing sta <vicreg>,x with the second byte. |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Just a curiosity:
what happens if, in the same frame, you use a sprite in a "normal" way, then you try to use as you want in the border?
Still have same $3FFF/$FF pattern (should be tested on RH...)? |
| |
tlr
Registered: Sep 2003 Posts: 1787 |
The pattern should be the same. The VIC-II fetches sprite data but doesn't have the bus. It's still a proper fetch. If there was no fetch happening the line would have been empty as the data from the previous sprite was already shifted out.
If you do a test program, please contribute it for inclusion in the vice test program repository. |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Quote: The pattern should be the same. The VIC-II fetches sprite data but doesn't have the bus. It's still a proper fetch. If there was no fetch happening the line would have been empty as the data from the previous sprite was already shifted out.
If you do a test program, please contribute it for inclusion in the vice test program repository.
There is one thing that i can't understand.
The sprite data fetching cycles are "hardwired" in some precise cycles in rasterline.
If vic start display a sprite before these fetching cycle, it should paint data that just he don't have.
It's a strange thing...
Or sprites data fetching mean just set some ram pointers used -just in time- to read and show data where sprite is visualized... |
| |
Copyfault
Registered: Dec 2001 Posts: 475 |
Quoting tlrPlacing a value on the internal bus is done by writing or reading a vic-ii register. As there is no dma going on it is possible to do this in the right spot. If you want to do this for both ff's go for a rmw instruction. Having independent arbitrary data for both ff's may prove tricky though.
One use for this is just to hide the upper bogus line even though the border is open. That's how it works in hcl's starion intro remake, intentional or not. Compare between x64 and x64sc.
Edit: arbitrary might be possible by preloading a vic register with the first byte then doing sta <vicreg>,x with the second byte.
It works just like you said by using a
sta abs,x
where abs must be a vicreg! By correctly placing the read/write-cycles of this command, the first $ff-byte is read from "abs+x (w/o hi-byte correction)" whereas the 2nd $ff-byte is exactly what's written to the adress (content of the accu in this case).
Thanks a lot for helping me understand this vic-behaviour! |
| |
Copyfault
Registered: Dec 2001 Posts: 475 |
Quoting FlaviowebThere is one thing that i can't understand.
The sprite data fetching cycles are "hardwired" in some precise cycles in rasterline.
If vic start display a sprite before these fetching cycle, it should paint data that just he don't have.
It's a strange thing...
Or sprites data fetching mean just set some ram pointers used -just in time- to read and show data where sprite is visualized...
This is what tlr pointed out: the sprite data fetch will be done on the hardwired cycles belongig to that sprite even if display is not active! If we have e.g. sprite3 at xpos=$164, we will see the data that was fetched at cycles 1 and 2 of the very same rasline! But as the sprite dma was not active yet during these fetch cycles, the sprite data buffer for sprite no.3 is filled with the data the vic "sees" during those fetch (half)cycles (e.g. vic-bus-data during 2nd halfcycle of cycle 1 for first buffer byte, ghostbyte for second buffer byte and vic-bus-data during 2nd halfcycle of cycle 2 for third buffer byte).
What a nice gfx chip we have in our machine ;) |
| |
chatGPZ
Registered: Dec 2001 Posts: 11354 |
now make a minimal test program that demonstrates this behaviour pretty please - so we can throw it into the testprograms repository :) |
| |
Oswald
Registered: Apr 2002 Posts: 5086 |
why are you so sure that the "$ff" bytes can be changed? it pretty much looks like the fli bug -> VIC tries to read from unconnected bus lines.
Are we sure that the internal bus is capable of holding earlier data without being connected to memory ? It's not a register but a "mechanism" to R/W the memory, right?
And even if its capable to hold the data, wont the failed memory read (when the cpu has the bus) overwrite it to $ff?
if this would be possible, why noone ever could change the color of the FLI bug?
Not that I know anything about such low levels, just wondering.
have you tried to change that $ff without precise timing? fill all vic bank with one value, all vic registers with another, open sideborders, etc ? it should be possible if the internal bus is capable of holding last read data. |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Quoting OswaldAre we sure that the internal bus is capable of holding earlier data without being connected to memory ? It's not a register but a "mechanism" to R/W the memory, right?
If you read my previous post on how to write RAM addresses $00/$01 and then read the values, you can say "yes, bus can hold data."
Quoting Oswaldif this would be possible, why noone ever could change the color of the FLI bug?
May be that no one has seen it from this perspective so far... |
| |
Oswald
Registered: Apr 2002 Posts: 5086 |
I dont agree/understand on how your $00/$01 trick works internally.
Writing: you are using that VIC reads the same byte for a longer period($3fff), think you can do the same inside the valid screen, just make sure VIC reads the byte in the cycle before the bus write... I guess. How would idle read contribute to the effect ? This is just speculation, but I guess on idle read adresses are not set, and the nmos $ff arises as adress, thats the reason. everything else on the bus is normal.
Reading: the cpu has its own read accesses while performing lda $01 ldx $de00, so why should the "unconnected bus line" contain the data from about 4 read cycles before ? what does exactly happen when reading from $de00 ? how does the value from the lda gets preserved on the bus, when there's more read accesses for performing ldx ?
most importantly, from my prvs post: wont the failed memory read (when the cpu has the bus) overwrite the "internal vic bus" to $ff? |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Quoting OswaldI dont agree/understand on how your $00/$01 trick works internally.
Ok, you are right.
I noticed that $00/$01 values changes during normal c64 activity, also if, apparently, nothing write to $00/$01 cpu internal "registers".
This is untrue, because if kernel, during normal operations, access $01 and then VIC make an access to $3FFF, also ram $01 value change.
This is why i noticed $3FFF/$01 value matching.
Quoting Oswald
Reading: the cpu has its own read accesses while performing lda $01 ldx $de00, so why should the "unconnected bus line" contain the data from about 4 read cycles before ? what does exactly happen when reading from $de00 ? how does the value from the lda gets preserved on the bus, when there's more read accesses for performing ldx ?
LDA read and put in .A the content of cpu internal $01, but setup data bus to access RAM $01... but don't read RAM value.
The next LDX to "unconnected address"... i don't know exactly how act on the bus, but grab "pending" value from previuos "$01" bus setup but "not executed"... |
| |
Oswald
Registered: Apr 2002 Posts: 5086 |
"LDA read and put in .A the content of cpu internal $01, but setup data bus to access RAM $01..."
and then cpu sets up the bus to read the opcode for ldx then it reads $00 and then $de. where is the read $01 value is magically stored for us while this happens? :)
writing: CPU sets the bus to write $01 but it doesnt puts data on the bus, but the VIC does in the next cycle the favor ? one possible way that it drives the bus value to its last read value, before setting bus address and R/W line ? but why would it do that?
what if simply the cpu throws the $01 data to both internal and ram, both when reading/writing? |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Quoting Oswaldwhat if simply the cpu throws the $01 data to both internal and ram, both when reading/writing?
Actually there is, at least, one opcode in excess in my theory...
What you mean, exactly, with "throws both data"?
LDA $00 read value from RAM $00 but result is "discarded"?
But the problem still here: "where" this vaule is discarded?
Where LDX $DE00 -rises- this value?
The value of .X is correct only if, previously, $00 or $01 are accessed by a "read" opcode...
If isn't "on bus"... where this value is? |
| |
chatGPZ
Registered: Dec 2001 Posts: 11354 |
i really wish we could split the thread, as the 0/1 issue is completely unrelated to this VIC stuff :)
as for the 0/1 thing, just look it up in that c=hacking issue on codebase, the explanation was quite accurate iirc |
| |
Oswald
Registered: Apr 2002 Posts: 5086 |
Quote: Quoting Oswaldwhat if simply the cpu throws the $01 data to both internal and ram, both when reading/writing?
Actually there is, at least, one opcode in excess in my theory...
What you mean, exactly, with "throws both data"?
LDA $00 read value from RAM $00 but result is "discarded"?
But the problem still here: "where" this vaule is discarded?
Where LDX $DE00 -rises- this value?
The value of .X is correct only if, previously, $00 or $01 are accessed by a "read" opcode...
If isn't "on bus"... where this value is?
I mean, the the cpu could just simply write both ram at $01 and its internal register at the same time ? and all this trickyng around is not needed ?
and tell me how is the bus value from 3 reads earlier magicallly preserved "at" $de00 ? shouldnt the next 3 reads (ldx $de 00) erase the earlier bus contents ?
even if it works, the explanation doesnt.
and back to spritefetch: even if you put data into VICII internal bus (does this even exists?), before it fetches sprite data. the fetch will happen and overwrite whatever there is. IMHO. |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Quoting Oswald
even if it works, the explanation does.
I opened another thread for this.
There is something strange about bytes and bus here.
Theoretically should not works... but work!
C64 have left some magic dust for us... |
| |
Copyfault
Registered: Dec 2001 Posts: 475 |
Quoting Oswald...
and back to spritefetch: even if you put data into VICII internal bus (does this even exists?), before it fetches sprite data. the fetch will happen and overwrite whatever there is. IMHO.
It really works like tlr stated - I have the code done and already tested on the real thing! I'll do my best to put a testprog together this weekend and will up it here lateron (the code I have done contains to much that I don't want to release yet, so I have to sort out the relevant part for the "sprite fetch feature").
But I think it really makes sense: if you read or write something from/to vic exactly during the sprite fetch cycles (e.g. cycles #1+2 for sprite 3), you make the vic "see" the read/sent data during the cpu-halfcycles. But the vic also writes something to its internal sprite buffer (for sprite 3) during these halfcycles, so it's highly probable that it just writes the data that it "sees" in the very same moment. Note: there is no normal sprite fetch as sprite dma is not turned on before cycle 58 (~ xpos $164).
What exactly makes you wonder about this explanation? |
| |
Oswald
Registered: Apr 2002 Posts: 5086 |
if there's no normal sprite dma (ie the vic doesnt drives the bus) then it makes sense, that it simply reads whats left there by the cpu. |
| |
Copyfault
Registered: Dec 2001 Posts: 475 |
More than a year has passed already since my last post promising a little test prog.
I wanted to keep my promise and uploaded it here as Sideborder Sprite Data Fetch TestProg. |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Since i can't test it on RH now...
...using vice X64SC, the test prg act as on rh, or the "pattern"
displayed on the first sprite line could be "wrong" (use other addresses/data)? |
| |
chatGPZ
Registered: Dec 2001 Posts: 11354 |
5 years later i looked at this program and added it to the VICE testbench: https://sourceforge.net/p/vice-emu/code/HEAD/tree/testprogs/VIC..
Some questions are open (to me anyway):
- apparently this problem applies to all sprites. (to my surprise) the problem always start at xpos $164. however, the cycles where the sta vicreg,x must be performed is different for each sprite - which are they? just all spaced 3 cycles apart? or 4? a little table would be a great addition to that readme i copypasted together :) it would also be nice to have this proved in testprogram(s) :)
- how does all this relate to sprite-sprite (and perhaps even sprite-background) collisions? i would guess that it works as expected, ie pixels that get displayed will also cause collisions. but is that really what happens? another test for this would nice to have :)
keep it coming :) |
| |
Copyfault
Registered: Dec 2001 Posts: 475 |
Quoting Groepaz[...]- apparently this problem applies to all sprites. (to my surprise) the problem always start at xpos $164. however, the cycles where the sta vicreg,x must be performed is different for each sprite - which are they? just all spaced 3 cycles apart? or 4? a little table would be a great addition to that readme i copypasted together :) it would also be nice to have this proved in testprogram(s) :) I'd say you need to set the sta abs,x-command two cycles apart, i.e. the last two cycles of that opcode must match with the sprite fetch cycles of the corresponding sprite (with spr0 being an exception, as the sprite fetch cycles have been correctly executed at this pos. of the rasterline).
Quoting Groepaz- how does all this relate to sprite-sprite (and perhaps even sprite-background) collisions? i would guess that it works as expected, ie pixels that get displayed will also cause collisions. but is that really what happens? another test for this would nice to have :)
keep it coming :) You're right, this calls for a proper update of the test prog... oh boy /o\
CF |