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


◇PS3 Linux SDLでプログラミング -SPEからメインメモリを読む-

○SPEの特徴

SPEからは内臓された 256KBのメモリにしかアクセスする事ができません
この内臓メモリはメインメモリからは完全に分離されています

では、どのようにしてメインメモリにアクセスするのかと言うと、MFCと言うコントローラを使います
メインメモリ ←→ MFC ←→ SPE内臓メモリ
このように、SPEへのアクセスは必ず MFCを介して行う、と考えておけば良いでしょう

○プログラム

unsigned long型の数値データを SPEに送ってみます
尚、このプログラムは libspe 2.0.1用です

・PPE側の処理
MFCでデータを送る為には、メインメモリ上のアドレスの 16バイト境界でなければなりません
難しい事は考えずに、変数宣言の後ろに __attribute__((aligned(16)))と記述するもの、と覚えましょう
あと、ローカール変数ではうまくいかない事があるようなので、不具合が発生したら疑ってみましょう

#include "SDL.h"
#include "libspe2.h"

//SPEに送るデータ用変数
unsigned long addrlist[2] __attribute__((aligned(16)));

int main(int args,char *argp[]){
  //中身に1と2を入れておいて、取り出して表示して一致する事を確認したいと思います
  addrlist[0] = 1;
  addrlist[1] = 2;

  //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側から送ったものと同じ変数をグローバル変数に定義します
MFCにDMA転送命令を出して、データを受け取ります

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

//受け取る変数を定義
unsigned long addrlist[2] __attribute__((aligned(16)));

int main(unsigned long long spe, unsigned long long argp, unsigned long long envp){
  //DMA転送のエレメントを作成
  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;

  //DMA転送定義をMFCに送信
  spu_mfcdma64(&addrlist,mfc_ea2l(argp),(unsigned int)(element), sizeof(element), tag, MFC_GETL_CMD);

  //この2つはこう書くらしい(ほとんどのサンプルがこう書いてあった)
  spu_writech(MFC_WrTagMask, 1 << tag);
  spu_mfcstat(MFC_TAG_UPDATE_ALL);

  //中身が合っている事を確認
  printf("%d %d\n", addrlist[0], addrlist[1]);

  return 0;
}

転送するための関数は色々とあるのですが、spu_mfcdma64はあらゆる転送方法が扱える万能関数です
エレメントと言う構造体を定義して、それを引数に渡して処理を行います
後にエレメントを用いて転送を色々と操る方法の説明も記述します

あと、spu_mfcstatはブロッキングする、と言う事を覚えておいて下さい

このプログラムをビルドして実行すると
1 2
と表示されるはずです


TOPプログラマ専用PS3 Linux SDL