Here's a makefile:
Code: Select all
all:
spu-gcc spe_distance.c -o spe_distance
embedspu calculate_distance_handle spe_distance spe_distance_csf.o
gcc ppe_distance.c spe_distance_csf.o -L/usr/lib -lspe -o distance
gcc ppe_distance_spe2.c spe_distance_csf.o -L/usr/lib -lspe2 -o distance2
Code: Select all
//Pull in DMA commands
#include <spu_mfcio.h>
//Struct for communication with the PPE
typedef struct {
float speed; //input parameter
float num_hours; //input parameter
float distance; //output parameter
float padding; //pad the struct a multiple of 16 bytes
} program_data;
int main(unsigned long long spe_id, unsigned long long program_data_ea, unsigned
long long env) {
program_data pd __attribute__((aligned(16)));
int tag_id = 0;
//READ DATA IN
//Initiate copy
mfc_get(&pd, program_data_ea, sizeof(pd), tag_id, 0, 0);
//Wait for completion
mfc_write_tag_mask(1<<tag_id);
mfc_read_tag_status_any();
//PROCESS DATA
pd.distance = pd.speed * pd.num_hours;
//WRITE RESULTS OUT
//Initiate copy
mfc_put(&pd, program_data_ea, sizeof(program_data), tag_id, 0, 0);
//Wait for completion
mfc_write_tag_mask(1<<tag_id);
mfc_read_tag_status_any();
return 0;
}
Code: Select all
#include <stdio.h>
#include <libspe.h>
//This global is for the SPE program code itself. It will be created by
//the embedspu program.
extern spe_program_handle_t calculate_distance_handle;
//This struct is used for input/output with the SPE task
typedef struct {
float speed; //input parameter
float num_hours; //input parameter
float distance; //output parameter
float padding; //pad the struct a multiple of 16 bytes
} program_data;
int main() {
program_data pd __attribute__((aligned(16))); //aligned for transfer
//GATHER DATA TO SEND TO SPE
printf("Enter the speed at which your car is travelling in miles/hr: ");
scanf("%f", &pd.speed);
printf("Enter the number of hours you have been driving at that speed: "
);
scanf("%f", &pd.num_hours);
//USE THE SPE TO PROCESS THE DATA
//Create SPE Task
speid_t spe_id = spe_create_thread(0, &calculate_distance_handle, &pd, N
ULL,
-1, 0);
//Check For Errors
if(spe_id == 0) {
fprintf(stderr, "Error creating SPE thread!\n");
return 1;
}
//Wait For Completion
spe_wait(spe_id, NULL, 0);
//FORMAT THE RESULTS FOR DISPLAY
printf("The distance travelled is %f miles.\n", pd.distance);
return 0;
}
Now, if I modify the PPU code to use libspe2.h by changing the header file line and the block between "USE THE SPE TO PROCESS THE DATA" and "FORMAT THE RESULTS FOR DISPLAY" to:
Code: Select all
unsigned int createflags = 0;
unsigned int runflags = 0;
unsigned int entry = SPE_DEFAULT_ENTRY;
spe_context_ptr_t spe = spe_context_create(createflags, NULL);
spe_stop_info_t stop_info;
spe_program_load(spe, &calculate_distance_handle);
spe_context_run(spe, &entry, runflags, &pd, NULL, NULL); //&stop_info);
spe_context_destroy(spe);
The problem doesn't seem so much to be the initiation of the DMA (although it's hard for me to check that), more that the call to mfc_read_tag_status_any() never returns.
I notice in tweakoz's spurast, he's forced compilation in 32-bit mode and written a mfc_put32 method. Somehow, this feels like the wrong solution though and when I tried to use -m32 and write an equivalent mfc_get32 function, that too exhibited exactly the same behaviour. It's interesting to note also that tweakoz never calls mfc_read_tag_status_any() (which is the method that hangs) but instead seems to do syncronisation solely with the PPU and by using spu_read_signal1() instead. This too feels wrong, and I'm not sure what would happen when the SPU is initiates too many DMA requests for the buffer. My guess is that some of the requests would just be silently lost.
So, basically, does anyone have any ideas? I'm starting to wonder if I should just stick to using libspe, even though I know it's on its way out...
(and apologies for the long first post!)