Nanashi-soft○プログラマ専用○Windows gcc SDL○
前回SPEからメインメモリを読むという例を記述しました
この方法だと1つの配列しか送れません
普通に考えると構造体にして送ろうとするのでしょうが、アラインメントとかを慎重に考えて作らなければなりません
そんな難しい事すると、すぐにリークを起こしてPS3がフリーズします(そうで無くてもしょっちゅうフリーズさせています(^^:)
前回の例はその伏線になっています
unsigned long型配列を送る例だったのですが、なぜ int型では無かったのかと言うと、ここにポインタをぶち込んで最初に送りつけておこうと思ったからです
こんなサンプル他じゃ無いですよ('-'*)
unsigned char型の2つの配列のポインタを unsigned long型の配列に入れて、引数にして渡す例です
尚、このプログラムは libspe 2.0.1用です
・PPE側の処理
使用する変数を全て 16バイト境界に合わせておきます
そして、送りたい変数のポインタをunsigned long型配列にぶちこんで送りつけます
#include "SDL.h" #include "libspe2.h" //SPEに渡す変数のアドレスリスト用 unsigned long addrlist[2] __attribute__((aligned(16))); //この2つの変数の中身をSPEに渡す unsigned char data1[64] __attribute__((aligned(16))); unsigned char data2[64] __attribute__((aligned(16))); int main(int args,char *argp[]){ //data1に0〜63、data2に64〜127を入れて、SPE側にちゃんと届いたか検証する int i; for(i=0; i < sizeof(data1); i++){ data1[i] = i; } for(i=0; i < sizeof(data2); i++){ data2[i] = 64+i; } //送りたい変数のポインタをぶち込む addrlist[0] = (unsigned long)&data1; addrlist[1] = (unsigned long)&data2; //SPEプログラムロード spe_program_handle_t *speopen=spe_image_open("./spetest"); if (speopen == NULL){ printf("spe_image_open error\n"); return -1; } spe_context_ptr_t specontext=spe_context_create(0, NULL); if (specontext == NULL){ printf("spe_context_create error\n"); return -1; } if (spe_program_load(specontext, speopen) < 0){ printf("spe_program_load error\n"); return -1; } //SPEプログラムラン spe_stop_info_t speret; unsigned int speentry=SPE_DEFAULT_ENTRY; if(spe_context_run(specontext, &speentry, 0, (unsigned long long*)&addrlist, NULL, &speret) < 0){ printf("spe_context_run error\n"); return -1; } //SPEプログラム破棄 if (spe_context_destroy(specontext) < 0){ printf("spe_context_destroy error\n"); return -1; } if (spe_image_close(speopen) < 0){ printf("spe_image_close error\n"); return -1; } return 0; }
・SPE側の処理
PPE側から送ったものと同じ変数をグローバル変数に定義します
最初にアドレスリストを受け取って、そのポインタを元に順に変数内のデータをDMA転送で受け取ります
#include "stdio.h" #include "spu_mfcio.h" //アドレスリストが入っている配列 unsigned long addrlist[2] __attribute__((aligned(16))); //送信内容を受け取る為の配列 unsigned char data1[64] __attribute__((aligned(16))); unsigned char data2[64] __attribute__((aligned(16))); 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); //データ取得1 element[0].notify = 0; element[0].reserved = 0; element[0].size = sizeof(data1); element[0].eal = mfc_ea2l(addrlist[0]); //アドレスリストの中のポインタをセット spu_mfcdma64(&data1,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); //データ取得2 element[0].notify = 0; element[0].reserved = 0; element[0].size = sizeof(data2); element[0].eal = mfc_ea2l(addrlist[1]); //アドレスリストの中のポインタをセット spu_mfcdma64(&data2,mfc_ea2h(addrlist[1]),(unsigned int)(element), sizeof(element), tag,MFC_GETL_CMD); spu_writech(MFC_WrTagMask, 1 << tag); spu_mfcstat(MFC_TAG_UPDATE_ALL); printf("data1:%d %d\n", data1[0], data1[63]); printf("data2:%d %d\n", data2[0], data2[63]); return 0; }
このプログラムをビルドして実行すると
data1:0 63
data2:64 127
と表示されるはずです
最初と最後の数値が合っているので、間の数値も合っているでしょう