CESOF(Cell Embeded Object Format)は、実行可能SPEプログラムをPPEプログラムに埋め込むためのフォーマット。
前回の[Cell] PPUプログラムにSPUプログラムを組み込むでは、ppu-embedespuコマンドでCESOFオブジェクト(hello_spu-embed.o)を作成して静的ライブラリにしPPUプログラムのリンク時に合わせてリンクすることで、PPUプログラムからspu_program_handle_t型の外部変数としてSPUプログラムを参照可能になるようにした。
作成されたCEOSFのシンボル表には、hello_spuシンボルが定義されておりこれによりPPUプログラムでSPUプログラムを参照できるようになっている。
% nm spu/hello_spu-embed.o
00000000 D hello_spu
%
今回作成するプログラムについて
同じくCESOFを使用してPPU/SPU間で変数を相互に参照するコードを書く。PPU側で宣言された変数をSPU側で参照し出力する。その変数をSPU側書き換えてSPUの処理が完了するのを待ってからPPU側で出力する。
まずは、作業ディレクトリを作成し、その中に次のようにディレクトリとファイルを構成する。
% ls -R
.:
Makefile ppu/ spu/
./ppu:
Makefile ppu_hello.c
./spu:
Makefile spu_hello.c spu_hello_toe.s
%
ppu/ppu_hello.c
PPUプログラムではhello_stringというシンボル名を持つ変数を宣言する。この変数がSPU側から参照されることになる。
#include <stdio.h>
#include <stdlib.h>
#include <libspe.h>
#include <errno.h>
#include <sched.h>
#define BUF_SIZE 256
/* this symbol definded in spu_hello-embed.o */
extern spe_program_handle_t spu_hello;
char hello_string[BUF_SIZE] = "Hello, World!";
int main() {
int status;
speid_t spe_id;
spe_gid_t gid;
/* Create SPE thread group */
gid = spe_create_group(SCHED_OTHER, 0, 1);
if(gid == 0) {
fprintf(stderr, "Failed spe_create_group(errno=%d)\n", errno);
return 1;
}
/* Create SPE thread */
printf("hello_string: %p\n", &hello_string);
spe_id = spe_create_thread(gid, &spu_hello, NULL, NULL, -1, 0);
if(spe_id == 0) {
fprintf(stderr, "Failed spe_create_thread(errno=%d)\n", errno);
return 1;
}
/* Waiting SPE thread */
spe_wait(spe_id, &status, 0);
/* print hello_string */
printf("PPU: %s\n", hello_string);
return 0;
}
spu/spu_helllo.c
PPUで宣言したhello_stringをSPU側で参照し値を出力する。SPU側では、_EAR_というプレフィックスを付けることで、spuembedがCESOFオブジェクトを作成する際にシンボル名から_EAR_取り除いた値に変換してくれる。EARはEffective Address Referenceの略。
(シンボルについては、下記で説明)
LSとメインメモリ間のデータ転送については、copy_to_ls/copy_from_ls関数を使用する。それぞれ、libmisc.hで定義されている。ppu-embededにより作成されるCESOFオブジェクト(下記の例ではspu_hello-embbed.o)では、_EAR_がとりのぞかれhello_stringで参照するように変換され、PPEリンカがシンボル名を解決する。
#include <stdio.h>
#include <stdlib.h>
#include <libmisc.h> /* copy_to_ls and copy_from_ls */
#include <spu_mfcio.h>
#include <string.h>
static const int BUF_SIZE = 256;
/* to be resolved by CESOF in the system memory */
extern unsigned long long _EAR_hello_string;
int main(unsigned long long spuid __attribute__((unused)),
unsigned long long argp __attribute__((unused))) {
char buf[BUF_SIZE];
/* Copy data from system memory to Local Storage */
printf("_EAR_hello_string: 0x%llX\n", _EAR_hello_string);
copy_to_ls((uint32_t)(&buf), _EAR_hello_string, sizeof(buf));
printf("SPU: %s\n", buf);
/* change buf */
strncpy(buf, "Welcome to SP program.", sizeof(buf));
copy_from_ls(_EAR_hello_string, (uint32_t)(&buf), sizeof(buf));
return 0;
}
% nm spu/spu_hello-embed.o
U hello_string
00000000 D spu_hello
% nm spu/spu_hello.o
00000000 r BUF_SIZE
U _EAR_hello_string
U copy_from_ls
U copy_to_ls
00000000 T main
U printf
U strncpy
%
このままでは、リンク時に_EAR_hello_stringシンボルの実効アドレスをリンカが解決できない。CESOFではEARは.toe(table of EARs)と呼ばれるセクションに置かれる。そこで、このセクションに関するアセンブリを書いて合わせてコンパイルする必要がある。(CESOFの詳細参照 <- 書いたらリンクに置き換える)
spu_hello_toe.s
.section .toe, "a", @progbits
.align 4
.global _EAR_hello_string
_EAR_hello_string:
.octa 0x0
作成したアセンブリはspu-asを使用することでオブジェクトファイルにコンパイルできる。コンパイルされたコードをリンク時に合わせてリンクすることで.toeセクションを追加できる。
% spu-as -I. -I /opt/IBM/cell-sdk-1.1/sysroot/usr/spu/include -o spu_hello_toe.o spu_hello_toe.s
CESOFの作成、静的ライブラリの作成、アセンブリコードのコンパイルといったこれらの処理も、下記に書くCell SDKが提供するMakefileを利用すれば全て自動的にやってくれる。
コンパイルに必要なMakefile達
Makefile
DIRS = spu ppuppu/Makefile
include /opt/IBM/cell-sdk-1.1/make.footer
PROGRAM_ppu = ppu_hellospu/Makefile
IMPORTS = ../spu/spu_hello.a -lspe
include /opt/IBM/cell-sdk-1.1/make.footer
PROGRAM_spu = spu_hello
LIBRARY_embed = spu_hello.a
IMPORTS = $(SDKLIB_spu)/libc.a $(SDKLIB_spu)/libmisc.a
include /opt/IBM/cell-sdk-1.1/make.footer
実行
# ./ppu_hello
hello_strint: 0x181688
_EAR_hello_string: 0x1816188
SPU: Hello, World!
PPU: Welocome to SPU Program.
#
TOEセクション
% spu-readelf -S spu/spu_hello | grep -w .toe
[ 6] .toe PROGBITS 00001680 0016c0 000010 00 A 0 0 16
%
% spu-objdump -s --start-address=0x1680 --stop-address=0x1690 spu/spu_hello
spu/spu_hello: file format elf32-spu
Contents of section .text:
Contents of section .rodata:
Contents of section .ctors:
Contents of section .dtors:
Contents of section .data:
Contents of section .toe:
1680 00000000 00000000 00000000 00000000 ................
Contents of section .comment:
Contents of section .debug_aranges:
Contents of section .debug_pubnames:
Contents of section .debug_info:
Contents of section .debug_abbrev:
Contents of section .debug_line:
Contents of section .debug_frame:
Contents of section .debug_str:
Contents of section .debug_loc:
Contents of section .note.spu_name:
%
TOEセクションの詳細とCESOFの動作原理の詳細については、あとで書く。