⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maverick.c

📁 这是Skyeye 0.9 版本的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  maverick.c -- Cirrus/DSP co-processor interface.
    Copyright (C) 2003 Free Software Foundation, Inc.
    Contributed by Aldy Hernandez (aldyh@redhat.com).
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

#include <assert.h>
#include "armdefs.h"
#include "ansidecl.h"
#include "armemu.h"

/*#define CIRRUS_DEBUG 1	/**/
#if CIRRUS_DEBUG
#  define printfdbg printf
#else
#  define printfdbg printf_nothing
#endif

#define POS64(i) ( (~(i)) >> 63 )
#define NEG64(i) ( (i) >> 63 )

/* Define Co-Processor instruction handlers here.  */

/* Here's ARMulator's DSP definition.  A few things to note:
   1) it has 16 64-bit registers and 4 72-bit accumulators
   2) you can only access its registers with MCR and MRC.  */

/* We can't define these in here because this file might not be linked
   unless the target is arm9e-*.  They are defined in wrapper.c.
   Eventually the simulator should be made to handle any coprocessor
   at run time.  */
struct maverick_regs
{
  union
  {
    int i;
    float f;
  } upper;

  union
  {
    int i;
    float f;
  } lower;
};

union maverick_acc_regs
{
  long double ld;		/* Acc registers are 72-bits.  */
};

struct maverick_regs DSPregs[16];
union maverick_acc_regs DSPacc[4];
ARMword DSPsc;

#define DEST_REG	(BITS (12, 15))
#define SRC1_REG	(BITS (16, 19))
#define SRC2_REG	(BITS (0, 3))

static int lsw_int_index, msw_int_index;
static int lsw_float_index, msw_float_index;

static double mv_getRegDouble (int);
static long long mv_getReg64int (int);
static void mv_setRegDouble (int, double val);
static void mv_setReg64int (int, long long val);

static union
{
  double d;
  long long ll;
  int ints[2];
} reg_conv;

static void
printf_nothing (void *foo, ...)
{
}

static void
cirrus_not_implemented (char *insn)
{
  fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn);
  fprintf (stderr, "aborting!\n");

  exit (1);
}

static unsigned
DSPInit (ARMul_State * state)
{
  ARMul_ConsolePrint (state, ", DSP present");
  return TRUE;
}

unsigned
DSPMRC4 (ARMul_State * state ATTRIBUTE_UNUSED,
	 unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value)
{
  switch (BITS (5, 7))
    {
    case 0:			/* cfmvrdl */
      /* Move lower half of a DF stored in a DSP reg into an Arm reg.  */
      printfdbg ("cfmvrdl\n");
      printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i);
      printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));

      *value = (ARMword) DSPregs[SRC1_REG].lower.i;
      break;

    case 1:			/* cfmvrdh */
      /* Move upper half of a DF stored in a DSP reg into an Arm reg.  */
      printfdbg ("cfmvrdh\n");
      printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i);
      printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));

      *value = (ARMword) DSPregs[SRC1_REG].upper.i;
      break;

    case 2:			/* cfmvrs */
      /* Move SF from upper half of a DSP register to an Arm register.  */
      *value = (ARMword) DSPregs[SRC1_REG].upper.i;
      printfdbg ("cfmvrs = mvf%d <-- %f\n",
		 SRC1_REG, DSPregs[SRC1_REG].upper.f);
      break;

#ifdef doesnt_work
    case 4:			/* cfcmps */
      {
	float a, b;
	int n, z, c, v;

	a = DSPregs[SRC1_REG].upper.f;
	b = DSPregs[SRC2_REG].upper.f;

	printfdbg ("cfcmps\n");
	printfdbg ("\tcomparing %f and %f\n", a, b);

	z = a == b;		/* zero */
	n = a != b;		/* negative */
	v = a > b;		/* overflow */
	c = 0;			/* carry */
	*value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
	break;
      }

    case 5:			/* cfcmpd */
      {
	double a, b;
	int n, z, c, v;

	a = mv_getRegDouble (SRC1_REG);
	b = mv_getRegDouble (SRC2_REG);

	printfdbg ("cfcmpd\n");
	printfdbg ("\tcomparing %g and %g\n", a, b);

	z = a == b;		/* zero */
	n = a != b;		/* negative */
	v = a > b;		/* overflow */
	c = 0;			/* carry */
	*value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
	break;
      }
#else
    case 4:			/* cfcmps */
      {
	float a, b;
	int n, z, c, v;

	a = DSPregs[SRC1_REG].upper.f;
	b = DSPregs[SRC2_REG].upper.f;

	printfdbg ("cfcmps\n");
	printfdbg ("\tcomparing %f and %f\n", a, b);

	z = a == b;		/* zero */
	n = a < b;		/* negative */
	c = a > b;		/* carry */
	v = 0;			/* fixme */
	printfdbg ("\tz = %d, n = %d\n", z, n);
	*value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
	break;
      }

    case 5:			/* cfcmpd */
      {
	double a, b;
	int n, z, c, v;

	a = mv_getRegDouble (SRC1_REG);
	b = mv_getRegDouble (SRC2_REG);

	printfdbg ("cfcmpd\n");
	printfdbg ("\tcomparing %g and %g\n", a, b);

	z = a == b;		/* zero */
	n = a < b;		/* negative */
	c = a > b;		/* carry */
	v = 0;			/* fixme */
	*value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
	break;
      }
#endif
    default:
      fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr);
      cirrus_not_implemented ("unknown");
      break;
    }

  return ARMul_DONE;
}

unsigned
DSPMRC5 (ARMul_State * state ATTRIBUTE_UNUSED,
	 unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value)
{
  switch (BITS (5, 7))
    {
    case 0:			/* cfmvr64l */
      /* Move lower half of 64bit int from Cirrus to Arm.  */
      *value = (ARMword) DSPregs[SRC1_REG].lower.i;
      printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n",
		 DEST_REG, (int) *value);
      break;

    case 1:			/* cfmvr64h */
      /* Move upper half of 64bit int from Cirrus to Arm.  */
      *value = (ARMword) DSPregs[SRC1_REG].upper.i;
      printfdbg ("cfmvr64h <-- %d\n", (int) *value);
      break;

    case 4:			/* cfcmp32 */
      {
	int res;
	int n, z, c, v;
	unsigned int a, b;

	printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG, SRC2_REG);

	/* FIXME: see comment for cfcmps.  */
	a = DSPregs[SRC1_REG].lower.i;
	b = DSPregs[SRC2_REG].lower.i;

	res = DSPregs[SRC1_REG].lower.i - DSPregs[SRC2_REG].lower.i;
	/* zero */
	z = res == 0;
	/* negative */
	n = res < 0;
	/* overflow */
	v = SubOverflow (DSPregs[SRC1_REG].lower.i, DSPregs[SRC2_REG].lower.i,
			 res);
	/* carry */
	c = (NEG (a) && POS (b) ||
	     (NEG (a) && POS (res)) || (POS (b) && POS (res)));

	*value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
	break;
      }

    case 5:			/* cfcmp64 */
      {
	long long res;
	int n, z, c, v;
	unsigned long long a, b;

	printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG, SRC2_REG);

	/* fixme: see comment for cfcmps.  */

	a = mv_getReg64int (SRC1_REG);
	b = mv_getReg64int (SRC2_REG);

	res = mv_getReg64int (SRC1_REG) - mv_getReg64int (SRC2_REG);
	/* zero */
	z = res == 0;
	/* negative */
	n = res < 0;
	/* overflow */
	v = ((NEG64 (a) && POS64 (b) && POS64 (res))
	     || (POS64 (a) && NEG64 (b) && NEG64 (res)));
	/* carry */
	c = (NEG64 (a) && POS64 (b) ||
	     (NEG64 (a) && POS64 (res)) || (POS64 (b) && POS64 (res)));

	*value = (n << 31) | (z << 30) | (c << 29) | (v << 28);
	break;
      }

    default:
      fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr);
      cirrus_not_implemented ("unknown");
      break;
    }

  return ARMul_DONE;
}

unsigned
DSPMRC6 (ARMul_State * state ATTRIBUTE_UNUSED,
	 unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword * value)
{
  switch (BITS (5, 7))
    {
    case 0:			/* cfmval32 */
      cirrus_not_implemented ("cfmval32");
      break;

    case 1:			/* cfmvam32 */
      cirrus_not_implemented ("cfmvam32");
      break;

    case 2:			/* cfmvah32 */
      cirrus_not_implemented ("cfmvah32");
      break;

    case 3:			/* cfmva32 */
      cirrus_not_implemented ("cfmva32");
      break;

    case 4:			/* cfmva64 */
      cirrus_not_implemented ("cfmva64");
      break;

    case 5:			/* cfmvsc32 */
      cirrus_not_implemented ("cfmvsc32");
      break;

    default:
      fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr);
      cirrus_not_implemented ("unknown");
      break;
    }

  return ARMul_DONE;
}

unsigned
DSPMCR4 (ARMul_State * state,
	 unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value)
{
  switch (BITS (5, 7))
    {
    case 0:			/* cfmvdlr */
      /* Move the lower half of a DF value from an Arm register into
         the lower half of a Cirrus register.  */
      printfdbg ("cfmvdlr <-- 0x%x\n", (int) value);
      DSPregs[SRC1_REG].lower.i = (int) value;
      break;

    case 1:			/* cfmvdhr */
      /* Move the upper half of a DF value from an Arm register into
         the upper half of a Cirrus register.  */
      printfdbg ("cfmvdhr <-- 0x%x\n", (int) value);
      DSPregs[SRC1_REG].upper.i = (int) value;
      break;

    case 2:			/* cfmvsr */
      /* Move SF from Arm register into upper half of Cirrus register.  */
      printfdbg ("cfmvsr <-- 0x%x\n", (int) value);
      DSPregs[SRC1_REG].upper.i = (int) value;
      break;

    default:
      fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr);
      cirrus_not_implemented ("unknown");
      break;
    }

  return ARMul_DONE;
}

unsigned
DSPMCR5 (ARMul_State * state,
	 unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value)
{
  union
  {
    int s;
    unsigned int us;
  } val;

  switch (BITS (5, 7))
    {
    case 0:			/* cfmv64lr */
      /* Move lower half of a 64bit int from an ARM register into the
         lower half of a DSP register and sign extend it.  */
      printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, (int) value);
      DSPregs[SRC1_REG].lower.i = (int) value;
      break;

    case 1:			/* cfmv64hr */
      /* Move upper half of a 64bit int from an ARM register into the
         upper half of a DSP register.  */
      printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n",
		 SRC1_REG, (int) value);
      DSPregs[SRC1_REG].upper.i = (int) value;
      break;

    case 2:			/* cfrshl32 */
      printfdbg ("cfrshl32\n");
      val.us = value;
      if (val.s > 0)
	DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i << value;
      else
	DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -value;
      break;

    case 3:			/* cfrshl64 */
      printfdbg ("cfrshl64\n");
      val.us = value;
      if (val.s > 0)
	mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) << value);
      else
	mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) >> -value);
      break;

    default:
      fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr);
      cirrus_not_implemented ("unknown");
      break;
    }

  return ARMul_DONE;
}

unsigned
DSPMCR6 (ARMul_State * state,
	 unsigned type ATTRIBUTE_UNUSED, ARMword instr, ARMword value)
{
  switch (BITS (5, 7))
    {
    case 0:			/* cfmv32al */
      cirrus_not_implemented ("cfmv32al");
      break;

    case 1:			/* cfmv32am */
      cirrus_not_implemented ("cfmv32am");
      break;

    case 2:			/* cfmv32ah */
      cirrus_not_implemented ("cfmv32ah");
      break;

    case 3:			/* cfmv32a */
      cirrus_not_implemented ("cfmv32a");
      break;

    case 4:			/* cfmv64a */
      cirrus_not_implemented ("cfmv64a");
      break;

    case 5:			/* cfmv32sc */
      cirrus_not_implemented ("cfmv32sc");
      break;

    default:
      fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr);
      cirrus_not_implemented ("unknown");
      break;
    }

  return ARMul_DONE;
}

unsigned
DSPLDC4 (ARMul_State * state ATTRIBUTE_UNUSED,
	 unsigned type, ARMword instr, ARMword data)
{
  static unsigned words;

  if (type != ARMul_DATA)
    {
      words = 0;
      return ARMul_DONE;
    }

  if (BIT (22))
    {				/* it's a long access, get two words */
      /* cfldrd */

      printfdbg ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n",
		 data, words, state->bigendSig, DEST_REG);

      if (words == 0)
	{
	  if (state->bigendSig)
	    DSPregs[DEST_REG].upper.i = (int) data;
	  else
	    DSPregs[DEST_REG].lower.i = (int) data;
	}
      else
	{
	  if (state->bigendSig)
	    DSPregs[DEST_REG].lower.i = (int) data;
	  else
	    DSPregs[DEST_REG].upper.i = (int) data;
	}

      ++words;

      if (words == 2)
	{
	  printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG,
		     mv_getRegDouble (DEST_REG));

	  return ARMul_DONE;
	}
      else
	return ARMul_INC;
    }
  else
    {
      /* Get just one word.  */

      /* cfldrs */
      printfdbg ("cfldrs\n");

      DSPregs[DEST_REG].upper.i = (int) data;

      printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG,
		 DSPregs[DEST_REG].upper.f);

      return ARMul_DONE;
    }
}

unsigned
DSPLDC5 (ARMul_State * state ATTRIBUTE_UNUSED,
	 unsigned type, ARMword instr, ARMword data)
{
  static unsigned words;

  if (type != ARMul_DATA)
    {
      words = 0;
      return ARMul_DONE;
    }

  if (BIT (22))
    {
      /* It's a long access, get two words.  */

      /* cfldr64 */
      printfdbg ("cfldr64: %d\n", data);

      if (words == 0)
	{
	  if (state->bigendSig)
	    DSPregs[DEST_REG].upper.i = (int) data;
	  else
	    DSPregs[DEST_REG].lower.i = (int) data;
	}
      else
	{
	  if (state->bigendSig)
	    DSPregs[DEST_REG].lower.i = (int) data;
	  else
	    DSPregs[DEST_REG].upper.i = (int) data;
	}

      ++words;

      if (words == 2)
	{
	  printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG,
		     mv_getReg64int (DEST_REG));

	  return ARMul_DONE;
	}
      else
	return ARMul_INC;
    }
  else
    {
      /* Get just one word.  */

      /* cfldr32 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -