vmove.c 7.41 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:	vmove.c
 * Creator:	hsa@sgi.com
 * Create Date:	Thu Jun 30 10:25:19 PDT 1994
 *
 * This file holds the coprocessor MOVE instructions for the VU.
 * Remember that these are actually SU instructions, but they
 * have pipelining impact and stall characteristics similar to the VU, so
 * we model them in the same way.
 *
 */

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


rsp_vuPipe_t	vu_MovePipe[rsp_VUPIPEDEPTH+1];

#define	MOVETO_FLAG	0x01
#define	MOVEFROM_FLAG	0x02
#define	CONTROLTO_FLAG	0x04

/*
 * schedules execution of a VU move instruction:
 */
static void
rsp_VUMoveExec(rsp_vuPipe_t *mp)
{
    int opcode;
    u16	tu16;

    opcode = ExtractBits(mp->inst, 25, 21);
    mp->rt = ExtractBits(mp->inst, 20, 16);
    mp->rd = ExtractBits(mp->inst, 15, 11);
    mp->format = ExtractBits(mp->inst, 10, 7);	/* 16-byte element */
    mp->stalled = FALSE;

    /* check for VU stall. */
    if ((mp->flags == MOVEFROM_FLAG) && rsp_VURegIsLocked(mp->rd, mp->pc)) {
	mp->stalled = TRUE;
    }

    /* check for SU stall. */
    if ((mp->flags == MOVETO_FLAG) && rsp_SURegIsLocked(mp->rt)) {
	mp->stalled = TRUE;
    }

    if (mp->stalled) {
	rsp_VUStalled = TRUE;
	rsp_Verbose(stderr,"VU move stalled... (%08x)\n",mp->pc);
    } else {
	switch (opcode) {

	  case 0x00:	/* MF */
	    strcpy(mp->opString, "mfc2");
	    /* tu16 = (u16) Get128By16(&(rsp_VUR[mp->rd]), mp->format);
            */
	    tu16 = ((u8)Get128By8(&(rsp_VUR[mp->rd]), mp->format))<<8;
	    tu16 |= (u8)Get128By8(&(rsp_VUR[mp->rd]), (mp->format+1)%16);
	    /* vu reg is sign-extend into GPR */
	    rsp_GPR[mp->rt] = (u32) (tu16|(tu16&0x8000?~0xFFFF:0));
	    rsp_Verbose(stderr,"VU move (%s) did write-back. (%d)\n",
			mp->opString, mp->rt);
            traceSU(mp->rt, rsp_GPR[mp->rt], mp->pc);
	    break;

	  case 0x02:	/* CF */
	    strcpy(mp->opString, "cfc2");
	    mp->rd &= 0x3;
	    if (mp->rd == 0) {		/* VCO is sign-extended into GPR */
		rsp_GPR[mp->rt] = (u32) (rsp_VCO|(rsp_VCO&0x8000?~0xFFFF:0));
	    } else if (mp->rd == 1) {	/* VCC is sign-extended into GPR */
		rsp_GPR[mp->rt] = (u32) (rsp_VCC|(rsp_VCC&0x8000?~0xFFFF:0));
	    } else if (mp->rd == 2) {	/* VCE not sign extended in GPR*/
		rsp_GPR[mp->rt] = (u32) rsp_VCE;
	    } else {
		rsp_Verbose(stderr,"CFC2 unknown VU control reg %d.\n",mp->rd);
	    }
            traceSU(mp->rt, rsp_GPR[mp->rt], mp->pc);
	    break;

	  case 0x04:	/* MT */
	    strcpy(mp->opString, "mtc2");
	    Set128(&(mp->result), &(rsp_VUR[mp->rd]));
	    /* simulate by-pass, get from temp location: */
	    tu16 = (u16) (mp->addr & 0x0000ffff);
	    Set128By8(&(mp->result), tu16>>8, mp->format);
	    if( mp->format+1 < 16 )
		Set128By8(&(mp->result), tu16&0xff, mp->format+1);	/* Don't wrap around */
            mp->res16_element = 0xc000>>mp->format;
	    break;

	  case 0x06:	/* CT */
	    mp->flags = CONTROLTO_FLAG;
	    strcpy(mp->opString, "ctc2");
	    mp->rd &= 0x3;
	    if (mp->rd == 0) {
		rsp_VCO = (u16) rsp_GPR[mp->rt];
	    } else if (mp->rd == 1) {
		rsp_VCC = (u16) rsp_GPR[mp->rt];
	    } else if (mp->rd == 2) {
		rsp_VCE = (u8) (rsp_GPR[mp->rt]&0xff);
	    } else {
		rsp_Verbose(stderr,"CTC2 unknown VU control reg %d.\n",mp->rd);
	    }
	    break;

	  default:
	    rsp_Verbose(stderr,"VU move opcode [%02x] not implemented.\n",opcode);
	    break;

	}

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


/* PUBLIC FUNCTIONS */

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

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

/*
 * install a VU MoveTo instruction into the pipeline
 */
void
rsp_VUMoveToInstall(u32 inst, u32 pc)
{
    int		i, rt;
    int	offset, opcode;

    for (i=0; i<rsp_VUPIPEDEPTH; i++) {
	if (vu_MovePipe[i].delay == 0 || VUZeroPipe) {
	    vu_MovePipe[i].inst = inst;
	    vu_MovePipe[i].pc = pc;
	    vu_MovePipe[i].delay = (VUZeroPipe) ? 1 : rsp_VUPIPEDEPTH;
	    vu_MovePipe[i].stalled = FALSE;
	    vu_MovePipe[i].flags = MOVETO_FLAG;
	    strcpy(vu_MovePipe[i].opString, "?");
	    rt = ExtractBits(inst, 20, 16);
	    vu_MovePipe[i].addr = rsp_GPR[rt];	/* temp storage */
	    
	    if (VUZeroPipe) rsp_VUMovePipeStep();
	    break;
	}
    }
}


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

    for (i=0; i<rsp_VUPIPEDEPTH; i++) {
	if (vu_MovePipe[i].delay == 0 || VUZeroPipe) {
	    vu_MovePipe[i].inst = inst;
	    vu_MovePipe[i].pc = pc;
	    vu_MovePipe[i].delay = (VUZeroPipe) ? 1 : rsp_VUPIPEDEPTH;
	    vu_MovePipe[i].stalled = FALSE;
	    vu_MovePipe[i].flags = MOVEFROM_FLAG;
	    strcpy(vu_MovePipe[i].opString, "?");

	    if (VUZeroPipe) rsp_VUMovePipeStep();
	    break;
	}
    }
}


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

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

	    /*
	     * see comment in vldst.c. This case is similar...
	     */
	    if ((vu_MovePipe[i].delay == (rsp_VUPIPE_STAGE_EX + 1) || 
		VUZeroPipe)) {
		if (vu_MovePipe[i].flags == MOVEFROM_FLAG) {
		    rsp_SULockReg(ExtractBits(vu_MovePipe[i].inst, 20, 16));
		} else {
		    /* don't lock control register this way! */
		    if (ExtractBits(vu_MovePipe[i].inst, 25, 21) != 0x06) {
			rsp_VURegLock(ExtractBits(vu_MovePipe[i].inst, 15, 11),
				      vu_MovePipe[i].pc);
		    }
		}
	    }

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

	    if (vu_MovePipe[i].delay == rsp_VUPIPE_STAGE_WB) {
		/* do write-back */
		if (vu_MovePipe[i].flags == MOVETO_FLAG) {
		    rsp_Verbose(stderr,"VU move (%s) did write-back. (v%d)\n",
				vu_MovePipe[i].opString, vu_MovePipe[i].rd);
		    Set128(&(rsp_VUR[vu_MovePipe[i].rd]), 
			   &(vu_MovePipe[i].result));
		    traceVUbySU(vu_MovePipe[i].rd,vu_MovePipe[i].res16_element,
                                &(vu_MovePipe[i].result),vu_MovePipe[i].pc);
		    /* mark registers not in use */
		    rsp_VURegUnLock(vu_MovePipe[i].rd, vu_MovePipe[i].pc);
		} else {
		    /* done already... */
		}
	    }
	}
    }
}