vpack.c 5.49 KB

/**************************************************************************
 *                                                                        *
 *               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.  *
 *                                                                        *
 *************************************************************************/

/*
 * File:	vpack.c
 * Creator:	hsa@sgi.com
 * Create Date:	Tue Mar  8 11:00:56 PST 1994
 *
 * This file holds the pack instructions for the VU.
 *
 */

#include <stdio.h>
#include "rsp.h"
#include "i128.h"
#include "rspctl.h"
#include "opcode.h"
#include "vu.h"
#include "trace_print.h"


rsp_vuPipe_t	vu_PackPipe[rsp_VUPIPEDEPTH+1];


/*
 * decode and execute a pack instruction
 */
static void
rsp_VUPackExec(rsp_vuPipe_t *mp)
{
    boolean	dopack;
    int		op, nib, i, fshift, nibsize[4], index, hi, lo;
    u16		du;
    u32		t32;	/* for macro usage */

    /* decode instruction */
    op = ExtractBits(mp->inst, 5, 0);
    mp->format = ExtractBits(mp->inst, 24, 21);
    mp->rt = ExtractBits(mp->inst, 20, 16);
    mp->rs = ExtractBits(mp->inst, 15, 11);
    mp->rd = ExtractBits(mp->inst, 10,  6);

    switch (mp->format) {
      case 0x01:
	nib = 0;
	break;

      case 0x02:
	nib = 1;
	break;

      case 0x04:
	nib = 2;
	break;

      case 0x08:
	nib = 3;
	break;

      default:
	fprintf(stderr,"bad element for vins/vext [%02x]\n",mp->format);
	break;
    }

    dopack = TRUE;
    fshift = 0;
    nibsize[0] = nibsize[1] = nibsize[2] = nibsize[3] = 4;
    switch (op) {
      case rsp_VEXTT:
	dopack = FALSE;	/* fall through */

      case rsp_VINST:
	fshift = 10;
	nibsize[0] = nibsize[1] = nibsize[2] = 5;
	nibsize[3] = 1;
	break;

      case rsp_VEXTQ:
	dopack = FALSE;	/* fall through */

      case rsp_VINSQ:
	fshift = 11;
	break;

      case rsp_VEXTN:
	dopack = FALSE;	/* fall through */

      case rsp_VINSN:
	break;
    }

    rsp_VURegLock(mp->rd, mp->pc);

    /* check for stall. If okay, execute and decrement delay field */
    if (rsp_VURegIsLocked(mp->rs, mp->pc)) {
	/* can't do anything right now... */
	mp->stalled = TRUE;
	rsp_VUStalled = TRUE;
	rsp_Verbose(stderr,"VU pack stalled... (%08x)\n",mp->pc);
    } else {
	/* execute */
	index = 16;	/* pick out nibble */
	for (i=0; i<=nib; i++)
	    index -= nibsize[i];
	lo = index;
	hi = index + nibsize[nib] - 1;

	if (dopack) {

	    /*
	    Set128(&(mp->result), &(rsp_VUR[mp->rd]));
	    */
	    for (i=0; i<8; i++) {	/* do all vector elements */
		du = (u32) Get128By16(&(rsp_VUR[mp->rs]), i);
		du >>= fshift;	/* move to right place in dest */
		/* fix up special cases */
		if (op == rsp_VINST && nib == 3) {
		    du >>= 4;	/* fix alpha bit */
		}
		du &= ((0x01 << nibsize[nib])-1);	/* clean up upper bits */

		t32 = (u32) Get128By16(&(rsp_VUR[mp->rt]), i);
		LoadField(t32, hi, lo, du);
		Set128By16(&(mp->result), (u16) t32, i);
	    }
	} else {

	    for (i=0; i<8; i++) {	/* all elements */
		t32 = (u32) Get128By16(&(rsp_VUR[mp->rs]), i);
		du = ExtractBits(t32, hi, lo);
		du <<= fshift;	/* move to right place in dest */
		/* fix up special cases */
		if (op == rsp_VEXTN) {	/* do sign-extend for nibble */
		    if (du & 0x08)
			du |= 0xfff8;
		} else if (op == rsp_VEXTT && nib == 3) {
		    du <<= 4;	/* fix alpha bit */
		}
		Set128By16(&(mp->result), (u16) du, i);
	    }
	}

	mp->stalled = FALSE;
	mp->delay--;
    }
}


/* PUBLIC FUNCTIONS */

/*
 * check pack pipeline for stalls
 * returns TRUE is stalled.
 */
boolean
rsp_VUPackCheckStall(void)
{
    int		i;

    for (i=0; i<rsp_VUPIPEDEPTH; i++) {
	if (vu_PackPipe[i].delay > 0 && vu_PackPipe[i].stalled)
	    return TRUE;
    }

    return FALSE;
}

/*
 * install a VU instruction into the pipeline
 */
void
rsp_VUPackInstall(u32 inst, u32 pc)
{
    int		i;

    for (i=0; i<rsp_VUPIPEDEPTH; i++) {
	if (vu_PackPipe[i].delay == 0 || VUZeroPipe) {
	    vu_PackPipe[i].inst = inst;
	    vu_PackPipe[i].pc = pc;
	    vu_PackPipe[i].delay = (VUZeroPipe) ? 1 : rsp_VUPIPEDEPTH;
	    vu_PackPipe[i].stalled = FALSE;
	    if (VUZeroPipe) rsp_VUPackPipeStep();
	    break;
	}
    }
}

/*
 * this function is called once per clock, advances the pack
 * pipeline one step.
 */
boolean
rsp_VUPackPipeStep(void)
{
    int		i;

    /* advance all the things in the pipe */
    for (i=0; i<rsp_VUPIPEDEPTH; i++) {
	if (vu_PackPipe[i].delay > 0) {

	    if (vu_PackPipe[i].delay == rsp_VUPIPE_STAGE_EX || VUZeroPipe) {
		/* do decode and exec, if possible */
		rsp_VUPackExec(&(vu_PackPipe[i]));
	    } else {
		/*
		 * fakes pipelining by waiting to write-back answer
		 */
               if (rsp_VUStalled==FALSE ||
                         vu_PackPipe[i].delay<rsp_VUPIPE_STAGE_EX)
		vu_PackPipe[i].delay--;
	    }

	    if (vu_PackPipe[i].delay == rsp_VUPIPE_STAGE_WB) {
		/* do write-back */
		rsp_Verbose(stderr,"VU PACK did write-back. (v%d)\n",
			    vu_PackPipe[i].rd);
		rsp_VUR[vu_PackPipe[i].rd] = vu_PackPipe[i].result;

		traceVUbyVU(vu_PackPipe[i].rd,0xff,&(vu_PackPipe[i].result),
				vu_PackPipe[i].pc);

		/* mark registers not in use */
		rsp_VURegUnLock(vu_PackPipe[i].rd, vu_PackPipe[i].pc);
	    }
	}
    }
}