bool ppc_frontend::describe(opcode_desc &desc, const opcode_desc *prev)
{
	UINT32 op, opswitch;
	int regnum;

	// compute the physical PC
	if (!ppccom_translate_address(&m_context, AS_PROGRAM, TRANSLATE_FETCH, &desc.physpc))
	{
		// uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and
		// mark as needing to validate; otherwise, just end the sequence here
		desc.flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE;
		return true;
	}

	// fetch the opcode
	op = desc.opptr.l[0] = m_context.direct->read_decrypted_dword(desc.physpc, m_context.codexor);

	// all instructions are 4 bytes and default to a single cycle each
	desc.length = 4;
	desc.cycles = 1;

	// parse the instruction
	opswitch = op >> 26;
	switch (opswitch)
	{
		case 0x02:	// TDI - 64-bit only
		case 0x1e:	// 0x1e group - 64-bit only
		case 0x3a:	// 0x3a group - 64-bit only
		case 0x3e:	// 0x3e group - 64-bit only
			return false;

		case 0x03:	// TWI
			GPR_USED(desc, G_RA(op));
			desc.flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
			if (is_603_class())
				desc.cycles = 2;	// 603
			return true;

		case 0x07:	// MULLI
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			if (is_403_class())
				desc.cycles = 4;	// 4XX
			else if (is_601_class())
				desc.cycles = 5;	// 601
			else if (is_603_class())
				desc.cycles = 2;	// 603: 2-3
			else
				desc.cycles = 2;	// ???
			return true;

		case 0x0e:	// ADDI
		case 0x0f:	// ADDIS
			GPR_USED_OR_ZERO(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			return true;

		case 0x0a:	// CMPLI
		case 0x0b:	// CMPI
			GPR_USED(desc, G_RA(op));
			XER_SO_USED(desc);
			CR_MODIFIED(desc, G_CRFD(op));
			return true;

		case 0x08:	// SUBFIC
		case 0x0c:	// ADDIC
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			XER_CA_MODIFIED(desc);
			return true;

		case 0x0d:	// ADDIC.
			GPR_USED(desc, G_RA(op));
			XER_SO_USED(desc);
			GPR_MODIFIED(desc, G_RT(op));
			XER_CA_MODIFIED(desc);
			CR_MODIFIED(desc, 0);
			return true;

		case 0x10:	// BCx
			if (!(G_BO(op) & 0x10))
			{
				CR_BIT_USED(desc, G_BI(op));
				// branch folding
				if (prev == NULL || prev->regout[2] == 0)
					desc.cycles = 0;
			}
			if (!(G_BO(op) & 0x04))
			{
				CTR_USED(desc);
				CTR_MODIFIED(desc);
			}
			if (op & M_LK)
				LR_MODIFIED(desc);
			if ((G_BO(op) & 0x14) == 0x14)
				desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
			else
				desc.flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
			desc.targetpc = (INT16)(G_BD(op) << 2) + ((op & M_AA) ? 0 : desc.pc);
			if (desc.targetpc == desc.pc && desc.cycles == 0)
				desc.cycles = 1;
			return true;

		case 0x11:	// SC
			if (!(m_context.cap & (PPCCAP_OEA | PPCCAP_4XX)))
				return false;
			desc.flags |= OPFLAG_WILL_CAUSE_EXCEPTION;
			if (is_601_class())
				desc.cycles = 16;	// 601
			else if (is_603_class())
				desc.cycles = 3;	// 603
			else
				desc.cycles = 3;	// ???
			return true;

		case 0x12:	// Bx
			if (op & M_LK)
				LR_MODIFIED(desc);
			desc.flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
			desc.targetpc = ((INT32)(G_LI(op) << 8) >> 6) + ((op & M_AA) ? 0 : desc.pc);
			// branch folding
			if (desc.targetpc != desc.pc)
				desc.cycles = 0;
			return true;

		case 0x13:	// 0x13 group
			return describe_13(op, desc, prev);

		case 0x14:	// RLWIMIx
			GPR_USED(desc, G_RS(op));
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RA(op));
			if (op & M_RC)
			{
				XER_SO_USED(desc);
				CR_MODIFIED(desc, 0);
			}
			return true;

		case 0x15:	// RLWINMx
			GPR_USED(desc, G_RS(op));
			GPR_MODIFIED(desc, G_RA(op));
			if (op & M_RC)
			{
				XER_SO_USED(desc);
				CR_MODIFIED(desc, 0);
			}
			return true;

		case 0x17:	// RLWNMx
			GPR_USED(desc, G_RS(op));
			GPR_USED(desc, G_RB(op));
			GPR_MODIFIED(desc, G_RA(op));
			if (op & M_RC)
			{
				XER_SO_USED(desc);
				CR_MODIFIED(desc, 0);
			}
			return true;

		case 0x18:	// ORI
		case 0x19:	// ORIS
		case 0x1a:	// XORI
		case 0x1b:	// XORIS
			GPR_USED(desc, G_RS(op));
			GPR_MODIFIED(desc, G_RA(op));
			return true;

		case 0x1c:	// ANDI.
		case 0x1d:	// ANDIS.
			GPR_USED(desc, G_RS(op));
			XER_SO_USED(desc);
			GPR_MODIFIED(desc, G_RA(op));
			CR_MODIFIED(desc, 0);
			return true;

		case 0x1f:	// 0x1f group
			return describe_1f(op, desc, prev);

		case 0x20:	// LWZ
		case 0x22:	// LBZ
		case 0x28:	// LHZ
		case 0x2a:	// LHA
			GPR_USED_OR_ZERO(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			desc.flags |= OPFLAG_READS_MEMORY;
			return true;

		case 0x21:	// LWZU
		case 0x23:	// LBZU
		case 0x29:	// LHZU
		case 0x2b:	// LHAU
			if (G_RA(op) == 0 || G_RA(op) == G_RD(op))
				return false;
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			GPR_MODIFIED(desc, G_RA(op));
			desc.flags |= OPFLAG_READS_MEMORY;
			return true;

		case 0x24:	// STW
		case 0x26:	// STB
		case 0x2c:	// STH
			GPR_USED_OR_ZERO(desc, G_RA(op));
			GPR_USED(desc, G_RS(op));
			desc.flags |= OPFLAG_WRITES_MEMORY;
			return true;

		case 0x25:	// STWU
		case 0x27:	// STBU
		case 0x2d:	// STHU
			if (G_RA(op) == 0)
				return false;
			GPR_USED(desc, G_RA(op));
			GPR_USED(desc, G_RS(op));
			GPR_MODIFIED(desc, G_RA(op));
			desc.flags |= OPFLAG_WRITES_MEMORY;
			return true;

		case 0x2e:	// LMW
			GPR_USED_OR_ZERO(desc, G_RA(op));
			for (regnum = G_RD(op); regnum < 32; regnum++)
				GPR_MODIFIED(desc, regnum);
			desc.flags |= OPFLAG_READS_MEMORY;
			desc.cycles = 32 - G_RD(op);
			return true;

		case 0x2f:	// STMW
			GPR_USED_OR_ZERO(desc, G_RA(op));
			for (regnum = G_RS(op); regnum < 32; regnum++)
				GPR_USED(desc, regnum);
			desc.flags |= OPFLAG_WRITES_MEMORY;
			desc.cycles = 32 - G_RS(op);
			return true;

		case 0x30:	// LFS
		case 0x32:	// LFD
			if (!(m_context.cap & PPCCAP_FPU))
				return false;
			GPR_USED_OR_ZERO(desc, G_RA(op));
			FPR_MODIFIED(desc, G_RD(op));
			desc.flags |= OPFLAG_READS_MEMORY;
			return true;

		case 0x31:	// LFSU
		case 0x33:	// LFDU
			if (!(m_context.cap & PPCCAP_FPU))
				return false;
			if (G_RA(op) == 0)
				return false;
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RA(op));
			FPR_MODIFIED(desc, G_RD(op));
			desc.flags |= OPFLAG_READS_MEMORY;
			return true;

		case 0x34:	// STFS
		case 0x36:	// STFD
			if (!(m_context.cap & PPCCAP_FPU))
				return false;
			GPR_USED_OR_ZERO(desc, G_RA(op));
			FPR_USED(desc, G_RS(op));
			desc.flags |= OPFLAG_WRITES_MEMORY;
			return true;

		case 0x35:	// STFSU
		case 0x37:	// STFDU
			if (!(m_context.cap & PPCCAP_FPU))
				return false;
			if (G_RA(op) == 0)
				return false;
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RA(op));
			FPR_USED(desc, G_RS(op));
			desc.flags |= OPFLAG_WRITES_MEMORY;
			return true;

		case 0x3b:	// 0x3b group
			return describe_3b(op, desc, prev);

		case 0x3f:	// 0x3f group
			return describe_3f(op, desc, prev);
	}

	return false;
}
Example #2
0
int ppcfe_describe(void *param, opcode_desc *desc, const opcode_desc *prev)
{
	powerpc_state *ppc = (powerpc_state *)param;
	UINT32 op, opswitch;
	int regnum;

	/* compute the physical PC */
	if (!ppccom_translate_address(ppc, ADDRESS_SPACE_PROGRAM, TRANSLATE_FETCH, &desc->physpc))
	{
		/* uh-oh: a page fault; leave the description empty and just if this is the first instruction, leave it empty and */
		/* mark as needing to validate; otherwise, just end the sequence here */
		desc->flags |= OPFLAG_VALIDATE_TLB | OPFLAG_CAN_CAUSE_EXCEPTION | OPFLAG_COMPILER_PAGE_FAULT | OPFLAG_VIRTUAL_NOOP | OPFLAG_END_SEQUENCE;
		return TRUE;
	}

	/* fetch the opcode */
	op = desc->opptr.l[0] = ppc->direct->read_decrypted_dword(desc->physpc, ppc->codexor);

	/* all instructions are 4 bytes and default to a single cycle each */
	desc->length = 4;
	desc->cycles = 1;

	/* parse the instruction */
	opswitch = op >> 26;
	switch (opswitch)
	{
		case 0x02:	/* TDI - 64-bit only */
		case 0x1e:	/* 0x1e group - 64-bit only */
		case 0x3a:	/* 0x3a group - 64-bit only */
		case 0x3e:	/* 0x3e group - 64-bit only */
			return FALSE;

		case 0x03:	/* TWI */
			GPR_USED(desc, G_RA(op));
			desc->flags |= OPFLAG_CAN_CAUSE_EXCEPTION;
			if (is_603_class(ppc))
				desc->cycles = 2;	/* 603 */
			return TRUE;

		case 0x07:	/* MULLI */
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			if (is_403_class(ppc))
				desc->cycles = 4;	/* 4XX */
			else if (is_601_class(ppc))
				desc->cycles = 5;	/* 601 */
			else if (is_603_class(ppc))
				desc->cycles = 2;	/* 603: 2-3 */
			else
				desc->cycles = 2;	/* ??? */
			return TRUE;

		case 0x0e:	/* ADDI */
		case 0x0f:	/* ADDIS */
			GPR_USED_OR_ZERO(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			return TRUE;

		case 0x0a:	/* CMPLI */
		case 0x0b:	/* CMPI */
			GPR_USED(desc, G_RA(op));
			XER_SO_USED(desc);
			CR_MODIFIED(desc, G_CRFD(op));
			return TRUE;

		case 0x08:	/* SUBFIC */
		case 0x0c:	/* ADDIC */
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			XER_CA_MODIFIED(desc);
			return TRUE;

		case 0x0d:	/* ADDIC. */
			GPR_USED(desc, G_RA(op));
			XER_SO_USED(desc);
			GPR_MODIFIED(desc, G_RT(op));
			XER_CA_MODIFIED(desc);
			CR_MODIFIED(desc, 0);
			return TRUE;

		case 0x10:	/* BCx */
			if (!(G_BO(op) & 0x10))
			{
				CR_BIT_USED(desc, G_BI(op));
				/* branch folding */
				if (prev == NULL || prev->regout[2] == 0)
					desc->cycles = 0;
			}
			if (!(G_BO(op) & 0x04))
			{
				CTR_USED(desc);
				CTR_MODIFIED(desc);
			}
			if (op & M_LK)
				LR_MODIFIED(desc);
			if ((G_BO(op) & 0x14) == 0x14)
				desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
			else
				desc->flags |= OPFLAG_IS_CONDITIONAL_BRANCH;
			desc->targetpc = (INT16)(G_BD(op) << 2) + ((op & M_AA) ? 0 : desc->pc);
			if (desc->targetpc == desc->pc && desc->cycles == 0)
				desc->cycles = 1;
			return TRUE;

		case 0x11:	/* SC */
			if (!(ppc->cap & (PPCCAP_OEA | PPCCAP_4XX)))
				return FALSE;
			desc->flags |= OPFLAG_WILL_CAUSE_EXCEPTION;
			if (is_601_class(ppc))
				desc->cycles = 16;	/* 601 */
			else if (is_603_class(ppc))
				desc->cycles = 3;	/* 603 */
			else
				desc->cycles = 3;	/* ??? */
			return TRUE;

		case 0x12:	/* Bx */
			if (op & M_LK)
				LR_MODIFIED(desc);
			desc->flags |= OPFLAG_IS_UNCONDITIONAL_BRANCH | OPFLAG_END_SEQUENCE;
			desc->targetpc = ((INT32)(G_LI(op) << 8) >> 6) + ((op & M_AA) ? 0 : desc->pc);
			/* branch folding */
			if (desc->targetpc != desc->pc)
				desc->cycles = 0;
			return TRUE;

		case 0x13:	/* 0x13 group */
			return describe_instruction_13(ppc, op, desc, prev);

		case 0x14:	/* RLWIMIx */
			GPR_USED(desc, G_RS(op));
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RA(op));
			if (op & M_RC)
			{
				XER_SO_USED(desc);
				CR_MODIFIED(desc, 0);
			}
			return TRUE;

		case 0x15:	/* RLWINMx */
			GPR_USED(desc, G_RS(op));
			GPR_MODIFIED(desc, G_RA(op));
			if (op & M_RC)
			{
				XER_SO_USED(desc);
				CR_MODIFIED(desc, 0);
			}
			return TRUE;

		case 0x17:	/* RLWNMx */
			GPR_USED(desc, G_RS(op));
			GPR_USED(desc, G_RB(op));
			GPR_MODIFIED(desc, G_RA(op));
			if (op & M_RC)
			{
				XER_SO_USED(desc);
				CR_MODIFIED(desc, 0);
			}
			return TRUE;

		case 0x18:	/* ORI */
		case 0x19:	/* ORIS */
		case 0x1a:	/* XORI */
		case 0x1b:	/* XORIS */
			GPR_USED(desc, G_RS(op));
			GPR_MODIFIED(desc, G_RA(op));
			return TRUE;

		case 0x1c:	/* ANDI. */
		case 0x1d:	/* ANDIS. */
			GPR_USED(desc, G_RS(op));
			XER_SO_USED(desc);
			GPR_MODIFIED(desc, G_RA(op));
			CR_MODIFIED(desc, 0);
			return TRUE;

		case 0x1f:	/* 0x1f group */
			return describe_instruction_1f(ppc, op, desc, prev);

		case 0x20:	/* LWZ */
		case 0x22:	/* LBZ */
		case 0x28:	/* LHZ */
		case 0x2a:	/* LHA */
			GPR_USED_OR_ZERO(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			desc->flags |= OPFLAG_READS_MEMORY;
			return TRUE;

		case 0x21:	/* LWZU */
		case 0x23:	/* LBZU */
		case 0x29:	/* LHZU */
		case 0x2b:	/* LHAU */
			if (G_RA(op) == 0 || G_RA(op) == G_RD(op))
				return FALSE;
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RD(op));
			GPR_MODIFIED(desc, G_RA(op));
			desc->flags |= OPFLAG_READS_MEMORY;
			return TRUE;

		case 0x24:	/* STW */
		case 0x26:	/* STB */
		case 0x2c:	/* STH */
			GPR_USED_OR_ZERO(desc, G_RA(op));
			GPR_USED(desc, G_RS(op));
			desc->flags |= OPFLAG_WRITES_MEMORY;
			return TRUE;

		case 0x25:	/* STWU */
		case 0x27:	/* STBU */
		case 0x2d:	/* STHU */
			if (G_RA(op) == 0)
				return FALSE;
			GPR_USED(desc, G_RA(op));
			GPR_USED(desc, G_RS(op));
			GPR_MODIFIED(desc, G_RA(op));
			desc->flags |= OPFLAG_WRITES_MEMORY;
			return TRUE;

		case 0x2e:	/* LMW */
			GPR_USED_OR_ZERO(desc, G_RA(op));
			for (regnum = G_RD(op); regnum < 32; regnum++)
				GPR_MODIFIED(desc, regnum);
			desc->flags |= OPFLAG_READS_MEMORY;
			desc->cycles = 32 - G_RD(op);
			return TRUE;

		case 0x2f:	/* STMW */
			GPR_USED_OR_ZERO(desc, G_RA(op));
			for (regnum = G_RS(op); regnum < 32; regnum++)
				GPR_USED(desc, regnum);
			desc->flags |= OPFLAG_WRITES_MEMORY;
			desc->cycles = 32 - G_RS(op);
			return TRUE;

		case 0x30:	/* LFS */
		case 0x32:	/* LFD */
			if (!(ppc->cap & PPCCAP_FPU))
				return FALSE;
			GPR_USED_OR_ZERO(desc, G_RA(op));
			FPR_MODIFIED(desc, G_RD(op));
			desc->flags |= OPFLAG_READS_MEMORY;
			return TRUE;

		case 0x31:	/* LFSU */
		case 0x33:	/* LFDU */
			if (!(ppc->cap & PPCCAP_FPU))
				return FALSE;
			if (G_RA(op) == 0)
				return FALSE;
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RA(op));
			FPR_MODIFIED(desc, G_RD(op));
			desc->flags |= OPFLAG_READS_MEMORY;
			return TRUE;

		case 0x34:	/* STFS */
		case 0x36:	/* STFD */
			if (!(ppc->cap & PPCCAP_FPU))
				return FALSE;
			GPR_USED_OR_ZERO(desc, G_RA(op));
			FPR_USED(desc, G_RS(op));
			desc->flags |= OPFLAG_WRITES_MEMORY;
			return TRUE;

		case 0x35:	/* STFSU */
		case 0x37:	/* STFDU */
			if (!(ppc->cap & PPCCAP_FPU))
				return FALSE;
			if (G_RA(op) == 0)
				return FALSE;
			GPR_USED(desc, G_RA(op));
			GPR_MODIFIED(desc, G_RA(op));
			FPR_USED(desc, G_RS(op));
			desc->flags |= OPFLAG_WRITES_MEMORY;
			return TRUE;

		case 0x3b:	/* 0x3b group */
			return describe_instruction_3b(ppc, op, desc, prev);

		case 0x3f:	/* 0x3f group */
			return describe_instruction_3f(ppc, op, desc, prev);
	}

	return FALSE;
}