SPE to SPE signaling

From Cellbe

(Difference between revisions)
Line 10: Line 10:
On PPE side:
On PPE side:
<pre>
<pre>
 +
        /*[...]*/
 +
const uint32_t flags = SPE_MAP_PS;
 +
 +
if (( context_ = spe_context_create(flags,NULL) ) == NULL ) {
 +
    return STATUS_FAIL_CONTEXT_CREATE;
 +
}
 +
 +
if ( spe_program_load(context_, &algo_spu) != 0 ) {
 +
    return STATUS_FAIL_PROGRAM_LOAD;
 +
}
 +
 +
        /*[...]*/
 +
spe_sig_notify_1_area_t *sig_area1 = (spe_sig_notify_1_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_1_AREA);
spe_sig_notify_1_area_t *sig_area1 = (spe_sig_notify_1_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_1_AREA);
spe_sig_notify_2_area_t *sig_area2 = (spe_sig_notify_2_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_2_AREA);
spe_sig_notify_2_area_t *sig_area2 = (spe_sig_notify_2_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_2_AREA);
Line 15: Line 28:
   addressSignalArea1_ = (uint64_t) (&(sig_area1->SPU_Sig_Notify_1));
   addressSignalArea1_ = (uint64_t) (&(sig_area1->SPU_Sig_Notify_1));
   addressSignalArea2_ = (uint64_t) (&(sig_area2->SPU_Sig_Notify_2));
   addressSignalArea2_ = (uint64_t) (&(sig_area2->SPU_Sig_Notify_2));
 +
 +
        /*[...]*/
</pre>
</pre>
On SPE sender side:
On SPE sender side:
Line 35: Line 50:
On SPE receiver side:
On SPE receiver side:
<pre>
<pre>
-
spu_read_signal1()
+
/*[...]*/
 +
uint32_t signal = spu_read_signal1()
 +
/*[...]*/
</pre>
</pre>
You're welcome to post your questions and suggestions on the discussion page.
You're welcome to post your questions and suggestions on the discussion page.

Revision as of 19:25, 11 January 2008

This tutorial shows how to send signals from one spe to another.

There are three entities in this tutorial:

  • starter: the PPE process who starts the spe threads
  • sender: the SPE thread who sends the signal
  • receiver the SPE thread who receives the signal

Contents

Version 3.0 Issues

Unfortunately this tutorial does not work under standard settings (Cell SDK v3.0). The following Sourcecode will give you some hints how to signal from one SPE to another. On PPE side:

        /*[...]*/
	const uint32_t flags = SPE_MAP_PS;
	
	if (( context_ = spe_context_create(flags,NULL) ) == NULL ) {
    	return STATUS_FAIL_CONTEXT_CREATE;
	}

	if ( spe_program_load(context_, &algo_spu) != 0 ) {
    	return STATUS_FAIL_PROGRAM_LOAD;
	}

        /*[...]*/

	spe_sig_notify_1_area_t *sig_area1 = (spe_sig_notify_1_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_1_AREA);
	spe_sig_notify_2_area_t	*sig_area2 = (spe_sig_notify_2_area_t*)spe_ps_area_get(context_,SPE_SIG_NOTIFY_2_AREA);
	  	
  	addressSignalArea1_ = (uint64_t) (&(sig_area1->SPU_Sig_Notify_1));
  	addressSignalArea2_ = (uint64_t) (&(sig_area2->SPU_Sig_Notify_2));

        /*[...]*/

On SPE sender side:

void sendSignal(uint64_t address,uint32_t value)
{
	uint32_t signal[4] __attribute__ ((aligned (128)));
	
	if ( address == 0 ) {
		return;
	}
	
	signal[3] = value;
	
	mfc_sndsig(((char *) &signal[0]) + 12,address, TAG_SIGNAL, 0, 0);
	mfc_write_tag_mask(TAG_SIGNAL);
	mfc_read_tag_status_all();
}

On SPE receiver side:

/*[...]*/
uint32_t signal = spu_read_signal1()
/*[...]*/

You're welcome to post your questions and suggestions on the discussion page. --78.54.169.70 14:21, 11 January 2008 (EST)

PPE side: starter

The process starter does basically this:

  1. creates the spe threads
  2. sends sender the address of the signal notify area of receiver
  3. joins the threads.

It's important to note that the contexts are created using the SPE_MAP_PS flag, because we want the problem state area of the SPEs to be mapped in the effective address space (the signals are sent with dma commands).


/*
 * =============================================================================
 *       Filename:  ppusig.c
 *    Description:  starter
 *         Author:  Alessandro Piras (laynor@gmail.com) 
 * =============================================================================
 */

#define ZZ_CTX_CREATE 	-2
#define ZZ_PRG_LOAD 	-3
#define ZZ_CTX_RUN	-4
#define ZZ_PTH_CREATE	-5
#define ZZ_PTH_JOIN	-6

#include <stdio.h>
#include <libspe2.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
//#include <commonlib.h>

extern spe_program_handle_t spurecv;
extern spe_program_handle_t spusend;

void *pth_rtn(void *arg)
{
	unsigned int entry=SPE_DEFAULT_ENTRY;
	int rc;
	void *argp=NULL;
	void *envp=NULL;
	spe_context_ptr_t ctx;

	ctx = *((spe_context_ptr_t *) arg);

	rc = spe_context_run(ctx, &entry, 0, argp, envp, NULL);
	if(rc < 0) {
		perror("spe_context_run()");
		exit(ZZ_CTX_RUN);
	}
	pthread_exit(NULL);
}	

int main()
{
	spe_context_ptr_t ctx[2];
	pthread_t pth[2];
	unsigned int flags = SPE_MAP_PS;
	int i;
	spe_sig_notify_1_area_t *sig_area;
	unsigned int sig_area1;

	//-----CTX creation
	for(i=0; i<2; i++){
		ctx[i] = spe_context_create(flags, 0);
		if(ctx[i] == NULL){
			perror("spe_context_create()");
			exit(ZZ_CTX_CREATE);
		}
	}

	//-----PRG load
	if(spe_program_load(ctx[0],&spurecv)){
		perror("spe_program_load()");
		exit(ZZ_PRG_LOAD);
	}
	if(spe_program_load(ctx[1],&spusend)){
		perror("spe_program_load()");
		exit(ZZ_PRG_LOAD);
	}

	//-----PTH creation
	for(i=0; i<2; i++)
		if(pthread_create(&pth[i], NULL, pth_rtn, &ctx[i])){
			perror("pthread_create()");
			exit(ZZ_PTH_CREATE);
		}

	sig_area = spe_ps_area_get(ctx[0], SPE_SIG_NOTIFY_1_AREA);
	sig_area1 = (unsigned int) (&(sig_area->SPU_Sig_Notify_1));
	spe_in_mbox_write(ctx[1], &sig_area1, 1, 1);
	
	//-----PTH join
	for(i=0; i<2; i++)
		if(pthread_join(pth[i], NULL)){
			perror("pthread_join()");
			exit(ZZ_PTH_JOIN);
		}

	//-----CTX destruction
	for(i=0; i<2; i++)
		spe_context_destroy(ctx[i]);
	return 0;
}

SPE side: sender

The important thing here is that the memory area which contain the signal must be aligned, but that's not all: the message should be placed 12 bytes after the base address of the aligned memory area. The address passed to mfc_sndsig is the address at which the message resides (base_address + 12bytes).

/*
 * =============================================================================
 *       Filename:  spusend.c
 *    Description:  sends a signal to "spe1"
 *         Author:  Alessandro Piras (laynor@gmail.com) 
 * =============================================================================
 */

#include <spu_intrinsics.h>
#include <spu_mfcio.h>
#include <stdio.h>

int main(unsigned long long spe_id __attribute__ ((unused)),
		unsigned long long argp __attribute__ ((unused)),
		unsigned long long envp __attribute__ ((unused)))
{
	unsigned int ps_area_ptr;

	//the memory area must be aligned 
	volatile unsigned int signal[4] __attribute__ ((aligned (128)));

	//the message should be placed 3 bytes after
	signal[3] = 201;
	ps_area_ptr = spu_read_in_mbox();
	printf("(spe) ps_area_ptr: %x\
", ps_area_ptr);

	//NB: the address passed is base address + 12 bytes
	mfc_sndsig(((char *) &signal[0]) + 12, 
			ps_area_ptr, 31, 0, 0);
			
	mfc_write_tag_mask(1<<31);
	mfc_read_tag_status_all();
	return 0;
}

SPE side: receiver

Not much to say here, it's pretty simple.


/*
 * =============================================================================
 *       Filename:  spurecv.c
 *    Description:  Waits for a signal and prints it
 *         Author:  Alessandro Piras (laynor@gmail.com) 
 * =============================================================================
 */

#include <spu_intrinsics.h>
#include <spu_mfcio.h>
#include <stdio.h>

int main(unsigned long long spe_id __attribute__ ((unused)),
		unsigned long long argp __attribute__ ((unused)),
		unsigned long long envp __attribute__ ((unused)))
{

	unsigned int value;
	value = spu_read_signal1();
	printf("(recvr) value: %u\
", value);
	return 0;
}
Personal tools