libc 解析 take.5 (newlib)
先日、SDK 2.0 が出ましたが、以前説明した libc の大部分が newlib にマー ジされています。また、SDK 1.1 ではアセンブラで記述されていた処理が C で 書き直されて理解しやすくなっています。
ということで、以下に中核となる send_to_ppe() 関数とサンプルとして fprintf() のソースコードを挙げておきます。(コードを追ってはいませんが、 レジスタ上にある引数のスタックへのコピーは va_start() でやっているんだと 思います)
newlib-1.14.0/newlib/libc/machine/spu/c99ppe.h
static void
send_to_ppe(int signalcode, int opcode, void *data)
{
unsigned int combined = ( ( opcode<<24 )&0xff000000 ) | ( ( unsigned int )data & 0x00ffffff );
struct spe_reg128* ret = data;
vector unsigned int stopfunc = {
signalcode, /* stop 0x210x*/
(unsigned int) combined,
0x4020007f, /* nop */
0x35000000 /* bi $0 */
};
void (*f) (void) = (void *) &stopfunc;
asm ("sync":::"memory");
f();
errno = ret->slot[3];
return;
}
newlib-1.14.0/newlib/libc/machine/spu/fprintf.c
typedef struct
{
FILE * fp;
unsigned int pad0[ 3 ];
char* fmt;
unsigned int pad1[ 3 ];
va_list ap;
} c99_fprintf_t;
int
fprintf(FILE * fp, _CONST char *fmt,...)
{
int* ret;
c99_fprintf_t args;
ret = (int*) &args;
args.fp = translate_fp(fp);
args.fmt = (char*) fmt;
#ifdef _HAVE_STDC
va_start (args.ap, args.fmt);
#else
va_start (args.ap);
#endif
send_to_ppe(SPE_C99_SIGNALCODE, SPE_C99_VFPRINTF, &args);
va_end (args.ap);
return *ret;
}
あと、SPU 用の newlib もすでに開発ツリーにマージされています。
他にもフレームワークとして、SPU code overlays や software managed cache がサンプルとして提供されていますので、この場で説明していければと思っ ています。



