Nanashi-softプログラマ専用Windows gcc SDL


◇PS3 Linux SDLでプログラミング -SPEから配列をランダムアクセスする-

○問題点

配列からランダムにデータを取り出したい場合、MFCの DMA転送は 16バイト境界でしか取り出せないので困ります
つまり、メインメモリ上のアドレスが 16で割り切れない箇所のデータは取り出せないのです

そこで、必要なデータを PPE側で 16バイト境界の配列に入れてから SPEに転送する
……という風に考えると私のようにハマります(汗)

そうでは無くて、必要なデータを含む 16バイト境界のデータを SPE側から取り出して、必要なデータのみをコピーする、と言う発想で行います

○プログラム

unsigned char型の2つの配列のポインタを unsigned long型の配列に入れて、引数にして渡す例です
尚、このプログラムは libspe 2.0.1用です

・PPE側の処理
SPEから配列を2つ読むと全く同じですので、そちらを見てください
『全く同じ』と言う点がポイントです

・SPE側の処理
data1の0〜63のうちから、3の倍数の数値(3,6,9,...63)を1つずつ取り出してみます
16バイト境界ではないので、どれ1つとして単体では取り出せません
必要なデータを含む 16バイトを転送して、必要なデータだけをコピーします

#include "stdio.h"
#include "spu_mfcio.h"

unsigned long addrlist[2] __attribute__((aligned(16)));

//データをDMA転送する為のワーク変数
unsigned char work[16] __attribute__((aligned(16)));

//結果を入れる変数(16バイト境界にしなくても良い所がポイント)
unsigned char kekka[21];

int main(unsigned long long spe, unsigned long long argp, unsigned long long envp){
  //まずは、アドレスリストを取得
  mfc_list_element_t element[1];
  element[0].notify = 0;
  element[0].reserved = 0;
  element[0].size = sizeof(addrlist);
  element[0].eal = mfc_ea2h(argp);

  int tag=3;
  spu_mfcdma64(&addrlist,mfc_ea2l(argp),(unsigned int)(element), sizeof(element), tag,MFC_GETL_CMD);
  spu_writech(MFC_WrTagMask, 1 << tag);
  spu_mfcstat(MFC_TAG_UPDATE_ALL);

  //3の倍数を取得
  int i;
  int j=0;
  for(i=3; i < 64; i += 3){
    element[0].notify = 0;
    element[0].reserved = 0;
    element[0].size = sizeof(work);
    //目的のデータを含む、16バイト境界を求めてDMA転送の先頭アドレスにセットする
    element[0].eal = mfc_ea2l(addrlist[0]) + (int)(i/16)*16;

    spu_mfcdma64(&work,mfc_ea2h(addrlist[0]),(unsigned int)(element), sizeof(element), tag,MFC_GETL_CMD);
    spu_writech(MFC_WrTagMask, 1 << tag);
    spu_mfcstat(MFC_TAG_UPDATE_ALL);

    //受け取ったデータの中から、目的のデータを探して取り出す
    kekka[j++] = work[i%16];
  }

  for(i=0; i < j; i++){
    printf("kekka:%d\n", kekka[i]);
  }
  return 0;
}


このプログラムをビルドして実行すると
kekka:3
kekka:6
...
kekka:63
と表示されるはずです

この方法を用いると 16バイト境界を気にせずにプログラミングを行う事ができます
但し、パフォーマンスは当然落ちます


TOPプログラマ専用PS3 Linux SDL