SPE to SPE DMA transfer
From Cellbe
Revision as of 11:41, 6 July 2007 by 151.65.233.81 (Talk)
This article shows a simple DMA transfer between two SPEs. The synchronization is done via mailbox with the aid of the PPE. The process "PGET" holds the target memory area; it writes 200 in the target area, then waits for the transfer, and prints the value stored in target area. The process "PPUT" writes a value in the target memory area. The order of operations is as follows:
- The SPE processes are started
- PGET communicates to the PPE the target address via mailbox, then synchronizes with the PPE with a mailbox read
- The PPE calculates the effective address of the target, and sends it to PPUT via mailbox, and synchronizes with PPUT with a mailbox read
- PPUT reads the target's effective address from mailbox, starts the dma trasfer, waits for it to finish and wakes up the PPE with a mailbox write
- The PPE wakes up, and writes a mailbox to PGET to wake it up.
- PGET wakes up, and prints the content of the target memory area.
Code snippet: PPE side
/* ============================================================================= * Filename: dmaspe.c * Description: Starts the spu threads and cares of synchronizing them with * Mailboxes * Author: Alessandro Piras (laynor@gmail.com) * Company: * ===========================================================================*/ #include <libspe2.h> #include <stdio.h> #include <pthread.h> #include <unistd.h> #include <stdlib.h> #include "common.h" #define MYALIGN(vardecl, n) vardecl\\ __attribute__ ((__aligned__ (n))) extern spe_program_handle_t dmaspespu_get; extern spe_program_handle_t dmaspespu_put; MYALIGN(unsigned int ls_addr, 128); /************************************ * Routine used to start the threads* ***********************************/ void *pthrtn(void *arg) { unsigned int entry = SPE_DEFAULT_ENTRY; spe_context_ptr_t ctx; ctx = *((spe_context_ptr_t *) arg); spe_context_run(ctx, &entry, 0, &ls_addr, NULL, NULL); pthread_exit(NULL); } int main() { spe_context_ptr_t ctx1, ctx2; unsigned int shared_lsaddr; pthread_t pth1, pth2; union eat ls_base_addr; union eat shared_ea; unsigned int bell; /* Creating the contexts, loading the programs and starting threads */ ctx1 = spe_context_create(0,NULL); ctx2 = spe_context_create(0,NULL); spe_program_load(ctx1, &dmaspespu_get); spe_program_load(ctx2, &dmaspespu_put); pthread_create(&pth1, NULL, pthrtn, &ctx1); pthread_create(&pth2, NULL, pthrtn, &ctx2); /* 1. Getting the ls address of the memory area where the put will be */ /* executed (via mailboxes) */ while(!spe_out_mbox_status(ctx1)); spe_out_mbox_read(ctx1, &shared_lsaddr, 1); /* 2. constructing the effective address adding the base address of */ /* LS area of the "get" process to the LS address just received */ ls_base_addr.e = 0; ls_base_addr.e =(unsigned long long) spe_ls_area_get(ctx1); shared_ea.e = shared_lsaddr + ls_base_addr.e; /* 3. Sending the calculated address to the "put" process. */ spe_in_mbox_write(ctx2, &shared_ea.h, 1, 1); spe_in_mbox_write(ctx2, &shared_ea.l, 1, 1); /* synchronizing with the put process for the termination of the dma */ /* transfer. */ while(!spe_out_mbox_status(ctx2)); spe_out_mbox_read(ctx1, &bell, 1); /* Waking up the "get" process */ spe_in_mbox_write(ctx1, &bell, 1, 1); /* Joining the threads */ pthread_join(pth1, NULL); pthread_join(pth2, NULL); spe_context_destroy(ctx1); spe_context_destroy(ctx2); return 0; }
Code snippet: process PGET, SPE side
/* ============================================================================= * * Filename: dmaspespu_get.c * * Description: waits for transfer and prints the value. * * Author: Alessandro Piras (laynor@gmail.com) * Company: * * ===========================================================================*/ #include <stdio.h> #include <spu_intrinsics.h> #include <spu_mfcio.h> #include <commonlib.h> #define MYALIGN(vardecl, n) vardecl\\ __attribute__ ((__aligned__ (n))) MYALIGN(volatile unsigned int cane, 128); int main(unsigned long long spe_id, unsigned long long argp, unsigned long long envp) { unsigned int cane_addr; cane = 200; /* spu_dsync(); */ /* I'm not sure if it's indeed useful/required, it worked without */ cane_addr = &cane; /* Sending the address of the memory area where the other spe */ /* process will transfer its data */ spu_write_out_mbox((unsigned int)cane_addr); /* Synchronizing with the ppe */ spu_read_in_mbox(); printf("(spu1) value: %u\ ", cane); return 0; }
Code snippet: process PPUT, SPE side
/* ============================================================================= * * Filename: dmaspespu_put.c * * Description: issues a dma on the LS of spe1. * * Author: Alessandro Piras (laynor@gmail.com) * Company: * * ===========================================================================*/ #include <stdio.h> #include <spu_intrinsics.h> #include <spu_mfcio.h> #include <commonlib.h> #include "../common.h" MYALIGN(volatile unsigned int x, 128); int main(unsigned long long spe_id, unsigned long long argp, unsigned long long envp) { union eat shared_ea; /* Getting the target LS area effective address from ppe */ shared_ea.h = spu_read_in_mbox(); shared_ea.l = spu_read_in_mbox(); x = 210; /* Starting the dma trasnfer */ mfc_put((volatile void *)&x, shared_ea.e, sizeof(unsigned int), 31, 0, 0); /* Waiting for the dma transfer to finish */ mfc_write_tag_mask(1<<31); mfc_read_tag_status_all(); printf("value = %d\ ", x); /* Synchronizing with the ppe */ spu_write_out_mbox(10); return 0; }