mirror of https://github.com/xemu-project/xemu.git
target-ppc: introduce opc4 for Expanded Opcode
ISA 3.0 has introduced EO - Expanded Opcode. Introduce third level indirect opcode table and corresponding parsing routines. EO (11:12) Expanded opcode field Formats: XX1 EO (11:15) Expanded opcode field Formats: VX, X, XX2 Signed-off-by: Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> [dwg: Trivial checkpatch fixup] Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
5f29cc8292
commit
323ad19bcc
|
@ -367,12 +367,13 @@ GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, PPC_NONE)
|
||||||
#define GEN_HANDLER2_E(name, onam, opc1, opc2, opc3, inval, type, type2) \
|
#define GEN_HANDLER2_E(name, onam, opc1, opc2, opc3, inval, type, type2) \
|
||||||
GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, type2)
|
GEN_OPCODE2(name, onam, opc1, opc2, opc3, inval, type, type2)
|
||||||
|
|
||||||
|
#define GEN_HANDLER_E_2(name, opc1, opc2, opc3, opc4, inval, type, type2) \
|
||||||
|
GEN_OPCODE3(name, opc1, opc2, opc3, opc4, inval, type, type2)
|
||||||
|
|
||||||
typedef struct opcode_t {
|
typedef struct opcode_t {
|
||||||
unsigned char opc1, opc2, opc3;
|
unsigned char opc1, opc2, opc3, opc4;
|
||||||
#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
|
#if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */
|
||||||
unsigned char pad[5];
|
unsigned char pad[4];
|
||||||
#else
|
|
||||||
unsigned char pad[1];
|
|
||||||
#endif
|
#endif
|
||||||
opc_handler_t handler;
|
opc_handler_t handler;
|
||||||
const char *oname;
|
const char *oname;
|
||||||
|
@ -452,6 +453,8 @@ EXTRACT_HELPER(opc1, 26, 6);
|
||||||
EXTRACT_HELPER(opc2, 1, 5);
|
EXTRACT_HELPER(opc2, 1, 5);
|
||||||
/* Opcode part 3 */
|
/* Opcode part 3 */
|
||||||
EXTRACT_HELPER(opc3, 6, 5);
|
EXTRACT_HELPER(opc3, 6, 5);
|
||||||
|
/* Opcode part 4 */
|
||||||
|
EXTRACT_HELPER(opc4, 16, 5);
|
||||||
/* Update Cr0 flags */
|
/* Update Cr0 flags */
|
||||||
EXTRACT_HELPER(Rc, 0, 1);
|
EXTRACT_HELPER(Rc, 0, 1);
|
||||||
/* Update Cr6 flags (Altivec) */
|
/* Update Cr6 flags (Altivec) */
|
||||||
|
@ -589,7 +592,7 @@ EXTRACT_HELPER(SP, 19, 2);
|
||||||
.opc1 = op1, \
|
.opc1 = op1, \
|
||||||
.opc2 = op2, \
|
.opc2 = op2, \
|
||||||
.opc3 = op3, \
|
.opc3 = op3, \
|
||||||
.pad = { 0, }, \
|
.opc4 = 0xff, \
|
||||||
.handler = { \
|
.handler = { \
|
||||||
.inval1 = invl, \
|
.inval1 = invl, \
|
||||||
.type = _typ, \
|
.type = _typ, \
|
||||||
|
@ -604,7 +607,7 @@ EXTRACT_HELPER(SP, 19, 2);
|
||||||
.opc1 = op1, \
|
.opc1 = op1, \
|
||||||
.opc2 = op2, \
|
.opc2 = op2, \
|
||||||
.opc3 = op3, \
|
.opc3 = op3, \
|
||||||
.pad = { 0, }, \
|
.opc4 = 0xff, \
|
||||||
.handler = { \
|
.handler = { \
|
||||||
.inval1 = invl1, \
|
.inval1 = invl1, \
|
||||||
.inval2 = invl2, \
|
.inval2 = invl2, \
|
||||||
|
@ -620,7 +623,7 @@ EXTRACT_HELPER(SP, 19, 2);
|
||||||
.opc1 = op1, \
|
.opc1 = op1, \
|
||||||
.opc2 = op2, \
|
.opc2 = op2, \
|
||||||
.opc3 = op3, \
|
.opc3 = op3, \
|
||||||
.pad = { 0, }, \
|
.opc4 = 0xff, \
|
||||||
.handler = { \
|
.handler = { \
|
||||||
.inval1 = invl, \
|
.inval1 = invl, \
|
||||||
.type = _typ, \
|
.type = _typ, \
|
||||||
|
@ -630,13 +633,28 @@ EXTRACT_HELPER(SP, 19, 2);
|
||||||
}, \
|
}, \
|
||||||
.oname = onam, \
|
.oname = onam, \
|
||||||
}
|
}
|
||||||
|
#define GEN_OPCODE3(name, op1, op2, op3, op4, invl, _typ, _typ2) \
|
||||||
|
{ \
|
||||||
|
.opc1 = op1, \
|
||||||
|
.opc2 = op2, \
|
||||||
|
.opc3 = op3, \
|
||||||
|
.opc4 = op4, \
|
||||||
|
.handler = { \
|
||||||
|
.inval1 = invl, \
|
||||||
|
.type = _typ, \
|
||||||
|
.type2 = _typ2, \
|
||||||
|
.handler = &gen_##name, \
|
||||||
|
.oname = stringify(name), \
|
||||||
|
}, \
|
||||||
|
.oname = stringify(name), \
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \
|
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) \
|
||||||
{ \
|
{ \
|
||||||
.opc1 = op1, \
|
.opc1 = op1, \
|
||||||
.opc2 = op2, \
|
.opc2 = op2, \
|
||||||
.opc3 = op3, \
|
.opc3 = op3, \
|
||||||
.pad = { 0, }, \
|
.opc4 = 0xff, \
|
||||||
.handler = { \
|
.handler = { \
|
||||||
.inval1 = invl, \
|
.inval1 = invl, \
|
||||||
.type = _typ, \
|
.type = _typ, \
|
||||||
|
@ -650,7 +668,7 @@ EXTRACT_HELPER(SP, 19, 2);
|
||||||
.opc1 = op1, \
|
.opc1 = op1, \
|
||||||
.opc2 = op2, \
|
.opc2 = op2, \
|
||||||
.opc3 = op3, \
|
.opc3 = op3, \
|
||||||
.pad = { 0, }, \
|
.opc4 = 0xff, \
|
||||||
.handler = { \
|
.handler = { \
|
||||||
.inval1 = invl1, \
|
.inval1 = invl1, \
|
||||||
.inval2 = invl2, \
|
.inval2 = invl2, \
|
||||||
|
@ -665,7 +683,7 @@ EXTRACT_HELPER(SP, 19, 2);
|
||||||
.opc1 = op1, \
|
.opc1 = op1, \
|
||||||
.opc2 = op2, \
|
.opc2 = op2, \
|
||||||
.opc3 = op3, \
|
.opc3 = op3, \
|
||||||
.pad = { 0, }, \
|
.opc4 = 0xff, \
|
||||||
.handler = { \
|
.handler = { \
|
||||||
.inval1 = invl, \
|
.inval1 = invl, \
|
||||||
.type = _typ, \
|
.type = _typ, \
|
||||||
|
@ -674,6 +692,20 @@ EXTRACT_HELPER(SP, 19, 2);
|
||||||
}, \
|
}, \
|
||||||
.oname = onam, \
|
.oname = onam, \
|
||||||
}
|
}
|
||||||
|
#define GEN_OPCODE3(name, op1, op2, op3, op4, invl, _typ, _typ2) \
|
||||||
|
{ \
|
||||||
|
.opc1 = op1, \
|
||||||
|
.opc2 = op2, \
|
||||||
|
.opc3 = op3, \
|
||||||
|
.opc4 = op4, \
|
||||||
|
.handler = { \
|
||||||
|
.inval1 = invl, \
|
||||||
|
.type = _typ, \
|
||||||
|
.type2 = _typ2, \
|
||||||
|
.handler = &gen_##name, \
|
||||||
|
}, \
|
||||||
|
.oname = stringify(name), \
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* SPR load/store helpers */
|
/* SPR load/store helpers */
|
||||||
|
@ -11905,9 +11937,10 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
|
||||||
} else {
|
} else {
|
||||||
ctx.opcode = cpu_ldl_code(env, ctx.nip);
|
ctx.opcode = cpu_ldl_code(env, ctx.nip);
|
||||||
}
|
}
|
||||||
LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n",
|
LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n",
|
||||||
ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
|
ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
|
||||||
opc3(ctx.opcode), ctx.le_mode ? "little" : "big");
|
opc3(ctx.opcode), opc4(ctx.opcode),
|
||||||
|
ctx.le_mode ? "little" : "big");
|
||||||
ctx.nip += 4;
|
ctx.nip += 4;
|
||||||
table = env->opcodes;
|
table = env->opcodes;
|
||||||
handler = table[opc1(ctx.opcode)];
|
handler = table[opc1(ctx.opcode)];
|
||||||
|
@ -11917,14 +11950,20 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
|
||||||
if (is_indirect_opcode(handler)) {
|
if (is_indirect_opcode(handler)) {
|
||||||
table = ind_table(handler);
|
table = ind_table(handler);
|
||||||
handler = table[opc3(ctx.opcode)];
|
handler = table[opc3(ctx.opcode)];
|
||||||
|
if (is_indirect_opcode(handler)) {
|
||||||
|
table = ind_table(handler);
|
||||||
|
handler = table[opc4(ctx.opcode)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Is opcode *REALLY* valid ? */
|
/* Is opcode *REALLY* valid ? */
|
||||||
if (unlikely(handler->handler == &gen_invalid)) {
|
if (unlikely(handler->handler == &gen_invalid)) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: "
|
qemu_log_mask(LOG_GUEST_ERROR, "invalid/unsupported opcode: "
|
||||||
"%02x - %02x - %02x (%08x) " TARGET_FMT_lx " %d\n",
|
"%02x - %02x - %02x - %02x (%08x) "
|
||||||
|
TARGET_FMT_lx " %d\n",
|
||||||
opc1(ctx.opcode), opc2(ctx.opcode),
|
opc1(ctx.opcode), opc2(ctx.opcode),
|
||||||
opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, (int)msr_ir);
|
opc3(ctx.opcode), opc4(ctx.opcode),
|
||||||
|
ctx.opcode, ctx.nip - 4, (int)msr_ir);
|
||||||
} else {
|
} else {
|
||||||
uint32_t inval;
|
uint32_t inval;
|
||||||
|
|
||||||
|
@ -11936,9 +11975,10 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
|
||||||
|
|
||||||
if (unlikely((ctx.opcode & inval) != 0)) {
|
if (unlikely((ctx.opcode & inval) != 0)) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: "
|
qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for opcode: "
|
||||||
"%02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n",
|
"%02x - %02x - %02x - %02x (%08x) "
|
||||||
ctx.opcode & inval, opc1(ctx.opcode),
|
TARGET_FMT_lx "\n", ctx.opcode & inval,
|
||||||
opc2(ctx.opcode), opc3(ctx.opcode),
|
opc1(ctx.opcode), opc2(ctx.opcode),
|
||||||
|
opc3(ctx.opcode), opc4(ctx.opcode),
|
||||||
ctx.opcode, ctx.nip - 4);
|
ctx.opcode, ctx.nip - 4);
|
||||||
gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL);
|
gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL);
|
||||||
break;
|
break;
|
||||||
|
@ -11965,9 +12005,9 @@ void gen_intermediate_code(CPUPPCState *env, struct TranslationBlock *tb)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tcg_check_temp_count()) {
|
if (tcg_check_temp_count()) {
|
||||||
fprintf(stderr, "Opcode %02x %02x %02x (%08x) leaked temporaries\n",
|
fprintf(stderr, "Opcode %02x %02x %02x %02x (%08x) leaked "
|
||||||
opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode),
|
"temporaries\n", opc1(ctx.opcode), opc2(ctx.opcode),
|
||||||
ctx.opcode);
|
opc3(ctx.opcode), opc4(ctx.opcode), ctx.opcode);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9253,13 +9253,47 @@ static int register_dblind_insn (opc_handler_t **ppc_opcodes,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int register_trplind_insn(opc_handler_t **ppc_opcodes,
|
||||||
|
unsigned char idx1, unsigned char idx2,
|
||||||
|
unsigned char idx3, unsigned char idx4,
|
||||||
|
opc_handler_t *handler)
|
||||||
|
{
|
||||||
|
opc_handler_t **table;
|
||||||
|
|
||||||
|
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
|
||||||
|
printf("*** ERROR: unable to join indirect table idx "
|
||||||
|
"[%02x-%02x]\n", idx1, idx2);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
table = ind_table(ppc_opcodes[idx1]);
|
||||||
|
if (register_ind_in_table(table, idx2, idx3, NULL) < 0) {
|
||||||
|
printf("*** ERROR: unable to join 2nd-level indirect table idx "
|
||||||
|
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
table = ind_table(table[idx2]);
|
||||||
|
if (register_ind_in_table(table, idx3, idx4, handler) < 0) {
|
||||||
|
printf("*** ERROR: unable to insert opcode "
|
||||||
|
"[%02x-%02x-%02x-%02x]\n", idx1, idx2, idx3, idx4);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
|
static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
|
||||||
{
|
{
|
||||||
if (insn->opc2 != 0xFF) {
|
if (insn->opc2 != 0xFF) {
|
||||||
if (insn->opc3 != 0xFF) {
|
if (insn->opc3 != 0xFF) {
|
||||||
if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
|
if (insn->opc4 != 0xFF) {
|
||||||
insn->opc3, &insn->handler) < 0)
|
if (register_trplind_insn(ppc_opcodes, insn->opc1, insn->opc2,
|
||||||
return -1;
|
insn->opc3, insn->opc4,
|
||||||
|
&insn->handler) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
|
||||||
|
insn->opc3, &insn->handler) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (register_ind_insn(ppc_opcodes, insn->opc1,
|
if (register_ind_insn(ppc_opcodes, insn->opc1,
|
||||||
insn->opc2, &insn->handler) < 0)
|
insn->opc2, &insn->handler) < 0)
|
||||||
|
@ -9335,7 +9369,7 @@ static void dump_ppc_insns (CPUPPCState *env)
|
||||||
{
|
{
|
||||||
opc_handler_t **table, *handler;
|
opc_handler_t **table, *handler;
|
||||||
const char *p, *q;
|
const char *p, *q;
|
||||||
uint8_t opc1, opc2, opc3;
|
uint8_t opc1, opc2, opc3, opc4;
|
||||||
|
|
||||||
printf("Instructions set:\n");
|
printf("Instructions set:\n");
|
||||||
/* opc1 is 6 bits long */
|
/* opc1 is 6 bits long */
|
||||||
|
@ -9355,34 +9389,51 @@ static void dump_ppc_insns (CPUPPCState *env)
|
||||||
for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN;
|
for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN;
|
||||||
opc3++) {
|
opc3++) {
|
||||||
handler = table[opc3];
|
handler = table[opc3];
|
||||||
if (handler->handler != &gen_invalid) {
|
if (is_indirect_opcode(handler)) {
|
||||||
/* Special hack to properly dump SPE insns */
|
table = ind_table(handler);
|
||||||
p = strchr(handler->oname, '_');
|
/* opc4 is 5 bits long */
|
||||||
if (p == NULL) {
|
for (opc4 = 0; opc4 < PPC_CPU_INDIRECT_OPCODES_LEN;
|
||||||
printf("INSN: %02x %02x %02x (%02d %04d) : "
|
opc4++) {
|
||||||
"%s\n",
|
handler = table[opc4];
|
||||||
opc1, opc2, opc3, opc1,
|
if (handler->handler != &gen_invalid) {
|
||||||
(opc3 << 5) | opc2,
|
printf("INSN: %02x %02x %02x %02x -- "
|
||||||
handler->oname);
|
"(%02d %04d %02d) : %s\n",
|
||||||
} else {
|
opc1, opc2, opc3, opc4,
|
||||||
q = "speundef";
|
opc1, (opc3 << 5) | opc2, opc4,
|
||||||
if ((p - handler->oname) != strlen(q) ||
|
|
||||||
memcmp(handler->oname, q, strlen(q)) != 0) {
|
|
||||||
/* First instruction */
|
|
||||||
printf("INSN: %02x %02x %02x (%02d %04d) : "
|
|
||||||
"%.*s\n",
|
|
||||||
opc1, opc2 << 1, opc3, opc1,
|
|
||||||
(opc3 << 6) | (opc2 << 1),
|
|
||||||
(int)(p - handler->oname),
|
|
||||||
handler->oname);
|
handler->oname);
|
||||||
}
|
}
|
||||||
if (strcmp(p + 1, q) != 0) {
|
}
|
||||||
/* Second instruction */
|
} else {
|
||||||
|
if (handler->handler != &gen_invalid) {
|
||||||
|
/* Special hack to properly dump SPE insns */
|
||||||
|
p = strchr(handler->oname, '_');
|
||||||
|
if (p == NULL) {
|
||||||
printf("INSN: %02x %02x %02x (%02d %04d) : "
|
printf("INSN: %02x %02x %02x (%02d %04d) : "
|
||||||
"%s\n",
|
"%s\n",
|
||||||
opc1, (opc2 << 1) | 1, opc3, opc1,
|
opc1, opc2, opc3, opc1,
|
||||||
(opc3 << 6) | (opc2 << 1) | 1,
|
(opc3 << 5) | opc2,
|
||||||
p + 1);
|
handler->oname);
|
||||||
|
} else {
|
||||||
|
q = "speundef";
|
||||||
|
if ((p - handler->oname) != strlen(q)
|
||||||
|
|| (memcmp(handler->oname, q, strlen(q))
|
||||||
|
!= 0)) {
|
||||||
|
/* First instruction */
|
||||||
|
printf("INSN: %02x %02x %02x"
|
||||||
|
"(%02d %04d) : %.*s\n",
|
||||||
|
opc1, opc2 << 1, opc3, opc1,
|
||||||
|
(opc3 << 6) | (opc2 << 1),
|
||||||
|
(int)(p - handler->oname),
|
||||||
|
handler->oname);
|
||||||
|
}
|
||||||
|
if (strcmp(p + 1, q) != 0) {
|
||||||
|
/* Second instruction */
|
||||||
|
printf("INSN: %02x %02x %02x "
|
||||||
|
"(%02d %04d) : %s\n", opc1,
|
||||||
|
(opc2 << 1) | 1, opc3, opc1,
|
||||||
|
(opc3 << 6) | (opc2 << 1) | 1,
|
||||||
|
p + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9858,8 +9909,8 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(dev);
|
PowerPCCPU *cpu = POWERPC_CPU(dev);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
opc_handler_t **table;
|
opc_handler_t **table, **table_2;
|
||||||
int i, j;
|
int i, j, k;
|
||||||
|
|
||||||
cpu_exec_exit(CPU(dev));
|
cpu_exec_exit(CPU(dev));
|
||||||
|
|
||||||
|
@ -9870,10 +9921,20 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error **errp)
|
||||||
if (is_indirect_opcode(env->opcodes[i])) {
|
if (is_indirect_opcode(env->opcodes[i])) {
|
||||||
table = ind_table(env->opcodes[i]);
|
table = ind_table(env->opcodes[i]);
|
||||||
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) {
|
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) {
|
||||||
if (table[j] != &invalid_handler &&
|
if (table[j] == &invalid_handler) {
|
||||||
is_indirect_opcode(table[j])) {
|
continue;
|
||||||
|
}
|
||||||
|
if (is_indirect_opcode(table[j])) {
|
||||||
|
table_2 = ind_table(table[j]);
|
||||||
|
for (k = 0; k < PPC_CPU_INDIRECT_OPCODES_LEN; k++) {
|
||||||
|
if (table_2[k] != &invalid_handler &&
|
||||||
|
is_indirect_opcode(table_2[k])) {
|
||||||
|
g_free((opc_handler_t *)((uintptr_t)table_2[k] &
|
||||||
|
~PPC_INDIRECT));
|
||||||
|
}
|
||||||
|
}
|
||||||
g_free((opc_handler_t *)((uintptr_t)table[j] &
|
g_free((opc_handler_t *)((uintptr_t)table[j] &
|
||||||
~PPC_INDIRECT));
|
~PPC_INDIRECT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] &
|
g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] &
|
||||||
|
|
Loading…
Reference in New Issue