main.c 10.6 KB

/*---------------------------------------------------------------------*
        Copyright (C) 1997 Nintendo.
        
        $RCSfile: main.c,v $
        $Revision: 1.1.1.1 $
        $Date: 2002/05/02 03:27:12 $
 *---------------------------------------------------------------------*/
#include"headers.h"
#define	NUM_INT_MESSAGES	3
static void	idle(void *);
static void	mainproc(void *);

OSMesgQueue	dmaMessageQ,rspMessageQ,rdpMessageQ,retraceMessageQ;
OSMesg		dmaMessageBuf,rspMessageBuf,rdpMessageBuf,retraceMessageBuf;
OSMesg		dummyMessage;
OSIoMesg	dmaIOMessageBuf;
OSMesgQueue rstMessageQ;OSMesg rstMessageBuf;

static OSMesgQueue intMessageQ;
static OSMesg	intMessageBuf[NUM_INT_MESSAGES];
static OSContStatus	ctrls[MAXCONTROLLERS];	/* controller status */
static OSContPad	ctrld[MAXCONTROLLERS];	/* controller data */

Dynamic dynamic;
Dynamic	*dynamicp;

OSTask	tlist;     	/* globaltask lists */
Gfx		*glistp;	/* global for test case procs */
char 	*kanjiSegment;
unsigned long long int dram_stack[SP_DRAM_STACK_SIZE64];

u64 	rdp_output_len;
u64 	rdp_output[16];		/*[4096*16]*/

int		rdp_DRAM_io = 0;
int		rdp_mspanFlushFlag = 0;
void	*cfb_ptrs[2];
int		draw_buffer = 0;

ctrl	Ctrl[4];

OSPiHandle *handler;

u64	bootStack[STACKSIZE/8];

static OSThread	idleThread;
static u64	idleThreadStack[STACKSIZE/8];

static OSThread	mainThread;
static u64	mainThreadStack[STACKSIZE/8];

static s32      error_handle(s32);

/*
 * Define for error_handle routine
 */
#define RETRY   0
#define FATAL   1

static OSMesg PiMessages[NUM_PI_MSGS];
static OSMesgQueue PiMessageQ;

/*
 * Buffer for leo library. This is used for "command queue", just
 * like pi manager.
 * Game developers should choose this number carefully to be suitable
 * for each game.
 */
#define NUM_LEO_MESGS   8

static  OSMesg  LeoMessages[NUM_LEO_MESGS];

int	timer,resetflag,color,mode,kanadr;

/* BOOT */
void boot(void)
{
	osInitialize();
	osCreateThread(&idleThread,1,idle,(void *)0,idleThreadStack+STACKSIZE/8,10);
	osStartThread(&idleThread);

        /*
         * never reached 
         */
}
/* IDLE */
static void idle(void *arg)
{
	/* Initialize video */
	osCreateViManager(OS_PRIORITY_VIMGR);
	osViSetMode(&osViModeTable[OS_VI_NTSC_LAN1]);
	osViBlack(TRUE);
	/* Start PI Mgr for access to cartridge */
	osCreatePiManager((OSPri)OS_PRIORITY_PIMGR,&PiMessageQ,PiMessages,NUM_PI_MSGS);
	/* Create main thread */
	osCreateThread(&mainThread,3,mainproc,arg,mainThreadStack+STACKSIZE/8,10);
	osStartThread(&mainThread);
	/* Become the idle thread */
	osSetThreadPri(0,0);
	while(1);
}
/* SETUP MESSAGE QUEUE */
static void setup_messagequeue(void)
{
	osCreateMesgQueue(&dmaMessageQ,&dmaMessageBuf,1);
	osCreateMesgQueue(&rspMessageQ,&rspMessageBuf,1);
	osSetEventMesg(OS_EVENT_SP,&rspMessageQ,dummyMessage);
	osCreateMesgQueue(&rdpMessageQ,&rdpMessageBuf,1);
	osSetEventMesg(OS_EVENT_DP,&rdpMessageQ,dummyMessage);
	osCreateMesgQueue(&retraceMessageQ,&retraceMessageBuf,1);
	osViSetEvent(&retraceMessageQ,dummyMessage,1);
	osCreateMesgQueue(&intMessageQ,intMessageBuf,NUM_INT_MESSAGES);
	osSetEventMesg(OS_EVENT_SI,&intMessageQ,dummyMessage);

	osCreateMesgQueue(&rstMessageQ,&rstMessageBuf,1);
	osSetEventMesg(OS_EVENT_PRENMI,&rstMessageQ,dummyMessage);
}

/* CONTROLLER INITIALIZE */
static void continit(void)
{
	int i;
	unsigned char pattern;

	osContInit(&intMessageQ,&pattern,&ctrls[0]);
	for(i=0;i<4;i++){
		Ctrl[i].flag=pattern&1;pattern>>=1;
	}
	osContStartReadData(&intMessageQ);
}

/* READ CONTOROLLER */
static void readcontroller(void)
{
	int i;
	osContGetReadData(ctrld);
	for(i=0;i<4;i++){
		if(Ctrl[i].flag){
			Ctrl[i].oldcon=Ctrl[i].nowcon;
			Ctrl[i].nowcon=(int)ctrld[i].button;
			Ctrl[i].nowtrg=(Ctrl[i].nowcon^Ctrl[i].oldcon)&Ctrl[i].nowcon;
			Ctrl[i].sx=ctrld[i].stick_x;
			Ctrl[i].sy=ctrld[i].stick_y;
		}
	}
}
/* BUILD GRAPHICS TASK */
static void build_graphics_task(OSTask *tlistp)
{
	tlistp->t.type = M_GFXTASK;
	tlistp->t.flags = OS_TASK_DP_WAIT;
	tlistp->t.ucode_boot = (unsigned long long *) rspbootTextStart;
	tlistp->t.ucode_boot_size = ((int)rspbootTextEnd - (int)rspbootTextStart);
	if(rdp_DRAM_io){
	    /* re-direct output to DRAM: */
	    tlistp->t.ucode=(unsigned long long *)gspFast3D_dramTextStart;
	    tlistp->t.ucode_data=(unsigned long long *)gspFast3D_dramDataStart; 
	}
	else{
	    /* SP output over XBUS to DP: */
	    tlistp->t.ucode=(unsigned long long *)gspFast3DTextStart;
	    tlistp->t.ucode_data=(unsigned long long *)gspFast3DDataStart;
	}
	tlistp->t.ucode_size = SP_UCODE_SIZE;
	tlistp->t.ucode_data_size = SP_UCODE_DATA_SIZE;
	tlistp->t.dram_stack = (unsigned long long *) &(dram_stack[0]);
	tlistp->t.dram_stack_size = SP_DRAM_STACK_SIZE8;
	if(rdp_DRAM_io){
	    tlistp->t.output_buff= (unsigned long long *)&(rdp_output[0]);
	    tlistp->t.output_buff_size= (unsigned long long *)&rdp_output_len;
	}
	else{
	    tlistp->t.output_buff = (unsigned long long *)0x0;
	    tlistp->t.output_buff_size = (unsigned long long *)0x0;
	}
	/* initial display list: */
	tlistp->t.data_ptr = (unsigned long long *)dynamicp->glist;
	tlistp->t.data_size = ((int)(glistp - dynamicp->glist) * sizeof (Gfx));
	tlistp->t.yield_data_ptr = (unsigned long long *)NULL;
	tlistp->t.yield_data_size = 0xDA0;
}
/* MAIN! */
static void mainproc(void *arg)
{
	OSTask		*tlistp;
	OSMesg 		actualMesg;
	char		*staticSegment;
	LEOCmd		cmdBlock;
	LEODiskID	diskID;
	s32		error;
	
    /* apps need to do this in order to init the R4300 floating point... */
	float	fix_float_bug = 1.0;
	cfb_ptrs[0] = (void *) K0_TO_PHYS((u32)&(cfb_16_a[0]));
	cfb_ptrs[1] = (void *) K0_TO_PHYS((u32)&(cfb_16_b[0]));
	setup_messagequeue();	 /* Setup the message queues */

        error = LeoCreateLeoManager((OSPri)OS_PRIORITY_LEOMGR - 1,
                                         (OSPri)OS_PRIORITY_LEOMGR,
                                         LeoMessages, NUM_LEO_MESGS);
        
        if(error != LEO_ERROR_GOOD)
          if (error_handle(error) == FATAL)               
          {
#ifdef _DEBUG
            osSyncPrintf("Fatal error\n");
#endif
          }

        /*
         * We must check that the current disk is the
         * same as to booted disk
         */
        do
        {
          LeoReadDiskID(&cmdBlock, &diskID, &dmaMessageQ);
          osRecvMesg(&dmaMessageQ, (OSMesg *)&error, OS_MESG_BLOCK);

          if (error == 0)
            break;
      
          if (!( (error == LEO_ERROR_MEDIUM_NOT_PRESENT) ||
                (error == LEO_ERROR_MEDIUM_MAY_HAVE_CHANGED )))
          {
#ifdef _DEBUG
            osSyncPrintf("error = 0x%x\n", error);
#endif
            for(;;);
          }
      
        } while(1);
        
        /*
         * Check that this disk is the same as the booted one.
         */
        if (bcmp((void *)&leoBootID, (void *)&diskID, sizeof(LEODiskID))
	    != 0)
          for(;;);              /* error */
        
	/*
	 * Initialize PI handler
	 */
#if 1
	handler = osCartRomInit();
#else
	handler = osDriveRomInit();
#endif

	/*
	 * Stick the static segment right after the code/data segment
	 */
	staticSegment = _codeSegmentEnd;
	do{
	  LeoReadWrite(&cmdBlock, OS_READ,
		       (u32)_staticSegmentDiskStart, staticSegment,
		       (u32)_staticSegmentDiskEnd - (u32)_staticSegmentDiskStart,
		       &dmaMessageQ);
                          
	  osRecvMesg(&dmaMessageQ, (OSMesg *)&error, OS_MESG_BLOCK);
                  
	  if (error == 0)
	    break;
#ifdef _DEBUG
	  osSyncPrintf("error = 0x%x\n", error);
#endif            
	  if (error_handle(error) == FATAL)
	  {
#ifdef _DEBUG
	    osSyncPrintf("Fatal error\n");
#endif
	    for(;;);
	  }
                          
	} while(1);
	
	continit();
	color=15;resetflag=mode=kanadr=0;
	osViBlack(FALSE);
	while(1){
		tlistp = &tlist;dynamicp = &dynamic;glistp = &(dynamicp->glist[0]);
		gSPSegment(glistp++,0,0x0);
		gSPSegment(glistp++,STATIC_SEGMENT,osVirtualToPhysical(staticSegment));
		if(rdp_mspanFlushFlag)gDPPipelineMode(glistp++,G_PM_1PRIMITIVE);
		osRecvMesg(&intMessageQ,&actualMesg,OS_MESG_BLOCK);
		readcontroller();
		if(MQ_IS_FULL(&rstMessageQ)){
			osRecvMesg(&rstMessageQ,&dummyMessage,OS_MESG_BLOCK);
			resetflag=1;
		}

		draw();
		osContStartReadData(&intMessageQ);

		build_graphics_task(tlistp);osWritebackDCacheAll();
		osSpTaskLoad(tlistp);osSpTaskStartGo(tlistp);
		if(rdp_DRAM_io){
			osRecvMesg(&rspMessageQ,&dummyMessage,OS_MESG_BLOCK);
			(void)osDpSetNextBuffer(&(rdp_output[0]),(u32)rdp_output_len);
			osRecvMesg(&rdpMessageQ,&dummyMessage,OS_MESG_BLOCK);
		}
		else osRecvMesg(&rdpMessageQ,&dummyMessage,OS_MESG_BLOCK);
		osViSwapBuffer(OS_PHYSICAL_TO_K0(cfb_ptrs[draw_buffer]));
		timer=osGetTime();
		if(MQ_IS_FULL(&retraceMessageQ)){
			osRecvMesg(&retraceMessageQ,&dummyMessage,OS_MESG_BLOCK);
		}
		/* Wait for Vertical retrace to finish swap buffers */
	    (void)osRecvMesg(&retraceMessageQ, &dummyMessage, OS_MESG_BLOCK);
		osSetTime(0);
		draw_buffer^=1;
		if(resetflag)while(1);
	}
	osExit();
}

s32 error_handle(s32 result)
{
  LEODiskID     diskID;
  LEOCmd        cmdBlock;
  s32           error;
  
  if (!( (result == LEO_ERROR_MEDIUM_NOT_PRESENT) ||
        (result == LEO_ERROR_MEDIUM_MAY_HAVE_CHANGED )))
    return FATAL;
  
  if (result == LEO_ERROR_MEDIUM_NOT_PRESENT){
#ifdef _DEBUG
    osSyncPrintf("Insert the disk\n");
#endif  
  }
  

  while(1)
  {
    /*
     * Do the following at a time
     *  1. Wait for the users to insert the disk (if the error
     *     was "NO MEDIA").
     *  2. Get the disk ID of the inserted disk.
     */
    do
    {
      LeoReadDiskID(&cmdBlock, &diskID, &dmaMessageQ);
      osRecvMesg(&dmaMessageQ, (OSMesg *)&error, OS_MESG_BLOCK);

      if (error == 0)
        break;
      
      if (!( (error == LEO_ERROR_MEDIUM_NOT_PRESENT) ||
            (error == LEO_ERROR_MEDIUM_MAY_HAVE_CHANGED )))
      {
#ifdef _DEBUG
        osSyncPrintf("error = 0x%x\n", error);
#endif
        return FATAL;
      }
      
    } while(1);
    
    /*
     * Check that this disk is the same as the previous one.
     */
    if (bcmp((void *)&leoBootID, (void *)&diskID, sizeof(LEODiskID))
        == 0)
      return RETRY;
    
    /*
     * Since the inserted disk is the wrong one, stop the spindle
     * motor and wait for the users to change the disk.
     */
#ifdef _DEBUG
    osSyncPrintf("This disk is wrong. Eject it and insert the right disk.\n");
#endif
    do
    {
      LeoSpdlMotor(&cmdBlock, SLEEP, &dmaMessageQ);
      osRecvMesg(&dmaMessageQ, (OSMesg *)&error, OS_MESG_BLOCK);
      if (!( (error == 0) ||
            (error == LEO_ERROR_MEDIUM_NOT_PRESENT) ||
            (error == LEO_ERROR_MEDIUM_MAY_HAVE_CHANGED )))
        return FATAL;
    } while ( error != LEO_ERROR_MEDIUM_MAY_HAVE_CHANGED );

  } /* while(1) */

  /* Never reached, only to remove warning message */
  return 0;
  
} /* error_handle() */