Skip to content

Commit

Permalink
target-ppc: introduce opc4 for Expanded Opcode
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
nikunjad authored and dgibson committed Sep 7, 2016
1 parent 5f29cc8 commit 323ad19
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 54 deletions.
82 changes: 61 additions & 21 deletions target-ppc/translate.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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) */
Expand Down Expand Up @@ -589,7 +592,7 @@ EXTRACT_HELPER(SP, 19, 2);
.opc1 = op1, \
.opc2 = op2, \
.opc3 = op3, \
.pad = { 0, }, \
.opc4 = 0xff, \
.handler = { \
.inval1 = invl, \
.type = _typ, \
Expand All @@ -604,7 +607,7 @@ EXTRACT_HELPER(SP, 19, 2);
.opc1 = op1, \
.opc2 = op2, \
.opc3 = op3, \
.pad = { 0, }, \
.opc4 = 0xff, \
.handler = { \
.inval1 = invl1, \
.inval2 = invl2, \
Expand All @@ -620,7 +623,7 @@ EXTRACT_HELPER(SP, 19, 2);
.opc1 = op1, \
.opc2 = op2, \
.opc3 = op3, \
.pad = { 0, }, \
.opc4 = 0xff, \
.handler = { \
.inval1 = invl, \
.type = _typ, \
Expand All @@ -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, \
Expand All @@ -650,7 +668,7 @@ EXTRACT_HELPER(SP, 19, 2);
.opc1 = op1, \
.opc2 = op2, \
.opc3 = op3, \
.pad = { 0, }, \
.opc4 = 0xff, \
.handler = { \
.inval1 = invl1, \
.inval2 = invl2, \
Expand All @@ -665,7 +683,7 @@ EXTRACT_HELPER(SP, 19, 2);
.opc1 = op1, \
.opc2 = op2, \
.opc3 = op3, \
.pad = { 0, }, \
.opc4 = 0xff, \
.handler = { \
.inval1 = invl, \
.type = _typ, \
Expand All @@ -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 */
Expand Down Expand Up @@ -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)];
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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);
}
}
Expand Down
127 changes: 94 additions & 33 deletions target-ppc/translate_init.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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 */
Expand All @@ -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);
}
}
}
}
Expand Down Expand Up @@ -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));

Expand All @@ -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] &
Expand Down

0 comments on commit 323ad19

Please sign in to comment.