Table of Contents

DMA101


Transfer DMA initiat de SPU

Urmand acest tutorial veti invata sa folositi comenzi initiate de SPE pentru a transfera date cu spatiul principal de stocare si anume veti vedea cum:

Cod SPU - transfer DMA initiat de SPU

spu.c
#include <spu_mfcio.h>
 
// Macro ce asteapta finalizarea grupului de comenzi DMA cu acelasi tag
// 1. scrie masca de tag
// 2. citeste statusul - blocant pana la finalizareac comenzilor
#define wait_tag(t) mfc_write_tag_mask(1<<t); mfc_read_tag_status_all();
 
// Local store buffer: aliniere la marime si adresa DMA
// - trebuie sa fie aliniat la 16B, altfel se genereaza eroare pe magistrala
// - poate fi aliniat la 128B pentru performante mai bune
volatile char str[256]  __attribute__ ((aligned(16)));
// argp - adresa efectiva in spatiul principal de stocare
// envp - marimea bufferului (in cazul nostru string) in octeti
 
int main( uint64_t spuid , uint64_t argp, uint64_t envp ){
    // rezervam tag folosind tag manager
    uint32_t tag_id = mfc_tag_reserve();
    if (tag_id==MFC_TAG_INVALID){
        printf("SPU: ERROR can't allocate tag ID\n"); return -1;
    }
 
    // get: ia datele din spatiul principal de stocare
    mfc_get((void *)(str), argp, (uint32_t)envp, tag_id, 0, 0);
 
    // asteapta sa se finalizeze comanda get pe acest tag
    wait_tag(tag_id);
 
    // proceseaza datele
    printf("SPU: %s\n", str);
    strcpy(str, "Completeaza formularul: Nume: Synergistic Processing Element");
    printf("SPU: %s\n", str);
 
    // put: trimite datele in spatiul principal de stocare
    mfc_put((void *)(str), argp, (uint32_t)envp, tag_id, 0, 0);
 
    // asteapta sa se finalizeze comanda put
    wait_tag(tag_id);
 
    // nu mai avem nevoie de tag
    mfc_tag_release(tag_id);
    return (0);
}

Cod PPU - transfer DMA initiat de SPU

ppu.c
#include <libspe2.h>
 
// macro pentru rotunjirea superioara a valorii la multiplu de 16 (pentru conditiile DMA)
#define spu_mfc_ceil16(value)   ((value +  15) &  ~15)
volatile char str[256]  __attribute__ ((aligned(16)));
 
extern spe_program_handle_t spu;
 
int main(int argc, char *argv[])
{
    void *spe_argp, *spe_envp;
    spe_context_ptr_t spe_ctx;
    spe_program_handle_t *program;
    unsigned int entry = SPE_DEFAULT_ENTRY;
 
    // trimiterea de parametrii catre SPE
    strcpy( str, "Completeaza formularul: Nume: ..............................");
    printf("PPU: %s\n", str);
    spe_argp=(void*)str;             // adresa
    spe_envp=(void*)strlen(str);
    spe_envp=(void*)spu_mfc_ceil16((unsigned int)spe_envp); //rotunjeste dimensiunea bufferului la 16B
 
    // rularea programului SPU:
    // - creare de context
    // - incarcarea programului SPU
    // - rulare
 
    // asteptam ca SPU sa termine de procesat
    printf("PPU: %s\n", str);
 
    return (0);
}

Redbook - pp. 124-126

Arhiva se poate descarca de aici dma-initiatspu.zip.


Transfer DMA initiat de PPU

Urmand acest tutorial veti invata sa initiati transferuri DMA de la PPU si anume veti vedea cum: * PPU mapeaza memoria locala a unui SPE in memoria partajata si primeste un pointer la adresa efectiva din Local Store * SPU foloseste mailbox sa trimita lui PPU offsetul zonei de date de transmis din memoria locala * PPU foloseste comanda de tip put pentru a transfera datele din memoria locala in spatiul principal de stocare * programul PPU asteapta finalizarea transferului inainte de a folosi datele

Cod PPU - transfer DMA initiat de PPU

ppu.c
#include <libspe2.h>
#include <ppu_intrinsics.h>
 
#define BUFF_SIZE 1024
spe_context_ptr_t spe_ctx;
unsigned int ls_offset; // offset (adresa) in local store a bufferului de la SPU
 
// buffer PPU
volatile char my_data[BUFF_SIZE] __attribute__ ((aligned(128)));
 
extern spe_program_handle_t spu;
 
int main(int argc, char *argv[]){
    int ret;
    unsigned int tag_id, status; 
    unsigned int entry = SPE_DEFAULT_ENTRY;
 
    // rezervam un tag: trebuie sa folosite taguri intre 0-15 (16-31 sunt folosite de kernel)
    tag_id = 1; 
 
    // rularea programului SPU:
    // - creare de context
    // - incarcarea programului SPU
    // - rulare
 
    // preia de la SPU adresa bufferului lui in Local Store prin mailbox (nu prea eficient)
    printf("PPU: Tema: scrie un eseu!\n");
    while(spe_out_mbox_read(spe_ctx, &ls_offset, 1)<=0);
 
    // comanda put pentru a prelua datele in spatiul principal de stocare
    do{
        ret=spe_mfcio_put( spe_ctx, ls_offset, (void*)my_data, BUFF_SIZE, tag_id, 0,0);
    }while( ret!=0);
 
    // asteapta executia comenzii put
    ret = spe_mfcio_tag_status_read(spe_ctx,0,SPE_TAG_ALL, &status);
    if(ret!=0){
        perror ("Error status was returned");
        exit (1);
    }
 
    // sincronizam inainte de a folosi datele
    __lwsync();
    printf("PPU: SPU mi-a trimis lucrarea sa - %s\n", my_data);
 
    return (0);
}

Cod SPU - transfer DMA initiat de PPU

spu.c
#include <spu_intrinsics.h>
#include <spu_mfcio.h>
#define BUFF_SIZE 1024
 
// buffer la SPU
volatile char my_data[BUFF_SIZE] __attribute__ ((aligned(128)));
int main(int speid , uint64_t argp)
{
    strcpy((char*)my_data, "'Lucrul in echipa' de SPU#\n" );
 
    // trimite PPU offsetul la buffer folosind mailbox - blocant daca mailboxul este plin
    spu_write_out_mbox((uint32_t)my_data);
 
    return 0;
}

Redbook - pp. 142-144

Arhiva se poate descarca de aici dma-initiatppu.zip.


Mai multe exemple:

Daca aveti instalat SDK, puteti gasi un exemplu un pic mai evoluat la: /opt/cell/sdk/src/tutorial/dma/simple. Programul PPU aloca spatiu de memorie in memoria principala si il populeaza cu valori din sirul Fibonacci, dupa care porneste un program SPU pasand ca argument adresa acestui spatiu. Datoria programului SPU este sa verifice ca numerele apartin sirului Fibonacci si sa incrementeze fiecare numar din buffer. Programul PPU va astepta incheierea programului pe SPU. Acest exemplu foloseste macro-uri MFC specificate in 'C/C++ Language Extensions for CBA'.