Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Stable Raster via Timer
2003-12-28 19:40
Copyfault

Registered: Dec 2001
Posts: 466
Stable Raster via Timer

Maybe some of you advanced coders can help me with the following oddity. I'll keep out the basic routine for stabilizing rasters with the timer method, as it is presumably known to everyone!

If we ignore Illegal Ops for the moment, the max. number of cycles occuring in the main prog is 7 (when executing an indexed RMW). When it comes to the different values the variance can take, there should also be 7 (0 to 6 cycles). I wrote some (working!) routines, but I always end up having 8 different variance values. Of course one can live with it, but I wonder where this 8th state comes from!

If necessary, I'll deliver more details. I'd be really happy to understand this behaviour!

Yours, Copyfault
2003-12-29 12:59
Graham
Account closed

Registered: Dec 2002
Posts: 990
you're wrong with 7 cycles max per opcode. illegal RMW instructions with indexed indirect zeropage addressing use 8 cycles.

http://oxyron.net/graham/opcodes02.html
2003-12-29 13:30
Copyfault

Registered: Dec 2001
Posts: 466
Yes, but the LEGAL Opcodes won't eat more than 7 cycles, will they? I am definitly NOT using any IllegalOps in my maincode, but I do get 8 different values for the variance! On some systems this can easily be verified by the following main prog:

MAIN
INC $adr,X
JMP MAIN

On other systems I had to fiddle around to get a more or less complicated loop, consisting only of legal Ops, that also delivered 8 variance vals. I must admit that I didn't try to use an 8-cycle-Illegal-Op - will there be 9 values for the variance then?
2003-12-29 20:06
Graham
Account closed

Registered: Dec 2002
Posts: 990
i only get 7 different delays on that one.
2003-12-29 21:50
Copyfault

Registered: Dec 2001
Posts: 466
This "easy" main rout has been tested on a plain C=128 and delivered 8 values - I think Ninja tested it, too, and can confirm this!

If you're interested and like to help me, I could send you the sourcecode of the "complicated loop" (as I named it above) via mail. This should work on most C=64's and give 8 different values for the variance.
2003-12-30 09:20
HCL

Registered: Feb 2003
Posts: 716
Finally one interesting topic here at CSDB ;). Sorry i cannot contribute with anything intelligent. It seems like it's not 0-6 cykles, but 0-7 cycles you get for LEGAL op-codes. It's kinda strange..
2003-12-30 11:40
Stryyker

Registered: Dec 2001
Posts: 465
Has there been a decent bit of theory written about using timers for stable raster interrupts? Or did I miss it in C= Hacking?
2003-12-30 12:01
Graham
Account closed

Registered: Dec 2002
Posts: 990
still, here there's only 7 different delays for a main program using that opcode, tested on a C128DCR.

you are using timers? i hope that you know that there are different CIAs in different machines, and some of them have a delay of 1 cycle on IRQs while others have not.
2003-12-30 12:11
Copyfault

Registered: Dec 2001
Posts: 466
Quote: Has there been a decent bit of theory written about using timers for stable raster interrupts? Or did I miss it in C= Hacking?

Marko Mäkelä wrote an article for c=hacking, issue 10! Basically it deals with stabilizing rasters on a VIC-20, but I think it quite ok to understand the theory. You can find it on his homepage

http://www.hut.fi/Misc/cbm/vic20-demos.html
2003-12-30 12:24
Copyfault

Registered: Dec 2001
Posts: 466
@Graham: this means one generally has to take 0-7 cycles of variance into consideration in order to avoid troubles on machines with those Delay-Cia's?

When does such a delay-cycle occur? It can't be constant, because this would only lead to (by one cycle) shifted variance values - but in fact we got 8 different ones.
2003-12-30 13:17
Graham
Account closed

Registered: Dec 2002
Posts: 990
it is a stable delay, so either you have it or you don't. so on one machine you will only get 7 different delays. maybe there's some other delay playing in? i can assure you that with a max 7 cycles opcode you will have max 7 cycles irq delay.
2003-12-30 14:45
Copyfault

Registered: Dec 2001
Posts: 466
Quote: it is a stable delay, so either you have it or you don't. so on one machine you will only get 7 different delays. maybe there's some other delay playing in? i can assure you that with a max 7 cycles opcode you will have max 7 cycles irq delay.

You mean max 7 different delay values, don't you? May I send you my source_code, or even worse: should I post it here *pleasedontforceme* ;)? I checked the prog again yesterday and get 8 different values!

Thanks for all the comments and the patience you guys, espescially Graham, had up to now. Hopefully the question can someday be answered to my full content (though most probably it won't reveal anything tremendous I think ;))!
2003-12-31 02:18
Copyfault

Registered: Dec 2001
Posts: 466
So, just came back from our bunker! I tested my rout again on different systems and always ended up with 8 different values. I think this has something todo with the branch-instructions. Try the following (also "easy";)) main prog:

MAIN
INC $adr,X
BPL MAIN
BMI MAIN

I also tried to get 9 different variance-values when using an 8-cycle-Illegal-Op instead of the INC $adr,x , but unfortunatly this did not give me any coherent values.

Please try the rout above and tell me what variance values you get-I deeply hope there will be 8 different ones, too!

Another question related to this topic: how can I distinguish between Delaying- and Nondelaying-CIA's?
2003-12-31 20:53
raven
Account closed

Registered: Jan 2002
Posts: 137
This may be a stupid question, but why even use
timers for getting stable raster?
There are easier & more elegant ways of doing it, like
the double-irq (my favourite) which is well documented
in C=Hacking & there's also CrossBow's way which works great as well.

So why timers? leave them free for better things ;)
2004-01-01 19:15
Cybernator

Registered: Jun 2002
Posts: 154
@Copyfault: There're two different CIAs: 6526 (old) and 6526A (new). (I guess there're also 85xx versions). The old CIA makes additional delay of one cycle when an IRQ occurs. I don't know in which case, though. This is what I read at comp.sys.cbm, and in my case they always worked the same way.

@Raven: What is Xbow's way of stable-raster?
2004-01-02 00:44
White Flame

Registered: Sep 2002
Posts: 136
Okay, this might be an incredibly dumb response, but if the delay can be 0-7 cycles, then it can be one of eight (count 'em: 0,1,2,3,4,5,6,7) different variances in the delay.
2004-01-02 02:09
chatGPZ

Registered: Dec 2001
Posts: 11113
mmmh yeah i'd be interisted about "xbows method" too :)
afaik there are generally 4 ways... 1) dividing and busy waiting (bad, needs several rasterlines to sync) 2) double irq (prolly the way of choice for general use) 3) lightpen register fiddling (also bad, since it fucks up when pressing space) and last not least 4) double timers (might look more tricky than double irq, but has some neat properties and needs even less time to sync). the latter seems to be a little bit underestimated on c64 (on some other systems its the only way for stable raster)....hcl seems to like it however :o)
2004-01-02 02:30
chatGPZ

Registered: Dec 2001
Posts: 11113
mmmh forgot... anyone tried to come up with a (preferably simple and reliable) way to detect if the cia delays one additional cycle or not then? :)
2004-01-02 08:08
Graham
Account closed

Registered: Dec 2002
Posts: 990
groepaz: there's a 5th way to achieve a stable irq, you can use a badline to correct the timing. this will mess up a few colors but in some cases this might be a good way to do.

and a 6th way: using sprites and well placed instruction you can have self-correcting timing. the earliest stable irqs accidently used that, for example in the old sideborder demos by 1001 crew.
2004-01-02 17:34
Copyfault

Registered: Dec 2001
Posts: 466
Oops-I'm sorry, maybe I should have been more precise when I started this topic! I don't use double timers but a raster IRQ for the main interrupt and *one* timer to sync! Maybe there is another delay when combinig it that way???

Now about those "old" delaying CIA's: does this additional cycle only occur when triggering a timer IRQ, or do I get different timer values on entering an IRQ *in general*??? This would confuse me...

Did someone test this INC-BPL-BMI-loop? Like to know if I'm totally wrong with my assumption or not...
2004-01-02 18:43
chatGPZ

Registered: Dec 2001
Posts: 11113
mmmmh...i remember the sprite thingy (never thought about using it for stable raster though...peacey used it for scrolling fli gfx around :=P) but could you explain what you mean by the "use a badline" thing?
2004-01-02 20:33
Cybernator

Registered: Jun 2002
Posts: 154
The timer is triggered once each frame, rite? Do you trigger it _exactly_ at the same cycle each frame? If not, this could make additional cycle later. (According to my theory ;)
2004-01-02 22:38
Copyfault

Registered: Dec 2001
Posts: 466
No, not once per frame! Before *any* IRQ occurs, I sync the timer so that it'll give me the same variance values on every non-bad-line Raster-IRQ! But unfortunatly these values lie within a range of 8! Also don't have a clue what other delay sources there might be... Isn't it possible that every *additional cycle* (those ones occuring when pagecrossing with a branch-instruction or pagecrossing with an indexed MW-instruction or when a branch-condition is fulfilled) cannot be interrupted? This would explain it at least...
2004-01-04 11:22
MagerValp

Registered: Dec 2001
Posts: 1055
So maybe that's the problem then - you have a 0-1 cycle jitter in your timer stabilization routine, which together with 0-6 cycles of instruction jitter gives you 0-7 cycles jitter in the raster code.
2004-01-04 11:26
Cybernator

Registered: Jun 2002
Posts: 154
I've tested this on CCS and there's 8 cycle variance, too! The type of the CIA has nothing to do with this, because a raster-irq is used. Having the possibilities to freeze the program and check the position of the beam, I've placed a breakpoint at the IRQ. The cycle (Beam-X) was moving in range from $0B - $12.
Ok, let's count them (: $0B, $0C, $0D, $0E, $0F, $10, $11, $12. Something definitely ferments here. :)

And this is definitely the most interesting topic I've even seen.

@MagerValp: Forget my theory. ;-)))
2004-01-04 13:07
Graham
Account closed

Registered: Dec 2002
Posts: 990
whatever i do, i only get 7 variance values, even with that INC Bcc code.
2004-01-05 14:27
WVL

Registered: Mar 2002
Posts: 886
@ Graham :

I tried to send you some e-mail, but your old cruise-adress doesn't work anymore, can you contact me? werner@vanloo.org!
2004-01-06 13:30
Ninja

Registered: Jan 2002
Posts: 404
First, a great new year to all of you who didn't get stuck in those "flame-discussions" ;)

@copyfault: yup, i also get 8 values.

@groepaz: Doc Bacardi once used a method with 2 timers. Well, he's crazy enough :)

@raven: I prefer using a timer because it's faster than double interrupt and I never needed all 4 timers at the same time up to now. But it's a matter of taste, after all...

BTW what is now the "Xbow-Method"? Back then, when GO64! was a magazine, he described at least 6 methods.
2004-01-06 17:56
Cybernator

Registered: Jun 2002
Posts: 154
Having 2 timers makes the stuff slightly easier. One of them is used to generate IRQs, while the other (the auxilary) is used to sync the raster. The auxilary timer follows the main one with a difference of a few cycles. Why would one do this? Simple, when the main timer generates IRQ, it counts-down from the start value (62). The auxilary timer will then have values in range from 0-7. So having the value, you do this:

lda #7
sec
sbc $value in auxilary timer
and #7 ; just in case :)
sta delay+1
lda #0

delay: beq <doesn't matter where :)>

lda #$a9
lda #$a9
lda #$a9
lda #$a9
bit $ea

- Neat, eh? :)
2004-01-07 07:52
Hoogo

Registered: Jun 2002
Posts: 102
Another very simple way I remember: You place 8 Sprites on the screen, each 8 Pixel to the right, overlapping. Then you watch the collision-register with lda, beq *-3. You find the jitter in the number of set bits. Not elegant, but very easy to do.
2004-01-07 11:17
Ninja

Registered: Jan 2002
Posts: 404
@Cybernator: But why would one use a timer just to generate IRQs when you can use Raster-IRQs instead? Well, I can think of some special cases but in general the Raster-IRQ will do fine, no?
2004-01-07 15:53
Cybernator

Registered: Jun 2002
Posts: 154
Let's suppose you want to do a 4x4 mode. An IRQ is generated every 8th rasterline. To achieve this with raster-IRQ, you'd need to add 8 to $d012 every time an IRQ occurs. If you use timer, you can set it to generate IRQ every 8*63 cycles, and you don't have to do anything, as the counter will start from beginning after it generates an IRQ (assuming it's in continuous mode :))
2004-01-07 18:03
chatGPZ

Registered: Dec 2001
Posts: 11113
@ninja: hehe i used the 2 timer thingy too in the mongobong thingy :) (infact its using 2 timers and raster-irq aswell). two timers seem to be much more useful than just one to me actually.
2004-01-07 18:15
Ninja

Registered: Jan 2002
Posts: 404
@Cybernator: Heh, I never used 4x4 :) Nevertheless, have you ever tried this? I remember rasterline $000 being one cycle off, or does this count just for the Raster-IRQ in line $000?
2004-01-07 20:08
Cybernator

Registered: Jun 2002
Posts: 154
I've only used dithered 4x4, 'coz the normal one don't look sexy enough. :) But they are technically the same. I start the timer right before the paper area, and I stop it after 25 interrupts. So the timer is resync-ed each frame.

I just wrote another routine, which starts the timer once, and I use raster IRQ. It works as well, so rasterline $000 also has 63 cycles. But the IRQ is generated at cycle 2, unlike the other rasterlines where it's generated at cycle 1 (counting cycles from 1-63). I still haven't tested this on the real thing. I'll do it right away, but first I need to add visual control. Anyway, the chances that it will work are 99.9% :)

Btw, I noticed that when I start the timer, it takes a few cycles (3?) until it starts the countdown. Is there any detailed info about the CIA? (A doc that explains the inner details, like the VIC-article does for the VIC-II)
2004-01-08 08:28
Oswald

Registered: Apr 2002
Posts: 5017
btw.. :) I havent coded a stable raster using CIA timers myself but I have a source... Now... I would like to put sprites over the routine. Is this possible ? And how should I change the routine to get it work ? I've checked what happens if I do this, but even one sprite messes up the routine way too badly... Maybe the solution is to make the interrupt happen as many cycles earlier as much the sprites eat up ? But in this case I need 2 timers... hmm anyone?:)
2004-01-08 08:55
Ninja

Registered: Jan 2002
Posts: 404
@Cybernator: Stupid me, of course rasterline $000 has 63 cycles, otherwise my routine with raster-irq and one timer wouldn't work as well. It is just that the IRQ is triggered one cycle later. I should really start thinking before using the keyboard :)
2004-01-08 09:49
Cybernator

Registered: Jun 2002
Posts: 154
The idea is to make the timer have values from 0-7 at the moment when you access it! How do we do that? First I recommend that you write the sync routine. Supposing we are using the one I mentioned above, we have:

(Assume the value is in $dc04)

lda #7
sec
sbc $dc04

The access to $dc04 occurs at the last (4th) cycle of SBC. Now the important thing is to find out where's this cycle in the rasterline. An IRQ condition is given in cycle 1 (with exception to the first rasterline). The processor first needs to finish the current instruction. The smallest nr. of cycles an instruction takes is 2 (eg. NOP). If the IRQ occurs in the first cycle of NOP, there will be 2 cycles delay. If it occurs in the second cycle, there will be 3 cycles delay! So the minimum delay is 2 cycles to finish the current instruction. Then the CPU needs 7 cycles to store the PC and flags to stack and jump to the IRQ routine. So cycle 1 + 2 + 7 = 10. The first possible cycle in which the first instruction of the IRQ will execute is 10.

If there're sprites active, the first possible cycle will happen somewhere later. Let's assume there're 8 sprites active: sprites 0,1,2 are processed at the right border, so they are irrelevant. But the rest of them are. :) I recommend the diagram shown in 'Pal Timing'. You'll see that the CPU is halted until cycle 11. So 10 + 11 = 21 (what a math-dude I am, eh? ;-P)

The first instr. (lda #7) will take cycles 21 and 22. Sec will take 23 and 24. Sbc takes 25, 26, 27 and 28. (or a few cycles later, do to jitter).

Oops! At cycle 28, the timer should have value 7! It's up to you to achieve this. As I mentioned, I noticed delay between the activation of the timer, and the actual countdown.
CCS may be helpful here, unless you really hate MUs. :)

@Ninja: Thinking is better when you have company. :)
2004-01-08 15:55
Copyfault

Registered: Dec 2001
Posts: 466
@Cybernator: Hmmm, I always thought that the max. delay that occurs with a NOP is 1?!? I mean, if the IRQ occurs in the first cycle of the NOP (let's call it c_1), there is one cycle delay and the IRQ starts at c_1 + 2. If it occurs in the second cycle, there is no delay and the IRQ also starts at c_1 + 2 (it can't start earlier as the instruction has to be finished!). So your calculations should be altered by -1 I assume...

I also observed that the timers do not start immediatly after the start instruction(e.g. STA $DC0E). A closer look at the inner workings of the CIA would really be nice...

Another observation: the timers never give value 0 - at least not in continous mode (that's what I've tried so far;))! Instead they give the max.value!So a stabilization routine like

LDA #$07
SEC
SBC $DC04
<appropriate branch>

should not work correctly!
2004-01-08 18:33
Cybernator

Registered: Jun 2002
Posts: 154
If the IRQ occurs in the _last_ cycle of any instruction, the CPU will also execute the next one! So if we have two NOPs in succession, there will be 3 cycles delay if the IRQ occured in the second cycle of the NOP!

As for the routine, it will work if there's 7 cycle variance. But with the 8 cycle variance you have shown, it won't. So yes, make it:

lda #8
sec
sbc $dc04

But the first possible cycle in which $dc04 is accessed, should be when $dc04 = 8.
2004-01-08 23:53
Copyfault

Registered: Dec 2001
Posts: 466
Ok, I see! This does not even contradict the max.of 7 different variance values, as you get some delay between 2 and 8 cycles(= 7 different states). But how does an IRQ behave when triggered during a fulfilled branch condition? When does the processor check the condition? Possibly a branch is internally always 2 cycles long, and if the condition is fulfilled, there will be an extracycle which ofcourse cannot be interrupted, too! This way you have a maximal delay of 9 cycles (e.g. LDA #$00 : BEQ *+2 : INC adr,X). But I guess I'm wrong with this assumption - how could I correctly test it?
2004-01-09 01:26
Stryyker

Registered: Dec 2001
Posts: 465
There is something wrong with the NOP behaviour you describe then. The simple double raster interrupt then CMP $d012 relies on there being only 1 cycle jitter and normally padded with 2 cycle opcodes in the first raster interrupt. If you can get 3 cycle delay then how come much double interrupt only has 1 cycle jitter?
2004-01-09 08:12
Oswald

Registered: Apr 2002
Posts: 5017
if anyone is interested, here is how the src I have does fix the jitter:

LDA #$3F
SBC $DC04
AND #$07
STA JUMP+1
JUMP BCS JUMP

LDA #$A9
LDA #$A9
LDA #$A9
LDA $A5EA
NOP
2004-01-09 08:57
Copyfault

Registered: Dec 2001
Posts: 466
@Strykker: when you have a sequence of NOPs, the minimal delay is 2 and the maximal one is 3 (as Cybernator described above). So the jitter (which is difference of them) is 1, and there's no prob with the double irq thingie!

@Oswald: is this your altered version for "stable raster via timer on rasterlines with sprites enabled" ? You can achieve it "easier" (depends on the taste;)) by just starting the (second) timer as many cycles earlier as the sprites eat up! Then the usual sync routine like LDA #$08 : SEC : SBC timer should work...

Also thought about Mager Valp's comment... IF my timer initialization should still have a jitter of one cycle (which is absolutly impossible from my point of view;)), then this wouldn't explain a total of 8 variance values, would it? It would rather lead to 7 values, but the range they lie in would depenend on the jitter of the init routine. As I do get a steady interval, I am still wondering...
2004-01-09 10:43
Cybernator

Registered: Jun 2002
Posts: 154
Copyfault wrote:

> Ok, I see! This does not even contradict the max.of
> 7 different variance values, as you get some delay
> between 2 and 8 cycles(= 7 different states).

I considered this, as I stated in the email.

> But how does an IRQ behave when triggered during a
> fulfilled branch condition?

Never thought about this. Maybe that is the answer to the 8-cycle variance thingy.

Quote from 64doc:
<-->
"To process the
interrupt before the next instruction, the interrupt must occur
before the last cycle of the current instruction."
<-->

Does this make any sense to anyone:
<-->
Relative addressing (BCC, BCS, BNE, BEQ, BPL, BMI, BVC, BVS)

# address R/W description
--- --------- --- ---------------------------------------------
1 PC R fetch opcode, increment PC
2 PC R fetch operand, increment PC
3 PC R Fetch opcode of next instruction,
If branch is taken, add operand to PCL.
Otherwise increment PC.
4+ PC* R Fetch opcode of next instruction.
Fix PCH. If it did not change, increment PC.
5! PC R Fetch opcode of next instruction,
increment PC.

Notes: The opcode fetch of the next instruction is included to
this diagram for illustration purposes. When determining
real execution times, remember to subtract the last
cycle.

* The high byte of Program Counter (PCH) may be invalid
at this time, i.e. it may be smaller or bigger by $100.

+ If branch is taken, this cycle will be executed.

! If branch occurs to different page, this cycle will be
executed.
<-->

Anyway, the last cycle _may_ refer to the minimum nr. of cycles an opcode can have. (eg. when not taking a branch, or when there's no page-crossing). In that case, this is probably the answer:

inc $c000,x: 1234567
bpl loop : 123

If the IRQ occurs in the 2nd cycle of BPL, there will be 9 cycles delay. On the other hand, if it occurs in the 6th cycle of INC, there will be 2 cycles delay.

Let's count once again: 2, 3, 4, 5, 6, 7, 8, 9... Err... 8-cycle variance! Was this fermenting? :)

Anyway, nothing has been proved yet!
2004-01-09 11:39
Stryyker

Registered: Dec 2001
Posts: 465
You saying if we are currently processing the branch and on the last cycle when the IRQ is triggered then the CPU will do next instruction then perform interrupt? That would explain the 8, 1 for the current cycle and 7 for the inc. Would be nice if C64 address and data lines could be plugged into PC and trace all this.
2004-01-09 12:22
Copyfault

Registered: Dec 2001
Posts: 466
Yes, Cybernator, this was exactly my thought! Thanks for presenting the details (thought they were clear to everone!).

*If* this is true, we should also get 9 different variance values, because a delay of 10 cycles should occur when the irq is triggered in the second cycle of a branch that _is_ taken _and_ goes over a page! And even worse, if you replace the INC adr,X by some Illegal-indexed-ZP-RMW (e.g. ISB (zp),Y), the delay should be 11 cycles long! I made some fast tests but didn't get any desired variance values...
2004-01-09 15:24
HCL

Registered: Feb 2003
Posts: 716
You guys are thinking too much ;)
2004-01-11 15:45
Cybernator

Registered: Jun 2002
Posts: 154
Since my post at CBM-Hackers received no replies, I took the liberty to contact Marko Makela. Here's what he says about the last cycle:

"By last cycle of an instruction, I meant the cycle that precedes the opcode
fetch cycle of the next instruction (which will be executed)."

If you check the table I copy-pasted above (it's completely messed up, take a look at 64doc instead), you'll see that branch instructions fetch the opcode of the next instruction. The first opcode fetch occurs at the 3rd cycle, so cycle 2 is the last one. If an IRQ occurs at cycle 2, there will be 9 cycles delay.

Simple, eh? :) Not really. What if the IRQ occurs at the first cycle? The first opcode of the IRQ should occur right after the branch. But the branch already fetches the opcode of the next instruction, and it increments PC! So the IRQ sequence would store PC+1 (after the opcode of the next instruction). Does this really happen? If so, there must be a way that the CPU remembers that is has already fetched the opcode. But does it really work this way? I'll have to do some experiments.
2004-01-12 08:34
Oswald

Registered: Apr 2002
Posts: 5017
copyfault: nope, this is taken from the routine without sprites :) Im doubt wether starting the timer earlier will work, but it really sounds as a good solution :)
2004-01-13 13:22
Cybernator

Registered: Jun 2002
Posts: 154
Talked to Andreas Boose and he kindly explained the feature. I decided to upload his message on my site, because copy-pasting here would mess the graphs.
www.geocities.com/lazeristoski/cpu.html

After you have read his message, let's continue :)

About the "branch not allowing IRQ even if it occurred at cycle 1" thingy... I think it's not correct, as this would produce 9-cycle jitter with Copyfault's loop. I'm discussing this right now.

As you can see, it's correct that if IRQ occurs at cycle 2 of the branch, the following instruction will also be executed. This totally explains the 8-cycle jitter (and I guess this only happens with branch instructions). Now for the other feature (about the IRQ after fetching the opcode): obviously the IRQ occurs before this, ie. it blocks the last cycle of the branch (because branch really takes 3, 4 or 5 cycles, according to 64doc).

But I have another explanation about this: the opcode fetch of the last cycle of the branch is really part of the next instruction, but the branch is finishing its operation here (due to pipelining). Similar with 'eor #$nn', this instruction really needs 3 cycles, but due to pipelining it effectively takes 2 cycles.

This also explains why Copyfault couldn't produce 10-cycle jitter. :)
2004-03-03 12:36
Copyfault

Registered: Dec 2001
Posts: 466
I felt like putting some final words on this thread;)

Ok, I still wonder why Graham did never have 8 different timer values, but there are eight states. Like Cybernator stated in his last posts, this has something to do with the way a branch_instruction is carried out: normally an IRQ_Condition can be acknowledged while an instruction is being executed. But there are socalled "Opcode_fetch"-cycles which won't allow ack'ing! Let's simplify things and say these opcode_fetches are always done on the first cycle of each instruction - then ofcourse we will only get 7 different timer value, corresponding to 0-6 cycles variance, or 1-7 cycles delay resp. But if the IRQ_Condition occurs on the second cycle of a taken branch that does not cross a page, there will be no ACK in the third cycle of the branch instruction as it also is an "opcode_fetch"-cycle. In this rare case we will get a delay of 1 cycle (coming from this 3rd branch_cycle) _plus_ n cycles from the following opcode! If the following instruction is an indexed RMW, this gives us a delay of 1+7=8 cycles, explaining the 8th state I was always wondering about;))

Cybernator and me coded some fast routines to proof this. The progs allow to let the RASIRQ_condition occur on a selected cycle of our main_code. If you're interested in these programs, then just drop me a privat line here, ok?

A big thank to everyone here - you all helped to push things forward! Above all, I definatly have to thank Cybernator for all his activities and his motivation to find an answer to my question! Keep up the good work, guys!
2004-03-24 16:40
White Flame

Registered: Sep 2002
Posts: 136
Regarding the differences in CIAs, could you guys run this program if you get a sec?

http://www.white-flame.com/cyclesperframe.prg

I get 17094 for my NTSC C128, and VICE's PAL mode gives 19655. I'm curious to see what the numbers would be with an older 6526; I'm guessing they'd be one less? The number reported is the CIA timer value that synchronizes with the screen refresh.
2004-03-25 05:52
Fungus

Registered: Sep 2002
Posts: 616
This is all very interesting...

I get 9 cycles depending on if something is crossing a page boundary or not.

Also, I think ive experienced this irq on bxx bug, as I had a raster routine here somewhere which crashes for no reason, and the PC is way off...

Ill have a look.
2004-04-15 06:54
JackAsser

Registered: Jun 2002
Posts: 1989
FYI, I also get 8 different delays using copyfault's main loop.

After reading this thread I got inspired and also wanted to try to stabalize rasters using double timers since they have quite nice properties. I'm however a bit confused. How come the raster is stable at the exact the same spot on the screen every time I run the code. Shouldn't this be pretty random or has this something to do with VICE (since I autolaunch the code as fast as possible)?
As a follow up question, what method should I use to always be certain that the raster is stable on the exact same position on the screen each time run the code? My first idea was to use double rasters for the first time to lock the exact spot on the screen then use the timers but this seems a bit overkill.
What do you guys think / how do you usually do it?

For example in those 4x4 modes, what is the preferred method to use the timers here? (not that I like 4x4 modes, but hey...) =)
2004-04-17 07:57
Cybernator

Registered: Jun 2002
Posts: 154
You have to use another method (eg. double IRQ) to sync the timer. It's not overkill as you only sync the timer once.

> For example in those 4x4 modes, what is the preferred
> method to use the timers here?

Preference is a subjective matter.
Whenever you have multiple IRQs close to each other, you might want to use a timer (eg. distorters). As for double timer, I don't know where else I'd use it except for 4x4.

@White Flame: Vice and CCS emulate the old CIA! I'll see what my commies say, asap.
2004-04-17 08:24
White Flame

Registered: Sep 2002
Posts: 136
Grab this instead, it's much better: http://www.white-flame.com/timingtest.prg I've got a 128, so I'm pretty positive it has 6526A's in it, and I get the same values as NTSC VICE.

It runs the timer on continuous mode, and syncs to the screen refresh with a latch value of 17094, which takes 17095 cycles, which is sensible (65 cycles/line * 263 lines). If the latch value would sync at 17093, it would report that the CIA delays by 1 cycle. Note that the program should work on any 64, no matter the VIC-II or CIA version.

So, with 6526 vs 6526A, is the one cycle difference a difference in the actual cycles spent during timer countdown (ie, on one CIA you need to inc your timer values compared to the other, which is what the program looks for), or is it a "phase offset" where it triggers the IRQ on a different cycle than the other (trigger when it hits 0 vs trigger when it reloads the latch value)?
2004-04-17 13:37
JackAsser

Registered: Jun 2002
Posts: 1989
Quote: You have to use another method (eg. double IRQ) to sync the timer. It's not overkill as you only sync the timer once.

> For example in those 4x4 modes, what is the preferred
> method to use the timers here?

Preference is a subjective matter.
Whenever you have multiple IRQs close to each other, you might want to use a timer (eg. distorters). As for double timer, I don't know where else I'd use it except for 4x4.

@White Flame: Vice and CCS emulate the old CIA! I'll see what my commies say, asap.


Ahh, ok. I usually use double IRQ, that's the only way I fully understands why it works. Can someone perhaps explain the half-variance method? I can understand that it should work but how do you reason when calculating the cycles.
2004-04-17 14:27
Cybernator

Registered: Jun 2002
Posts: 154
Half-variance method !?

> So, with 6526 vs 6526A, is the one cycle
> difference a difference in the actual cycles
> spent during timer countdown (ie, on one CIA
> you need to inc your timer values compared to
> the other, which is what the program looks for),

I doubt it's the case, because that would lead to significant incompatibility!

> or is it a "phase offset" where it triggers the
> IRQ on a different cycle than the other (trigger
> when it hits 0 vs trigger when it reloads the
> latch value)?

Most probably! The problem finally occurred in my 4x4 routine. At first it worked a-ok, then (after a lot of mods in the code) it began to flicker like hell while it worked perfectly in an emu. I tried an old C64 and it worked there too! (Might have been page-crossing thing). The IRQ was occurring one cycle earlier and after a quick patch the routine worked on both CIAs.

Btw, you could never read 0 from $dc04 (or whatever) when on continuous mode! Let's suppose the timer counts down from 5. What you'd read is: 5, 4, 3, 2, 1, 5, 5, 4, 3, 2, 1, 5, 5, 4, etc... Maybe the whole issue starts here? ;)
There's an article written by Wolfgang Lorenz at Funet, explaining this behaviour. Have a look!

2004-04-17 16:27
JackAsser

Registered: Jun 2002
Posts: 1989
Half-variance, the method used on VIC20 for instance, when you can't use raster interrupts.
2004-04-17 20:16
White Flame

Registered: Sep 2002
Posts: 136
> Btw, you could never read 0 from $dc04 (or whatever) when
> on continuous mode! Let's suppose the timer counts down
> from 5. What you'd read is: 5, 4, 3, 2, 1, 5, 5, 4, 3, 2,
> 1, 5, 5, 4, etc... Maybe the whole issue starts here? ;)

It's still a 6-cycle pattern when 5 is loaded, so there should be no difference. I don't read the timer value at all. I'll check that article out, though.

Graham, do you have any more info on the 6526/6526A difference? I don't have a 6526 in any of my machines. I don't think that a 1-cycle offset will matter incredibly much for my routine (since it does a cycle patchup via reading $d011), but it does need to be cycle-exact.
2004-04-18 20:13
Cybernator

Registered: Jun 2002
Posts: 154
@JackAsser: Never really tried to understand that method. Maybe I will when I decide to code a Viccy demo. ;)

> It's still a 6-cycle pattern when 5 is loaded,
> so there should be no difference. I don't read
> the timer value at all. I'll check that article
> out, though.

I wasn't talking about your code. It was an idea, which crossed my mind that maybe the chip's designers have had their trouble here, which lead to incompatibility. But that's pretty much irrelevant.

Tested both routines on 6526A - PAL.

Cycles per Frame:
19655

Timing test:
63 cycles per line
19656 cycles per frame
312 lines
CIA #2 timer delays by 0 cycles

Haven't tested with an old CIA, but I'm pretty sure that the values would be the same as in Vice. And strange enough, they are the same as on 6526A. Is the timer on continuous or one-shot mode?
2004-04-18 21:23
White Flame

Registered: Sep 2002
Posts: 136
The timer is in continuous mode. The number reported in "cyclesperframe.prg" just gives the timer value that syncs to the screen. "timingtest.prg" adds 1 to the value, because then it actually reflects the number of clocks per countdown cycle.

It shouldn't be too difficult for me to measure the "phase offset" effect of the old timer, if that's what it does. However, if somebody could run that program on a machine with old 6526's and verify that it still reports a timer delay of 0 cycles, that'd be awesome.
2004-04-20 07:47
JackAsser

Registered: Jun 2002
Posts: 1989
I'm getting a little bit paranoid about all these timing differences on different CIAs. If I've undestood everything correct is that if you are using the timer approach (either signel or double) to gain stable rasters you have to be aware if you have an old or new CIA, right? So, usually I only care about if it's PAL or NTSC and in most cases I actually simply drop the NTSC support, so what about the CIA chip? Is one chip version more common than another? Are the any unwritten rules what chip the compo machine have, etc..? Or do I simply have to detect and support both inorder to not get flamed by various people? =)
2004-04-20 09:58
Krill

Registered: Apr 2002
Posts: 2839
Graham, please don't scare people so much =) In reality, the different CIA delays won't be any problem. Graham said there are different timings of CIA interrupts on different machines. Well, so what?
The most common implementation of a CIA-timed raster stabilizer (on the C64) would be to set up _one_ timer (to repeatedly count 63 cycles on PAL) in the main loop under sterile circumstances (in the border without sprites and no other possible delay factors), using the half-variance method.
Then you set up a _VIC_ raster interrupt which should have the same timing on every machine. In the irq handler, you can read out the CIA timer register and delay accordingly to get to always the same cycle and have a stable timing. The value the CIA gives is the same on every machine.
Et voilà, stable raster position on every machine.
2004-04-20 10:54
Graham
Account closed

Registered: Dec 2002
Posts: 990
@krill:

i had a pure timer based 4x4 routine in oneder and there were visible bugs on some machines due to irqs being 1 cycle too late. since the discussion is about "stable raster via timer" it is a problem.
2004-04-20 12:34
Cybernator

Registered: Jun 2002
Posts: 154
Yup! As I mentioned above, this has happened to me too!
2004-04-20 13:43
Krill

Registered: Apr 2002
Posts: 2839
that's why the method i described is the best one with timers, no cia detection needed, working same on every machine.
2004-04-20 14:43
Copyfault

Registered: Dec 2001
Posts: 466
This topic seems to get outta control... at the very beginning I only had the version with _one_ timer in my mind (like Krill) !

Up to now I haven't used the double_timer method. The _only_ advantage is that you can save some cycles on IRQ_entry - or is there even more? If we are at it at the moment:
i) what is the shortest possible way to sync the "1st" timer...

ii) ...and how do we test the CIA-Versions reliably?


...there _are_ solutions to this prob, aren't there?

One last question in my head: why do people always use two timers? Ok, it says "double timer method", but it should be possible to sync one timer (usually called the "1st" in the double_timer method), and use exactly the same one as "2nd" timer to kill the variance cycles - or do I miss something?

Later
/Copyfault
2004-04-21 05:04
White Flame

Registered: Sep 2002
Posts: 136
Well, I pulled apart my 128, and lo and behold there are a pair of non-A 6526's staring up at me. :-P So, can I get a few testers for yet another version of http://www.white-flame.com/timingtest.prg ? This one *should* detect between a 6526 and 6526A. I'll yank apart some non-working C64s from home and see if I can get some 6526A's.

(I also was curious as to whether or not sprite DMA still happened when you turned the screen off... it does)

Here's the relevant code:

;---------
; 6526 vs 6526A
;
; Set off a single-shot NMI to interrupt
; immediately before an INC statement. The
; older 6526 triggers one cycle later, so it
; will run the INC while the newer one won't.

testCIAVersion:
; Set NMI vector
lda #<continue
sta $fffa
lda #>continue
sta $fffb

; Set timer to 5 cycles
lda #4
sta $dd04
lda #0
sta $dd05

; Clear the detection flag
sta oldCIA

; Fire a 1-shot timer
lda #%10011001
sta $dd0e

; This should be interrupted before the INC
; only if it's a newer chip.
lda $dd0d
lda $dd0d
inc oldCIA
jmp * ; just in case

continue:
lda $dd0d
pla
pla
pla
rts

oldCIA:
.res 1
2011-09-30 11:37
Cruzer

Registered: Dec 2001
Posts: 1048
So glad I found this topic! :)
2011-09-30 12:21
chatGPZ

Registered: Dec 2001
Posts: 11113
one of the better summaries on the topic indeed :)
2011-09-30 13:02
ready.

Registered: Feb 2003
Posts: 441
Quoting Krill
Graham, please don't scare people so much =) In reality, the different CIA delays won't be any problem. Graham said there are different timings of CIA interrupts on different machines. Well, so what?
The most common implementation of a CIA-timed raster stabilizer (on the C64) would be to set up _one_ timer (to repeatedly count 63 cycles on PAL) in the main loop under sterile circumstances (in the border without sprites and no other possible delay factors), using the half-variance method.
Then you set up a _VIC_ raster interrupt which should have the same timing on every machine. In the irq handler, you can read out the CIA timer register and delay accordingly to get to always the same cycle and have a stable timing. The value the CIA gives is the same on every machine.
Et voilà, stable raster position on every machine.


I fully agree! Best topic on the subject. Especially Krill's post really opened my mind and made "Aurora 100%" last part possible, where I needed 100% stable raster for the fullscreen sprite split. I even mentioned Krill in the note for his post!
2011-10-02 13:44
Cruzer

Registered: Dec 2001
Posts: 1048
Btw, does anyone know if 9 different jitter cases (0-8 cycles) is the absolute maximum one has to take into consideration, or have there been other even more extreme situations discovered?
2011-10-02 17:38
terric
Account closed

Registered: Feb 2009
Posts: 47
Most intresting topic.

( How it works ,My shot( a guess ):
Those Jittercases is an ongoing instruction and interrupt have to wait 0-8 cycles to occur.
So if processor just has gotten an instruction irq have to wait max of 7 cycles ( an example asl $1234,x ) and a fetch cycle for pc? )
What about those illegal ops, are there any know cycleburners? :D
2011-10-02 18:10
terric
Account closed

Registered: Feb 2009
Posts: 47
About those extreme situations.

Most situations is controllable. We have seen restore disablers and other stuff. (restore fires off a nmi right?!)
So my advice, disable irq that are not needed and you
have control over which sources that will take cycles.
By example:
You have a timer interrupt.
It fires off at once a frame.
What the timer does is like playing music, shifting to finished screen and acknowledges interrupt and ends interr.
Still rastertime left, yes we have
and goes back to where processor was last time.

And where were the processor,
Frst frame:
Processor have just finished the initilising code for the timer int and jmped to music_init. Heads back to code after.(an loop)

x frame: Processor heads back to stored location in loop.

Hope some need a little advice, or like remember this right! :)

RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Mike
Lazycow
Apollyon/ALD
Genius/Xenon
jmin
Guests online: 126
Top Demos
1 Next Level  (9.8)
2 Mojo  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 Comaland 100%  (9.6)
6 No Bounds  (9.6)
7 Uncensored  (9.6)
8 Wonderland XIV  (9.6)
9 Bromance  (9.6)
10 Memento Mori  (9.6)
Top onefile Demos
1 It's More Fun to Com..  (9.7)
2 Party Elk 2  (9.7)
3 Cubic Dream  (9.6)
4 Copper Booze  (9.5)
5 TRSAC, Gabber & Pebe..  (9.5)
6 Rainbow Connection  (9.5)
7 Onscreen 5k  (9.5)
8 Wafer Demo  (9.5)
9 Dawnfall V1.1  (9.5)
10 Quadrants  (9.5)
Top Groups
1 Oxyron  (9.3)
2 Nostalgia  (9.3)
3 Booze Design  (9.3)
4 Censor Design  (9.3)
5 Crest  (9.3)
Top Musicians
1 Rob Hubbard  (9.7)
2 Jeroen Tel  (9.7)
3 Stinsen  (9.6)
4 Mutetus  (9.6)
5 Linus  (9.6)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.135 sec.