我正在尝试通过嵌入式操作码数组创建PPU解释器,以执行处理程序来解释指令。指令可以是几种形式之一(I形式,B形式,D形式,X形式等),但是对于主要操作码31的X形式我有一个小问题。我正在使用模板类InterpretArray可以在数组中自动分配处理程序。此类也可以用作处理程序的子数组,可以从处理程序中调用该子数组。 VS2013编译器给我致命错误:
1> main.cpp(196):致命错误C1202:递归类型或函数依赖项上下文过于复杂
template < size_t xo_rc >
struct Interpreter < X_Form_31_XORc < xo_rc > >
听起来编译器不喜欢X_Form_31_XORc,为什么?我该如何避免呢?
如果未定义X_FORM,则可以在此处编译源代码:
#include <iostream>
#define B_FORM
//#define X_FORM
using namespace std;
// Dummy stuff
typedef unsigned int u32;
typedef signed int s32;
union Instruction
{
#define FIELD(from, to, type) struct{ u32:(32-to-1); type:(to-from+1); u32:from; }
u32 instruction;
// Opcode fields
FIELD(0, 5, u32 opcode); // Primary opcode
FIELD(26, 31, u32 op4); // Extended opcode of 6-bits (up to 0x3F)
FIELD(21, 31, u32 op4_); // Extended opcode of 11-bits (up to 0x7FF)
FIELD(21, 30, u32 op19); // Extended opcode of 10-bits (up to 0x3FF)
FIELD(27, 29, u32 op30); // Extended opcode of 3-bits (up to 0x7)
FIELD(21, 30, u32 op31); // Extended opcode of 10-bits (up to 0x3FF)
FIELD(30, 31, u32 op58); // Extended opcode of 2-bits (up to 0x3)
FIELD(26, 30, u32 op59); // Extended opcode of 5-bits (up to 0x1F)
FIELD(30, 31, u32 op62); // Extended opcode of 2-bits (up to 0x3)
FIELD(26, 30, u32 op63); // Extended opcode of 5-bits (up to 0x1F)
FIELD(21, 30, u32 op63_); // Extended opcode of 10-bits (up to 0x3FF)
// Instruction fields
FIELD(30, 30, u32 aa); // Bit/Flags: Absolute address bit
FIELD(31, 31, u32 lk); // Bit/Flags: Link bit: Update the link register (LR)
FIELD(21, 21, u32 oe); // Bit/Flags: OE bit: Enable enable setting OV and SO in the XER
FIELD(31, 31, u32 rc); // Bit/Flags: Record bit: Update the condition register (CR)
FIELD(6, 6, u32 l6); // Bit/Flags: ?
FIELD(10, 10, u32 l10); // Bit/Flags: ?
FIELD(11, 11, u32 l11); // Bit/Flags: ?
FIELD(9, 10, u32 l9_10); // Bit/Flags: ?
FIELD(6, 10, u32 bo); // Branching: Options for the branch conditional instructions
FIELD(11, 15, u32 bi); // Branching: CR bit to trigger branch conditional instructions
FIELD(16, 29, s32 bd); // Branching: Immediate 14-bit signed integer for branch displacement
FIELD(19, 20, u32 bh); // ?
FIELD(11, 13, u32 bfa); // ?
FIELD(6, 8, u32 crfd); // CR fields: Destination CR or FPSCR field
FIELD(11, 13, u32 crfs); // CR fields: Source CR or FPSCR field
FIELD(6, 10, u32 crbd); // CR fields: Destination bit in the CR or FPSCR
FIELD(11, 15, u32 crba); // CR fields: Source bit in the CR
FIELD(16, 20, u32 crbb); // CR fields: Source bit in the CR
FIELD(12, 19, u32 crm); // Identify the CR fields that are to be updated by the mtcrf instruction
FIELD(16, 31, s32 d); // Immediate 16-bit signed integer
FIELD(16, 27, u32 dq); // ?
FIELD(16, 29, s32 ds); // ?
FIELD(7, 14, u32 fm); // ?
FIELD(6, 10, u32 frd); // FPR: Destination
FIELD(6, 10, u32 frs); // FPR: Source
FIELD(11, 15, u32 fra); // FPR: Source
FIELD(16, 20, u32 frb); // FPR: Source
FIELD(21, 25, u32 frc); // FPR: Source
FIELD(16, 19, u32 imm); // Immediate for to place in FPSCR
FIELD(6, 29, s32 li); // Branching:
FIELD(6, 29, s32 ll); // Branching:
FIELD(21, 25, u32 mb); // First '1' bit of a 64-bit mask in rotate instructions
FIELD(26, 26, u32 mb_); // First '1' bit of a 64-bit mask in rotate instructions: Split field
FIELD(26, 30, u32 me); // Last '1' bit of a 64-bit mask in rotate instructions
FIELD(21, 25, u32 me_); // Last '1' bit of a 64-bit mask in rotate instructions: Split field
FIELD(26, 26, u32 me__); // Last '1' bit of a 64-bit mask in rotate instructions: Split field
FIELD(16, 20, u32 nb); // Number of bytes to move in an immediate string load or store
FIELD(6, 10, u32 rd); // GPR: Destination
FIELD(6, 10, u32 rs); // GPR: Source
FIELD(11, 15, u32 ra); // GPR: Source
FIELD(16, 20, u32 rb); // GPR: Source
FIELD(16, 20, u32 sh); // Shift amount
FIELD(30, 30, u32 sh_); // Shift amount: Split field
FIELD(11, 20, u32 spr); // Special-purpose register
FIELD(9, 10, u32 strm); // ?
FIELD(20, 26, u32 lev); // ?
FIELD(16, 31, s32 simm); // Immediate 16-bit signed integer
FIELD(16, 31, u32 uimm); // Immediate 16-bit unsigned integer
FIELD(9, 10, u32 th); // Data stream variant of the dcbt instruction
FIELD(6, 10, u32 to); // Trap conditions
FIELD(6, 10, u32 vd); // Vector/SIMD: Destination vector register
FIELD(6, 10, u32 vs); // Vector/SIMD: Source vector register
FIELD(11, 15, u32 va); // Vector/SIMD: Source vector register
FIELD(16, 20, u32 vb); // Vector/SIMD: Source vector register
FIELD(21, 25, u32 vc); // Vector/SIMD: Source vector register
FIELD(22, 25, u32 vshb); // Vector/SIMD: Specifies a shift amount in bytes
FIELD(11, 15, s32 vsimm); // Vector/SIMD: Immediate 5-bit signed integer
FIELD(11, 15, u32 vuimm); // Vector/SIMD: Immediate 5-bit unsigned integer
#undef FIELD
};
struct PPUThread {}; // register context but we do not need it here
// Opcode part
// auto-initialize by recursively assigning all handlers in an opcode array
template< template< typename > class Handler,
template< size_t > class Indexer,
size_t start_index,
size_t end_index >
struct OpcodeArrayRange
{
template< typename Owner >
static __forceinline void initialize(Owner & owner)
{
owner.array[start_index] = Handler< Indexer< start_index > >::handle;
OpcodeArrayRange< Handler, Indexer, start_index + 1, end_index >::initialize(owner);
}
};
// auto-initialize by assigning the last handler in an opcode array
template< template< typename > class Handler,
template< size_t > class Indexer,
size_t start_index >
struct OpcodeArrayRange < Handler, Indexer, start_index, start_index >
{
template< typename Owner >
static __forceinline void initialize(Owner & owner)
{
owner.array[start_index] = Handler< Indexer< start_index > >::handle;
}
};
template < size_t po >
struct OPCD // Primary opcode, used for Indexer in OpcodeArrayRange
{
};
#ifdef B_FORM
template < size_t po >
using B_Form = OPCD < po >;
template < size_t bo_bi >
struct B_Form_BOBI
{
};
#endif
#ifdef X_FORM
template < size_t po >
using X_Form = OPCD < po > ; // Primary opcode + Extended opcode + Record bit
template < size_t po, size_t xo, size_t rc >
struct X_Form_XO_Rc // Primary opcode + Extended opcode + Record bit
{
};
template < size_t po, size_t xo_rc >
struct X_Form_XORc // glue Extended opcode and Record bit into one field, used for Indexer in OpcodeArrayRange
{
};
template < size_t xo_rc >
using X_Form_31_XORc = X_Form_XORc < 31, xo_rc > ; // alias to X_Form_XORc with Primary opcode 31
#endif
// Interpreter part
template< typename T >
struct Interpreter
{
};
// generic interpreter array
template< template< size_t > class OpcodeFormat,
size_t start_index,
size_t end_index >
struct InterpretArray :
OpcodeArrayRange < Interpreter, OpcodeFormat, start_index, end_index >
{
InterpretArray()
{
initialize(*this);
}
__forceinline void operator()(size_t index,
Instruction code,
PPUThread& thread)
{
array[index](code, thread);
}
void(*array[1 + end_index - start_index])(Instruction, PPUThread&);
};
// implementation for interpreting opcodes
template< size_t po >
struct Interpreter < OPCD < po > >
{
static void handle(Instruction /*code*/, PPUThread& /*thread*/)
{
std::cout
<< "OPCD #"
<< po
<< std::endl;
}
};
#ifdef B_FORM
template < size_t bo_bi >
struct Interpreter < B_Form_BOBI < bo_bi > >
{
static void handle(Instruction code, PPUThread& thread)
{
std::cout
<< "OPCD #31, BO #"
<< (bo_bi >> 5)
<< ", BI #"
<< (bo_bi & 31)
<< ", AA #"
<< (code.aa)
<< ", LK #"
<< (code.lk)
<< std::endl;
}
};
static InterpretArray < B_Form_BOBI, 0, 0x3FF > interpret_B_Form_BOBI;
template< >
struct Interpreter < B_Form < 16 > >
{
static void handle(Instruction code, PPUThread& thread)
{
interpret_B_Form_BOBI((code.instruction >> 16) & 0x3FF, code, thread);
}
};
#endif
#ifdef X_FORM
template < size_t xo_rc >
struct Interpreter < X_Form_31_XORc < xo_rc > >
{
static void handle(Instruction /*code*/, PPUThread& /*thread*/)
{
std::cout
<< "OPCD #31, XO #"
<< (xo_rc >> 1)
<< ", Rc #"
<< (xo_rc & 1)
<< std::endl;
}
};
// specific interpreter array for instructions selected by their extended code
// and Record bit when primary opcode is 31
static InterpretArray < X_Form_31_XORc, 0, 0x7FF > interpret_X_Form_31;
template< >
struct Interpreter < X_Form < 31 > > // note that X_Form is an alias to OPCD
{
static void handle(Instruction code, PPUThread& thread)
{
interpret_X_Form_31((code.instruction & 0x7FF), code, thread);
}
};
#endif
// specific interpreter array for instructions
// selected by primary opcode
static InterpretArray < OPCD, 0, 0x3F > interpret;
int main()
{
Instruction insn;
PPUThread thread;
{
insn.opcode = 2;
interpret(insn.opcode, insn, thread);
}
#ifdef B_FORM
{
insn.opcode = 16;
insn.bo = 2;
insn.bi = 3;
insn.aa = 1;
insn.lk = 1;
interpret(insn.opcode, insn, thread);
}
#endif
#ifdef X_FORM
{
insn.opcode = 31;
insn.op31 = 2;
insn.rc = 0;
interpret(insn.opcode, insn, thread);
}
{
insn.opcode = 31;
insn.op31 = 2;
insn.rc = 1;
interpret(insn.opcode, insn, thread);
}
#endif
}
编辑:我添加了B_Form,它类似于X_Form,但不使用别名并且可以工作(但构建速度很慢)。
最佳答案
template< template< typename > class Handler,
template< size_t > class Indexer,
size_t start_index,
size_t end_index >
struct OpcodeArrayRange
{
template< typename Owner >
static __forceinline void initialize(Owner & owner)
{
owner.array[start_index] = Handler< Indexer< start_index > >::handle;
OpcodeArrayRange< Handler, Indexer, start_index + 1, end_index >::initialize(owner);
}
};
...
template< template< size_t > class OpcodeFormat,
size_t start_index,
size_t end_index >
struct InterpretArray :
OpcodeArrayRange < Interpreter, OpcodeFormat, start_index, end_index >
...
static InterpretArray < X_Form_31_XORc, 0, 0x7FF > interpret_X_Form_31;
InterpretArray < X_Form_31_XORc, 0, 0x7FF >
的实例化触发其基类OpcodeArrayRange < Interpreter, X_Form_31_XORc, 0, 0x7FF >
的实例化。OpcodeArrayRange < Interpreter, X_Form_31_XORc, 0, 0x7FF >
的实例化会触发OpcodeArrayRange < Interpreter, X_Form_31_XORc, 1, 0x7FF >
的实例化,这是因为您如何定义initialize
方法。OpcodeArrayRange < Interpreter, X_Form_31_XORc, 1, 0x7FF >
的实例化会触发OpcodeArrayRange < Interpreter, X_Form_31_XORc, 2, 0x7FF >
的实例化,这是因为您如何定义initialize
方法。OpcodeArrayRange < Interpreter, X_Form_31_XORc, 2, 0x7FF >
的实例化会触发OpcodeArrayRange < Interpreter, X_Form_31_XORc, 3, 0x7FF >
的实例化,这是因为您如何定义initialize
方法。等等
模板的此递归实例受到限制。您已经超出了编译器的限制(以及GCC和clang的限制)。您可能根本不应该在
initialize
方法中引用其他模板实例。