Many Client channel ends -> 1 server channel end

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Many Client channel ends -> 1 server channel end

Post by lilltroll »

I wrote a program to test it out.
1) The question is how should I handle the control tokens so all clients can send data-messages?
2) What happens with a token on a loose channel-end that hasn't a receiver, is it killed by the switch or is it trapped in a FIFO ?

This program receives a package of data from any core, but all other clients become trapped at
chkct, since the CT_END token they sent ended up somewhere else, killed or trapped ??

It's easier to read the program from the bottom.
The main() is rather easy to understand.

Code: Select all

#define CT_END 1
#define CT_PAUSE 2
#define CT_ACK 3
#define CT_NACK 4
#define len 8

static inline
int TESTCT(unsigned Chanend) {
	int ret;
	asm("testct %0,res[%1]":"=r"(ret) : "r"(Chanend));
	return ret;
}
static inline
void OUTCT_END(unsigned Chanend) {
	asm("outct res[%0],%1" ::"r"(Chanend),"r"(CT_END));
}
static inline
void OUTCHK_END(unsigned Chanend) {
	asm("chkct res[%0],%1" ::"r"(Chanend),"r"(CT_END));
}
static inline
void SETD_CLIENT(unsigned Chanend, unsigned ServerCore) {
	asm("setd res[%0],%1" ::"r"(Chanend),"r"((ServerCore<<16)+0x102));
}
static inline
void SETD_SERVER(unsigned Chanend, unsigned ClientCore) {
	asm("setd res[%0],%1" ::"r"(Chanend),"r"((ClientCore<<16)+0x102));
}

static inline
unsigned GETR_CHANEND() {
	unsigned Chanend;
	asm("getr %0,2":"=r"(Chanend));
	return Chanend;
}

void client(unsigned sh, unsigned ServerCore) {
	unsigned Chanend;
	Chanend = GETR_CHANEND();
	SETD_CLIENT(Chanend, ServerCore);
	OUTCT_END(Chanend);
	OUTCHK_END(Chanend);
	for (int i = 0; i < len; i++)
		asm("out res[%0],%1" ::"r"(Chanend),"r"(i<<sh));
	OUTCT_END(Chanend);
	OUTCHK_END(Chanend);
}

void server(unsigned startScan,unsigned stopScan) {
	unsigned Chanend;
	int data;
	unsigned ClientChanEnd;
	Chanend = GETR_CHANEND();
	while (1) {
		for (int i = startScan; i <= stopScan; i++) {
			ClientChanEnd = (i << 16) + 0x102;
			if (TESTCT(ClientChanEnd)) {
				SETD_SERVER(Chanend, i);
				OUTCHK_END(Chanend);
				OUTCT_END(Chanend);
				for (int i = 0; i < len; i++) {
					asm("in %0,res[%1] ":"=r"(data):"r"(Chanend));
					printint(data);
					printstr(", ");
				}
				OUTCHK_END(Chanend);
				OUTCT_END(Chanend);
				printstrln(" END");
			}
		}
	}
}

int main() {
	par {
		on stdcore[0]:client(1, 3);  //3 == Server is on stdcore[3]
		on stdcore[1]:client(2, 3);  //3 == Server is on stdcore[3]
		on stdcore[2]:client(3, 3);  //3 == Server is on stdcore[3]
		on stdcore[3]:server(0,2);  //0,2 == Scan clients from stdcore[0] to stdcore[2]
	}
}


Probably not the most confused programmer anymore on the XCORE forum.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Nobody hinting ;) ?

I remember that David May himself talk about this along time ago, but I cannot remember where, maybe XMOSlinkers. But back then I was on a very basic level.

Otherwise I have to penetrate the XLOG module fully.

Found this much newer topic about the matter:

https://www.xcore.com/forum/viewtopic.php?p=4654#p4654

But this is still Point to Point
Probably not the most confused programmer anymore on the XCORE forum.
bearcat
Respected Member
Posts: 283
Joined: Fri Mar 19, 2010 4:49 am

Post by bearcat »

Anymore insight into this is welcome. The last thread still had questions for me. I never really determined exactly the algorithims or constraints for tokens in relation to multiple channel ends, listeners, threads, switches, etc.

As a final solution, I used a streaming channel with a single channel end. I tunnel low bandwidth "subchannels" through the link using control tokens, then pass via variables to other threads or subroutines. I do use tokens in both directions.
User avatar
Jamie
Experienced Member
Posts: 99
Joined: Mon Dec 14, 2009 1:01 pm

Post by Jamie »

lilltroll wrote:This program receives a package of data from any core, but all other clients become trapped at
chkct, since the CT_END token they sent ended up somewhere else, killed or trapped ??
Just a thought - won't the first channel end returned by GETR have resource id 0, not 1 as you have in the example?
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

I used print to console to check it out earlier

it's using the form
XLOG_SERVER_CHANEND ((XLOG_NODECOREID << 16) | XLOG_CHANID << 8 | 0x02)
and using the methods in xc1.h gave me the same result.
Probably not the most confused programmer anymore on the XCORE forum.
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

I'm a bit confused as to what you are trying to do with that code. The server shouldn't need to know the resource IDs of the clients in advance. The server shouldn't need to use testct().

The server needs to get hold of a channel end with a known resource ID. When you want to communicate with the server a client should allocate a channel end, set the destination to the known resource ID of the server and send a packet with some data.

If communication is one way (i.e. the client doesn't need a response) then this is the minimum that is required. The server should be a while(1) loop which receives and handles one packet from a client in each iteration of the loop. If the client needs a response from the server then the resource ID of the client channel end should be contained in the original request. The server should set the destination of its channel end to the resource ID specified in the request before sending the response.
User avatar
Jamie
Experienced Member
Posts: 99
Joined: Mon Dec 14, 2009 1:01 pm

Post by Jamie »

The reason why the code isn't working is that you're trying to execute a testct with one of the client's channel resource identifiers. If you change TESTCT(ClientChannelEnd) to TESTCT(Chanend) in the server process it should work.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Richard -> That seems very convenient!


Jamie, do you mean like this?

Code: Select all

void server(unsigned startScan,unsigned stopScan) {
	unsigned Chanend;
	int data;
	unsigned ClientChanEnd;
	Chanend = GETR_CHANEND();
	while (1) {
		for (int i = startScan; i <= stopScan; i++) {
			ClientChanEnd = (i << 16) + 0x102;
			if (TESTCT(Chanend)) {
				SETD_SERVER(Chanend, i);
				OUTCHK_END(Chanend);
				OUTCT_END(Chanend);
				for (int i = 0; i < len; i++) {
					asm("in %0,res[%1] ":"=r"(data):"r"(Chanend));
					printint(data);
					printstr(", ");
				}
				OUTCHK_END(Chanend);
				OUTCT_END(Chanend);
				printstrln(" END");
			}
		}
	}
}
The console output is:
0, 2, 4, 6, 8, 10, 12, 14, END

e.g it locked after the first client.
Probably not the most confused programmer anymore on the XCORE forum.
richard
Respected Member
Posts: 318
Joined: Tue Dec 15, 2009 12:46 am

Post by richard »

The testct instruction will pause until there is at least one token available and then return 1 if it is control token and 0 otherwise. The token isn't discarded from the channel. Doing another testct on the same channel without consuming data in between is pointless since it will give exactly the same result. Because of this your server code:

Code: Select all

while (1) {
  if (testct(c)) {
    // do stuff
  }
}
is equivalent to:

Code: Select all

while (1) {
  if (!testct()) {
    while(1) {}  // loop for ever
  } else {
    // do stuff
  }
}
I very much doubt this is what you intended.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

The intention.

To have up to 8 clients on each core[0] to core[2], that can send text-strings to one server on core[3]. This with minimum number of channel allocation.
It might happen that several clients tries and send at the same time. The data cannot be lost, it must reach the server. If the client ends up in a blocked mode during it's waiting is ok. No FIFO is needed.

Very similar to XLOG that redirects all prints to the uart core.
Probably not the most confused programmer anymore on the XCORE forum.