n64main.c 3.76 KB
#include <ultra64.h>
#include <os.h>
#include <ultralog.h>
#include <assert.h>
#include "sched.h"
#include "gfx.h"
#include "spec.h"


/* Stacks for the threads and message queues  */
u64     bootStack[STACKSIZE/8]; 

static void mainproc(char *);
static void gameproc(char *);
extern void midiproc(char *);

static OSThread	rmonThread;
static OSThread	mainThread;
static OSThread	gameThread;
static OSThread	midiThread;

static u64	rmonThreadStack[RMON_STACKSIZE/8];
static u64	mainThreadStack[STACKSIZE/8];
static u64	gameThreadStack[STACKSIZE/8];
static u64	midiThreadStack[STACKSIZE/8];

/* For PI manager */
#define PI_QUEUE_SIZE  256  /* You must specify this before you create the PI manager */
                            /* unfortunately, you don't know how many you really need. */
                            /* Go for a large number. It's a small amount for each */
static OSMesg PiMessages[PI_QUEUE_SIZE];
static OSMesgQueue PiMessageQ;


/**** Scheduler globals ****/
OSSched         sc;
OSMesgQueue     *sched_cmdQ;
u64             scheduleStack[OS_SC_STACKSIZE/8];

OSMesgQueue     gfxFrameMsgQ;
OSMesg          gfxFrameMsgBuf[8];

#define SCHEDULER_PRIORITY 10
#define NUM_FIELDS         1

extern GFXInfo  gInfo[];

boot(void)
{
    osInitialize();
    osCreateThread(&mainThread, 1, (void(*)(void *))mainproc, 0,
		  (u8*)mainThreadStack+STACKSIZE, 10);

    osStartThread(&mainThread);
}

static void mainproc(char *argv) 
{    
    osCreateThread(&gameThread, 3, (void(*)(void *))gameproc, argv,
                       (u8*)gameThreadStack+STACKSIZE, 10); 

    /* Initialize video */
    osCreateViManager(OS_PRIORITY_VIMGR);
    osViSetMode(&osViModeTable[OS_VI_NTSC_LAN1]);

    /* Start PI Mgr for access to cartridge & GIO    */
    osCreatePiManager(OS_PRIORITY_PIMGR, &PiMessageQ, PiMessages, 
		      PI_QUEUE_SIZE); 
    osCreateThread(&rmonThread, 0, rmonMain, (void *)0,
                  (u8*)rmonThreadStack+ RMON_STACKSIZE, OS_PRIORITY_RMON );
    osStartThread(&rmonThread);
    osStartThread(&gameThread);  
    
    /* Become the idle thread   */
    osSetIntMask( OS_IM_ALL );
    osSetThreadPri( 0, 0 );
    for (;;);
}

static void gameproc(char *argv)
{
    u32             drawbuffer = 0;
    u32             pendingGFX = 0;
    OSScClient      gfxClient;
    GFXMsg          *msg;

/*    osSetErrorHandler((OSErrorHandler)__assert); */
    osCreateScheduler(&sc, (void *)(scheduleStack + OS_SC_STACKSIZE/8),
                      SCHEDULER_PRIORITY, OS_VI_NTSC_LAN1, NUM_FIELDS);

    sched_cmdQ = osScGetCmdQ(&sc);

    osCreateMesgQueue(&gfxFrameMsgQ, gfxFrameMsgBuf, 8);

    
    osCreateThread(&midiThread, 4, (void(*)(void *))midiproc, argv,
                  (u8*)midiThreadStack+STACKSIZE, 8);

    osStartThread(&midiThread);

    osScAddClient(&sc, &gfxClient, &gfxFrameMsgQ); 
    
    initGFX(); 

    while(1)
    {
	osRecvMesg(&gfxFrameMsgQ, (OSMesg *)&msg, OS_MESG_BLOCK);
        switch (msg->gen.type) 
        {
            case (OS_SC_RETRACE_MSG):
                /**** Create a new gfx task unless we already have 2  ****/  
                if (pendingGFX < 2) 
                {
                    createGfxTask(&gInfo[drawbuffer]);
                    pendingGFX++;
                    drawbuffer ^= 1; /* switch the drawbuffer */

                }
                break;

            case (OS_SC_DONE_MSG):
                pendingGFX--;        /* decrement number of pending tasks */
                break;

            case (OS_SC_PRE_NMI_MSG): /* stop creation of graphics tasks */
                pendingGFX += 2;
                break;
        }
    }
}


#if 0
extern u32 messageCt;
extern char *messageSt;
void __assert(const char* expr, const char *file, int linenum)
{
    messageCt = 200;
    osSetThreadPri( 0, 2 );
    messageSt = file;
    while(1)
	;
}

#endif