On Tue, Jul 26, 2016 at 05:28:38PM +0530, Nikunj A Dadhania wrote: > 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 <nik...@linux.vnet.ibm.com>
Reviewed-by: David Gibson <da...@gibson.dropbear.id.au> > --- > target-ppc/translate.c | 82 ++++++++++++++++++++-------- > target-ppc/translate_init.c | 126 > ++++++++++++++++++++++++++++++++------------ > 2 files changed, 154 insertions(+), 54 deletions(-) > > diff --git a/target-ppc/translate.c b/target-ppc/translate.c > index ec7064f..d522566 100644 > --- a/target-ppc/translate.c > +++ b/target-ppc/translate.c > @@ -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) > \ > 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 { > - unsigned char opc1, opc2, opc3; > + unsigned char opc1, opc2, opc3, opc4; > #if HOST_LONG_BITS == 64 /* Explicitly align to 64 bits */ > - unsigned char pad[5]; > -#else > - unsigned char pad[1]; > + unsigned char pad[4]; > #endif > opc_handler_t handler; > const char *oname; > @@ -452,6 +453,8 @@ EXTRACT_HELPER(opc1, 26, 6); > EXTRACT_HELPER(opc2, 1, 5); > /* Opcode part 3 */ > EXTRACT_HELPER(opc3, 6, 5); > +/* Opcode part 4 */ > +EXTRACT_HELPER(opc4, 16, 5); > /* Update Cr0 flags */ > EXTRACT_HELPER(Rc, 0, 1); > /* Update Cr6 flags (Altivec) */ > @@ -589,7 +592,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, > \ > .opc2 = op2, > \ > .opc3 = op3, > \ > - .pad = { 0, }, > \ > + .opc4 = 0xff, > \ > .handler = { > \ > .inval1 = invl, > \ > .type = _typ, > \ > @@ -604,7 +607,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, > \ > .opc2 = op2, > \ > .opc3 = op3, > \ > - .pad = { 0, }, > \ > + .opc4 = 0xff, > \ > .handler = { > \ > .inval1 = invl1, > \ > .inval2 = invl2, > \ > @@ -620,7 +623,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, > \ > .opc2 = op2, > \ > .opc3 = op3, > \ > - .pad = { 0, }, > \ > + .opc4 = 0xff, > \ > .handler = { > \ > .inval1 = invl, > \ > .type = _typ, > \ > @@ -630,13 +633,28 @@ EXTRACT_HELPER(SP, 19, 2); > }, > \ > .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 > #define GEN_OPCODE(name, op1, op2, op3, invl, _typ, _typ2) > \ > { > \ > .opc1 = op1, > \ > .opc2 = op2, > \ > .opc3 = op3, > \ > - .pad = { 0, }, > \ > + .opc4 = 0xff, > \ > .handler = { > \ > .inval1 = invl, > \ > .type = _typ, > \ > @@ -650,7 +668,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, > \ > .opc2 = op2, > \ > .opc3 = op3, > \ > - .pad = { 0, }, > \ > + .opc4 = 0xff, > \ > .handler = { > \ > .inval1 = invl1, > \ > .inval2 = invl2, > \ > @@ -665,7 +683,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, > \ > .opc2 = op2, > \ > .opc3 = op3, > \ > - .pad = { 0, }, > \ > + .opc4 = 0xff, > \ > .handler = { > \ > .inval1 = invl, > \ > .type = _typ, > \ > @@ -674,6 +692,20 @@ EXTRACT_HELPER(SP, 19, 2); > }, > \ > .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 > > /* SPR load/store helpers */ > @@ -11906,9 +11938,10 @@ void gen_intermediate_code(CPUPPCState *env, struct > TranslationBlock *tb) > } else { > ctx.opcode = cpu_ldl_code(env, ctx.nip); > } > - LOG_DISAS("translate opcode %08x (%02x %02x %02x) (%s)\n", > - ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), > - opc3(ctx.opcode), ctx.le_mode ? "little" : "big"); > + LOG_DISAS("translate opcode %08x (%02x %02x %02x %02x) (%s)\n", > + ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), > + opc3(ctx.opcode), opc4(ctx.opcode), > + ctx.le_mode ? "little" : "big"); > ctx.nip += 4; > table = env->opcodes; > handler = table[opc1(ctx.opcode)]; > @@ -11918,14 +11951,20 @@ void gen_intermediate_code(CPUPPCState *env, struct > TranslationBlock *tb) > if (is_indirect_opcode(handler)) { > table = ind_table(handler); > handler = table[opc3(ctx.opcode)]; > + if (is_indirect_opcode(handler)) { > + table = ind_table(handler); > + handler = table[opc4(ctx.opcode)]; > + } > } > } > /* Is opcode *REALLY* valid ? */ > if (unlikely(handler->handler == &gen_invalid)) { > 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), > - 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 { > uint32_t inval; > > @@ -11937,9 +11976,10 @@ void gen_intermediate_code(CPUPPCState *env, struct > TranslationBlock *tb) > > if (unlikely((ctx.opcode & inval) != 0)) { > qemu_log_mask(LOG_GUEST_ERROR, "invalid bits: %08x for > opcode: " > - "%02x - %02x - %02x (%08x) " TARGET_FMT_lx > "\n", > - ctx.opcode & inval, opc1(ctx.opcode), > - opc2(ctx.opcode), opc3(ctx.opcode), > + "%02x - %02x - %02x - %02x (%08x) " > + TARGET_FMT_lx "\n", ctx.opcode & inval, > + opc1(ctx.opcode), opc2(ctx.opcode), > + opc3(ctx.opcode), opc4(ctx.opcode), > ctx.opcode, ctx.nip - 4); > gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL); > break; > @@ -11966,9 +12006,9 @@ void gen_intermediate_code(CPUPPCState *env, struct > TranslationBlock *tb) > break; > } > if (tcg_check_temp_count()) { > - fprintf(stderr, "Opcode %02x %02x %02x (%08x) leaked > temporaries\n", > - opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), > - ctx.opcode); > + fprintf(stderr, "Opcode %02x %02x %02x %02x (%08x) leaked " > + "temporaries\n", opc1(ctx.opcode), opc2(ctx.opcode), > + opc3(ctx.opcode), opc4(ctx.opcode), ctx.opcode); > exit(1); > } > } > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c > index 0d8cff1..f627cfe 100644 > --- a/target-ppc/translate_init.c > +++ b/target-ppc/translate_init.c > @@ -9253,13 +9253,47 @@ static int register_dblind_insn (opc_handler_t > **ppc_opcodes, > 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) > { > if (insn->opc2 != 0xFF) { > if (insn->opc3 != 0xFF) { > - if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2, > - insn->opc3, &insn->handler) < 0) > - return -1; > + if (insn->opc4 != 0xFF) { > + if (register_trplind_insn(ppc_opcodes, insn->opc1, > insn->opc2, > + 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 { > if (register_ind_insn(ppc_opcodes, insn->opc1, > insn->opc2, &insn->handler) < 0) > @@ -9335,7 +9369,7 @@ static void dump_ppc_insns (CPUPPCState *env) > { > opc_handler_t **table, *handler; > const char *p, *q; > - uint8_t opc1, opc2, opc3; > + uint8_t opc1, opc2, opc3, opc4; > > printf("Instructions set:\n"); > /* opc1 is 6 bits long */ > @@ -9355,34 +9389,50 @@ static void dump_ppc_insns (CPUPPCState *env) > for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN; > opc3++) { > handler = table[opc3]; > - 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) : " > - "%s\n", > - opc1, opc2, opc3, opc1, > - (opc3 << 5) | opc2, > - 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), > + if (is_indirect_opcode(handler)) { > + table = ind_table(handler); > + /* opc4 is 5 bits long */ > + for (opc4 = 0; opc4 < > PPC_CPU_INDIRECT_OPCODES_LEN; > + opc4++) { > + handler = table[opc4]; > + if (handler->handler != &gen_invalid) { > + printf("INSN: %02x %02x %02x %02x -- " > + "(%02d %04d %02d) : %s\n", > + opc1, opc2, opc3, opc4, > + opc1, (opc3 << 5) | opc2, opc4, > 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) > : " > "%s\n", > - opc1, (opc2 << 1) | 1, opc3, opc1, > - (opc3 << 6) | (opc2 << 1) | 1, > - p + 1); > + opc1, opc2, opc3, opc1, > + (opc3 << 5) | opc2, > + 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 +9908,8 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, Error > **errp) > { > PowerPCCPU *cpu = POWERPC_CPU(dev); > CPUPPCState *env = &cpu->env; > - opc_handler_t **table; > - int i, j; > + opc_handler_t **table, **table_2; > + int i, j, k; > > cpu_exec_exit(CPU(dev)); > > @@ -9870,10 +9920,20 @@ static void ppc_cpu_unrealizefn(DeviceState *dev, > Error **errp) > if (is_indirect_opcode(env->opcodes[i])) { > table = ind_table(env->opcodes[i]); > for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; j++) { > - if (table[j] != &invalid_handler && > - is_indirect_opcode(table[j])) { > + if (table[j] == &invalid_handler) { > + 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] & > - ~PPC_INDIRECT)); > + ~PPC_INDIRECT)); > } > } > g_free((opc_handler_t *)((uintptr_t)env->opcodes[i] & -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature