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
Resuming properly from interrupts.
-
- Experienced Member
- Posts: 99
- Joined: Mon Dec 14, 2009 1:01 pm
-
- XCore Expert
- Posts: 844
- Joined: Sun Jul 11, 2010 1:31 am
As far as I know, you always should return to SPC, except when returning from a KCALL.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.
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 :-)
That is impossible to do in general, so that makes me think it doesn't work this way,It's fine to detect if an instruction is paused, but I'm not sure how you detect a new branch...
as well.
-
- Experienced Member
- Posts: 99
- Joined: Mon Dec 14, 2009 1:01 pm
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.As far as I know, you always should return to SPC, except when returning from a KCALL.
-
- XCore Expert
- Posts: 844
- Joined: Sun Jul 11, 2010 1:31 am
The proiblem is not the stack. The issue is that the KCALL insn leaves the address ofJamie wrote: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.As far as I know, you always should return to SPC, except when returning from a KCALL.
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?
-
- Experienced Member
- Posts: 99
- Joined: Mon Dec 14, 2009 1:01 pm
Indeed, KCALL invokes an interrupt so the effect is the same as an interrupt occurring at the same point.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.
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.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.
-
- XCore Expert
- Posts: 844
- Joined: Sun Jul 11, 2010 1:31 am
There is no way to detect whether the last executed insn was a jump, so if what you say isThat'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.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.
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
-
- Experienced Member
- Posts: 99
- Joined: Mon Dec 14, 2009 1:01 pm
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.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!
-
- Member++
- Posts: 31
- Joined: Thu Dec 10, 2009 10:11 pm
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.
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.
-
- XCore Expert
- Posts: 844
- Joined: Sun Jul 11, 2010 1:31 am
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 :-(
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 :-(
-
- Experienced Member
- Posts: 99
- Joined: Mon Dec 14, 2009 1:01 pm
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:
When compiled and run as:
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);
}
}
Code: Select all
xcc test.xc -target=XK-1 -O2
xsim a.xe -t --iss > dump.txt