/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * The Original Code is mozilla.org code.
 *
 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1998 Netscape Communications Corporation. All
 * Rights Reserved.
 *
 * Contributor(s): 
 */

#ifndef _SPARC_INSTRUCTION_H_
#define _SPARC_INSTRUCTION_H_

#include "Fundamentals.h"
#include "Instruction.h"

//
// Instruction format A (op=1): CALL
//
// |31   |29                                                                                      0|
// |-----------------------------------------------------------------------------------------------|
// | op  |                                       disp30                                            |
// |-----------------------------------------------------------------------------------------------|
//
//
// Instruction format B (op=0): SETHI & Branches
//
// |31   |29|28         |24      |21                                                              0|
// |-----------------------------------------------------------------------------------------------|
// | op  |       rd     |   op2  |                             imm22                               |
// |-----------------------------------------------------------------------------------------------|
// | op  |a |   cond    |   op2  |                             disp22                              |
// |-----------------------------------------------------------------------------------------------|
//
//
// Instruction format C (op=2|op=3): arithmetic, logical, shift, memory instructions & remaining.
//
// |31   |29            |24               |18            |13|12                     |4            0|
// |-----------------------------------------------------------------------------------------------|
// | op  |       rd     |        op3      |      rs1     |0 |           asi         |      rs2     |
// |-----------------------------------------------------------------------------------------------|
// | op  |       rd     |        op3      |      rs1     |1 |               simm13                 |
// |-----------------------------------------------------------------------------------------------|
// | op  |       rd     |        op3      |      rs1     |            opf           |      rs2     |
// |-----------------------------------------------------------------------------------------------|
//

enum SparcInstructionKind
{
  siAnd,
  siAndCC,
  siAndN,
  siAndNCC,
  siOr,
  siOrCC,
  siOrN,
  siOrNCC,
  siXor,
  siXorCC,
  siXNor,
  siXNorCC,
  siSll,
  siSrl,
  siSra,
  siAdd,
  siAddCC,
  siAddX,
  siAddXCC,
  siSub,
  siSubCC,
  siSubX,
  siSubXCC,
  siUMul,
  siUMulCC,
  siSMul,
  siSMulCC,
  siUDiv,
  siUDivCC,
  siSDiv,
  siSDivCC,
  siTrap,
  siLdSb,
  siLdSh,
  siLdUb,
  siLdUh,
  siLd,
  siLdd,
  siStSb,
  siStSh,
  siSt,
  siStd,
  siBranch,
  nSparcInstructionKind
};

enum SparcAccessKind
{
  saRRR, // insn r[s1],r[s2],r[d]
  saRIR, // insn r[s1],imm13,r[d]
  saRZR, // insn r[s1],r[g0],r[d]
  saZRR, // insn r[g0],r[s2],r[d]
  saZIR, // insn r[g0],imm13,r[d]
  saZZR, // insn r[g0],r[g0],r[d]
  saRRZ, // insn r[s1],r[s2],r[g0]
  saRIZ, // insn r[s1],imm13,r[g0]
  saRZZ, // insn r[s1],r[g0],r[g0]
  nSparcAccessKind
};

#define saRR saRRZ
#define saRI saRIZ
#define saRZ saRZZ

enum SparcConditionKind
{
  scA,   // always
  scN,   // never
  scNe,  // on Not Equal
  scE,   // on Equal
  scG,   // on Greater
  scLe,  // on Less or Equal
  scGe,  // on Greater or Equal
  scL,   // on Less
  scGu,  // on Greater Unsigned
  scLeu, // on Less or Equal Unsigned
  scCc,  // on Carry Clear (Greater than or Equal, Unsigned)
  scGeu,
  scCs,  // on Carry Set (Less than, Unsigned)
  scLu,
  scPos, // on Positive
  scNeg, // on Negative
  scVc,  // on Overflow Clear
  scVs,  // on Overflow Set
  nSparcConditionKind
};

enum SparcRegisterNumber
{
  g0, g1, g2, g3, g4, g5, g6, g7,
  o0, o1, o2, o3, o4, o5, sp, o7,
  l0, l1, l2, l3, l4, l5, l6, l7,
  i0, i1, i2, i3, i4, i5, fp, i7
};

struct SparcConditionInfo
{
  SparcConditionKind kind;
  uint8 cond;
  char *string;
};

struct SparcInstructionInfo
{
  SparcInstructionKind kind;
  uint8 op;
  uint8 op3;
  char* string;
};

struct SparcAccessInfo
{
  SparcAccessKind kind;
  uint8 nConsumer;
  uint8 nProducer;
};

extern SparcInstructionInfo siInfo[];
extern SparcAccessInfo saInfo[];
extern SparcConditionInfo scInfo[];
extern char* registerNumberToString[];
extern SparcRegisterNumber colorToRegisterNumber[];
extern uint8 registerNumberToColor[];

class SparcFormatBCond : public InsnUseXDefineYFromPool
{
protected:
  SparcInstructionKind kind;
  SparcConditionKind cond;
  bool a;
  ControlNode& target;

public:
  SparcFormatBCond(DataNode* inPrimitive, Pool& inPool, ControlNode& t, SparcInstructionKind iKind, SparcConditionKind cKind, bool annul) :
	InsnUseXDefineYFromPool(inPrimitive, inPool, 1, 0),
	kind(iKind), cond(cKind), a(annul), target(t) {}

  virtual void printPretty(FILE* f);
  virtual size_t getFormattedSize() {return (a ? 8 : 4);}
  virtual void formatToMemory(void* inStart, uint32 inOffset);
};


class SparcBranch : public SparcFormatBCond
{
public:
  SparcBranch(DataNode* inPrimitive, Pool& inPool, ControlNode& t, SparcConditionKind cKind, bool annul) :
	SparcFormatBCond(inPrimitive, inPool, t, siBranch, cKind, annul) {}
};

class SparcFormatC : public InsnUseXDefineYFromPool
{
protected:
  SparcInstructionKind kind;
  SparcAccessKind access;
  int16 imm13;

public:
  SparcFormatC(DataNode* inPrimitive, Pool& inPool, uint8 nConsumer = 0, uint8 nProducer = 0) : 
	InsnUseXDefineYFromPool(inPrimitive, inPool, nConsumer, nProducer) {}

  virtual void printPretty(FILE* f);
  virtual size_t getFormattedSize() {return 4;}		
  virtual void formatToMemory(void* inStart, uint32 /*inOffset*/);


  inline SparcRegisterNumber useToRegisterNumber(InstructionUse& use);
  inline SparcRegisterNumber defineToRegisterNumber(InstructionDefine& use);

  virtual uint8 getRS1();
  virtual uint8 getRS2();
  virtual uint8 getRD();
};

class SparcInsn : public SparcFormatC
{
public:
  SparcInsn(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, int16 constant = 0) : 
	SparcFormatC(inPrimitive, inPool, saInfo[aKind].nConsumer, saInfo[aKind].nProducer)
	{kind = iKind; access = aKind; imm13 = constant;}

  virtual InstructionFlags getFlags() const {if (kind == siOr && access == saRZR) return (ifCopy); else return(ifNone);}
};

class SparcTrap : public SparcFormatC
{
protected:
  SparcConditionKind cond;
public:
  SparcTrap(DataNode* inPrimitive, Pool& inPool, SparcConditionKind cKind, SparcAccessKind aKind, int16 constant = 0) :
	SparcFormatC(inPrimitive, inPool, 1, 0), cond(cKind)
	{kind = siTrap; access = aKind; imm13 = constant;}
  virtual uint8 getRS1() {return g0;}
  virtual uint8 getRS2() {return g0;}
  virtual uint8 getRD() {return scInfo[cond].cond;}
  virtual void printPretty(FILE* f);
};

class SparcCmp : public SparcFormatC
{
public:
  SparcCmp(DataNode* inPrimitive, Pool& inPool, SparcAccessKind aKind, int16 constant = 0) : 
	SparcFormatC(inPrimitive, inPool, saInfo[aKind].nConsumer, 1)
	{kind = siSubCC; access = aKind; imm13 = constant;}
};

class SparcLoadStore : public SparcFormatC
{
protected:
  bool hasMemoryEdge;
  bool isLoad;
  bool isLoadC;

public:
  SparcLoadStore(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, bool has_mem, bool is_load, bool is_loadC, int16 constant = 0) : 
	SparcFormatC(inPrimitive, inPool, is_load ? (is_loadC ? 1 : 2) : 3, (is_load && has_mem) ? 2 : 1), hasMemoryEdge(has_mem), isLoad(is_load), isLoadC(is_loadC)
	{
	  kind = iKind; access = aKind; imm13 = constant;
	}
  virtual void printPretty(FILE* f);
  virtual uint8 getRS1();
  virtual uint8 getRS2();
  virtual uint8 getRD();
};

class SparcLoadC : public SparcLoadStore
{
public:
  SparcLoadC(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, int16 constant = 0) : 
	SparcLoadStore(inPrimitive, inPool, iKind, aKind, false, true, true, constant) {}
};

class SparcLoad : public SparcLoadStore
{
public:
  SparcLoad(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, bool memEdge, int16 constant = 0) : 
	SparcLoadStore(inPrimitive, inPool, iKind, aKind, memEdge, true, false, constant) {}
};

class SparcStore : public SparcLoadStore
{
public:
  SparcStore(DataNode* inPrimitive, Pool& inPool, SparcInstructionKind iKind, SparcAccessKind aKind, int16 constant = 0) : 
	SparcLoadStore(inPrimitive, inPool, iKind, aKind, true, false, false, constant) {}
};

inline SparcRegisterNumber SparcFormatC::
useToRegisterNumber(InstructionUse& use)
{
  assert(use.isVirtualRegister());
  return (colorToRegisterNumber[use.getVirtualRegister().getColor()]);
}

inline SparcRegisterNumber SparcFormatC::
defineToRegisterNumber(InstructionDefine& def)
{
  assert(def.isVirtualRegister());
  return (colorToRegisterNumber[def.getVirtualRegister().getColor()]);
}

#endif /* _SPARC_INSTRUCTION_H_ */
