Nanashi-soft○プログラマ専用○Windows gcc SDL○
配列からランダムにデータを取り出したい場合、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バイト境界を気にせずにプログラミングを行う事ができます
但し、パフォーマンスは当然落ちます