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 > Cycles to get into IRQ routine
2015-05-20 04:17
Hypnosis

Registered: Mar 2015
Posts: 36
Cycles to get into IRQ routine

How many cycles does it take from an IRQ trigger to the start of the IRQ routine, assuming the CPU finished the instruction when it triggers? It should be around 6-9 cycles but I'm not sure how many.
2015-05-20 04:34
Mixer

Registered: Apr 2008
Posts: 447
http://codebase64.org/doku.php?id=base:making_stable_raster_rou..

Read that. See background section. It'll explain what is going on.
2015-05-20 04:37
Hypnosis

Registered: Mar 2015
Posts: 36
Thanks a lot!
2015-05-20 07:12
MagerValp

Registered: Dec 2001
Posts: 1074
See the section "Interrupts" here: http://vice-emu.sourceforge.net/plain/64doc.txt

Note that IRQs are checked *before* the last cycle of an instruction executes, and not between instructions as you might expect.
2015-05-20 09:00
Hypnosis

Registered: Mar 2015
Posts: 36
Ooh, that was really handy, showing the memory accesses per cycle and instruction in nice tables!
2015-05-22 08:06
JackAsser

Registered: Jun 2002
Posts: 2014
Things get a bit more tricky men using NMI together with IRQ. If an NMI triggers while the IRQ is being setup, the NMI will get stalled the addional cycles it takes for the CPU to complete the IRQ-setup.
2015-05-22 12:22
MagerValp

Registered: Dec 2001
Posts: 1074
You're not talking about an NMI "stealing" an IRQ in progress are you? Please explain what you mean by "setup" and "stalled".
2015-05-22 16:18
Hypnosis

Registered: Mar 2015
Posts: 36
I would assume setup would mean push PC and status on stack and stalled would mean waiting for additional cycles to push on the stack, perhaps another 7 cycles?
2015-05-22 18:08
Flavioweb

Registered: Nov 2011
Posts: 463
Quoting Hypnosis
I would assume setup would mean push PC and status on stack and stalled would mean waiting for additional cycles to push on the stack, perhaps another 7 cycles?

This seems to be a "borderline case", where we can have an "Interrupt hijacking".

The MOS 6502 and by extension the 2A03/2A07 has a quirk that can cause one type of interrupt to partially hijack another type if they occur very close to one another.

For example, if NMI is asserted during the first four ticks of a BRK instruction, the BRK instruction will execute normally at first (PC increments will occur and the status word will be pushed with the B flag set), but execution will branch to the NMI vector instead of the IRQ/BRK vector:

Each [] is a CPU tick. [...] is whatever tick precedes the BRK opcode fetch.

Asserting NMI during the interval marked with * causes a branch to the NMI routine instead of the IRQ/BRK routine:

     ********************
[...][BRK][BRK][BRK][BRK][BRK][BRK][BRK]


http://wiki.nesdev.com/w/index.php/CPU_interrupts
2015-05-23 09:58
MagerValp

Registered: Dec 2001
Posts: 1074
Yes, this is the NMI stealing or hijacking a BRK or IRQ, however you want to call it. There are no stalls here though, it's the same 7 cycles as always, just jumping to the NMI vector at the end.
2015-05-23 15:12
JackAsser

Registered: Jun 2002
Posts: 2014
Quote: Yes, this is the NMI stealing or hijacking a BRK or IRQ, however you want to call it. There are no stalls here though, it's the same 7 cycles as always, just jumping to the NMI vector at the end.

Well. I had to conpensate for an additional 3c jitter i clearly remember.
2015-05-23 17:20
MagerValp

Registered: Dec 2001
Posts: 1074
Maybe from CLI/SEI/PLP as described in the link above?
2015-05-23 19:18
JackAsser

Registered: Jun 2002
Posts: 2014
Quote: Maybe from CLI/SEI/PLP as described in the link above?

Didn't investigate it too deep. With plain NMI I had 7c jitter which I compensated for using indirect jumps into code places on the timer-addresses. Adding raster IRQ gave me an additional 3c jitter. Supporting old and new CIA I treated just like yet another 1c jitter. So in total I had 11 compensation routines at $xx00.
2015-05-23 19:52
lft

Registered: Jul 2007
Posts: 369
Perhaps you ran into this little corner case.
2015-05-23 20:30
MagerValp

Registered: Dec 2001
Posts: 1074
Interesting, I don't think my emulator core handles that case!
2015-05-23 21:33
Flavioweb

Registered: Nov 2011
Posts: 463
Quoting JackAsser
Didn't investigate it too deep. With plain NMI I had 7c jitter which I compensated for using indirect jumps into code places on the timer-addresses.

Seems that, to be totally sure to "compensate" all possible jitter ranges (without using illegal opcodes), we need to have a 10 cycles "compensation code".
- 2 cycles for minimum irq jitter;
- 1 cycle or 3 cycles if "branch taken" + next opcode cycles.
So, worst case: 3 + 7 cycles like
LOOP
    INC $FFFF,X
    DEX
    BNE LOOP

if irq is triggered on first cycle of BNE, then BNE + INC are executed before CPU starts irq sequence...
But this isn't related on have an irq that occur very close to one another, and should happen anyway.
2015-05-25 21:42
Copyfault

Registered: Dec 2001
Posts: 475
Without any unintended opcodes there's a 8c jitter - this was discussed "a decade ago" in Stable Raster via Timer.

It's interesting to see that 7c jitter still seems to be THE standard for max jitter; I hoped this had changed by the discussion once and for all.


However, mixing IRQ with NMI and having them overlapped as mentioned by Jackasser was not focused on back then. Are there really different states resulting in more than 8c jitter? Following the final explanation of the old discussion this could be the case if the first IRQ cycles are also "opcode fetch cycles" that block other interrupts.

Maybe it's a good idea to do a complete writeup of the irq jitter topic, e.g. a chart with all possible IRQ settings and the resulting jitter max values (just like Groepaz did for the unintended opcodes some time ago;))
2015-05-26 05:14
Oswald

Registered: Apr 2002
Posts: 5086
So how can the inc be executed if irq happens on first cycle of bne ?

according to copyfault "Note that IRQs are checked *before* the last cycle of an instruction executes, "
2015-05-26 07:40
HCL

Registered: Feb 2003
Posts: 727
I think 7 cycles jitter is enough in most cases, as it depends on what kind of op-codes you are using. Legal op-codes use max 7 cycles, only a few illegal ones use 8 cycles. So.. if you are not planning on using them outside your irq, you can of course have less jitter.
2015-05-26 19:23
Copyfault

Registered: Dec 2001
Posts: 475
From what I remember right now (it's a little while ago;)):

@Oswald: if the irq happens on the first cycle of a branch, it will be processed after the second cycle of the branch; but if an irq happens during the second cycle of a branch, processing is delayed until the end of the opcode following the branch instruction.

@HCL: 8c jitter is the uncomfortable reality even when sticking to the socalled legal opcodes outside the irq. This was the major conclusion of the thread I started those years ago. This comes from the oddity of the branch logic: if a branch is taken, the additional "branch taken"-cycle adds to the no. of cycles of the following opcode and it can not be interrupted. Thus, if there is an indexed RMW instruction that can be reached by a branch _and_ if the irq happens on the second cycle of the branch (which is going to be taken), the jitter will be 8 cycles.

So it does not depend on wether using illegals or not but rather on what opcode can be reached by a branch. Ok, I have to admit that this specific case is also not very probable ;))

I'll have a look if I can find the test code I did back then; maybe I should release it here for everyone to play around with it.
2015-05-26 19:34
chatGPZ

Registered: Dec 2001
Posts: 11360
dont forget to submit that kind of code snippets for use in the VICE testprog repo :)
2015-05-26 19:38
Flavioweb

Registered: Nov 2011
Posts: 463
Quoting Copyfault
if the irq happens on the first cycle of a branch, it will be processed after the second cycle of the branch; but if an irq happens during the second cycle of a branch, processing is delayed until the end of the opcode following the branch instruction.

So, with this code
LOOP
    INC $FFFF,X
    DEX
    BNE LOOP

if an irq happens durng second cycle of BNE, and branch is taken, 2(BNE)+7(INC)=9 cycles are executed before irq and, as a "borderline case of the corner cases", if BNE cross page boundary, 3+7=10 cycles are executed.
I'm wrong?
(Ok... i know we all need to avoid boundary cross... and probably no one use a INC $FFFF,X... but it's just to see if my thoughts are correct.)
2015-05-26 20:28
Oswald

Registered: Apr 2002
Posts: 5086
"if irq is triggered on first cycle of BNE, then BNE + INC are executed before CPU starts irq sequence..."

this still doesnt seem to make sence. last cycle of bne will check forr irq condition, if bne finished then cpu jmps to irq, or why not ?
2015-05-26 20:30
Copyfault

Registered: Dec 2001
Posts: 475
@Flavio: I remember there was a different behaviour when that branch was pagecrossing.

No pagecrossing, branch taken, irq on 2nd branch cycle (marked with <>):
next op.....cycles
BNE (taken) [R=1st branch cycle]<R=2nd branch cycle>[R=add.cycle]
INC abs,X   [R=1st INC cycle][2][3][4][5][6][7]
<irq processing starts here>


Same with pagecrossing:
next op.....cycles
BNE (taken) [R=1st branch cycle]<R=2nd branch cycle>[R=add.cycle for branch taken][R=add.cycle for pagecrossing]
<irq processing starts here>


There was this explanation with socalled "opcode fetch cycles" that do not allow irq acknowledging and that an irq is not processed before it was acknowledged. Having a pagecrossing situation, the first additional branch cycle belongs to those opcode fetch cycles whereas the next additional cycle for the page crossing does not; thus, it results in less jitter.
2015-05-26 20:36
Flavioweb

Registered: Nov 2011
Posts: 463
Quoting Oswald
last cycle of bne will check for irq condition, if bne finished then cpu jmps to irq, or why not ?

If branch isn't taken, last cycle is the second, if branch is taken, last cycle is the third (or the fourth if the page boundary is crossed)...
maybe that's the "problem" ...
2015-05-26 21:52
MagerValp

Registered: Dec 2001
Posts: 1074
Quoting Oswald
this still doesnt seem to make sence. last cycle of bne will check forr irq condition, if bne finished then cpu jmps to irq, or why not ?


Branches are special. Normally IRQs are evaluated before the last cycle, which for an untaken branch is the second cycle. When branches are extended to three cycles as they are taken, or four cycles when taken across a page boundary, the IRQ evaluation at the second cycle still triggers the IRQ.

I wonder if this is true also for other instructions that are extended on page crossing, such as LDA $FFFF,X.
2015-05-27 05:11
Oswald

Registered: Apr 2002
Posts: 5086
okay, so IRQ is triggered, but not taken until BNE ends? or IRQ is taken at 2 cycle of a 4 cycle BNE, then how does the CPU find its way back to the middle of the BNE ? I dont think this latter one happens.

what exactly happens when an IRQ is evaluated ? I still dont get it how irq could be delayed to happen after the next instruction after the BNE, if it happens during a BNE.
2015-05-27 06:55
Flavioweb

Registered: Nov 2011
Posts: 463
I suppose that BNE "decides" to execute next op during his second cycles, but as copyfault stated, additional cycles are "added" later... so cpu execute added operations then execute next op, like if irq is triggered on second as last cycle of bne.
2015-05-27 10:09
lft

Registered: Jul 2007
Posts: 369
I think the key is to ask: Why is the interrupt inhibited during the second tentative opcode fetch, but not during the first?

That is, on a 4-cycle branch, we're performing two speculative opcode fetches before the third (correct) fetch. It appears that the first speculative fetch can be replaced with a BRK/IRQ (so the interrupt immediately follows a 2-cycle branch-not-taken). The third fetch can also be replaced (so the interrupt immediately follows a 4-cycle branch with page crossing). But the second is inhibited.

I think the answer has to do with how the PC register is updated. It can be incremented in a single cycle, or it can be loaded through the ALU in one or two cycles depending on whether there is a carry. The interrupt mechanism needs to push PC to the stack.

During a normal fetch, the PC reflects the value that needs to be pushed, so if the fetch is replaced with a BRK, we can presumably also inhibit the normal increment, and write the PC to the stack.

During the first tentative fetch, the PC also reflects the value that needs to be pushed if the branch is not taken---which we know at this point.

But during the second tentative fetch, the PC could be wrong. We have already written the PC LSB, so there's no way to go back; we have to do the carry-adjust (if ALU reports a carry). Thus, we cannot at this point push the PC to the stack. Actually, we could, but we'd have to take the carry signal from the ALU into consideration. I think, quite simply, that the design team were cutting corners here, and saving silicon by leaving out that special case.

So it boils down to this: We cannot divert an opcode fetch that follows a 3-cycle branch-taken, because we don't know yet whether this is a 4-cycle branch. And thus we could potentially be pushing an invalid return address.

But what about an infinite branch-to-self? Surely it can be interrupted? Has anybody investigated?
2015-05-27 10:23
MagerValp

Registered: Dec 2001
Posts: 1074
What? No, the branch doesn't get split in two. Evaluation, that is whether an IRQ should be acted on, is separate from triggering. They don't happen at the same time. Roughly speaking IRQs and NMIs just force the CPU to execute a BRK instruction instead of the next opcode. The point is that IRQ evaluation happens one cycle earlier than what most programmers and emulator writers expect, and in the case of branch instructions even earlier in some cases.
2015-05-27 10:31
lft

Registered: Jul 2007
Posts: 369
@MagerValp: I'm not sure if that was a response to my post, but here's what's confusing: Consider a 4-cycle branch. After fetching the branch opcode and the branch offset, there are three cycles in which the next opcode is fetched. The first two are thrown away. Of these three cycles, it appears that the first and the third can be diverted to interrupt handling (BRK). So there's a conspicuous gap in the middle, which cannot be explained simply by saying that the evaluation happens at some specific time.
2015-05-27 10:31
MagerValp

Registered: Dec 2001
Posts: 1074
Quoting lft
But what about an infinite branch-to-self? Surely it can be interrupted? Has anybody investigated?


Of course. If I'm reading the 6502.org thread correctly the only gotcha is that if the IRQ is activated during cycle 3 of a taken branch it'll loop one more time before the IRQ handler is triggered, compared to an IRQ activating during other cycles.

Is there perhaps a test program in the VICE repo for this?
2015-05-27 11:50
lft

Registered: Jul 2007
Posts: 369
This nesdev page is also interesting:

Quote:
The branch instructions have more subtle interrupt polling behavior. Interrupts are always polled before the second CPU cycle (the operand fetch). Additionally, for taken branches that cross a page boundary, interrupts are polled before the PCH fixup cycle


This confirms the observed behaviour, but it doesn't explain the design rationale. My post is an attempt at that.
2015-05-27 15:28
MagerValp

Registered: Dec 2001
Posts: 1074
Quoting lft
@MagerValp: I'm not sure if that was a response to my post

No, that was a response to Oswald, your post happened while I was writing :)
2015-05-27 16:17
tlr

Registered: Sep 2003
Posts: 1787
Quote: Quoting lft
But what about an infinite branch-to-self? Surely it can be interrupted? Has anybody investigated?


Of course. If I'm reading the 6502.org thread correctly the only gotcha is that if the IRQ is activated during cycle 3 of a taken branch it'll loop one more time before the IRQ handler is triggered, compared to an IRQ activating during other cycles.

Is there perhaps a test program in the VICE repo for this?


The best bet would be:
https://sourceforge.net/p/vice-emu/code/HEAD/tree/testprogs/int..

I don't remember if this particular case is tested.
These tests do not test very specific cases so it can be really hard to tell the root cause of what failed.

Should work in x64sc.
2015-05-27 19:54
Copyfault

Registered: Dec 2001
Posts: 475
Isn't it amazing that this little 8-bit-bastard still keeps us busy finding explanations for its behaviour? I'm loving it!!!

My guess for an explanation of how those branches and the irqs are handled: wouldn't it be easiest (also in terms of transistors needed) to have a dedicated opcode pipe pc? This one is equal to the normal pc but will be set to the irq adress during an irq acknowledge. Now depending on the processed cycle there is an irq acknowledgment or not. During a socalled "opcode fetch cycles" the byte read from memory is fed to the instruction pipe thus it makes sense to prevent any "opcode pipe pc"-updates. Consequently, those opcode fetch cycles DO NOT acknowledge an irq.

If there's no opcode fetch, an irq can be acknowledged and the opcode pipe pc can be set to the irq adress. It might be a bit more complicated as the irq adress consists of two bytes and an update of such an "opcode pipe pc" would probably need at least two cycles, but the basic idea works for me.


I'd like to point to Jackassers findings again about jitter values larger than 8c when combining NMI and IRQ. A test prog for this case is badly needed, I'm sure my old one did not cope mixing of differnt irq types.
2015-05-27 19:56
chatGPZ

Registered: Dec 2001
Posts: 11360
protip: throw some test snippets at visual6502 - its an eye opener lots of the time :)
2015-05-27 21:01
lft

Registered: Jul 2007
Posts: 369
Do they have support for interrupts now?
2015-05-27 21:15
Flavioweb

Registered: Nov 2011
Posts: 463
I found this:
http://visual6502.org/wiki/index.php?title=6502_Timing_of_Inter..
2015-05-28 07:35
Oswald

Registered: Apr 2002
Posts: 5086
http://forum.6502.org/viewtopic.php?t=1634

interesting, so:

at *only* 3 cycle branches irq only happens after the next instruction. even if it is a branch to itself IRQ will happen during the next instruction.

"A branch may be a case a bit like an indexed write where the final instruction state must be reserved in case a page is crossed. In the case of a branch, the next instruction isn't known to have started until it's known that there's no page crossing. The following instruction after a taken branch doesn't have a normal first cycle. And so a taken branch doesn't have a 'final' state, and so it wouldn't be interruptible. Instead it begins the interrupt handler during T2, which means the NMI needs to enter the chip a bit earlier than the usual case in order to catch the window. We see that the other way around: the interrupt appears to have been deferred. "
2015-05-28 10:30
Flavioweb

Registered: Nov 2011
Posts: 463
I wrote some code to test:
https://www.dropbox.com/sh/j7v66nnzflvv8l9/AADRjZG4Aa_y5SUMbCh2..
"branch_cross.prg" to test irq with branch crossing page boundary;
"branch_no_cross.prg" to test irq with branch not crossing the boundary;
"branch_test.s" the 64tass source to check for my mistakes.
I noticed that:
- when branch NOT cross the boundary, jitter reach 10 cycles.
- when branch cross boundary, jitter stay in 8 or less cycles.
My code just check if jitter is >= 10c then change border color.
This code works the same way both on rh and vice (x64) so i suppose the emu do it the right way.
I double checked for cycles delay count via code and via breakpoint in vice (at $0900 for no cross or $0a00 for cross boundary version) and i can see that main irq code start between 9 and 17 cycles for -no cross- version, and between 9 and 15 cycles for the "cross" version.
#1 (Trace  exec 0900)  250 009
.C:0900  8D 28 09    STA $0928      - A:01 X:02 Y:00 SP:fc ..-..I.C   39465351
#1 (Trace  exec 0900)  252 009
.C:0900  8D 28 09    STA $0928      - A:01 X:01 Y:00 SP:fc ..-..I.C   39465477
#1 (Trace  exec 0900)  254 009
.C:0900  8D 28 09    STA $0928      - A:01 X:02 Y:00 SP:fc ..-..I.C   39465603
#1 (Trace  exec 0900)  000 017
.C:0900  8D 28 09    STA $0928      - A:01 X:02 Y:00 SP:fc ..-..I.C   39469265
#2 (Stop on  exec 0918)  000 047
.C:0918  8D 20 D0    STA $D020      - A:0A X:02 Y:00 SP:fc ..-..IZC   39469295

I did it properly or i did something wrong?

-EDIT-
Seems that 10c jitter only occurs on raster line 0.
In other lines max jitter is 9c.
-EDIT 2-
If IRQ is triggered on SECOND cycle of a taken branch opcode, the IRQ is delayed by one opcode.
If IRQ is triggered on FIRST cycle, IRQ is delayed by 3 cycles, in other words, executed just after branch opcode.
This means that:
An IRQ can be dalyed by 9 cycles if the taken loop is "branch opcode looping to a 7 cycles opcode" and IRQ were triggered on second cycle of branch opcode.
For a RASTER IRQ this condition (IRQ delayed by 10c) can happen only on raster line 0, because here IRQ is triggered on cycle 1. Usually, raster IRQ can be delayed by 9c if the first cycle of branch opcode were executed on last cycle of previous line.
2015-06-11 12:50
lft

Registered: Jul 2007
Posts: 369
Remember in the movie Magnolia, when the kid is watching as frogs fall from the sky? "This happens. This is something that happens."

Today I had this weird crash that would go away whenever I changed something. I finally tracked it down. My decruncher was reading a bitfield by shifting a byte in memory, in a loop. Something like:

loop
   asl   memory
   rol
   dey
   bne   loop


A raster interrupt occurred during the branch instruction, just like we discussed here, so it was delayed until after the shift instruction. This is the maximum delay if we only use legal opcodes.

Meanwhile, my raster interrupt was moving along with a border sprite, so it happened to be on rasterline 0 at this exact moment. Therefore, the interrupt was first delayed by one cycle (because rasterline 0), and then an additional eight cycles for the bne+asl combo.

The jitter compensation code was reading a timer that is counting down 8,8,7,...,1 that would normally be in the range 1..7, corresponding to the expected range of interrupt latencies. The value is EORed with 7 and stored into a branch instruction followed by a clockslide. The extra latency made the timer return 8; the branch offset became 15 and the program crashed.

As soon as I changed anything, anywhere, the crunched data would come out a little differently, and the interrupt on rasterline 0 wouldn't strike exactly on that Achilles' heel.
2015-07-27 23:23
Copyfault

Registered: Dec 2001
Posts: 475
Upped my old test prog here: Cycle Jitter TestProg. I have to admit that I was not motivated to include nmi irqs so this still needs a suitable test suite.
Quoting Flavioweb

...
-EDIT-
Seems that 10c jitter only occurs on raster line 0.
In other lines max jitter is 9c.
...

Hmm, in my routine the values read from $dc04 lie between $10 and $17, giving eight different values. In line 0 it's clear that there's another cycle offset, but for the other lines I'm not sure if you really have _nine_ different jitter values???
2015-07-28 07:47
Flavioweb

Registered: Nov 2011
Posts: 463
I registered the _nine_ cycles when, using this loop
LOOP 
    INC $FFFF,X 
    DEX 
    BNE LOOP

the first BNE cycle was executed on last cycle of previous raster line where irq is triggered.
2015-07-28 09:08
lft

Registered: Jul 2007
Posts: 369
Just to establish some common terminology:

Latency: The number of cycles from an interrupt until the first instruction in the interrupt handler starts to execute.

Jitter: The random variation in latency, i.e. the difference between minimum latency and maximum latency.

If minimum latency is equal to maximum latency, the amount of jitter is zero. Thus, if we observe e.g. four different timer values, there is a jitter of three cycles.

Returning to the topic, here's a recapitulation:

The 6502 normally checks for interrupts at the end of the second-to-last cycle of an instruction. The minimum latency is therefore 2 + 7 cycles: two for the two last cycles of the current instruction, and seven to handle the interrupt (push on stack etc.)

If we get the interrupt while executing a stream of nops, as in the double-irq method, the maximum latency is 1 + 2 + 7 cycles: one for the last cycle of the first nop (we just missed the check!), and then as above.

The longest legal instruction is seven cycles (e.g. asl abs,x). If an interrupt happens during the final cycle of the previous instruction, the latency is therefore 1 + 7 + 7 cycles.

So far, we have a jitter of (1 + 7 + 7) - (2 + 7) = 6 cycles.

Now we add the special case discussed in this thread, where a non-page-crossing branch "sticks" to the subsequent instruction (the branch target). Maximum latency is now 3 + 7 + 7, and the jitter becomes 8 cycles.

With illegal opcodes, the longest instruction is 8 cycles. If we also consider the delayed IRQ on rasterline 0 as latency, the total jitter becomes (1 + 3 + 8 + 7) - (2 + 7) = 10 cycles.

That is, we can expect 11 different timer values.

Did I get that right?
2015-07-28 09:11
Flavioweb

Registered: Nov 2011
Posts: 463
Lft: yep, you're right.
2015-07-28 09:16
lft

Registered: Jul 2007
Posts: 369
No, hang on. For branch instructions, the interrupt flag is actually checked at the end of the first cycle (but not at the end of the second cycle). So for the worst case, we're only stuck with the last two cycles of the branch. (1 + 2 + 8 + 7) - (2 + 7) = 9 cycles jitter, 10 different timer values.
2015-07-28 10:31
Flavioweb

Registered: Nov 2011
Posts: 463
Yes.
If second cycle of a taken branch opcode, is executed on cycle zero of a rasterline (first cycle of branch op is on last cycle of previous line), then cycles added to wait for current opcode to finish are 2 from taken branch, plus next opcode cycles.
So, if we have branch opcode + 7 cycles opcode, cpu wait for 2 cycles from branch + 7 cycles from next opcode.
If we are on raster line 0, and first cycle of branch is on first cycle of the line, irq is triggered on cycle 1 so our first irq opcode is far 1 + 2 + 7 + 7 = 17 cycles from first cycle of the line.
2015-07-29 19:32
Copyfault

Registered: Dec 2001
Posts: 475
Quoting lft
Just to establish some common terminology:

Latency: The number of cycles from an interrupt until the first instruction in the interrupt handler starts to execute.

Jitter: The random variation in latency, i.e. the difference between minimum latency and maximum latency.
...


Thanks for giving a proper definition of jitter - I'd even suggest to say jitter value as jitter refers more to the phenomenon itself ;).

To be honest I have been using the term jitter (value) in two different ways: sometimes for the delay until the irq handler starts, which makes sense only for a fixed situation, on other occasions for the difference between the maximal and the minimal occuring latency, which makes sense only when looking at a complete set of situations (e.g. all possible situations).

To distinguish between them I also used current jitter value and maximal jitter value resp., but your definitions suit our needs way better.

Back to the actual jitter values: my tests give
Set of situations                       jitter value/differnt timer values 
--------------------------------------  ----------------------------------
no illegals, raster irq outside line=0  7/8
illegals, raster irq outside line=0     8/9
no illegals, raster irq on line=0       8/9
illegals, raster irq on line=0          9/10

Missing in the list above is the Set of "NMI interrupts IRQ"-situations. Did anyone already have a look at these cases?
2016-03-21 06:14
Hypnosis

Registered: Mar 2015
Posts: 36
I revisited this topic since I seemed to miscalculate when I was implementing a timer interrupt. I single stepped in Vice to see where the cycles ended up. I have a stable raster interrupt firing a timer A interrupt while executing nop instructions. I use timer B to measure cycles.

What happens in Vice is that

1. timer A wraps around
2. one nop is executed
3. another nop is executed
4. next instruction is now the nmi interrupt's first instruction

What's confusing is that there are 9 cycles between step 3 and 4. If so, why is the first nop executed?
2016-03-21 07:56
lft

Registered: Jul 2007
Posts: 369
Possibly there is a delay before the CIA generates the interrupt. I believe the old and new CIA versions differ in the details here.
2016-03-21 12:03
Flavioweb

Registered: Nov 2011
Posts: 463
Seven cycles are used to "setup things" and then go to irq first opcode.
Your code seems that trigger the irq on the second cycle of first nop, so the next opcode will be executed (next nop in this case).
So: irq triggered on second nop cycle, plus 2 cycles of next nop, plus seven cycles of irq "setup code": the first cycle of your irq code is executed 10 cycles after irq is triggered...
Edit: the irq is triggered on second nop cycle, probably because you are using an old cia, where irq is triggered 1 cycle "after". Maybe if you use a new cia, only first nop will be executed...
2016-03-21 16:49
Hypnosis

Registered: Mar 2015
Posts: 36
Thanks for the input. I'll try the other CIA. This could be it.
2016-03-21 19:04
Hypnosis

Registered: Mar 2015
Posts: 36
Yep. I get the expected behavior using the new CIA.
2016-03-21 19:08
Oswald

Registered: Apr 2002
Posts: 5086
"Seven cycles are used to "setup things" "

from what I was told, irq is a hacked JSR inside the cpu, probably the +1 cycle is the status reg to stack.
2016-03-21 20:09
Copyfault

Registered: Dec 2001
Posts: 475
To work around that 1-cycle CIA-irq-trigger-latency between the different CIA revision I always use the combination of raster irq + CIA timer for dejittering.

But I know there are situations in which the double timer method is a must... doesn't Codebase have some example code for CIA type detection including the corresponding code adjustments ready to use?
2016-03-21 20:22
chatGPZ

Registered: Dec 2001
Posts: 11360
if not, there are plenty such routines in the VICE testrepo :)
2016-03-22 06:09
Hypnosis

Registered: Mar 2015
Posts: 36
I solved it by treating it as another jitter cycle.
2016-03-22 07:53
JackAsser

Registered: Jun 2002
Posts: 2014
Quote: I solved it by treating it as another jitter cycle.

My standard approach as well, unless you really really need that one extra cycle in your super optimised raster code.
2016-03-22 07:58
Bitbreaker

Registered: Oct 2002
Posts: 504
And how can a demo effect profit from all this knowledge? :-D
2016-03-22 08:23
lft

Registered: Jul 2007
Posts: 369
Typical application: 8-bit sample playback. NMI triggers a routine which must be cycle-exact, and it happens 156 times per frame so every saved cycle matters.

When using distributed jitter correction (different code variants in the 0100-08ff range), you have to take the CIA difference into account. However, you don't necessarily have to detect the CIA version, it can be enough to initialise the timer from within an NMI handler.
2016-03-22 08:53
JackAsser

Registered: Jun 2002
Posts: 2014
Quote: And how can a demo effect profit from all this knowledge? :-D

They already did... First time I did it was in the vector balls on top of 4x4 fli tunnel in The Wild Bunch f.e.
2016-03-22 08:54
Flavioweb

Registered: Nov 2011
Posts: 463
Opening sideborder using stable cia based irq... just stop working if running on -wrong- cia...
2016-03-22 10:38
Hypnosis

Registered: Mar 2015
Posts: 36
In my case it is 8-bit sample playback. I'm doing the memory saving option first with dynamic cycle delay in code.
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
Haplo
Wayne/Art Ravers
iceout/Avatar/HF
WVL/Xenon
Higgie/Kraze/Slackers
instant
Guests online: 91
Top Demos
1 Next Level  (9.7)
2 13:37  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 Mojo  (9.6)
6 The Demo Coder  (9.6)
7 What Is The Matrix 2  (9.6)
8 Uncensored  (9.6)
9 Wonderland XIV  (9.6)
10 Comaland 100%  (9.6)
Top onefile Demos
1 Layers  (9.6)
2 Party Elk 2  (9.6)
3 Cubic Dream  (9.6)
4 Copper Booze  (9.6)
5 Libertongo  (9.5)
6 Rainbow Connection  (9.5)
7 Onscreen 5k  (9.5)
8 Morph  (9.5)
9 Dawnfall V1.1  (9.5)
10 It's More Fun to Com..  (9.5)
Top Groups
1 Performers  (9.3)
2 Booze Design  (9.3)
3 Oxyron  (9.3)
4 Nostalgia  (9.3)
5 Triad  (9.2)
Top NTSC-Fixers
1 Pudwerx  (10)
2 Booze  (9.7)
3 Stormbringer  (9.7)
4 Fungus  (9.6)
5 Grim Reaper  (9.3)

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