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


◇PS3 Linux SDLでプログラミング -SPEから配列を2つ読む-

○方法の説明

前回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
と表示されるはずです
最初と最後の数値が合っているので、間の数値も合っているでしょう


TOPプログラマ専用PS3 Linux SDL