
/**************************************************************************
 *                                                                        *
 *               Copyright (C) 1994, Silicon Graphics, Inc.               *
 *                                                                        *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright  law.  They  may not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *                                                                        *
 *************************************************************************/
#include <ultra64.h>
#include <ultrahost.h>
#include <gu.h>

#ifndef _FINALROM

/*
 * guParseGbiDL works in conjunction with the dlprint tool. dlprint must be
 * running on the host Indy. guParseGbiDL, sends a bunch of blocks of data,
 * with a minimum of one display list, but typically, the principle display
 * list with a bunch of branched or nested display lists, as well as all the
 * vertex and matrix data that will be used. After all the blocks of data 
 * are sent, a GU_PARSE_READY command is sent, and dlprint parses out the
 * data printing it to stdout.
 *
 * In order to know what data to send, guParseGbiDL must step through the 
 * display list, find all the gSPDisplayList and gSPBranchList calls, go
 * to those lists, and also find and send info for all the matrix and vertex
 * calls.
 */
void guParseGbiDL(u64 *gbi_dl, u32 nbytes, u8 flags)
{
    guDLPrintCB    cntlBlk;
    Gfx*           dlStk[11];
    s32            dlcount = 0;
    Gfx            *curGfx,*dlPtr,*vaddr;
    s8             op;
    u32            *word0;
    u32            *word1;
    u32            segments[16];
    u32            param, seg;
    u32            paddr,len;


    cntlBlk.dataSize = nbytes;
    cntlBlk.flags = flags;
    cntlBlk.dlType = GU_PARSE_GBI_TYPE;
    cntlBlk.paddr = osVirtualToPhysical(gbi_dl);

    osWriteHost(&cntlBlk,sizeof(cntlBlk));
    osWriteHost(gbi_dl,nbytes);  
        
    dlStk[0] = (Gfx*)gbi_dl;
    while((dlcount >= 0) && (dlcount <= 10))
    {
        curGfx = dlStk[dlcount];    /* get the current graphics display list */
        op = *((s8*)curGfx);        /* get the first byte */
        dlStk[dlcount]++;           /* increment to next gfx command */
        switch(op)
        {
	    case G_MOVEWORD:
                word0 = (u32*)curGfx;       /* get ptr to first word */
                if(((*word0) & 0x000000ff) == G_MW_SEGMENT)
                {
                    u32  seg;
                    seg = (((*word0) & 0x00ffff00) >> 8) >> 2;
                    word1 = word0 + 1;
                    segments[seg] = *word1;
                }
                break;
            case G_ENDDL:   
                dlcount--;
                break;
            case G_DL:
                word0 = (u32*)curGfx;       /* get ptr to first word */
                param = ((*word0) & 0x00ff0000) >> 16; /* get param */
                word1 = word0 + 1;          /* get pointer to second word */
                seg = ((*word1) & 0x0f000000) >> 24; /* get the segment */
                paddr = segments[seg] + ((*word1) & 0x00ffffff);
                vaddr = (Gfx*)osPhysicalToVirtual(paddr);
                len = 1;
                dlPtr = vaddr;
                while((*(s8*)dlPtr) != G_ENDDL)
                {
                    len++;
                    dlPtr++;
                }
                len *= sizeof(Gfx);
                        
                cntlBlk.dataSize = len;
                cntlBlk.dlType = GU_PARSE_GBI_TYPE;
                cntlBlk.paddr = paddr;
                        
                osWriteHost(&cntlBlk,sizeof(cntlBlk));
                osWriteHost((u8*)vaddr,len); 
                if(param == G_DL_PUSH)
                {
                    if(dlcount < 10)
                        dlcount++;
                    else
                        osSyncPrintf("Display lists nested too deep!!!\n");
                }
                dlStk[dlcount] = (Gfx*)vaddr;
                break;
            case G_VTX:
            case G_MOVEMEM:
            case G_MTX:
                word0 = (u32*)curGfx;       /* get ptr to first word */
                word1 = word0 + 1;          /* get pointer to second word */
                seg = ((*word1) & 0x0f000000) >> 24; /* get the segment */
                paddr = segments[seg] + ((*word1) & 0x00ffffff);
                vaddr = (Gfx*)osPhysicalToVirtual(paddr);
                len = (*word0) & 0x0000ffff;
                cntlBlk.dataSize = len;  /* always send 32 bytes, the most used */
                cntlBlk.dlType = GU_PARSE_MEM_BLOCK;
                cntlBlk.paddr = paddr;
                osWriteHost(&cntlBlk,sizeof(cntlBlk));
                osWriteHost((u8*)vaddr,len);
                break;
                
        }
    }

    cntlBlk.dlType = GU_PARSE_READY;
    osWriteHost(&cntlBlk,sizeof(cntlBlk)); 
}

#endif

