mirror of https://github.com/proxmox/mirror_qemu
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>master
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) \
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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] &
|
||||
|
|
Loading…
Reference in New Issue