SPE to SPE signaling
From Cellbe
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
PPE side: starter
The process starter does basically this:
- creates the spe threads
- sends sender the address of the signal notify area of receiver
- 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;
}
