mirror of
https://github.com/qemu/qemu.git
synced 2024-12-13 22:43:32 +08:00
target/ppc: move opcode table logic to translate.c
code motion to remove opcode callback table from translate_init.c.inc to translate.c in preparation to remove the #include <translate_init.c.inc> from translate.c. Also created destroy_ppc_opcodes and removed that logic from ppc_cpu_unrealize Signed-off-by: Bruno Larsen (billionai) <bruno.larsen@eldorado.org.br> Message-Id: <20210429162130.2412-2-bruno.larsen@eldorado.org.br> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
35a5d74e82
commit
7468e2c842
@ -216,6 +216,14 @@ void ppc_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
|
||||
MMUAccessType access_type,
|
||||
int mmu_idx, uintptr_t retaddr);
|
||||
|
||||
/* translate.c */
|
||||
|
||||
/* #define PPC_DUMP_CPU */
|
||||
|
||||
int ppc_fixup_cpu(PowerPCCPU *cpu);
|
||||
void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp);
|
||||
void destroy_ppc_opcodes(PowerPCCPU *cpu);
|
||||
|
||||
/* gdbstub.c */
|
||||
void ppc_gdb_init(CPUState *cs, PowerPCCPUClass *ppc);
|
||||
gchar *ppc_gdb_arch_name(CPUState *cs);
|
||||
|
@ -7825,6 +7825,400 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
||||
#undef RFPL
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Opcode types */
|
||||
enum {
|
||||
PPC_DIRECT = 0, /* Opcode routine */
|
||||
PPC_INDIRECT = 1, /* Indirect opcode table */
|
||||
};
|
||||
|
||||
#define PPC_OPCODE_MASK 0x3
|
||||
|
||||
static inline int is_indirect_opcode(void *handler)
|
||||
{
|
||||
return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT;
|
||||
}
|
||||
|
||||
static inline opc_handler_t **ind_table(void *handler)
|
||||
{
|
||||
return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK);
|
||||
}
|
||||
|
||||
/* Instruction table creation */
|
||||
/* Opcodes tables creation */
|
||||
static void fill_new_table(opc_handler_t **table, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
table[i] = &invalid_handler;
|
||||
}
|
||||
}
|
||||
|
||||
static int create_new_table(opc_handler_t **table, unsigned char idx)
|
||||
{
|
||||
opc_handler_t **tmp;
|
||||
|
||||
tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||
fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||
table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int insert_in_table(opc_handler_t **table, unsigned char idx,
|
||||
opc_handler_t *handler)
|
||||
{
|
||||
if (table[idx] != &invalid_handler) {
|
||||
return -1;
|
||||
}
|
||||
table[idx] = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_direct_insn(opc_handler_t **ppc_opcodes,
|
||||
unsigned char idx, opc_handler_t *handler)
|
||||
{
|
||||
if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
|
||||
printf("*** ERROR: opcode %02x already assigned in main "
|
||||
"opcode table\n", idx);
|
||||
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
|
||||
printf(" Registered handler '%s' - new handler '%s'\n",
|
||||
ppc_opcodes[idx]->oname, handler->oname);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_ind_in_table(opc_handler_t **table,
|
||||
unsigned char idx1, unsigned char idx2,
|
||||
opc_handler_t *handler)
|
||||
{
|
||||
if (table[idx1] == &invalid_handler) {
|
||||
if (create_new_table(table, idx1) < 0) {
|
||||
printf("*** ERROR: unable to create indirect table "
|
||||
"idx=%02x\n", idx1);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!is_indirect_opcode(table[idx1])) {
|
||||
printf("*** ERROR: idx %02x already assigned to a direct "
|
||||
"opcode\n", idx1);
|
||||
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
|
||||
printf(" Registered handler '%s' - new handler '%s'\n",
|
||||
ind_table(table[idx1])[idx2]->oname, handler->oname);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (handler != NULL &&
|
||||
insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
|
||||
printf("*** ERROR: opcode %02x already assigned in "
|
||||
"opcode table %02x\n", idx2, idx1);
|
||||
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
|
||||
printf(" Registered handler '%s' - new handler '%s'\n",
|
||||
ind_table(table[idx1])[idx2]->oname, handler->oname);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_ind_insn(opc_handler_t **ppc_opcodes,
|
||||
unsigned char idx1, unsigned char idx2,
|
||||
opc_handler_t *handler)
|
||||
{
|
||||
return register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
|
||||
}
|
||||
|
||||
static int register_dblind_insn(opc_handler_t **ppc_opcodes,
|
||||
unsigned char idx1, unsigned char idx2,
|
||||
unsigned char idx3, opc_handler_t *handler)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
|
||||
handler) < 0) {
|
||||
printf("*** ERROR: unable to insert opcode "
|
||||
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 (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) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_opcode_table(opc_handler_t **table, int len)
|
||||
{
|
||||
int i, count, tmp;
|
||||
|
||||
for (i = 0, count = 0; i < len; i++) {
|
||||
/* Consistency fixup */
|
||||
if (table[i] == NULL) {
|
||||
table[i] = &invalid_handler;
|
||||
}
|
||||
if (table[i] != &invalid_handler) {
|
||||
if (is_indirect_opcode(table[i])) {
|
||||
tmp = test_opcode_table(ind_table(table[i]),
|
||||
PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||
if (tmp == 0) {
|
||||
free(table[i]);
|
||||
table[i] = &invalid_handler;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void fix_opcode_tables(opc_handler_t **ppc_opcodes)
|
||||
{
|
||||
if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) {
|
||||
printf("*** WARNING: no opcode defined !\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
|
||||
{
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
opcode_t *opc;
|
||||
|
||||
fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN);
|
||||
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
|
||||
if (((opc->handler.type & pcc->insns_flags) != 0) ||
|
||||
((opc->handler.type2 & pcc->insns_flags2) != 0)) {
|
||||
if (register_insn(cpu->opcodes, opc) < 0) {
|
||||
error_setg(errp, "ERROR initializing PowerPC instruction "
|
||||
"0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2,
|
||||
opc->opc3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
fix_opcode_tables(cpu->opcodes);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void destroy_ppc_opcodes(PowerPCCPU *cpu)
|
||||
{
|
||||
opc_handler_t **table, **table_2;
|
||||
int i, j, k;
|
||||
|
||||
for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) {
|
||||
if (cpu->opcodes[i] == &invalid_handler) {
|
||||
continue;
|
||||
}
|
||||
if (is_indirect_opcode(cpu->opcodes[i])) {
|
||||
table = ind_table(cpu->opcodes[i]);
|
||||
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; 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));
|
||||
}
|
||||
}
|
||||
g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] &
|
||||
~PPC_INDIRECT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PPC_DUMP_CPU)
|
||||
static void dump_ppc_insns(CPUPPCState *env)
|
||||
{
|
||||
opc_handler_t **table, *handler;
|
||||
const char *p, *q;
|
||||
uint8_t opc1, opc2, opc3, opc4;
|
||||
|
||||
printf("Instructions set:\n");
|
||||
/* opc1 is 6 bits long */
|
||||
for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) {
|
||||
table = env->opcodes;
|
||||
handler = table[opc1];
|
||||
if (is_indirect_opcode(handler)) {
|
||||
/* opc2 is 5 bits long */
|
||||
for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) {
|
||||
table = env->opcodes;
|
||||
handler = env->opcodes[opc1];
|
||||
table = ind_table(handler);
|
||||
handler = table[opc2];
|
||||
if (is_indirect_opcode(handler)) {
|
||||
table = ind_table(handler);
|
||||
/* opc3 is 5 bits long */
|
||||
for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN;
|
||||
opc3++) {
|
||||
handler = table[opc3];
|
||||
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);
|
||||
}
|
||||
}
|
||||
} 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, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (handler->handler != &gen_invalid) {
|
||||
printf("INSN: %02x %02x -- (%02d %04d) : %s\n",
|
||||
opc1, opc2, opc1, opc2, handler->oname);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (handler->handler != &gen_invalid) {
|
||||
printf("INSN: %02x -- -- (%02d ----) : %s\n",
|
||||
opc1, opc1, handler->oname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
int ppc_fixup_cpu(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
/*
|
||||
* TCG doesn't (yet) emulate some groups of instructions that are
|
||||
* implemented on some otherwise supported CPUs (e.g. VSX and
|
||||
* decimal floating point instructions on POWER7). We remove
|
||||
* unsupported instruction groups from the cpu state's instruction
|
||||
* masks and hope the guest can cope. For at least the pseries
|
||||
* machine, the unavailability of these instructions can be
|
||||
* advertised to the guest via the device tree.
|
||||
*/
|
||||
if ((env->insns_flags & ~PPC_TCG_INSNS)
|
||||
|| (env->insns_flags2 & ~PPC_TCG_INSNS2)) {
|
||||
warn_report("Disabling some instructions which are not "
|
||||
"emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")",
|
||||
env->insns_flags & ~PPC_TCG_INSNS,
|
||||
env->insns_flags2 & ~PPC_TCG_INSNS2);
|
||||
}
|
||||
env->insns_flags &= PPC_TCG_INSNS;
|
||||
env->insns_flags2 &= PPC_TCG_INSNS2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ppc_cpu_dump_statistics(CPUState *cs, int flags)
|
||||
{
|
||||
#if defined(DO_PPC_STATISTICS)
|
||||
|
@ -42,7 +42,6 @@
|
||||
#include "fpu/softfloat.h"
|
||||
#include "qapi/qapi-commands-machine-target.h"
|
||||
|
||||
/* #define PPC_DUMP_CPU */
|
||||
/* #define PPC_DEBUG_SPR */
|
||||
/* #define PPC_DUMP_SPR_ACCESSES */
|
||||
/* #define USE_APPLE_GDB */
|
||||
@ -9560,366 +9559,6 @@ static void dump_ppc_sprs(CPUPPCState *env)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Opcode types */
|
||||
enum {
|
||||
PPC_DIRECT = 0, /* Opcode routine */
|
||||
PPC_INDIRECT = 1, /* Indirect opcode table */
|
||||
};
|
||||
|
||||
#define PPC_OPCODE_MASK 0x3
|
||||
|
||||
static inline int is_indirect_opcode(void *handler)
|
||||
{
|
||||
return ((uintptr_t)handler & PPC_OPCODE_MASK) == PPC_INDIRECT;
|
||||
}
|
||||
|
||||
static inline opc_handler_t **ind_table(void *handler)
|
||||
{
|
||||
return (opc_handler_t **)((uintptr_t)handler & ~PPC_OPCODE_MASK);
|
||||
}
|
||||
|
||||
/* Instruction table creation */
|
||||
/* Opcodes tables creation */
|
||||
static void fill_new_table(opc_handler_t **table, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
table[i] = &invalid_handler;
|
||||
}
|
||||
}
|
||||
|
||||
static int create_new_table(opc_handler_t **table, unsigned char idx)
|
||||
{
|
||||
opc_handler_t **tmp;
|
||||
|
||||
tmp = g_new(opc_handler_t *, PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||
fill_new_table(tmp, PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||
table[idx] = (opc_handler_t *)((uintptr_t)tmp | PPC_INDIRECT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int insert_in_table(opc_handler_t **table, unsigned char idx,
|
||||
opc_handler_t *handler)
|
||||
{
|
||||
if (table[idx] != &invalid_handler) {
|
||||
return -1;
|
||||
}
|
||||
table[idx] = handler;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_direct_insn(opc_handler_t **ppc_opcodes,
|
||||
unsigned char idx, opc_handler_t *handler)
|
||||
{
|
||||
if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
|
||||
printf("*** ERROR: opcode %02x already assigned in main "
|
||||
"opcode table\n", idx);
|
||||
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
|
||||
printf(" Registered handler '%s' - new handler '%s'\n",
|
||||
ppc_opcodes[idx]->oname, handler->oname);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_ind_in_table(opc_handler_t **table,
|
||||
unsigned char idx1, unsigned char idx2,
|
||||
opc_handler_t *handler)
|
||||
{
|
||||
if (table[idx1] == &invalid_handler) {
|
||||
if (create_new_table(table, idx1) < 0) {
|
||||
printf("*** ERROR: unable to create indirect table "
|
||||
"idx=%02x\n", idx1);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!is_indirect_opcode(table[idx1])) {
|
||||
printf("*** ERROR: idx %02x already assigned to a direct "
|
||||
"opcode\n", idx1);
|
||||
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
|
||||
printf(" Registered handler '%s' - new handler '%s'\n",
|
||||
ind_table(table[idx1])[idx2]->oname, handler->oname);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (handler != NULL &&
|
||||
insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
|
||||
printf("*** ERROR: opcode %02x already assigned in "
|
||||
"opcode table %02x\n", idx2, idx1);
|
||||
#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
|
||||
printf(" Registered handler '%s' - new handler '%s'\n",
|
||||
ind_table(table[idx1])[idx2]->oname, handler->oname);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_ind_insn(opc_handler_t **ppc_opcodes,
|
||||
unsigned char idx1, unsigned char idx2,
|
||||
opc_handler_t *handler)
|
||||
{
|
||||
return register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
|
||||
}
|
||||
|
||||
static int register_dblind_insn(opc_handler_t **ppc_opcodes,
|
||||
unsigned char idx1, unsigned char idx2,
|
||||
unsigned char idx3, opc_handler_t *handler)
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
|
||||
handler) < 0) {
|
||||
printf("*** ERROR: unable to insert opcode "
|
||||
"[%02x-%02x-%02x]\n", idx1, idx2, idx3);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 (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) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_opcode_table(opc_handler_t **table, int len)
|
||||
{
|
||||
int i, count, tmp;
|
||||
|
||||
for (i = 0, count = 0; i < len; i++) {
|
||||
/* Consistency fixup */
|
||||
if (table[i] == NULL) {
|
||||
table[i] = &invalid_handler;
|
||||
}
|
||||
if (table[i] != &invalid_handler) {
|
||||
if (is_indirect_opcode(table[i])) {
|
||||
tmp = test_opcode_table(ind_table(table[i]),
|
||||
PPC_CPU_INDIRECT_OPCODES_LEN);
|
||||
if (tmp == 0) {
|
||||
free(table[i]);
|
||||
table[i] = &invalid_handler;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void fix_opcode_tables(opc_handler_t **ppc_opcodes)
|
||||
{
|
||||
if (test_opcode_table(ppc_opcodes, PPC_CPU_OPCODES_LEN) == 0) {
|
||||
printf("*** WARNING: no opcode defined !\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void create_ppc_opcodes(PowerPCCPU *cpu, Error **errp)
|
||||
{
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
opcode_t *opc;
|
||||
|
||||
fill_new_table(cpu->opcodes, PPC_CPU_OPCODES_LEN);
|
||||
for (opc = opcodes; opc < &opcodes[ARRAY_SIZE(opcodes)]; opc++) {
|
||||
if (((opc->handler.type & pcc->insns_flags) != 0) ||
|
||||
((opc->handler.type2 & pcc->insns_flags2) != 0)) {
|
||||
if (register_insn(cpu->opcodes, opc) < 0) {
|
||||
error_setg(errp, "ERROR initializing PowerPC instruction "
|
||||
"0x%02x 0x%02x 0x%02x", opc->opc1, opc->opc2,
|
||||
opc->opc3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
fix_opcode_tables(cpu->opcodes);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
#if defined(PPC_DUMP_CPU)
|
||||
static void dump_ppc_insns(CPUPPCState *env)
|
||||
{
|
||||
opc_handler_t **table, *handler;
|
||||
const char *p, *q;
|
||||
uint8_t opc1, opc2, opc3, opc4;
|
||||
|
||||
printf("Instructions set:\n");
|
||||
/* opc1 is 6 bits long */
|
||||
for (opc1 = 0x00; opc1 < PPC_CPU_OPCODES_LEN; opc1++) {
|
||||
table = env->opcodes;
|
||||
handler = table[opc1];
|
||||
if (is_indirect_opcode(handler)) {
|
||||
/* opc2 is 5 bits long */
|
||||
for (opc2 = 0; opc2 < PPC_CPU_INDIRECT_OPCODES_LEN; opc2++) {
|
||||
table = env->opcodes;
|
||||
handler = env->opcodes[opc1];
|
||||
table = ind_table(handler);
|
||||
handler = table[opc2];
|
||||
if (is_indirect_opcode(handler)) {
|
||||
table = ind_table(handler);
|
||||
/* opc3 is 5 bits long */
|
||||
for (opc3 = 0; opc3 < PPC_CPU_INDIRECT_OPCODES_LEN;
|
||||
opc3++) {
|
||||
handler = table[opc3];
|
||||
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);
|
||||
}
|
||||
}
|
||||
} 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, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (handler->handler != &gen_invalid) {
|
||||
printf("INSN: %02x %02x -- (%02d %04d) : %s\n",
|
||||
opc1, opc2, opc1, opc2, handler->oname);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (handler->handler != &gen_invalid) {
|
||||
printf("INSN: %02x -- -- (%02d ----) : %s\n",
|
||||
opc1, opc1, handler->oname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
static int ppc_fixup_cpu(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
/*
|
||||
* TCG doesn't (yet) emulate some groups of instructions that are
|
||||
* implemented on some otherwise supported CPUs (e.g. VSX and
|
||||
* decimal floating point instructions on POWER7). We remove
|
||||
* unsupported instruction groups from the cpu state's instruction
|
||||
* masks and hope the guest can cope. For at least the pseries
|
||||
* machine, the unavailability of these instructions can be
|
||||
* advertised to the guest via the device tree.
|
||||
*/
|
||||
if ((env->insns_flags & ~PPC_TCG_INSNS)
|
||||
|| (env->insns_flags2 & ~PPC_TCG_INSNS2)) {
|
||||
warn_report("Disabling some instructions which are not "
|
||||
"emulated by TCG (0x%" PRIx64 ", 0x%" PRIx64 ")",
|
||||
env->insns_flags & ~PPC_TCG_INSNS,
|
||||
env->insns_flags2 & ~PPC_TCG_INSNS2);
|
||||
}
|
||||
env->insns_flags &= PPC_TCG_INSNS;
|
||||
env->insns_flags2 &= PPC_TCG_INSNS2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ppc_cpu_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CPUState *cs = CPU(dev);
|
||||
@ -10131,40 +9770,12 @@ static void ppc_cpu_unrealize(DeviceState *dev)
|
||||
{
|
||||
PowerPCCPU *cpu = POWERPC_CPU(dev);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||
opc_handler_t **table, **table_2;
|
||||
int i, j, k;
|
||||
|
||||
pcc->parent_unrealize(dev);
|
||||
|
||||
cpu_remove_sync(CPU(cpu));
|
||||
|
||||
for (i = 0; i < PPC_CPU_OPCODES_LEN; i++) {
|
||||
if (cpu->opcodes[i] == &invalid_handler) {
|
||||
continue;
|
||||
}
|
||||
if (is_indirect_opcode(cpu->opcodes[i])) {
|
||||
table = ind_table(cpu->opcodes[i]);
|
||||
for (j = 0; j < PPC_CPU_INDIRECT_OPCODES_LEN; 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));
|
||||
}
|
||||
}
|
||||
g_free((opc_handler_t *)((uintptr_t)cpu->opcodes[i] &
|
||||
~PPC_INDIRECT));
|
||||
}
|
||||
}
|
||||
destroy_ppc_opcodes(cpu);
|
||||
}
|
||||
|
||||
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
|
||||
|
Loading…
Reference in New Issue
Block a user