Message ID | 1468861517-2508-14-git-send-email-nikunj@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Mon, Jul 18, 2016 at 10:35:17PM +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 <nikunj@linux.vnet.ibm.com> > --- > target-ppc/translate.c | 73 +++++++++++++++++++++++++------ > target-ppc/translate_init.c | 103 ++++++++++++++++++++++++++++++++------------ > 2 files changed, 136 insertions(+), 40 deletions(-) > > diff --git a/target-ppc/translate.c b/target-ppc/translate.c > index 6c5a4a6..733d68d 100644 > --- a/target-ppc/translate.c > +++ b/target-ppc/translate.c > @@ -40,6 +40,7 @@ > /* Include definitions for instructions classes and implementations flags */ > //#define PPC_DEBUG_DISAS > //#define DO_PPC_STATISTICS > +//#define PPC_DUMP_CPU > > #ifdef PPC_DEBUG_DISAS > # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) > @@ -367,12 +368,15 @@ 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]; > + unsigned char pad[4]; > #else > - unsigned char pad[1]; > + unsigned char pad[4]; /* 4-byte pad to maintain pad in opcode table */ IIUC the point here is to align entries to the wordsize. If the worsize is 32-bit you shouldn't need any extra padding here.
David Gibson <david@gibson.dropbear.id.au> writes: > [ Unknown signature status ] > On Mon, Jul 18, 2016 at 10:35:17PM +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 <nikunj@linux.vnet.ibm.com> >> --- >> target-ppc/translate.c | 73 +++++++++++++++++++++++++------ >> target-ppc/translate_init.c | 103 ++++++++++++++++++++++++++++++++------------ >> 2 files changed, 136 insertions(+), 40 deletions(-) >> >> diff --git a/target-ppc/translate.c b/target-ppc/translate.c >> index 6c5a4a6..733d68d 100644 >> --- a/target-ppc/translate.c >> +++ b/target-ppc/translate.c >> @@ -40,6 +40,7 @@ >> /* Include definitions for instructions classes and implementations flags */ >> //#define PPC_DEBUG_DISAS >> //#define DO_PPC_STATISTICS >> +//#define PPC_DUMP_CPU >> >> #ifdef PPC_DEBUG_DISAS >> # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) >> @@ -367,12 +368,15 @@ 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]; >> + unsigned char pad[4]; >> #else >> - unsigned char pad[1]; >> + unsigned char pad[4]; /* 4-byte pad to maintain pad in opcode table */ > > IIUC the point here is to align entries to the wordsize. If the > worsize is 32-bit you shouldn't need any extra padding here. You are right, the reason I had added this here is to keep the code clean in the GEN_OPCODEx #define GEN_OPCODE(name, op1, op2, op3, op4, invl, _typ, _typ2) \ { \ .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ .opc4 = 0xff, \ #if HOST_LONG_BITS == 64 \ .pad = { 0, }, \ #endif \ .handler = { \ .inval1 = invl, \ .type = _typ, \ .type2 = _typ2, \ .handler = &gen_##name, \ .oname = stringify(name), \ }, \ .oname = stringify(name), \ } I am fine with both the approach, but thought of the current one as cleaner, we would waste 4byte per opcode in 32-bit case. Regards Nikunj
On Fri, Jul 22, 2016 at 11:05:54AM +0530, Nikunj A Dadhania wrote: > David Gibson <david@gibson.dropbear.id.au> writes: > > > [ Unknown signature status ] > > On Mon, Jul 18, 2016 at 10:35:17PM +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 <nikunj@linux.vnet.ibm.com> > >> --- > >> target-ppc/translate.c | 73 +++++++++++++++++++++++++------ > >> target-ppc/translate_init.c | 103 ++++++++++++++++++++++++++++++++------------ > >> 2 files changed, 136 insertions(+), 40 deletions(-) > >> > >> diff --git a/target-ppc/translate.c b/target-ppc/translate.c > >> index 6c5a4a6..733d68d 100644 > >> --- a/target-ppc/translate.c > >> +++ b/target-ppc/translate.c > >> @@ -40,6 +40,7 @@ > >> /* Include definitions for instructions classes and implementations flags */ > >> //#define PPC_DEBUG_DISAS > >> //#define DO_PPC_STATISTICS > >> +//#define PPC_DUMP_CPU > >> > >> #ifdef PPC_DEBUG_DISAS > >> # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) > >> @@ -367,12 +368,15 @@ 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]; > >> + unsigned char pad[4]; > >> #else > >> - unsigned char pad[1]; > >> + unsigned char pad[4]; /* 4-byte pad to maintain pad in opcode table */ > > > > IIUC the point here is to align entries to the wordsize. If the > > worsize is 32-bit you shouldn't need any extra padding here. > > You are right, the reason I had added this here is to keep the code > clean in the GEN_OPCODEx > > #define GEN_OPCODE(name, op1, op2, op3, op4, invl, _typ, _typ2) \ > { \ > .opc1 = op1, \ > .opc2 = op2, \ > .opc3 = op3, \ > .opc4 = 0xff, \ > #if HOST_LONG_BITS == 64 \ > .pad = { 0, }, \ > #endif \ Hrm.. you're using C99 designated initializers, which means I'm pretty sure you can just leave out the pad field, since you don't care about it's value. That should avoid the need for an ifdef. > .handler = { \ > .inval1 = invl, \ > .type = _typ, \ > .type2 = _typ2, \ > .handler = &gen_##name, \ > .oname = stringify(name), \ > }, \ > .oname = stringify(name), \ > } > > I am fine with both the approach, but thought of the current one as > cleaner, we would waste 4byte per opcode in 32-bit case. > > Regards > Nikunj >
David Gibson <david@gibson.dropbear.id.au> writes: > [ Unknown signature status ] > On Fri, Jul 22, 2016 at 11:05:54AM +0530, Nikunj A Dadhania wrote: >> David Gibson <david@gibson.dropbear.id.au> writes: >> >> > [ Unknown signature status ] >> > On Mon, Jul 18, 2016 at 10:35:17PM +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 <nikunj@linux.vnet.ibm.com> >> >> --- >> >> target-ppc/translate.c | 73 +++++++++++++++++++++++++------ >> >> target-ppc/translate_init.c | 103 ++++++++++++++++++++++++++++++++------------ >> >> 2 files changed, 136 insertions(+), 40 deletions(-) >> >> >> >> diff --git a/target-ppc/translate.c b/target-ppc/translate.c >> >> index 6c5a4a6..733d68d 100644 >> >> --- a/target-ppc/translate.c >> >> +++ b/target-ppc/translate.c >> >> @@ -40,6 +40,7 @@ >> >> /* Include definitions for instructions classes and implementations flags */ >> >> //#define PPC_DEBUG_DISAS >> >> //#define DO_PPC_STATISTICS >> >> +//#define PPC_DUMP_CPU >> >> >> >> #ifdef PPC_DEBUG_DISAS >> >> # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) >> >> @@ -367,12 +368,15 @@ 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]; >> >> + unsigned char pad[4]; >> >> #else >> >> - unsigned char pad[1]; >> >> + unsigned char pad[4]; /* 4-byte pad to maintain pad in opcode table */ >> > >> > IIUC the point here is to align entries to the wordsize. If the >> > worsize is 32-bit you shouldn't need any extra padding here. >> >> You are right, the reason I had added this here is to keep the code >> clean in the GEN_OPCODEx >> >> #define GEN_OPCODE(name, op1, op2, op3, op4, invl, _typ, _typ2) \ >> { \ >> .opc1 = op1, \ >> .opc2 = op2, \ >> .opc3 = op3, \ >> .opc4 = 0xff, \ >> #if HOST_LONG_BITS == 64 \ >> .pad = { 0, }, \ >> #endif \ > > Hrm.. you're using C99 designated initializers, which means I'm pretty > sure you can just leave out the pad field, since you don't care about > it's value. That should avoid the need for an ifdef. Sure then, will update accordingly. Regards, Nikunj
On Mon, Jul 18, 2016 at 10:35 PM, Nikunj A Dadhania <nikunj@linux.vnet.ibm.com> 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 <nikunj@linux.vnet.ibm.com> > --- > target-ppc/translate.c | 73 +++++++++++++++++++++++++------ > target-ppc/translate_init.c | 103 ++++++++++++++++++++++++++++++++------------ > 2 files changed, 136 insertions(+), 40 deletions(-) > > diff --git a/target-ppc/translate.c b/target-ppc/translate.c > index 6c5a4a6..733d68d 100644 > --- a/target-ppc/translate.c > +++ b/target-ppc/translate.c > @@ -40,6 +40,7 @@ > /* Include definitions for instructions classes and implementations flags */ > //#define PPC_DEBUG_DISAS > //#define DO_PPC_STATISTICS > +//#define PPC_DUMP_CPU > > #ifdef PPC_DEBUG_DISAS > # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) > @@ -367,12 +368,15 @@ 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]; > + unsigned char pad[4]; > #else > - unsigned char pad[1]; > + unsigned char pad[4]; /* 4-byte pad to maintain pad in opcode table */ > #endif > opc_handler_t handler; > const char *oname; > @@ -452,6 +456,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,6 +595,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, \ > .opc2 = op2, \ > .opc3 = op3, \ > + .opc4 = 0xff, \ > .pad = { 0, }, \ > .handler = { \ > .inval1 = invl, \ > @@ -604,6 +611,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, \ > .opc2 = op2, \ > .opc3 = op3, \ > + .opc4 = 0xff, \ > .pad = { 0, }, \ > .handler = { \ > .inval1 = invl1, \ > @@ -620,6 +628,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, \ > .opc2 = op2, \ > .opc3 = op3, \ > + .opc4 = 0xff, \ > .pad = { 0, }, \ > .handler = { \ > .inval1 = invl, \ > @@ -630,12 +639,29 @@ 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, \ > + .pad = { 0, }, \ > + .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, \ > + .opc4 = 0xff, \ > .pad = { 0, }, \ > .handler = { \ > .inval1 = invl, \ > @@ -650,6 +676,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, \ > .opc2 = op2, \ > .opc3 = op3, \ > + .opc4 = 0xff, \ > .pad = { 0, }, \ > .handler = { \ > .inval1 = invl1, \ > @@ -665,6 +692,7 @@ EXTRACT_HELPER(SP, 19, 2); > .opc1 = op1, \ > .opc2 = op2, \ > .opc3 = op3, \ > + .opc4 = 0xff, \ > .pad = { 0, }, \ > .handler = { \ > .inval1 = invl, \ > @@ -674,6 +702,21 @@ 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, \ > + .pad = { 0, }, \ > + .handler = { \ > + .inval1 = invl, \ > + .type = _typ, \ > + .type2 = _typ2, \ > + .handler = &gen_##name, \ > + }, \ > + .oname = stringify(name), \ > +} > #endif > > /* SPR load/store helpers */ > @@ -11946,9 +11989,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)]; > @@ -11958,14 +12002,19 @@ 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; > > @@ -11977,10 +12026,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", > + "%02x - %02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n", > ctx.opcode & inval, opc1(ctx.opcode), > opc2(ctx.opcode), opc3(ctx.opcode), > - ctx.opcode, ctx.nip - 4); > + opc4(ctx.opcode), ctx.opcode, ctx.nip - 4); > gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL); > break; > } > @@ -12006,9 +12055,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", > + fprintf(stderr, "Opcode %02x %02x %02x %02x (%08x) leaked temporaries\n", > opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), > - ctx.opcode); > + opc4(ctx.opcode), ctx.opcode); > exit(1); > } > } > diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c > index d207f68..7c723e9 100644 > --- a/target-ppc/translate_init.c > +++ b/target-ppc/translate_init.c > @@ -9252,13 +9252,45 @@ 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; > +} If you are adding a 3rd level opcode table, explicit freeing of the same from ppc_cpu_unrealizefn() is necessary right ? Regards, Bharata.
Bharata B Rao <bharata.rao@gmail.com> writes: > On Mon, Jul 18, 2016 at 10:35 PM, Nikunj A Dadhania > <nikunj@linux.vnet.ibm.com> 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 <nikunj@linux.vnet.ibm.com> >> --- >> +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; >> +} > > If you are adding a 3rd level opcode table, explicit freeing of the > same from ppc_cpu_unrealizefn() is necessary right ? Yes, you are right, will add in my next revision. Regards, Nikunj
diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 6c5a4a6..733d68d 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -40,6 +40,7 @@ /* Include definitions for instructions classes and implementations flags */ //#define PPC_DEBUG_DISAS //#define DO_PPC_STATISTICS +//#define PPC_DUMP_CPU #ifdef PPC_DEBUG_DISAS # define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) @@ -367,12 +368,15 @@ 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]; + unsigned char pad[4]; #else - unsigned char pad[1]; + unsigned char pad[4]; /* 4-byte pad to maintain pad in opcode table */ #endif opc_handler_t handler; const char *oname; @@ -452,6 +456,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,6 +595,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ + .opc4 = 0xff, \ .pad = { 0, }, \ .handler = { \ .inval1 = invl, \ @@ -604,6 +611,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ + .opc4 = 0xff, \ .pad = { 0, }, \ .handler = { \ .inval1 = invl1, \ @@ -620,6 +628,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ + .opc4 = 0xff, \ .pad = { 0, }, \ .handler = { \ .inval1 = invl, \ @@ -630,12 +639,29 @@ 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, \ + .pad = { 0, }, \ + .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, \ + .opc4 = 0xff, \ .pad = { 0, }, \ .handler = { \ .inval1 = invl, \ @@ -650,6 +676,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ + .opc4 = 0xff, \ .pad = { 0, }, \ .handler = { \ .inval1 = invl1, \ @@ -665,6 +692,7 @@ EXTRACT_HELPER(SP, 19, 2); .opc1 = op1, \ .opc2 = op2, \ .opc3 = op3, \ + .opc4 = 0xff, \ .pad = { 0, }, \ .handler = { \ .inval1 = invl, \ @@ -674,6 +702,21 @@ 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, \ + .pad = { 0, }, \ + .handler = { \ + .inval1 = invl, \ + .type = _typ, \ + .type2 = _typ2, \ + .handler = &gen_##name, \ + }, \ + .oname = stringify(name), \ +} #endif /* SPR load/store helpers */ @@ -11946,9 +11989,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)]; @@ -11958,14 +12002,19 @@ 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; @@ -11977,10 +12026,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", + "%02x - %02x - %02x - %02x (%08x) " TARGET_FMT_lx "\n", ctx.opcode & inval, opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), - ctx.opcode, ctx.nip - 4); + opc4(ctx.opcode), ctx.opcode, ctx.nip - 4); gen_inval_exception(ctxp, POWERPC_EXCP_INVAL_INVAL); break; } @@ -12006,9 +12055,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", + fprintf(stderr, "Opcode %02x %02x %02x %02x (%08x) leaked temporaries\n", opc1(ctx.opcode), opc2(ctx.opcode), opc3(ctx.opcode), - ctx.opcode); + opc4(ctx.opcode), ctx.opcode); exit(1); } } diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index d207f68..7c723e9 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -9252,13 +9252,45 @@ 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) @@ -9334,7 +9366,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 */ @@ -9354,34 +9386,49 @@ 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); + } } } }
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> --- target-ppc/translate.c | 73 +++++++++++++++++++++++++------ target-ppc/translate_init.c | 103 ++++++++++++++++++++++++++++++++------------ 2 files changed, 136 insertions(+), 40 deletions(-)