Annotation of qemu/translate-all.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  *  Host code generation
                      3:  * 
                      4:  *  Copyright (c) 2003 Fabrice Bellard
                      5:  *
                      6:  * This library is free software; you can redistribute it and/or
                      7:  * modify it under the terms of the GNU Lesser General Public
                      8:  * License as published by the Free Software Foundation; either
                      9:  * version 2 of the License, or (at your option) any later version.
                     10:  *
                     11:  * This library is distributed in the hope that it will be useful,
                     12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     14:  * Lesser General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU Lesser General Public
                     17:  * License along with this library; if not, write to the Free Software
                     18:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     19:  */
                     20: #include <stdarg.h>
                     21: #include <stdlib.h>
                     22: #include <stdio.h>
                     23: #include <string.h>
                     24: #include <inttypes.h>
                     25: 
                     26: #include "config.h"
                     27: 
                     28: #define NO_CPU_IO_DEFS
                     29: #include "cpu.h"
                     30: #include "exec-all.h"
                     31: #include "disas.h"
                     32: 
                     33: extern int dyngen_code(uint8_t *gen_code_buf,
                     34:                        uint16_t *label_offsets, uint16_t *jmp_offsets,
                     35:                        const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels);
                     36: 
                     37: enum {
                     38: #define DEF(s, n, copy_size) INDEX_op_ ## s,
                     39: #include "opc.h"
                     40: #undef DEF
                     41:     NB_OPS,
                     42: };
                     43: 
                     44: uint16_t gen_opc_buf[OPC_BUF_SIZE];
                     45: uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
                     46: long gen_labels[OPC_BUF_SIZE];
                     47: int nb_gen_labels;
                     48: 
                     49: target_ulong gen_opc_pc[OPC_BUF_SIZE];
                     50: uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
                     51: #if defined(TARGET_I386)
                     52: uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
                     53: #elif defined(TARGET_SPARC)
                     54: target_ulong gen_opc_npc[OPC_BUF_SIZE];
                     55: target_ulong gen_opc_jump_pc[2];
1.1.1.2 ! root       56: #elif defined(TARGET_MIPS)
        !            57: uint32_t gen_opc_hflags[OPC_BUF_SIZE];
1.1       root       58: #endif
                     59: 
                     60: int code_copy_enabled = 1;
                     61: 
                     62: #ifdef DEBUG_DISAS
                     63: static const char *op_str[] = {
                     64: #define DEF(s, n, copy_size) #s,
                     65: #include "opc.h"
                     66: #undef DEF
                     67: };
                     68: 
                     69: static uint8_t op_nb_args[] = {
                     70: #define DEF(s, n, copy_size) n,
                     71: #include "opc.h"
                     72: #undef DEF
                     73: };
                     74: 
                     75: static const unsigned short opc_copy_size[] = {
                     76: #define DEF(s, n, copy_size) copy_size,
                     77: #include "opc.h"
                     78: #undef DEF
                     79: };
                     80: 
                     81: void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
                     82: {
                     83:     const uint16_t *opc_ptr;
                     84:     const uint32_t *opparam_ptr;
                     85:     int c, n, i;
                     86: 
                     87:     opc_ptr = opc_buf;
                     88:     opparam_ptr = opparam_buf;
                     89:     for(;;) {
                     90:         c = *opc_ptr++;
                     91:         n = op_nb_args[c];
                     92:         fprintf(logfile, "0x%04x: %s", 
                     93:                 (int)(opc_ptr - opc_buf - 1), op_str[c]);
                     94:         for(i = 0; i < n; i++) {
                     95:             fprintf(logfile, " 0x%x", opparam_ptr[i]);
                     96:         }
                     97:         fprintf(logfile, "\n");
                     98:         if (c == INDEX_op_end)
                     99:             break;
                    100:         opparam_ptr += n;
                    101:     }
                    102: }
                    103: 
                    104: #endif
                    105: 
                    106: /* compute label info */
                    107: static void dyngen_labels(long *gen_labels, int nb_gen_labels,
                    108:                           uint8_t *gen_code_buf, const uint16_t *opc_buf)
                    109: {
                    110:     uint8_t *gen_code_ptr;
                    111:     int c, i;
                    112:     unsigned long gen_code_addr[OPC_BUF_SIZE];
                    113:     
                    114:     if (nb_gen_labels == 0)
                    115:         return;
                    116:     /* compute the address of each op code */
                    117:     
                    118:     gen_code_ptr = gen_code_buf;
                    119:     i = 0;
                    120:     for(;;) {
                    121:         c = opc_buf[i];
                    122:         gen_code_addr[i] =(unsigned long)gen_code_ptr;
                    123:         if (c == INDEX_op_end)
                    124:             break;
                    125:         gen_code_ptr += opc_copy_size[c];
                    126:         i++;
                    127:     }
                    128:     
                    129:     /* compute the address of each label */
                    130:     for(i = 0; i < nb_gen_labels; i++) {
                    131:         gen_labels[i] = gen_code_addr[gen_labels[i]];
                    132:     }
                    133: }
                    134: 
                    135: /* return non zero if the very first instruction is invalid so that
                    136:    the virtual CPU can trigger an exception. 
                    137: 
                    138:    '*gen_code_size_ptr' contains the size of the generated code (host
                    139:    code).
                    140: */
                    141: int cpu_gen_code(CPUState *env, TranslationBlock *tb,
                    142:                  int max_code_size, int *gen_code_size_ptr)
                    143: {
                    144:     uint8_t *gen_code_buf;
                    145:     int gen_code_size;
                    146: 
                    147: #ifdef USE_CODE_COPY
                    148:     if (code_copy_enabled &&
                    149:         cpu_gen_code_copy(env, tb, max_code_size, &gen_code_size) == 0) {
                    150:         /* nothing more to do */
                    151:     } else
                    152: #endif
                    153:     {
                    154:         if (gen_intermediate_code(env, tb) < 0)
                    155:             return -1;
                    156: 
                    157:         /* generate machine code */
                    158:         tb->tb_next_offset[0] = 0xffff;
                    159:         tb->tb_next_offset[1] = 0xffff;
                    160:         gen_code_buf = tb->tc_ptr;
                    161: #ifdef USE_DIRECT_JUMP
                    162:         /* the following two entries are optional (only used for string ops) */
                    163:         tb->tb_jmp_offset[2] = 0xffff;
                    164:         tb->tb_jmp_offset[3] = 0xffff;
                    165: #endif
                    166:         dyngen_labels(gen_labels, nb_gen_labels, gen_code_buf, gen_opc_buf);
                    167: 
                    168:         gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
                    169: #ifdef USE_DIRECT_JUMP
                    170:                                     tb->tb_jmp_offset,
                    171: #else
                    172:                                     NULL,
                    173: #endif
                    174:                                     gen_opc_buf, gen_opparam_buf, gen_labels);
                    175:     }
                    176:     *gen_code_size_ptr = gen_code_size;
                    177: #ifdef DEBUG_DISAS
                    178:     if (loglevel & CPU_LOG_TB_OUT_ASM) {
                    179:         fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
                    180:         disas(logfile, tb->tc_ptr, *gen_code_size_ptr);
                    181:         fprintf(logfile, "\n");
                    182:         fflush(logfile);
                    183:     }
                    184: #endif
                    185:     return 0;
                    186: }
                    187: 
                    188: /* The cpu state corresponding to 'searched_pc' is restored. 
                    189:  */
                    190: int cpu_restore_state(TranslationBlock *tb, 
                    191:                       CPUState *env, unsigned long searched_pc,
                    192:                       void *puc)
                    193: {
                    194:     int j, c;
                    195:     unsigned long tc_ptr;
                    196:     uint16_t *opc_ptr;
                    197: 
                    198: #ifdef USE_CODE_COPY
                    199:     if (tb->cflags & CF_CODE_COPY) {
                    200:         return cpu_restore_state_copy(tb, env, searched_pc, puc);
                    201:     }
                    202: #endif
                    203:     if (gen_intermediate_code_pc(env, tb) < 0)
                    204:         return -1;
                    205:     
                    206:     /* find opc index corresponding to search_pc */
                    207:     tc_ptr = (unsigned long)tb->tc_ptr;
                    208:     if (searched_pc < tc_ptr)
                    209:         return -1;
                    210:     j = 0;
                    211:     opc_ptr = gen_opc_buf;
                    212:     for(;;) {
                    213:         c = *opc_ptr;
                    214:         if (c == INDEX_op_end)
                    215:             return -1;
                    216:         tc_ptr += opc_copy_size[c];
                    217:         if (searched_pc < tc_ptr)
                    218:             break;
                    219:         opc_ptr++;
                    220:     }
                    221:     j = opc_ptr - gen_opc_buf;
                    222:     /* now find start of instruction before */
                    223:     while (gen_opc_instr_start[j] == 0)
                    224:         j--;
                    225: #if defined(TARGET_I386)
                    226:     {
                    227:         int cc_op;
                    228: #ifdef DEBUG_DISAS
                    229:         if (loglevel & CPU_LOG_TB_OP) {
                    230:             int i;
                    231:             fprintf(logfile, "RESTORE:\n");
                    232:             for(i=0;i<=j; i++) {
                    233:                 if (gen_opc_instr_start[i]) {
                    234:                     fprintf(logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]);
                    235:                 }
                    236:             }
                    237:             fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", 
                    238:                     searched_pc, j, gen_opc_pc[j] - tb->cs_base, 
                    239:                     (uint32_t)tb->cs_base);
                    240:         }
                    241: #endif
                    242:         env->eip = gen_opc_pc[j] - tb->cs_base;
                    243:         cc_op = gen_opc_cc_op[j];
                    244:         if (cc_op != CC_OP_DYNAMIC)
                    245:             env->cc_op = cc_op;
                    246:     }
                    247: #elif defined(TARGET_ARM)
                    248:     env->regs[15] = gen_opc_pc[j];
                    249: #elif defined(TARGET_SPARC)
                    250:     {
                    251:         target_ulong npc;
                    252:         env->pc = gen_opc_pc[j];
                    253:         npc = gen_opc_npc[j];
                    254:         if (npc == 1) {
                    255:             /* dynamic NPC: already stored */
                    256:         } else if (npc == 2) {
                    257:             target_ulong t2 = (target_ulong)puc;
                    258:             /* jump PC: use T2 and the jump targets of the translation */
                    259:             if (t2) 
                    260:                 env->npc = gen_opc_jump_pc[0];
                    261:             else
                    262:                 env->npc = gen_opc_jump_pc[1];
                    263:         } else {
                    264:             env->npc = npc;
                    265:         }
                    266:     }
                    267: #elif defined(TARGET_PPC)
                    268:     {
                    269:         int type;
                    270:         /* for PPC, we need to look at the micro operation to get the
                    271:            access type */
                    272:         env->nip = gen_opc_pc[j];
                    273:         switch(c) {
                    274: #if defined(CONFIG_USER_ONLY)
                    275: #define CASE3(op)\
                    276:         case INDEX_op_ ## op ## _raw
                    277: #else
                    278: #define CASE3(op)\
                    279:         case INDEX_op_ ## op ## _user:\
                    280:         case INDEX_op_ ## op ## _kernel
                    281: #endif
                    282:             
                    283:         CASE3(stfd):
                    284:         CASE3(stfs):
                    285:         CASE3(lfd):
                    286:         CASE3(lfs):
                    287:             type = ACCESS_FLOAT;
                    288:             break;
                    289:         CASE3(lwarx):
                    290:             type = ACCESS_RES;
                    291:             break;
                    292:         CASE3(stwcx):
                    293:             type = ACCESS_RES;
                    294:             break;
                    295:         CASE3(eciwx):
                    296:         CASE3(ecowx):
                    297:             type = ACCESS_EXT;
                    298:             break;
                    299:         default:
                    300:             type = ACCESS_INT;
                    301:             break;
                    302:         }
                    303:         env->access_type = type;
                    304:     }
                    305: #elif defined(TARGET_MIPS)
                    306:     env->PC = gen_opc_pc[j];
1.1.1.2 ! root      307:     env->hflags &= ~MIPS_HFLAG_BMASK;
        !           308:     env->hflags |= gen_opc_hflags[j];
1.1       root      309: #endif
                    310:     return 0;
                    311: }

unix.superglobalmegacorp.com