960 lines
28 KiB
C++
960 lines
28 KiB
C++
/* -*- 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):
|
|
*/
|
|
// PPCInstructions.h
|
|
//
|
|
// Scott M. Silver
|
|
// Peter Desantis
|
|
|
|
#ifndef _H_PPCINSTRUCTIONS
|
|
#define _H_PPCINSTRUCTIONS
|
|
|
|
#include "prtypes.h"
|
|
#include "Instruction.h"
|
|
#include "ControlNodes.h"
|
|
|
|
typedef Uint8 PPCInsnFlags;
|
|
enum
|
|
{
|
|
pfNil = 0x00, // nothing special
|
|
pfRc = 0x01, // sets a condition code
|
|
pfOE = 0x02 // set the overflow flag
|
|
};
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊPPCInstructionXY ¥
|
|
#endif
|
|
|
|
// PPCInstructionXY
|
|
//
|
|
// Base class for all PPC instructions
|
|
class PPCInstructionXY :
|
|
public InsnUseXDefineYFromPool
|
|
{
|
|
public:
|
|
inline PPCInstructionXY(DataNode* inPrimitive, Pool& inPool, Uint8 inX, Uint8 inY) :
|
|
InsnUseXDefineYFromPool(inPrimitive, inPool, inX, inY) { }
|
|
virtual size_t getFormattedSize(MdFormatter& /*inFormatter*/) { return (4); }
|
|
};
|
|
|
|
|
|
// Fixed point color to register map.
|
|
const Uint8 sFixedPointRegisterMap[] =
|
|
{
|
|
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 31, // -> first non-volatile
|
|
30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
|
|
19, 18, 17, 16, 15, 14 // 13 // -> last non-volatile, but used as globals
|
|
};
|
|
|
|
const Uint8 sFloatingPointRegisterMap[] =
|
|
{
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
11, 12, 13, // -> first non-volatile
|
|
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
|
|
25, 26, 27, 28, 29, 30, 31 // -> last non-volatile
|
|
};
|
|
|
|
// udToRegisterNumber
|
|
//
|
|
// Map colors of registers to real register numbers
|
|
inline Uint8
|
|
udToRegisterNumber(InstructionUseOrDefine& inUse)
|
|
{
|
|
Uint32 color = inUse.getVirtualRegister().colorInfo.color;
|
|
if (inUse.getVirtualRegister().getClass() == vrcInteger)
|
|
{
|
|
if (color < sizeof(sFixedPointRegisterMap) / sizeof(Uint8))
|
|
return (sFixedPointRegisterMap[color]);
|
|
#ifdef DEBUG
|
|
else
|
|
return 255;
|
|
#endif
|
|
}
|
|
else if (inUse.getVirtualRegister().getClass() == vrcFloatingPoint)
|
|
{
|
|
if (color < sizeof(sFloatingPointRegisterMap) / sizeof(Uint8))
|
|
return (sFloatingPointRegisterMap[color]);
|
|
#ifdef DEBUG
|
|
else
|
|
return 255;
|
|
#endif
|
|
}
|
|
else
|
|
assert(false);
|
|
return 255; // never reached
|
|
}
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊD-Form ¥
|
|
#endif
|
|
|
|
#define MAKE_DFORM_ENUM(inName) df##inName,
|
|
|
|
#define DFORM_ARITH_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
|
|
#define DFORM_ARITHCC_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
|
|
#define DFORM_LOAD_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
|
|
#define DFORM_LOADU_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
|
|
#define DFORM_STORE_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
|
|
#define DFORM_STOREU_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
|
|
#define DFORM_TRAP_DEFINE(inName, inOpcode) MAKE_DFORM_ENUM(inName)
|
|
#define DO_DFORM
|
|
enum DFormKind
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
dfLast
|
|
};
|
|
|
|
#undef DFORM_ARITH_DEFINE
|
|
#undef DFORM_ARITHCC_DEFINE
|
|
#undef DFORM_LOAD_DEFINE
|
|
#undef DFORM_LOADU_DEFINE
|
|
#undef DFORM_STORE_DEFINE
|
|
#undef DFORM_STOREU_DEFINE
|
|
#undef DFORM_TRAP_DEFINE
|
|
|
|
struct DFormInstructionInfo
|
|
{
|
|
Uint16 opcode;
|
|
char* formatStr;
|
|
};
|
|
|
|
#define MAKE_DFORM_INFO(inOpcode, inString) \
|
|
{ inOpcode, inString },
|
|
|
|
#define DFORM_ARITH_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, r%d, %d")
|
|
#define DFORM_ARITHCC_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, r%d, %d")
|
|
#define DFORM_LOAD_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
|
|
#define DFORM_LOADU_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
|
|
#define DFORM_STORE_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
|
|
#define DFORM_STOREU_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName" r%d, %d(r%d)")
|
|
#define DFORM_TRAP_DEFINE(inName, inOpcode) MAKE_DFORM_INFO(inOpcode, #inName"%s r%d, %d")
|
|
|
|
const DFormInstructionInfo sDFormInfos[] =
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
};
|
|
#undef DO_DFORM
|
|
|
|
|
|
|
|
|
|
|
|
class DFormXY :
|
|
public PPCInstructionXY
|
|
{
|
|
public:
|
|
inline DFormXY(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint8 inX, Uint8 inY) :
|
|
PPCInstructionXY(inPrimitive, inPool, inX, inY),
|
|
mKind(inKind) { }
|
|
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
|
|
|
|
protected:
|
|
Uint8 getOPCD() { return (sDFormInfos[mKind].opcode); }
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
|
|
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
|
|
virtual Uint16 getIMM() = 0;
|
|
|
|
const Uint16 mKind;
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) {fprintf(f, sDFormInfos[mKind].formatStr, getD(), getA(), getIMM());}
|
|
#endif
|
|
};
|
|
|
|
class DFormXYImmediate :
|
|
public DFormXY
|
|
{
|
|
public:
|
|
inline DFormXYImmediate(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint8 inX, Uint8 inY, Uint16 inImmediate) :
|
|
mImmediate(inImmediate),
|
|
DFormXY(inPrimitive, inPool, inKind, inX, inY) { }
|
|
|
|
virtual Uint16 getIMM() { return mImmediate; }
|
|
|
|
Uint16 mImmediate; // immediate value
|
|
};
|
|
|
|
|
|
|
|
template<Uint8 tUses, Uint8 tDefines, Uint8 tAOffset, Uint8 tDOffset>
|
|
class LdD :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline LdD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, tUses, tDefines, inImmediate) { }
|
|
|
|
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[tAOffset])); }
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[tDOffset])); }
|
|
};
|
|
|
|
|
|
template<Uint8 tFixedSourceRegister>
|
|
class LdD_FixedSource :
|
|
public LdD<0, 1, 0, 0>
|
|
{
|
|
public:
|
|
inline LdD_FixedSource(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
|
|
LdD<0, 1, 0, 0>(inPrimitive, inPool, inKind, inImmediate) { assert (tFixedSourceRegister < 32); }
|
|
|
|
virtual Uint8 getA() { return (tFixedSourceRegister); }
|
|
};
|
|
|
|
// the formatToMemory routine does a fix-up
|
|
// based on the real toc offset
|
|
class LdD_RTOC :
|
|
public LdD_FixedSource<2>
|
|
{
|
|
public:
|
|
inline LdD_RTOC(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
|
|
LdD_FixedSource<2>(inPrimitive, inPool, inKind, inImmediate) { }
|
|
|
|
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& inFormatter);
|
|
};
|
|
|
|
typedef LdD<2, 1, 1, 0> LdD_; // Rvalue | mem Raddress
|
|
typedef LdD<2, 2, 1, 1> LdD_V; // mem Rvalue | mem Raddress
|
|
|
|
// Rvalue | Sstackslot
|
|
class LdD_SpillRegister :
|
|
public LdD<1, 1, 0, 0>
|
|
{
|
|
public:
|
|
inline LdD_SpillRegister(DataNode* inPrimitive, Pool& inPool, VirtualRegister& inStackSlot, VirtualRegister& inDefine) :
|
|
LdD<1, 1, 0, 0>(inPrimitive, inPool, dfLwz, 0) { addUse(0, inStackSlot); addDefine(0, inDefine); }
|
|
|
|
// FIX-ME what about 64 bit fregs.
|
|
virtual Uint16 getIMM() { return ((Uint16)(getInstructionUseBegin()[0].getVirtualRegister().getColor() * -4) - 4); }
|
|
virtual Uint8 getA() { return (1); }
|
|
};
|
|
|
|
// --
|
|
|
|
// mem | mem Raddress Rvalue
|
|
class StD :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline StD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Int16 inImmediate, Uint8 inUses = 3, Uint8 inDefines = 1) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, inUses, inDefines, inImmediate) { }
|
|
|
|
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[2])); }
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) {fprintf(f, sDFormInfos[mKind].formatStr, getD(), getA(), getIMM());}
|
|
#endif
|
|
};
|
|
|
|
// Sstackslot | Rvalue
|
|
class StD_SpillRegister :
|
|
public StD
|
|
{
|
|
public:
|
|
inline StD_SpillRegister(DataNode* inPrimitive, Pool& inPool, VirtualRegister& inStackSlot, VirtualRegister& inUse) :
|
|
StD(inPrimitive, inPool, dfStw, 0, 1, 1) { addDefine(0, inStackSlot); addUse(0, inUse); }
|
|
|
|
virtual Uint16 getIMM() { return ((Uint16)(getInstructionUseBegin()[0].getVirtualRegister().getColor() * -4) - 4); }
|
|
virtual Uint8 getA() { return (1); }
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
|
|
};
|
|
|
|
// mem | mem value
|
|
template<Uint8 tFixedDestRegister>
|
|
class StD_FixedDestRegister :
|
|
public StD
|
|
{
|
|
public:
|
|
inline StD_FixedDestRegister(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
|
|
StD(inPrimitive, inPool, inKind, inImmediate, 2, 1) { }
|
|
|
|
virtual Uint8 getA() { return (tFixedDestRegister); }
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
|
|
};
|
|
|
|
class ArithID :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline ArithID(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Int16 inImmediate) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, 1, 1, inImmediate) { }
|
|
|
|
virtual InstructionFlags getFlags() const { return ((mImmediate == 0 && mKind == dfAddi) ? ifCopy : ifNone); }
|
|
};
|
|
|
|
class LogicalID :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline LogicalID(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Int16 inImmediate) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, 1, 1, inImmediate) { }
|
|
|
|
Uint8 getA() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
|
|
Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
|
|
virtual InstructionFlags getFlags() const { return ((mImmediate == 0 && mKind == dfAddi) ? ifCopy : ifNone); }
|
|
};
|
|
|
|
|
|
class ArithIZeroInputD :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline ArithIZeroInputD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate, Uint8 inFakeUses = 0) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, inFakeUses, 1, inImmediate) { }
|
|
|
|
Uint8 getA() { return (0); }
|
|
};
|
|
|
|
class LogicalIZeroInputD :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline LogicalIZeroInputD(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate, Uint8 inFakeUses = 0) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, inFakeUses, 1, inImmediate) { }
|
|
|
|
Uint8 getA() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
|
|
Uint8 getD() { return (0); }
|
|
};
|
|
|
|
|
|
class Copy_I :
|
|
public ArithID
|
|
{
|
|
public:
|
|
inline Copy_I(DataNode* inPrimitive, Pool& inPool) :
|
|
ArithID(inPrimitive, inPool, dfAddi, 0) { }
|
|
};
|
|
|
|
|
|
class ArithIDSetCC :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline ArithIDSetCC(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, 2, 2, inImmediate) { }
|
|
};
|
|
|
|
|
|
class CmpID :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline CmpID(DataNode* inPrimitive, Pool& inPool, DFormKind inKind, Uint16 inImmediate) :
|
|
DFormXYImmediate(inPrimitive, inPool, inKind, 1, 1, inImmediate) { }
|
|
|
|
protected:
|
|
virtual Uint8 getD() { return (0); } // always use cr0, and L=0
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) { fprintf(f, sDFormInfos[mKind].formatStr, getD() >> 2, getA(), getIMM()); }
|
|
#endif
|
|
};
|
|
|
|
// the bits in order (or offsets into a condition register)
|
|
// neg (lt)
|
|
// pos (gt)
|
|
// zero (eq)
|
|
// summary overflow (so)
|
|
// 0010y branch if cond is false
|
|
// 0110y branch if cond is true
|
|
struct TrapCondition
|
|
{
|
|
char* name;
|
|
Uint8 to;
|
|
};
|
|
|
|
// indexed by Condition2
|
|
static TrapCondition sSignedTrapConditions[] =
|
|
{
|
|
{"", 31},
|
|
{"lt", 16},
|
|
{"eq", 4},
|
|
{"le", 20},
|
|
{"gt", 8},
|
|
{"ne", 24},
|
|
{"ge", 12}
|
|
};
|
|
|
|
// indexed by Condition2
|
|
static TrapCondition sUnsignedTrapConditions[] =
|
|
{
|
|
{"", 31},
|
|
{"llt", 2},
|
|
{"eq", 4},
|
|
{"lle", 6},
|
|
{"lgt", 1},
|
|
{"ne", 24},
|
|
{"lge", 5}
|
|
};
|
|
|
|
class TrapD :
|
|
public DFormXYImmediate
|
|
{
|
|
public:
|
|
inline TrapD(DataNode* inPrimitive, Pool& inPool, Condition2 inCondition, bool inSigned, Uint16 inImmediate) :
|
|
DFormXYImmediate(inPrimitive, inPool, dfTwi, 1, 0, inImmediate),
|
|
mSigned(inSigned),
|
|
mCond(inCondition) { }
|
|
|
|
protected:
|
|
virtual Uint8 getD() { return (mSigned ? sSignedTrapConditions[mCond].to : sUnsignedTrapConditions[mCond].to); }
|
|
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
|
|
|
|
const bool mSigned;
|
|
const Condition2 mCond;
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) { fprintf(f, sDFormInfos[mKind].formatStr, mSigned ? sSignedTrapConditions[mCond].name : sUnsignedTrapConditions[mCond].name, getA(), getIMM()); }
|
|
#endif
|
|
};
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊX & XO-Form ¥
|
|
#endif
|
|
|
|
|
|
#define MAKE_XFORM_ENUM(inName) xf##inName,
|
|
|
|
#define XFORM_ARITH_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_INAONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_CMP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_LOAD_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_LOADU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_STORE_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_STOREU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_TRAP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define XFORM_INBONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_ENUM(inName)
|
|
#define DO_XFORM
|
|
enum XFormKind
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
xfLast
|
|
};
|
|
|
|
#undef XFORM_ARITH_DEFINE
|
|
#undef XFORM_INAONLY_DEFINE
|
|
#undef XFORM_CMP_DEFINE
|
|
#undef XFORM_LOAD_DEFINE
|
|
#undef XFORM_LOADU_DEFINE
|
|
#undef XFORM_STORE_DEFINE
|
|
#undef XFORM_STOREU_DEFINE
|
|
#undef XFORM_TRAP_DEFINE
|
|
#undef XFORM_INBONLY_DEFINE
|
|
|
|
struct XFormInstructionInfo
|
|
{
|
|
Uint16 opcode;
|
|
Uint16 primary;
|
|
char* formatStr;
|
|
};
|
|
|
|
#define MAKE_XFORM_INFO(inOpcode, inPrimary, inString) \
|
|
{ inOpcode, inPrimary, inString },
|
|
|
|
#define XFORM_ARITH_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_INAONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_CMP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_LOAD_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_LOADU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_STORE_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_STOREU_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_TRAP_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
#define XFORM_INBONLY_DEFINE(inName, inOpcode, inPrimary) MAKE_XFORM_INFO(inOpcode, inPrimary, #inName" r%d, r%d, r%d")
|
|
|
|
const XFormInstructionInfo sXFormInfos[] =
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
};
|
|
#undef DO_XFORM
|
|
|
|
static char*
|
|
sFlagsExtensionTbl[] =
|
|
{
|
|
"", // none
|
|
".", // pfRc
|
|
"o", // pfOE
|
|
"o." // pfRC | afOE
|
|
};
|
|
|
|
|
|
class XFormXY :
|
|
public PPCInstructionXY
|
|
{
|
|
public:
|
|
inline XFormXY(DataNode* inPrimitive, Pool& inPool, Uint8 inX, Uint8 inY, XFormKind inKind, PPCInsnFlags inFlags) :
|
|
PPCInstructionXY(inPrimitive, inPool, inX, inY),
|
|
mFlags(inFlags),
|
|
mKind(inKind) { }
|
|
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
|
|
|
|
protected:
|
|
virtual Uint8 getOPCD() { return (31); }
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
|
|
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
|
|
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
|
|
virtual Uint16 getXO() { return (sXFormInfos[mKind].opcode); }
|
|
|
|
PPCInsnFlags mFlags;
|
|
XFormKind mKind;
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) { fprintf(f, sXFormInfos[mKind].formatStr, flagsToExtension(), getD(), getA(), getB()); }
|
|
const char* flagsToExtension() { return sFlagsExtensionTbl[mFlags & 3]; } // only look at OE and Rc bits
|
|
#endif
|
|
};
|
|
|
|
|
|
class TrapX :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
inline TrapX(DataNode* inPrimitive, Pool& inPool, Condition2 inCondition, bool inSigned, PPCInsnFlags inFlags) :
|
|
XFormXY(inPrimitive, inPool, 2, 0, xfTw, inFlags),
|
|
mSigned(inSigned),
|
|
mCond(inCondition) { }
|
|
|
|
protected:
|
|
virtual Uint8 getD() { return (mSigned ? sSignedTrapConditions[mCond].to : sUnsignedTrapConditions[mCond].to); }
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) { fprintf(f, sXFormInfos[mKind].formatStr, mSigned ? sSignedTrapConditions[mCond].name : sUnsignedTrapConditions[mCond].name, getA(), getB()); }
|
|
#endif
|
|
|
|
protected:
|
|
bool mSigned;
|
|
Condition2 mCond;
|
|
};
|
|
|
|
template<Uint8 inX, Uint8 inY, Uint8 inD, Uint8 inA, Uint8 inB>
|
|
class LdX :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
inline LdX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind) :
|
|
XFormXY(inPrimitive, inPool, inX, inY, inKind, pfNil) { assert(inKind >= xfLbzx && inKind <= xfLwzx); }
|
|
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[inD])); }
|
|
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[inA])); }
|
|
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[inB])); }
|
|
};
|
|
|
|
typedef LdX<2, 1, 0, 0, 1> LdX_C; // Rvalue <- Raddress Radddress
|
|
typedef LdX<3, 2, 1, 1, 2> LdX_V; // mem Rvalue Raddress <- mem Raddress Raddress
|
|
typedef LdX<3, 1, 0, 1, 2> LdX_; // Rvalue <- mem Raddress Raddress
|
|
|
|
|
|
// mem <- mem Raddress Raddress Value
|
|
class StX :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
inline StX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind) :
|
|
XFormXY(inPrimitive, inPool, 4, 1, inKind, pfNil) { assert(inKind >= xfStbx && inKind <= xfStwx); }
|
|
|
|
virtual Uint8 getD() { return (udToRegisterNumber(getInstructionUseBegin()[3])); }
|
|
virtual Uint8 getA() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
|
|
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[2])); }
|
|
};
|
|
|
|
|
|
class ArithX :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
inline ArithX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
|
|
XFormXY(inPrimitive, inPool, 2, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, inFlags) { }
|
|
};
|
|
|
|
class XOInAOnly :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
// if we want to use the lswi, need to deal with memory edge
|
|
inline XOInAOnly(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
|
|
XFormXY(inPrimitive, inPool, 1, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, inFlags) {}
|
|
|
|
protected:
|
|
virtual Uint8 getA() { return 0; }
|
|
};
|
|
|
|
class XInAOnly :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
// if we want to use the lswi, need to deal with memory edge
|
|
inline XInAOnly(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags, Uint8 inB) :
|
|
XFormXY(inPrimitive, inPool, 1, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, (inFlags | pfOE)),
|
|
mB(inB) { }
|
|
|
|
protected:
|
|
virtual Uint8 getD() { return (XFormXY::getA()); }
|
|
virtual Uint8 getA() { return (XFormXY::getD()); }
|
|
virtual Uint8 getB() { assert (mB < (1 << 6)); return mB; }
|
|
Uint8 mB;
|
|
};
|
|
|
|
class XInBOnly :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
inline XInBOnly(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
|
|
XFormXY(inPrimitive, inPool, 1, ((inFlags & pfRc) == 0) ? 1 : 2, inKind, inFlags) { }
|
|
|
|
protected:
|
|
virtual Uint8 getA() { return (0); }
|
|
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
|
|
virtual InstructionFlags getFlags() const { return ((mKind == xfFmr) ? ifCopy : ifNone); }
|
|
Uint8 mA;
|
|
};
|
|
|
|
class CmpIX :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
inline CmpIX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
|
|
XFormXY(inPrimitive, inPool, 2, 1, inKind, inFlags) { }
|
|
|
|
protected:
|
|
virtual Uint8 getD() { return (0); } // always use cr0
|
|
};
|
|
|
|
class CmpFX :
|
|
public XFormXY
|
|
{
|
|
public:
|
|
inline CmpFX(DataNode* inPrimitive, Pool& inPool, XFormKind inKind, PPCInsnFlags inFlags) :
|
|
XFormXY(inPrimitive, inPool, 2, 1, inKind, inFlags) { }
|
|
|
|
protected:
|
|
virtual Uint8 getD() { return (0); } // always use cr0
|
|
};
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊIForm ¥
|
|
#endif
|
|
|
|
class BranchI :
|
|
public PPCInstructionXY
|
|
{
|
|
public:
|
|
inline BranchI(DataNode* inPrimitive, Pool& inPool, ControlNode& inTarget, bool inAbsolute = false, bool inLink = false) :
|
|
PPCInstructionXY(inPrimitive, inPool, 0, 0), mTarget(inTarget)
|
|
{ mIForm.OPCD = 18; mIForm.LI = 0; mIForm.AA = inAbsolute; mIForm.LK = inLink;}
|
|
|
|
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
|
|
#ifdef DEBUG
|
|
virtual void printPretty(FILE* f) { fprintf(f, "bxx %d", mTarget.getNativeOffset()); }
|
|
#endif
|
|
|
|
protected:
|
|
ControlNode& mTarget;
|
|
|
|
struct
|
|
{
|
|
int OPCD:6;
|
|
int LI:24;
|
|
int AA:1;
|
|
int LK:1;
|
|
} mIForm;
|
|
};
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊIForm ¥
|
|
#endif
|
|
|
|
// the bits in order (or offsets into a condition register)
|
|
// neg (lt)
|
|
// pos (gt)
|
|
// zero (eq)
|
|
// summary overflow (so)
|
|
// 0010y branch if cond is false
|
|
// 0110y branch if cond is true
|
|
struct BranchCondition
|
|
{
|
|
char* name;
|
|
Uint8 bo;
|
|
Uint8 bi;
|
|
};
|
|
|
|
// indexed by Condition2
|
|
const BranchCondition sBranchConditions[] =
|
|
{
|
|
{"always", 0, 0},
|
|
{"lt", 12, 0},
|
|
{"eq", 12, 2},
|
|
{"le", 4, 1},
|
|
{"gt", 12, 1},
|
|
{"ne", 4, 2},
|
|
{"ge", 4, 0}
|
|
};
|
|
|
|
#if 0
|
|
BO BI
|
|
cond0, // 0000 Always false
|
|
condLt, // 0001 arg1 < arg2 0110y 0 lt
|
|
condEq, // 0010 arg1 = arg2 0110y 2 eq
|
|
condLe, // 0011 arg1 <= arg2 0010y 1 not gt
|
|
condGt, // 0100 arg1 > arg2 0110y 1 gt
|
|
condLgt, // 0101 arg1 <> arg2 0010y 2 not eq
|
|
condGe, // 0110 arg1 >= arg2 0010y 0 not lt
|
|
|
|
-- only up to these are supported
|
|
condOrd, // 0111 arg1 <=> arg2 (i.e. arg1 and arg2 are ordered) 0110y 3 so ?? nan
|
|
condUnord, // 1000 arg1 ? arg2 (i.e. arg1 and arg2 are unordered) 0010y 3 not so
|
|
condULt, // 1001 arg1 ?< arg2 do we have to deal with these below here??
|
|
condUEq, // 1010 arg1 ?= arg2
|
|
condULe, // 1011 arg1 ?<= arg2
|
|
condUGt, // 1100 arg1 ?> arg2
|
|
condNe, // 1101 arg1 != arg2
|
|
condUGe, // 1110 arg1 ?>= arg2
|
|
cond1 // 1111 Always true
|
|
#endif
|
|
|
|
class BranchCB :
|
|
public PPCInstructionXY
|
|
{
|
|
public:
|
|
BranchCB(DataNode* inPrimitive, Pool& inPool, ControlNode& inTarget, Condition2 inCondition, bool inAbsolute = false, bool inLink = false);
|
|
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
|
|
|
|
|
|
protected:
|
|
ControlNode& mTarget;
|
|
|
|
struct
|
|
{
|
|
unsigned int OPCD:6;
|
|
unsigned int BO:5;
|
|
// unsigned int Y:1;
|
|
unsigned int BI:5;
|
|
unsigned int BD:14;
|
|
unsigned int AA:1;
|
|
unsigned int LK:1;
|
|
} mCForm;
|
|
|
|
#if DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) { fprintf(f, "b%s %d", sBranchConditions[mCond].name, mTarget.getNativeOffset()); }
|
|
|
|
protected:
|
|
Condition2 mCond;
|
|
#endif
|
|
};
|
|
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊM-Form ¥
|
|
#endif
|
|
|
|
#define DO_MFORM
|
|
struct MFormInstructionInfo
|
|
{
|
|
Uint16 opcode;
|
|
char* formatStr;
|
|
};
|
|
|
|
|
|
#define MAKE_MFORM_ENUM(inName) mf##inName,
|
|
#define MFORM_DEFINE(inName, inOpcode) MAKE_MFORM_ENUM(inName)
|
|
|
|
enum MFormKind
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
mfLast
|
|
};
|
|
|
|
#undef MFORM_DEFINE
|
|
|
|
#define MAKE_MFORM_INFO(inName, inOpcode) \
|
|
{ inOpcode, #inName"%s r%d, r%d, r%d, %d, %d"},
|
|
|
|
#define MFORM_DEFINE(inName, inOpcode) MAKE_MFORM_INFO(inName, inOpcode)
|
|
|
|
const MFormInstructionInfo sMFormInfos[] =
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
};
|
|
|
|
#undef MFORM_DEFINE
|
|
#undef DO_MFORM
|
|
|
|
class MForm :
|
|
public PPCInstructionXY
|
|
{
|
|
public:
|
|
inline MForm(DataNode* inPrimitive, Pool& inPool, Uint8 inUses, MFormKind inKind, Uint8 inMaskBegin, Uint8 inMaskEnd, PPCInsnFlags inFlags) :
|
|
PPCInstructionXY(inPrimitive, inPool, inUses, 1 + (bool) (inFlags & pfRc)),
|
|
mFlags(inFlags),
|
|
mKind(inKind),
|
|
mMaskBegin(inMaskBegin),
|
|
mMaskEnd(inMaskEnd) { }
|
|
virtual void formatToMemory(void* inStart, Uint32 inOffset, MdFormatter& /*inFormatter*/);
|
|
|
|
|
|
|
|
protected:
|
|
Uint16 getOPCD() { return (sXFormInfos[mKind].opcode); }
|
|
Uint8 getS() { return (udToRegisterNumber(getInstructionUseBegin()[0])); }
|
|
Uint8 getA() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
|
|
virtual Uint8 getB() { return (udToRegisterNumber(getInstructionUseBegin()[1])); }
|
|
Uint8 getMB() { return (mMaskBegin); }
|
|
Uint8 getME() { return (mMaskEnd); }
|
|
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* f) { fprintf(f, sMFormInfos[mKind].formatStr, flagsToExtension(), getA(), getS(), getB(), getMB(), getME()); }
|
|
protected:
|
|
const char* flagsToExtension() { return sFlagsExtensionTbl[mFlags & 1]; /* only look at Rc bit */ }
|
|
#endif
|
|
|
|
PPCInsnFlags mFlags;
|
|
MFormKind mKind;
|
|
Uint8 mMaskBegin;
|
|
Uint8 mMaskEnd;
|
|
};
|
|
|
|
|
|
class MFormInAOnly :
|
|
public MForm
|
|
{
|
|
public:
|
|
inline MFormInAOnly(DataNode* inPrimitive, Pool& inPool, MFormKind inKind, Uint8 inB, Uint8 inMaskBegin, Uint8 inMaskEnd, PPCInsnFlags inFlags) :
|
|
MForm(inPrimitive, inPool, 1, inKind, inMaskBegin, inMaskEnd, inFlags),
|
|
mB(inB) { }
|
|
protected:
|
|
virtual Uint8 getB() { return (mB); }
|
|
|
|
Uint8 mB;
|
|
};
|
|
|
|
#ifdef __MWERKS__
|
|
#pragma mark -
|
|
#pragma mark ¥ÊA-Form ¥
|
|
#endif
|
|
|
|
|
|
#define DO_AFORM
|
|
|
|
|
|
#define MAKE_AFORM_ENUM(inName) af##inName,
|
|
#define AFORM_DEFINE(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc) MAKE_AFORM_ENUM(inName)
|
|
|
|
enum AFormKind
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
afLast
|
|
};
|
|
|
|
#undef AFORM_DEFINE
|
|
|
|
template <bool tHasA, bool tHasB, bool tHasC, bool tRc>
|
|
class AForm :
|
|
public PPCInstructionXY
|
|
{
|
|
public:
|
|
inline AForm(DataNode* inPrimitive, Pool& inPool, AFormKind inKind) :
|
|
PPCInstructionXY(inPrimitive, inPool, tHasA + tHasB + tHasC, tRc + 1),
|
|
mKind(inKind) {}
|
|
|
|
protected:
|
|
Uint16 getOPCD() { return (sAFormInfos[mKind].opcode); }
|
|
Uint8 getD() { return (udToRegisterNumber(getInstructionDefineBegin()[0])); }
|
|
Uint8 getA() { return (tHasA ? udToRegisterNumber(getInstructionUseBegin()[0]) : 0); }
|
|
Uint8 getB() { return (tHasB ? udToRegisterNumber(getInstructionUseBegin()[tHasA]) : 0); }
|
|
Uint8 getC() { return (tHasC ? udToRegisterNumber(getInstructionUseBegin()[tHasA + tHasB]) : 0); }
|
|
|
|
public:
|
|
virtual void
|
|
formatToMemory(void* inStart, Uint32 /*inOffset*/, MdFormatter& /*inFormatter*/)
|
|
{
|
|
struct
|
|
{
|
|
uint OPCD:6;
|
|
uint D:5;
|
|
uint A:5;
|
|
uint B:5;
|
|
uint C:5;
|
|
uint XO:5;
|
|
uint RC:1;
|
|
} aForm;
|
|
|
|
aForm.OPCD = sAFormInfos[mKind].opcode;
|
|
aForm.D = getD();
|
|
aForm.A = getA();
|
|
aForm.B = getB();
|
|
aForm.C = getC();
|
|
aForm.XO = sAFormInfos[mKind].xo;
|
|
aForm.RC = tRc;
|
|
|
|
*(Uint32*) inStart = *(Uint32*) &aForm;
|
|
}
|
|
|
|
static Instruction&
|
|
createInstruction(DataNode& inPrimitive, Pool& mPool, AFormKind inKind)
|
|
{
|
|
return *new(mPool) AForm<tHasA, tHasB, tHasC, tRc>(&inPrimitive, mPool, inKind);
|
|
}
|
|
|
|
protected:
|
|
const AFormKind mKind;
|
|
#ifdef DEBUG
|
|
public:
|
|
virtual void printPretty(FILE* /*f*/) {}
|
|
protected:
|
|
const char* flagsToExtension() { return sFlagsExtensionTbl[tRc]; } // only look at Rc bit
|
|
#endif
|
|
};
|
|
|
|
struct AFormInstructionInfo
|
|
{
|
|
Uint16 opcode;
|
|
Uint16 xo;
|
|
Instruction& (*creatorFunction)(DataNode&, Pool&, AFormKind);
|
|
char* formatStr;
|
|
};
|
|
|
|
#define MAKE_AFORM_INFO(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc) \
|
|
{ inOpcode, inXo, AForm<inHasA, inHasB, inHasC, inRc>::createInstruction, #inName"%s r%d, r%d, r%d, %d, %d"},
|
|
|
|
#define AFORM_DEFINE(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc) MAKE_AFORM_INFO(inName, inOpcode, inXo, inHasA, inHasB, inHasC, inRc)
|
|
|
|
const AFormInstructionInfo sAFormInfos[] =
|
|
{
|
|
#include "PPCInstructionTemplates.h"
|
|
};
|
|
|
|
#undef AFORM_DEFINE
|
|
#undef DO_AFORM
|
|
|
|
#endif // _H_PPCINSTRUCTIONS
|