How to detect data presence in channels

Non-technical related questions should go here.
User avatar
fabriceo
XCore Addict
Posts: 220
Joined: Mon Jan 08, 2018 4:14 pm

How to detect data presence in channels

Post by fabriceo »

Hello,
I would like to test the presence of a new data or token in a channel within a while(1) loop from C langage, and not using XC select.

From my understand and testing, sending a data or token over a channel stores the value in a buffer (some sort of fifo) and this doesn't block the sender unless the buffer is full.
On the receiver side, reading a channel with in or inct will block the program until a data or token is present, same for testct.
I d like to avoid that situation for an asynchronous transfer.

But looking into the ISA documentation, I didn't find any instruction to access the event status of a given resource. am I wrong ?

the only way I can imagine would be to implement a test sub routine with following code:

Code: Select all

int void testchannel(unsigned c) {
SETV res[c], Label //initialise event vector with address pointing to Label below
EEU res[c]   //enable events for this channel
LDC R0,0
SETSR 1 //this will now enable event handling in the thread and possibly jump immediately to vector Label
NOP
EDU res[c]  //disable events for this channel
SUB R0,R0,1
Label:
ADD R0,R0,1
SETSR 0   //disable event handling in the thread
CLRE
return R0 }
when calling the routine, if there is no data pending in the channel buffer then no event will be triggered and therefore the result of the routine will be 0.
otherwise an event will be triggered when enabling them in the thread status register (with SETSR 1) and then the SUB R0,R0,1 will not be executed, the result of the routine will be 1.

Any other idea, feedback or thought welcome, thanks !
User avatar
fabriceo
XCore Addict
Posts: 220
Joined: Mon Jan 08, 2018 4:14 pm

Post by fabriceo »

okay, I got this to work :)

Code: Select all

static inline int testchanend( chanend ch){
    int result;
    asm volatile (
        "\n\t   ldap r11, .Levent%= "          //get address of temporary label below
        "\n\t   setv res[%1], r11 "            //set resource vector
        "\n\t   { ldc %0, 1 ; eeu  res[%1] }"  //default result to 1 and enable resource event
        "\n\t   setsr 1"                       //enable events in our thread
        "\n\t   { ldc %0, 0 ; clrsr 1 }"       //result forced to 0 if no events
        "\n     .Levent%=:"                    //event entry point
        : "=r"(result) : "r"(ch) : "r11" );    //return result
    return result;
}
it works with either streaming or non-streaming channel.
for C langage, just replace the parameter "chanend ch" by "unsigned ch".
this proposed version is dual-issue but can be rewritten in single issue.
and it takes only 5 cycles.
User avatar
fabriceo
XCore Addict
Posts: 220
Joined: Mon Jan 08, 2018 4:14 pm

Post by fabriceo »

Hello
in the code above, the "clrsr 1" instruction is not enough, as it does not disable the channel event-enable flag.
see chapter 17.1 in the xs3 architecture document (or 16.1 in xs2 architecture)
So if somewhere else in the program an "setsr 1" instruction is met, then there is a risk that our channel ressource force an event and jump to the "old" Levent vector.
So it has to be replaced by a "clre" instruction, which will disable the EEBLE flag in SR and ALL resource-event-enable flag.
the final code is:

Code: Select all

[[dual_issue]] static inline int testchanend( chanend ch){
    int result;
    asm volatile (
        "\n\t   ldap r11, .Levent%= "          //get address of temporary label below
        "\n\t   setv res[%1], r11 "            //set resource vector
        "\n\t   { ldc %0, 1 ; eeu  res[%1] }"  //default result to 1 and enable resource event
        "\n\t   setsr 1"                       //enable events in our thread
        "\n\t   { ldc %0, 0 ; clre }"          //result forced to 0 if no events, cores all enable flags
        "\n     .Levent%=:"                    //event entry point
        : "=r"(result) : "r"(ch) : "r11" );    //return result
    return result;
}
User avatar
Ross
Verified
XCore Expert
Posts: 1016
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Yes this correct general scheme - as used by an XC select with a default case. There a couple of ways to do this (you can do do the eeu/edu as the last step or setsr/clrsr, for example)
Technical Director @ XMOS. Opinions expressed are my own.
grayb
Newbie
Posts: 1
Joined: Mon Jan 08, 2024 1:54 pm

Post by grayb »

Hi there!

Considering your asynchronous transfer requirements in C, your proposed approach using the event handling routine looks solid. While I don't see a direct ISA instruction for accessing the event status of a given resource, your workaround seems effective for testing the presence of new data or tokens in a channel without blocking the program.

Your explanation of the routine is clear, and the logic behind enabling and disabling events for the channel to trigger the desired asynchronous behavior makes sense. If it meets your requirements and you've considered potential edge cases, it seems like a reasonable solution.

If you're open to alternative suggestions, you might explore any additional documentation or community forums related to your specific hardware or compiler, as they could provide insights or alternative approaches.
User avatar
fabriceo
XCore Addict
Posts: 220
Joined: Mon Jan 08, 2018 4:14 pm

Post by fabriceo »

Hello,
going through some code, I found in clock gen.xc something which seems to do the same trick ..

Code: Select all

static int channelContainsControlToken(chanend x)
{
    unsigned char tmpc;
    select
    {
        case inct_byref(x, tmpc):
            return 1;
        default:
            return 0;
    }
}
just a select outside of a while(1) ...