aboutsummaryrefslogtreecommitdiff
path: root/target-ppc
diff options
context:
space:
mode:
authorNikunj A Dadhania <nikunj@linux.vnet.ibm.com>2016-07-26 17:28:38 +0530
committerDavid Gibson <david@gibson.dropbear.id.au>2016-09-07 12:33:33 +1000
commit323ad19bcc601d3ec9cb6f0f5b4d67b602fc519e (patch)
tree3fa4719ccc6105cf8b29592fe69b2b39cd63a0c7 /target-ppc
parent5f29cc829225f777ca4697cb955572feebaf0748 (diff)
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>
Diffstat (limited to 'target-ppc')
-rw-r--r--target-ppc/translate.c82
-rw-r--r--target-ppc/translate_init.c127
2 files changed, 155 insertions, 54 deletions
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 0b21ea28ac..4036bc3442 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 */
@@ -11905,9 +11937,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)];
@@ -11917,14 +11950,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;
@@ -11936,9 +11975,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;
@@ -11965,9 +12005,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 6bb4162e6b..293cc3d3d8 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,51 @@ 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 +9909,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 +9921,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] &