Resuming properly from interrupts.

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
Jamie
Experienced Member
Posts: 99
Joined: Mon Dec 14, 2009 1:01 pm

Resuming properly from interrupts.

Post by Jamie »

I'm not sure if I'm missing something, but it seems like returning from an interrupt to the correct position and state of your program properly is tricky for the following reasons.

* If you interrupt a non-branching, non-paused instruction you must increment the PC. If the instruction is of a long form this need to be Bpw, or for a short instruction Bpw/2.
* If the instruction is paused, i.e. a blocking input, then you return to this same PC.
* If the last instruction was a branch then you must also return to this PC.

It's fine to detect if an instruction is paused, but I'm not sure how you detect a new branch...

I'm also wondering if this is the best way to go about dealing with this issue? And if there are any other interrupt cases to be aware of.

Jamie


User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Jamie wrote:I'm not sure if I'm missing something, but it seems like returning from an interrupt to the correct position and state of your program properly is tricky for the following reasons.

* If you interrupt a non-branching, non-paused instruction you must increment the PC. If the instruction is of a long form this need to be Bpw, or for a short instruction Bpw/2.
As far as I know, you always should return to SPC, except when returning from a KCALL.
I might be wrong, I haven't tested interrupts yet, and the architecture manual isn't
totally clear. Is there some other doc?

Also, 4 and 2 bytes, not Bpw and Bpw/2 :-)
It's fine to detect if an instruction is paused, but I'm not sure how you detect a new branch...
That is impossible to do in general, so that makes me think it doesn't work this way,
as well.
User avatar
Jamie
Experienced Member
Posts: 99
Joined: Mon Dec 14, 2009 1:01 pm

Post by Jamie »

As far as I know, you always should return to SPC, except when returning from a KCALL.
My interrupt handler switches to a kernel stack (KENTSP...KRESTSP) but I'm not sure why it would be any different for an interrupt handler which uses the program stack, the same issues apply.
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Jamie wrote:
As far as I know, you always should return to SPC, except when returning from a KCALL.
My interrupt handler switches to a kernel stack (KENTSP...KRESTSP) but I'm not sure why it would be any different for an interrupt handler which uses the program stack, the same issues apply.
The proiblem is not the stack. The issue is that the KCALL insn leaves the address of
itself in SPC, so returning to it would cause a loop.

As far as I understand, when an interrupt happens, the current instruction is not executed,
but a special "interrupt noop" is executed instead. So SPC points to the correct instruction
to return to.

Do you see something else happening?
User avatar
Jamie
Experienced Member
Posts: 99
Joined: Mon Dec 14, 2009 1:01 pm

Post by Jamie »

The proiblem is not the stack. The issue is that the KCALL insn leaves the address of
itself in SPC, so returning to it would cause a loop.
Indeed, KCALL invokes an interrupt so the effect is the same as an interrupt occurring at the same point.
As far as I understand, when an interrupt happens, the current instruction is not executed,
but a special "interrupt noop" is executed instead. So SPC points to the correct instruction
to return to.
That's not the case, it's not post-incremented as you might expect; the pc remains on the last executed instruction, or in the case of branches, the computed value.
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

As far as I understand, when an interrupt happens, the current instruction is not executed,
but a special "interrupt noop" is executed instead. So SPC points to the correct instruction
to return to.
That's not the case, it's not post-incremented as you might expect; the pc remains on the last executed instruction, or in the case of branches, the computed value.
There is no way to detect whether the last executed insn was a jump, so if what you say is
true, there is no reliable way to return from an interrupt.

So, again, do you have any reference for this? Let's hope it's not actually terminally
broken!


Segher
User avatar
Jamie
Experienced Member
Posts: 99
Joined: Mon Dec 14, 2009 1:01 pm

Post by Jamie »

There is no way to detect whether the last executed insn was a jump, so if what you say is
true, there is no reliable way to return from an interrupt.

So, again, do you have any reference for this? Let's hope it's not actually terminally
broken!
I've observed this with the software I'm working on but as you can imagine it's difficult to reproduce. Based on the facts though, there *should* be a way to cope with this behaviour. I guess it's most likely I'm missing something here but it is not obvious how I could take a different approach.
User avatar
dave
Member++
Posts: 31
Joined: Thu Dec 10, 2009 10:11 pm

Post by dave »

When an interrupt is taken, the spc will be pointing to the next instruction to be executed after the interrupt. So a KRET will return to the correct place.

When an exception occurs, the spc will point to the instruction that gave rise to the exception. This makes it possible to find out exactly what has caused the exception, and potentially to take some action that will enable the instruction to re-execute correctly.

When a KCALL or KCALLI is executed, the effect is the same as an exception. This is not actually necessary and means that the spc has to be modified before executing KRET after a kcall.
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Excellent, so everything is sane and nice and easy -- well except possibly the kcall behaviour :-)

Dave, while we have your attention, a related question: when an event happens, what is the
exact timing? There is a single fetch noop, but anyhing else? Does this also happen when
the vector happens to point to code already fetched (not very likely, but...) And in fast mode?
And the same question for interrupts :-)

It isn't totally clear to me from the existing documentation, I'm afraid :-(
User avatar
Jamie
Experienced Member
Posts: 99
Joined: Mon Dec 14, 2009 1:01 pm

Post by Jamie »

So it turns out that xsim (erroneously) produces this kind of behaviour with the --iss (instruction set simulation only) flag.

This example code reproduces the problem:

Code: Select all

#include <xs1.h>

send1(int i, chanend o1) {
   timer t;
   for(int k = 0; k < 50; k++) {
       i += 1000;
       t when timerafter(i) :> void;
       outct(o1, 3);
       outuchar(o1, 2);
   }
}

send2(int i, chanend o1) {
   timer t;
   for(int k = 0; k < 50; k++) {
       i += 1000;
       t when timerafter(i+k) :> void;
       outct(o1, 1);
       outuchar(o1, 2);
   }
}

consume(chanend c1, chanend c2) {

    asm("ldap r11, handle\n"
       "setv res[%0], r11\n"
       "setc res[%0], 0xa\n"
       "eeu res[%0]\n"
       "setsr 2\n"
       "bu overthis\n"
       "handle:\n"
       "chkct res[r1], 1\n"
       "int r11, res[r1]\n"
       "kret\n"
       "overthis:\n"
       :: "r" (c2));

    for(int k = 0; k < 50; k++) {
       chkct(c1, 3);
       inuchar(c1);
   }
   inuchar(c2);
}

main() {
   timer t;
   int i = 0;
   chan c1, c2;
   t :> i;
   par {
       consume(c1, c2);
       send1(i, c1);
       send2(i, c2);
   }
}
When compiled and run as:

Code: Select all

xcc test.xc -target=XK-1 -O2
xsim a.xe -t --iss > dump.txt