SPE to SPE DMA transfer
From Cellbe
(Difference between revisions)
Line 9: | Line 9: | ||
==Code snippet: PPE side== | ==Code snippet: PPE side== | ||
+ | <pre> | ||
+ | /* ============================================================================= | ||
+ | * 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; | ||
+ | |||
+ | } | ||
+ | </pre> | ||
+ | ==Code snippet: process ''PGET'', SPE side== | ||
+ | <pre> | ||
+ | |||
+ | /* ============================================================================= | ||
+ | * | ||
+ | * 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; | ||
+ | } | ||
+ | </pre> | ||
+ | ==Code snippet: process ''PPUT'', SPE side== | ||
+ | <pre> | ||
+ | /* ============================================================================= | ||
+ | * | ||
+ | * 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; | ||
+ | } | ||
+ | </pre> |
Revision as of 11:41, 6 July 2007
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; }