Example #1
0
Spurs *
initSpurs(const char *prefix_name)
{
   Spurs *spurs = NULL;
   SpursAttribute attributeSpurs;
   int ret;

   ret = sysSpuInitialize (6, 0);
   printf ("sysSpuInitialize return %d\n", ret);

   /* initialize spurs */
   printf ("Initializing spurs\n");
   spurs = (Spurs *)(void *)memalign (SPURS_ALIGN, sizeof (Spurs));
   printf ("Initializing spurs attribute\n");

   ret = spursAttributeInitialize (&attributeSpurs, 5, 250, 1000, true);
   if (ret)
     {
        printf ("error : spursAttributeInitialize failed  %x\n", ret);
        goto error;
     }

   printf ("Setting name prefix\n");
   if (!prefix_name)
     prefix_name = SPURS_DEFAULT_PREFIX_NAME;
   ret = spursAttributeSetNamePrefix (&attributeSpurs,
                                      prefix_name, strlen (prefix_name));
   if (ret)
     {
        printf ("error : spursAttributeInitialize failed %x\n", ret);
        goto error;
     }

   printf ("Initializing with attribute\n");
   ret = spursInitializeWithAttribute (spurs, &attributeSpurs);
   if (ret)
     {
        printf ("error: spursInitializeWithAttribute failed  %x\n", ret);
        goto error;
     }

   return spurs;

error:
   if (spurs)
     free (spurs);
   return NULL;
}
Example #2
0
int main(int argc, const char* argv[])
{
  padInfo padinfo;
  padData paddata;
  s32 status;
  u32 joinstatus;

  displayData vdat;
  char filename[64];
  int picturecount = 0;

  atexit(appCleanup);
  sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0, eventHandle, NULL);

  init_screen(&vdat);
  printf("screen res: %dx%d buffers: %p %p\n",
       vdat.res.width, vdat.res.height, vdat.buffer[0], vdat.buffer[1]);
  ioPadInit(7);

  sysSpuImage image;
  u32 group_id;
  sysSpuThreadAttribute attr = { ptr2ea("mythread"), 8+1, SPU_THREAD_ATTR_NONE };
  sysSpuThreadGroupAttribute grpattr = { 7+1, ptr2ea("mygroup"), 0, 0 };
  sysSpuThreadArgument arg[6];
  u32 cause;
  int i, j;
  volatile spustr_t *spu = memalign(16, 6*sizeof(spustr_t));

  printf("Initializing 6 SPUs... ");
  status = sysSpuInitialize(6, 0);
  printf("%08x\n", status);

  printf("Loading ELF image... ");
  status = sysSpuImageImport(&image, spu_bin, 0);
  printf("%08x\n", status);

  printf("Creating thread group... ");
  status = sysSpuThreadGroupCreate(&group_id, 6, 100, &grpattr);
  printf("%08x\n", status);
  printf("group id = %d\n", group_id);

  /* create 6 spu threads */
  for (i = 0; i < 6; i++) {
    /* Populate the data structure for the SPU */
    spu[i].rank = i;
    spu[i].count = 6;
    spu[i].sync = 0;
    spu[i].width = vdat.res.width;
    spu[i].height = vdat.res.height;
    spu[i].zoom = 1.0f;
    spu[i].xc = -0.5f;
    spu[i].yc = 0.f;

    /* The first argument of the main function for the SPU program is the
     * address of its dedicated structure, so it can fetch its contents via DMA
     */
    arg[i].arg0 = ptr2ea(&spu[i]);

    printf("Creating SPU thread... ");
    status = sysSpuThreadInitialize((u32*)&spu[i].id, group_id, i, &image, &attr, &arg[i]);
    printf("%08x\n", status);
    printf("thread id = %d\n", spu[i].id);

    printf("Configuring SPU... %08x\n",
    sysSpuThreadSetConfiguration(spu[i].id, SPU_SIGNAL1_OVERWRITE|SPU_SIGNAL2_OVERWRITE));
  }

  printf("Starting SPU thread group... ");
  status = sysSpuThreadGroupStart(group_id);
  printf("%08x\n", status);

  /* Now all the SPU threads have been started. For the moment they are blocked
   * waiting for a value in their signal notification register 1 (the
   * spu_read_signal1() call in SPU program).
   */

  int quit = 0;
  uint32_t scr_ea;

  while (!quit) {
    /* Check the pads. */
    ioPadGetInfo(&padinfo);
    for (i=0; i<MAX_PADS; i++) {
      if (padinfo.status[i]) {
        ioPadGetData(i, &paddata);
        if (paddata.BTN_CROSS)
          quit = 1;
        int ah = center0(paddata.ANA_L_H);
        int av = center0(paddata.ANA_L_V);
        int az = center0(paddata.ANA_R_V);
        for (j = 0; j < 6; j++) {
          spu[j].xc += ah*0.001f*spu[j].zoom;
          spu[j].yc += av*0.001f*spu[j].zoom;
          spu[j].zoom *= (1.f + az*0.0005f);
          if (spu[j].zoom < 0.0001)
            spu[j].zoom = 0.0001;
        }
        if (paddata.BTN_SQUARE) {
          sprintf(filename, "/dev_usb/mandel%04d.bmp", ++picturecount);
          export_bmp(filename, vdat.buffer[vdat.curr_fb], vdat.res.width, vdat.res.height);
        }
        if (paddata.BTN_START) {
          for (j = 0; j < 6; j++) {
            spu[j].xc = -.5f;
            spu[j].yc = 0.f;
            spu[j].zoom = 1.f;
          }
        }
      }
    }

    waitFlip(); /* Wait for the last flip to finish, so we can draw to the old buffer */
#if 0
    /* test code */
    int x, y;
    u32 *p=vdat.buffer[vdat.curr_fb];
    u32 c = 0x01010101 * (vdat.framecnt&0xff);
    for (y=0; y<1080; ++y) {
      for (x=0; x<1920; ++x) {
        *p++ = c;
      }
    }
#endif
    scr_ea = ptr2ea(vdat.buffer[vdat.curr_fb]);
    for (i = 0; i < 6; i++) {
      spu[i].sync = 0;
      status = sysSpuThreadWriteSignal(spu[i].id, 0, scr_ea);
      assert(status == 0);
    }
    for (i = 0; i < 6; i++) {
      while (spu[i].sync == 0);
    }
    flip(&vdat); /* Flip buffer onto screen */
    sysUtilCheckCallback();
  }

  for (i = 0; i < 6; i++) {
    status = sysSpuThreadWriteSignal(spu[i].id, 0, 0);
    assert(status == 0);
  }

  printf("Joining SPU thread group... ");
  status = sysSpuThreadGroupJoin(group_id, &cause, &joinstatus);
  printf("%08x\n", status);
  printf("cause=%d status=%d\n", cause, joinstatus);

  printf("Closing image... %08x\n", sysSpuImageClose(&image));
  free((void*)spu);

  return 0;
}
Example #3
0
int
initSpurs ()
{
  int ret;
  int i;
  sys_ppu_thread_t ppu_thread_id;
  int ppu_prio;
  unsigned int nthread;

  ret = sysSpuInitialize (6, 0);
  printf ("sysSpuInitialize return %d\n", ret);

  ret = sysThreadGetId (&ppu_thread_id);
  printf ("sysThreadGetId return %d ppu_thread_id %x\n", ret, ppu_thread_id);

  ret = sysThreadGetPriority (ppu_thread_id, &ppu_prio);
  printf ("sysThreadGetPriority return %d ppu_prio %d\n", ret, ppu_prio);

  /* initialize spurs */
  printf ("Initializing spurs\n");
  spurs = (void *) memalign (SPURS_ALIGN, sizeof (Spurs));
  printf ("Initializing spurs attribute\n");
  SpursAttribute attributeSpurs;

  ret = spursAttributeInitialize (&attributeSpurs, 5, 250, ppu_prio - 1, true);
  if (ret) {
    printf ("error : spursAttributeInitialize failed  %x\n", ret);
    return (ret);
  }

  printf ("Setting name prefix\n");
  ret =
      spursAttributeSetNamePrefix (&attributeSpurs, SPURS_PREFIX_NAME,
      strlen (SPURS_PREFIX_NAME));
  if (ret) {
    printf ("error : spursAttributeInitialize failed %x\n", ret);
    return (ret);
  }

  printf ("Initializing with attribute\n");
  ret = spursInitializeWithAttribute (spurs, &attributeSpurs);
  if (ret) {
    printf ("error: spursInitializeWithAttribute failed  %x\n", ret);
    return (ret);
  }

  ret = spursGetNumSpuThread (spurs, &nthread);
  if (ret) {
    printf ("error: spursGetNumSpuThread failed %x\n", ret);
  }

  sys_spu_thread_t *threads =
      (sys_spu_thread_t *) malloc (sizeof (sys_spu_thread_t) * nthread);

  ret = spursGetSpuThreadId (spurs, threads, &nthread);
  if (ret) {
    printf ("error: spursGetSpuThreadId failed %x\n", ret);
  }

  printf ("SPURS %d spu threads availables\n", nthread);
  for (i = 0; i < nthread; i++) {
    printf ("SPU Number:%d\tSPU Thread ID:%x\n", i, threads[i]);
  }
  printf ("\n");

  printf ("checking SpursInfo\n");
  SpursInfo info;

  ret = spursGetInfo (spurs, &info);
  if (ret) {
    printf ("error: spursGetInfo failed %x\n", ret);
  }
  printf ("SpursInfo: \n");
  printf ("nSpus=%d \n", info.nSpus);
  printf ("spuGroupPriority=%d \n", info.spuGroupPriority);
  printf ("ppuThreadPriority=%d \n", info.ppuThreadPriority);
  printf ("exitIfNoWork=%d \n", info.exitIfNoWork);
  printf ("namePrefix=%s \n", info.namePrefix);
  for (i = 0; i < info.nSpus; i++) {
    printf ("SPU Number:%d\tSPU Thread ID:%x\n", i, info.spuThreads[i]);
  }
  printf ("SPURS initialized correctly!!!\n");

}
Example #4
0
int main(int argc, char *argv[])
{
    int     ret, server_mode;
    void    *host_addr = memalign(1024 * 1024, HOST_SIZE);
    msgType dialog_type;
	sys_ppu_thread_t id; // start server thread

    load_modules();

    init_logging();

	netInitialize();
	netCtlInit();

    // Initialize SPUs
    LOG(lm_main, LOG_DEBUG, ("Initializing SPUs\n"));
    ret = sysSpuInitialize(MAX_PHYSICAL_SPU, MAX_RAW_SPU);
    if (ret != 0)
    {
        LOG(lm_main, LOG_ERROR, ("sysSpuInitialize failed: %d\n", ret));
        goto quit;
    }

    init_screen(host_addr, HOST_SIZE);
    ioPadInit(7);

    ret = initialize_exit_handlers();
    if (ret != 0)
        goto quit;

    show_version();

    if (user_requested_exit())
        goto quit;

	u64 CEX=0x4345580000000000ULL;
	u64 DEX=0x4445580000000000ULL;
	u64 DEH=0x4445480000000000ULL;

	if(lv2peek(0x80000000002E79C8ULL)==DEX) {dex_mode=2; c_firmware=3.41f;}
	else
	if(lv2peek(0x80000000002CFF98ULL)==CEX) {dex_mode=0; c_firmware=3.41f;}
	else
	if(lv2peek(0x80000000002EFE20ULL)==DEX) {dex_mode=2; c_firmware=3.55f;}
	else
	if(lv2peek(0x80000000002D83D0ULL)==CEX) {dex_mode=0; c_firmware=3.55f;}
	else
	if(lv2peek(0x8000000000302D88ULL)==DEX) {dex_mode=2; c_firmware=4.21f;}
	else
	if(lv2peek(0x80000000002E8610ULL)==CEX) {dex_mode=0; c_firmware=4.21f;}
	else
	if(lv2peek(0x80000000002E9F08ULL)==CEX) {dex_mode=0; c_firmware=4.30f;}
	else
	if(lv2peek(0x8000000000304630ULL)==DEX) {dex_mode=2; c_firmware=4.30f;}
	else
	if(lv2peek(0x80000000002E9F18ULL)==CEX) {dex_mode=0; c_firmware=4.31f;}
	else
	if(lv2peek(0x80000000002EA488ULL)==CEX) {dex_mode=0; c_firmware=4.40f;}
	else
	if(lv2peek(0x80000000002EA498ULL)==CEX) {dex_mode=0; c_firmware=4.41f;}
	else
	if(lv2peek(0x8000000000304EF0ULL)==DEX) {dex_mode=2; c_firmware=4.41f;}
	else
	if(lv2peek(0x80000000002EA9B8ULL)==CEX) {dex_mode=0; c_firmware=4.46f;}
	else
	if(lv2peek(0x8000000000305410ULL)==DEX) {dex_mode=2; c_firmware=4.46f;}
	else
	if(lv2peek(0x80000000002E9BE0ULL)==CEX) {dex_mode=0; c_firmware=4.50f;}
	else
	if(lv2peek(0x8000000000309698ULL)==DEX) {dex_mode=2; c_firmware=4.50f;}
	else
	if(lv2peek(0x80000000002E9D70ULL)==CEX) {dex_mode=0; c_firmware=4.53f;}
	else
	if(lv2peek(0x80000000002EC5E0ULL)==CEX) {dex_mode=0; c_firmware=4.55f;}
	else
	if(lv2peek(0x80000000002ED850ULL)==CEX) {dex_mode=0; c_firmware=4.60f;}
	else
	if(lv2peek(0x80000000002ED860ULL)==CEX) {dex_mode=0; c_firmware=4.65f;}
	else
	if(lv2peek(0x800000000030F1A8ULL)==DEX) {dex_mode=2; c_firmware=4.65f;}
	else
	if(lv2peek(0x80000000002ED778ULL)==CEX) {dex_mode=0; c_firmware=4.70f;}
	else
	if(lv2peek(0x800000000030F240ULL)==DEX) {dex_mode=2; c_firmware=4.70f;}
	else
	if(lv2peek(0x80000000002ED818ULL)==CEX) {dex_mode=0; c_firmware=4.75f;}
	else
	if(lv2peek(0x800000000030F2D0ULL)==DEX) {dex_mode=2; c_firmware=4.75f;}
	else
	if(lv2peek(0x80000000002ED808ULL)==CEX) {dex_mode=0; c_firmware=4.80f;}
	else
	if(lv2peek(0x800000000030F3A0ULL)==DEX) {dex_mode=2; c_firmware=4.80f;}
	else
	if(lv2peek(0x800000000030F3B0ULL)==DEX) {dex_mode=2; c_firmware=4.81f;}
	else
	if(lv2peek(0x800000000032EB60ULL)==DEH) {deh_mode=2; c_firmware=4.81f;}
	else	
		c_firmware=0.00f;

	if(c_firmware==3.55f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_355D;
	}
	else
	if(c_firmware==3.55f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_355;
	}
	else
	if(c_firmware==4.21f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_421;
	}
	else
	if(c_firmware==4.30f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_430;
	}
	else
	if(c_firmware==4.30f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_430D;
	}
	else
	if(c_firmware==4.31f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_431;
	}
	else
	if(c_firmware==4.40f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_440;
	}
	else
	if(c_firmware==4.41f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_441;
	}
	else
	if(c_firmware==4.41f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_441D;
	}
	else
	if(c_firmware==4.46f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_446;
	}
	else
	if(c_firmware==4.50f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_450;
	}
	else
	if(c_firmware==4.53f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_453;
	}
	else
	if(c_firmware==4.55f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_455;
	}
	else
	if(c_firmware==4.60f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_460;
	}
	else
	if(c_firmware==4.65f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_465;
	}
	else
	if(c_firmware==4.65f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_465D;
	}
	else
	if(c_firmware==4.70f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_470;
	}
	else
	if(c_firmware==4.70f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_470D;
	}
	else
	if(c_firmware==4.75f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_475;
	}
	else
	if(c_firmware==4.80f && !dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_480;
	}
	else
	if(c_firmware==4.80f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_480D;
	}
	else
	if(c_firmware==4.75f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_475D;
	}
	else
	if(c_firmware==4.81f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_481D;
	}
	else
	if(c_firmware==4.46f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_446D;
	}
	else
	if(c_firmware==4.50f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_450D;
	}
	else
	if(c_firmware==4.21f && dex_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_421D;
	}
	else
	if(c_firmware==3.41f)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_341;
	}
	else
	if(c_firmware==4.81f && deh_mode)
	{
		SYSCALL_TABLE			= SYSCALL_TABLE_481H;
	}	
/*
	if(c_firmware>=4.20f && SYSCALL_TABLE)
	{
		// add and enable lv2 peek/poke + lv1 peek/poke
		lv2poke(0x800000000000171CULL,       0x7C0802A6F8010010ULL);
		lv2poke(0x800000000000171CULL +   8, 0x396000B644000022ULL);
		lv2poke(0x800000000000171CULL +  16, 0x7C832378E8010010ULL);
		lv2poke(0x800000000000171CULL +  24, 0x7C0803A64E800020ULL);
		lv2poke(0x800000000000171CULL +  32, 0x7C0802A6F8010010ULL);
		lv2poke(0x800000000000171CULL +  40, 0x396000B744000022ULL);
		lv2poke(0x800000000000171CULL +  48, 0x38600000E8010010ULL);
		lv2poke(0x800000000000171CULL +  56, 0x7C0803A64E800020ULL);
		lv2poke(0x800000000000171CULL +  64, 0x7C0802A6F8010010ULL);
		lv2poke(0x800000000000171CULL +  72, 0x7D4B537844000022ULL);
		lv2poke(0x800000000000171CULL +  80, 0xE80100107C0803A6ULL);
		lv2poke(0x800000000000171CULL +  88, 0x4E80002080000000ULL);
		lv2poke(0x800000000000171CULL +  96, 0x0000170C80000000ULL);
		lv2poke(0x800000000000171CULL + 104, 0x0000171480000000ULL);
		lv2poke(0x800000000000171CULL + 112, 0x0000171C80000000ULL);
		lv2poke(0x800000000000171CULL + 120, 0x0000173C80000000ULL);
		lv2poke(0x800000000000171CULL + 128, 0x0000175C00000000ULL);
		lv2poke(SYSCALL_PTR( 6), 0x8000000000001778ULL); //sc6
		lv2poke(SYSCALL_PTR( 7), 0x8000000000001780ULL); //sc7
		lv2poke(SYSCALL_PTR( 8), 0x8000000000001788ULL); //sc8
		lv2poke(SYSCALL_PTR( 9), 0x8000000000001790ULL); //sc9
		lv2poke(SYSCALL_PTR(10), 0x8000000000001798ULL); //sc10
	}*/
    // remove patch protection
	if(c_firmware==3.55f)
	    remove_protection();

	if(c_firmware==0.00f)
		ret = -1;
	else
	    ret = patch_lv1_ss_services();
    if (ret < 0)
    {
        dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON);
        msgDialogOpen2(dialog_type, "ERROR: Couldn't patch lv1 services, returning to the XMB.\nMake sure you are running a firmware which allows patching!", dialog_handler, NULL, NULL);

        dialog_action = 0;
        while (!dialog_action && !user_requested_exit())
        {
            sysUtilCheckCallback();
            flip();
        }
        msgDialogAbort();

        goto quit;
    }

    // patch syscall 864 to allow drive re-init
	if(c_firmware==0.0f)
		ret = -1;
	else
	    ret = patch_syscall_864();
    if (ret < 0)
    {
        dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON);
        msgDialogOpen2(dialog_type, "ERROR: Couldn't patch syscall 864, returning to the XMB.\nMake sure you are running a firmware which allows patching!", dialog_handler, NULL, NULL);

        dialog_action = 0;
        while (!dialog_action && !user_requested_exit())
        {
            sysUtilCheckCallback();
            flip();
        }
        msgDialogAbort();

        goto quit;
    }

    // install the necessary modules
    ret = install_modules();
    if (ret < 0)
    {
        dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON);
        msgDialogOpen2(dialog_type, "Installation was aborted, returning to the XMB.", dialog_handler, NULL, NULL);

        dialog_action = 0;
        while (!dialog_action && !user_requested_exit())
        {
            sysUtilCheckCallback();
            flip();
        }
        msgDialogAbort();

        goto quit;
    }

    if (user_requested_exit())
        goto quit;

    // reset & re-authenticate the BD drive
    sys_storage_reset_bd();
    sys_storage_authenticate_bd();

    // eject current disc
    {
        int fd;
        ret = sys_storage_open(BD_DEVICE, &fd);
        if (ret == 0)
        {
            ioctl_eject(fd);
            sys_storage_close(fd);
        }
    }

    ret = sysDiscRegisterDiscChangeCallback(&bd_eject_disc_callback, &bd_insert_disc_callback);

    // poll for an output_device
    poll_output_devices();

    server_mode = user_select_server_mode();

    if (user_requested_exit())
        goto quit;

    if (server_mode)
    {
#ifdef ENABLE_LOGGING
        if (output_device)
        {
            char file_path[100];
            sprintf(file_path, "%s/daemon_log.txt", output_device);
            set_log_file(file_path);
        }
#endif
    	sysThreadCreate(&id, listener_thread, NULL, 1500, 0x400, 0, "listener");

        while (1)
        {
            // server loop
            server_loop();

            // break out of the loop when requested
            if (user_requested_exit())
                break;
        }
    }
    else
    {
        while (1)
        {
            // main loop
            main_loop();

            // break out of the loop when requested
            if (user_requested_exit())
                break;
        }
    }

    ret = sysDiscUnregisterDiscChangeCallback();

 quit:

    unpatch_lv1_ss_services();

    destroy_logging();
	netDeinitialize();
    unload_modules();

    free(host_addr);

    return 0;
}
Example #5
0
int main(int argc,char *argv[])
{
	u32 *array;
	u32 group_id;
	spustr_t *spu;
	sysSpuImage image;
	u32 cause,status,i;
	sysSpuThreadArgument arg[6];
	sysSpuThreadGroupAttribute grpattr = { 7+1, ptr2ea("mygroup"), 0, 0 };
	sysSpuThreadAttribute attr = { ptr2ea("mythread"), 8+1, SPU_THREAD_ATTR_NONE };

	printf("spuchain starting....\n");

	sysSpuInitialize(6,0);
	sysSpuImageImport(&image,spu_bin,0);
	sysSpuThreadGroupCreate(&group_id,6,100,&grpattr);

	spu = (spustr_t*)memalign(128,6*sizeof(spustr_t));
	array = (u32*)memalign(128,4*sizeof(u32));

	for(i=0;i<6;i++) {
		spu[i].rank = i;
		spu[i].count = 6;
		spu[i].sync = 0;
		spu[i].array_ea = ptr2ea(array);
		arg[i].arg0 = ptr2ea(&spu[i]);

		printf("Creating SPU thread... ");
		sysSpuThreadInitialize(&spu[i].id,group_id,i,&image,&attr,&arg[i]);
		printf("%08x\n",spu[i].id);
		sysSpuThreadSetConfiguration(spu[i].id,(SPU_SIGNAL1_OVERWRITE | SPU_SIGNAL2_OVERWRITE));
	}

	printf("Starting SPU thread group....\n");
	sysSpuThreadGroupStart(group_id);

	printf("Initial array: ");
	for(i=0;i<4;i++) {
		array[i] = (i + 1);
		printf(" %d",array[i]);
	}
	printf("\n");

	/* Send signal notification to SPU 0 */
	printf("sending signal.... \n");
	sysSpuThreadWriteSignal(spu[0].id,0,1);

	/* Wait for SPU 5 to return */
	while(spu[5].sync==0);

	printf("Output array: ");
	for(i=0;i<4;i++) printf(" %d",array[i]);
	printf("\n");

	printf("Joining SPU thread group....\n");
	sysSpuThreadGroupJoin(group_id,&cause,&status);
	sysSpuImageClose(&image);

	free(array);
	free(spu);

	return 0;
}