X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=target-i386%2Ftranslate-copy.c;h=d68764360b7443984ed7c070d9e831e475a76d8b;hb=7385ac0ba2456159a52b9b2cbb5f6c71921d0c23;hp=340864ac70df085ff4a5b32b63ce9e58031c0aac;hpb=58fe2f10f0e9ddd63bc6004776ef6e874101e9c5;p=qemu diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c index 340864a..d687643 100644 --- a/target-i386/translate-copy.c +++ b/target-i386/translate-copy.c @@ -1,6 +1,6 @@ /* * i386 on i386 translation - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -17,27 +17,32 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "config.h" + #include #include #include #include #include -#include #include -#include -#include #include "cpu.h" #include "exec-all.h" #include "disas.h" +#ifdef USE_CODE_COPY + +#include +#include +#include + extern char exec_loop; /* operand size */ enum { OT_BYTE = 0, OT_WORD, - OT_LONG, + OT_LONG, OT_QUAD, }; @@ -52,21 +57,22 @@ typedef struct DisasContext { int override; /* -1 if no override */ int prefix; int aflag, dflag; - uint8_t *pc; /* pc = eip + cs_base */ + target_ulong pc; /* pc = eip + cs_base */ int is_jmp; /* 1 = means jump (stop translation), 2 means CPU static state change (stop translation) */ /* code output */ uint8_t *gen_code_ptr; uint8_t *gen_code_start; - + /* current block context */ - uint8_t *cs_base; /* base of CS segment */ + target_ulong cs_base; /* base of CS segment */ int pe; /* protected mode */ int code32; /* 32 bit code segment */ int f_st; /* currently unused */ int vm86; /* vm86 mode */ int cpl; int iopl; + int flags; struct TranslationBlock *tb; } DisasContext; @@ -99,22 +105,22 @@ static inline void gjmp(DisasContext *s, long val) gl(s, val - (long)(s->gen_code_ptr + 4)); } -static inline void gen_movl_addr_im(DisasContext *s, +static inline void gen_movl_addr_im(DisasContext *s, uint32_t addr, uint32_t val) { gb(s, CPU_SEG); /* seg movl im, addr */ - gb(s, 0xc7); + gb(s, 0xc7); gb(s, 0x05); gl(s, addr); gl(s, val); } -static inline void gen_movw_addr_im(DisasContext *s, +static inline void gen_movw_addr_im(DisasContext *s, uint32_t addr, uint32_t val) { gb(s, CPU_SEG); /* seg movl im, addr */ - gb(s, 0x66); - gb(s, 0xc7); + gb(s, 0x66); + gb(s, 0xc7); gb(s, 0x05); gl(s, addr); gw(s, val); @@ -149,7 +155,7 @@ static void gen_jcc(DisasContext *s, int op, gb(s, 0xe9); /* jmp */ tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start; gl(s, 0); - + tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start; gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip); gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb); @@ -188,7 +194,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) base = rm; index = 0; scale = 0; - + if (base == 4) { havesib = 1; code = ldub_code(s->pc++); @@ -216,7 +222,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) s->pc += 4; break; } - + } else { switch (mod) { case 0: @@ -242,7 +248,7 @@ static inline void gen_lea_modrm(DisasContext *s, int modrm) static inline void parse_modrm(DisasContext *s, int modrm) { if ((modrm & 0xc0) != 0xc0) - gen_lea_modrm(s, modrm); + gen_lea_modrm(s, modrm); } static inline uint32_t insn_get(DisasContext *s, int ot) @@ -271,10 +277,10 @@ static inline uint32_t insn_get(DisasContext *s, int ot) be stopped. */ static int disas_insn(DisasContext *s) { - uint8_t *pc_start, *pc_tmp, *pc_start_insn; + target_ulong pc_start, pc_tmp, pc_start_insn; int b, prefixes, aflag, dflag, next_eip, val; int ot; - int modrm, mod, op; + int modrm, mod, op, rm; pc_start = s->pc; prefixes = 0; @@ -345,7 +351,7 @@ static int disas_insn(DisasContext *s) /* extended op code */ b = ldub_code(s->pc++) | 0x100; goto reswitch; - + /**************************/ /* arith & logic */ case 0x00 ... 0x05: @@ -364,7 +370,7 @@ static int disas_insn(DisasContext *s) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - + switch(f) { case 0: /* OP Ev, Gv */ modrm = ldub_code(s->pc++); @@ -383,13 +389,14 @@ static int disas_insn(DisasContext *s) case 0x80: /* GRP1 */ case 0x81: + case 0x82: case 0x83: { if ((b & 1) == 0) ot = OT_BYTE; else ot = dflag ? OT_LONG : OT_WORD; - + modrm = ldub_code(s->pc++); parse_modrm(s, modrm); @@ -397,6 +404,7 @@ static int disas_insn(DisasContext *s) default: case 0x80: case 0x81: + case 0x82: insn_get(s, ot); break; case 0x83: @@ -467,8 +475,8 @@ static int disas_insn(DisasContext *s) break; case 2: /* call Ev */ /* XXX: optimize and handle MEM exceptions specifically - fs movl %eax, regs[0] - movl Ev, %eax + fs movl %eax, regs[0] + movl Ev, %eax pushl next_eip fs movl %eax, eip */ @@ -477,8 +485,8 @@ static int disas_insn(DisasContext *s) goto unsupported_op; case 4: /* jmp Ev */ /* XXX: optimize and handle MEM exceptions specifically - fs movl %eax, regs[0] - movl Ev, %eax + fs movl %eax, regs[0] + movl Ev, %eax fs movl %eax, eip */ goto unsupported_op; @@ -498,7 +506,7 @@ static int disas_insn(DisasContext *s) ot = dflag ? OT_LONG : OT_WORD; insn_get(s, ot); break; - + case 0x98: /* CWDE/CBW */ break; case 0x99: /* CDQ/CWD */ @@ -518,8 +526,8 @@ static int disas_insn(DisasContext *s) break; case 0x84: /* test Ev, Gv */ - case 0x85: - + case 0x85: + case 0x1c0: case 0x1c1: /* xadd Ev, Gv */ @@ -575,7 +583,7 @@ static int disas_insn(DisasContext *s) goto illegal_op; parse_modrm(s, modrm); break; - + /**************************/ /* push/pop */ case 0x50 ... 0x57: /* push */ @@ -644,48 +652,37 @@ static int disas_insn(DisasContext *s) op = R_GS; do_lxx: goto unsupported_op; -#if 0 /************************/ /* floats */ - case 0xd8 ... 0xdf: + case 0xd8 ... 0xdf: +#if 1 + /* currently not stable enough */ + goto unsupported_op; +#else + if (s->flags & (HF_EM_MASK | HF_TS_MASK)) + goto unsupported_op; +#endif +#if 0 + /* for testing FPU context switch */ + { + static int count; + count = (count + 1) % 3; + if (count != 0) + goto unsupported_op; + } +#endif modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; rm = modrm & 7; op = ((b & 7) << 3) | ((modrm >> 3) & 7); if (mod != 3) { /* memory op */ - gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + parse_modrm(s, modrm); switch(op) { case 0x00 ... 0x07: /* fxxxs */ case 0x10 ... 0x17: /* fixxxl */ case 0x20 ... 0x27: /* fxxxl */ case 0x30 ... 0x37: /* fixxx */ - { - int op1; - op1 = op & 7; - - switch(op >> 4) { - case 0: - gen_op_flds_FT0_A0(); - break; - case 1: - gen_op_fildl_FT0_A0(); - break; - case 2: - gen_op_fldl_FT0_A0(); - break; - case 3: - default: - gen_op_fild_FT0_A0(); - break; - } - - gen_op_fp_arith_ST0_FT0[op1](); - if (op1 == 3) { - /* fcomp needs pop */ - gen_op_fpop(); - } - } break; case 0x08: /* flds */ case 0x0a: /* fsts */ @@ -699,102 +696,28 @@ static int disas_insn(DisasContext *s) case 0x38: /* filds */ case 0x3a: /* fists */ case 0x3b: /* fistps */ - - switch(op & 7) { - case 0: - switch(op >> 4) { - case 0: - gen_op_flds_ST0_A0(); - break; - case 1: - gen_op_fildl_ST0_A0(); - break; - case 2: - gen_op_fldl_ST0_A0(); - break; - case 3: - default: - gen_op_fild_ST0_A0(); - break; - } - break; - default: - switch(op >> 4) { - case 0: - gen_op_fsts_ST0_A0(); - break; - case 1: - gen_op_fistl_ST0_A0(); - break; - case 2: - gen_op_fstl_ST0_A0(); - break; - case 3: - default: - gen_op_fist_ST0_A0(); - break; - } - if ((op & 7) == 3) - gen_op_fpop(); - break; - } - break; case 0x0c: /* fldenv mem */ - gen_op_fldenv_A0(s->dflag); - break; case 0x0d: /* fldcw mem */ - gen_op_fldcw_A0(); - break; case 0x0e: /* fnstenv mem */ - gen_op_fnstenv_A0(s->dflag); - break; case 0x0f: /* fnstcw mem */ - gen_op_fnstcw_A0(); - break; case 0x1d: /* fldt mem */ - gen_op_fldt_ST0_A0(); - break; case 0x1f: /* fstpt mem */ - gen_op_fstt_ST0_A0(); - gen_op_fpop(); - break; case 0x2c: /* frstor mem */ - gen_op_frstor_A0(s->dflag); - break; case 0x2e: /* fnsave mem */ - gen_op_fnsave_A0(s->dflag); - break; case 0x2f: /* fnstsw mem */ - gen_op_fnstsw_A0(); - break; case 0x3c: /* fbld */ - gen_op_fbld_ST0_A0(); - break; case 0x3e: /* fbstp */ - gen_op_fbst_ST0_A0(); - gen_op_fpop(); - break; case 0x3d: /* fildll */ - gen_op_fildll_ST0_A0(); - break; case 0x3f: /* fistpll */ - gen_op_fistll_ST0_A0(); - gen_op_fpop(); break; default: goto illegal_op; } } else { /* register float ops */ - opreg = rm; - switch(op) { case 0x08: /* fld sti */ - gen_op_fpush(); - gen_op_fmov_ST0_STN((opreg + 1) & 7); - break; case 0x09: /* fxchg sti */ - gen_op_fxchg_ST0_STN(opreg); break; case 0x0a: /* grp d9/2 */ switch(rm) { @@ -807,149 +730,43 @@ static int disas_insn(DisasContext *s) case 0x0c: /* grp d9/4 */ switch(rm) { case 0: /* fchs */ - gen_op_fchs_ST0(); - break; case 1: /* fabs */ - gen_op_fabs_ST0(); - break; case 4: /* ftst */ - gen_op_fldz_FT0(); - gen_op_fcom_ST0_FT0(); - break; case 5: /* fxam */ - gen_op_fxam_ST0(); break; default: goto illegal_op; } break; case 0x0d: /* grp d9/5 */ - { - switch(rm) { - case 0: - gen_op_fpush(); - gen_op_fld1_ST0(); - break; - case 1: - gen_op_fpush(); - gen_op_fldl2t_ST0(); - break; - case 2: - gen_op_fpush(); - gen_op_fldl2e_ST0(); - break; - case 3: - gen_op_fpush(); - gen_op_fldpi_ST0(); - break; - case 4: - gen_op_fpush(); - gen_op_fldlg2_ST0(); - break; - case 5: - gen_op_fpush(); - gen_op_fldln2_ST0(); - break; - case 6: - gen_op_fpush(); - gen_op_fldz_ST0(); - break; - default: - goto illegal_op; - } - } - break; - case 0x0e: /* grp d9/6 */ switch(rm) { - case 0: /* f2xm1 */ - gen_op_f2xm1(); - break; - case 1: /* fyl2x */ - gen_op_fyl2x(); - break; - case 2: /* fptan */ - gen_op_fptan(); - break; - case 3: /* fpatan */ - gen_op_fpatan(); - break; - case 4: /* fxtract */ - gen_op_fxtract(); - break; - case 5: /* fprem1 */ - gen_op_fprem1(); - break; - case 6: /* fdecstp */ - gen_op_fdecstp(); + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: break; default: - case 7: /* fincstp */ - gen_op_fincstp(); - break; + goto illegal_op; } break; + case 0x0e: /* grp d9/6 */ + break; case 0x0f: /* grp d9/7 */ - switch(rm) { - case 0: /* fprem */ - gen_op_fprem(); - break; - case 1: /* fyl2xp1 */ - gen_op_fyl2xp1(); - break; - case 2: /* fsqrt */ - gen_op_fsqrt(); - break; - case 3: /* fsincos */ - gen_op_fsincos(); - break; - case 5: /* fscale */ - gen_op_fscale(); - break; - case 4: /* frndint */ - gen_op_frndint(); - break; - case 6: /* fsin */ - gen_op_fsin(); - break; - default: - case 7: /* fcos */ - gen_op_fcos(); - break; - } break; case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */ case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */ case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */ - { - int op1; - - op1 = op & 7; - if (op >= 0x20) { - gen_op_fp_arith_STN_ST0[op1](opreg); - if (op >= 0x30) - gen_op_fpop(); - } else { - gen_op_fmov_FT0_STN(opreg); - gen_op_fp_arith_ST0_FT0[op1](); - } - } break; case 0x02: /* fcom */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); break; case 0x03: /* fcomp */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); break; case 0x15: /* da/5 */ switch(rm) { case 1: /* fucompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); break; default: goto illegal_op; @@ -958,15 +775,10 @@ static int disas_insn(DisasContext *s) case 0x1c: switch(rm) { case 0: /* feni (287 only, just do nop here) */ - break; case 1: /* fdisi (287 only, just do nop here) */ - break; + goto unsupported_op; case 2: /* fclex */ - gen_op_fclex(); - break; case 3: /* fninit */ - gen_op_fninit(); - break; case 4: /* fsetpm (287 only, just do nop here) */ break; default: @@ -974,42 +786,22 @@ static int disas_insn(DisasContext *s) } break; case 0x1d: /* fucomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); - s->cc_op = CC_OP_EFLAGS; break; case 0x1e: /* fcomi */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); - s->cc_op = CC_OP_EFLAGS; + break; + case 0x28: /* ffree sti */ break; case 0x2a: /* fst sti */ - gen_op_fmov_STN_ST0(opreg); break; case 0x2b: /* fstp sti */ - gen_op_fmov_STN_ST0(opreg); - gen_op_fpop(); break; case 0x2c: /* fucom st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); break; case 0x2d: /* fucomp st(i) */ - gen_op_fmov_FT0_STN(opreg); - gen_op_fucom_ST0_FT0(); - gen_op_fpop(); break; case 0x33: /* de/3 */ switch(rm) { case 1: /* fcompp */ - gen_op_fmov_FT0_STN(1); - gen_op_fcom_ST0_FT0(); - gen_op_fpop(); - gen_op_fpop(); break; default: goto illegal_op; @@ -1018,49 +810,25 @@ static int disas_insn(DisasContext *s) case 0x3c: /* df/4 */ switch(rm) { case 0: - gen_op_fnstsw_EAX(); break; default: goto illegal_op; } break; case 0x3d: /* fucomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fucomi_ST0_FT0(); - gen_op_fpop(); - s->cc_op = CC_OP_EFLAGS; break; case 0x3e: /* fcomip */ - if (s->cc_op != CC_OP_DYNAMIC) - gen_op_set_cc_op(s->cc_op); - gen_op_fmov_FT0_STN(opreg); - gen_op_fcomi_ST0_FT0(); - gen_op_fpop(); - s->cc_op = CC_OP_EFLAGS; break; case 0x10 ... 0x13: /* fcmovxx */ case 0x18 ... 0x1b: - { - int op1; - const static uint8_t fcmov_cc[8] = { - (JCC_B << 1), - (JCC_Z << 1), - (JCC_BE << 1), - (JCC_P << 1), - }; - op1 = fcmov_cc[op & 3] | ((op >> 3) & 1); - gen_setcc(s, op1); - gen_op_fcmov_ST0_STN_T0(opreg); - } break; default: goto illegal_op; } } + s->tb->cflags |= CF_TB_FP_USED; break; -#endif + /**************************/ /* mov */ case 0xc6: @@ -1082,7 +850,7 @@ static int disas_insn(DisasContext *s) goto illegal_op; parse_modrm(s, modrm); break; - + case 0xa0: /* mov EAX, Ov */ case 0xa1: case 0xa2: /* mov Ov, EAX */ @@ -1120,14 +888,14 @@ static int disas_insn(DisasContext *s) parse_modrm(s, modrm); ldub_code(s->pc++); break; - + /************************/ /* string ops */ case 0xa4: /* movsS */ case 0xa5: break; - + case 0xaa: /* stosS */ case 0xab: break; @@ -1187,7 +955,7 @@ static int disas_insn(DisasContext *s) case 0xc3: /* ret */ gb(s, CPU_SEG); - if (!s->dflag) + if (!s->dflag) gb(s, 0x66); /* d16 */ gb(s, 0x8f); /* pop addr */ gb(s, 0x05); @@ -1243,7 +1011,7 @@ static int disas_insn(DisasContext *s) if (dflag) { val = insn_get(s, OT_LONG); } else { - val = (int16_t)insn_get(s, OT_WORD); + val = (int16_t)insn_get(s, OT_WORD); } do_jcc: next_eip = s->pc - s->cs_base; @@ -1303,6 +1071,10 @@ static int disas_insn(DisasContext *s) case 0x90: /* nop */ break; case 0x9b: /* fwait */ + if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == + (HF_MP_MASK | HF_TS_MASK)) { + goto unsupported_op; + } break; case 0xcc: /* int3 */ goto unsupported_op; @@ -1399,34 +1171,36 @@ static int disas_insn(DisasContext *s) #define GEN_CODE_MAX_INSN_SIZE 512 static inline int gen_intermediate_code_internal(CPUState *env, - TranslationBlock *tb, + TranslationBlock *tb, uint8_t *gen_code_ptr, int *gen_code_size_ptr, int search_pc, uint8_t *tc_ptr) { DisasContext dc1, *dc = &dc1; - uint8_t *pc_insn, *pc_start, *gen_code_end; + target_ulong pc_insn, pc_start, cs_base; + uint8_t *gen_code_end; int flags, ret; - uint8_t *cs_base; if (env->nb_breakpoints > 0 || env->singlestep_enabled) return -1; flags = tb->flags; - if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | + if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK)) return -1; if (!(flags & HF_SS32_MASK)) return -1; - gen_code_end = gen_code_ptr + + if (tb->cflags & CF_SINGLE_INSN) + return -1; + gen_code_end = gen_code_ptr + GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE; dc->gen_code_ptr = gen_code_ptr; dc->gen_code_start = gen_code_ptr; /* generate intermediate code */ - pc_start = (uint8_t *)tb->pc; - cs_base = (uint8_t *)tb->cs_base; + pc_start = tb->pc; + cs_base = tb->cs_base; dc->pc = pc_start; dc->cs_base = cs_base; dc->pe = (flags >> HF_PE_SHIFT) & 1; @@ -1436,7 +1210,8 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->cpl = (flags >> HF_CPL_SHIFT) & 3; dc->iopl = (flags >> IOPL_SHIFT) & 3; dc->tb = tb; - + dc->flags = flags; + dc->is_jmp = 0; for(;;) { @@ -1469,12 +1244,14 @@ static inline int gen_intermediate_code_internal(CPUState *env, break; } } - + #ifdef DEBUG_DISAS - if (loglevel) { + if (loglevel & CPU_LOG_TB_IN_ASM) { fprintf(logfile, "----------------\n"); - fprintf(logfile, "IN: COPY: %s\n", lookup_symbol(pc_start)); - disas(logfile, pc_start, dc->pc - pc_start, 0, !dc->code32); + fprintf(logfile, "IN: COPY: %s fpu=%d\n", + lookup_symbol(pc_start), + tb->cflags & CF_TB_FP_USED ? 1 : 0); + target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32); fprintf(logfile, "\n"); } #endif @@ -1482,7 +1259,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, if (!search_pc) { *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start; tb->size = dc->pc - pc_start; - tb->cflags = CF_CODE_COPY; + tb->cflags |= CF_CODE_COPY; return 0; } else { return -1; @@ -1502,14 +1279,14 @@ int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb, tb->tb_jmp_offset[2] = 0xffff; tb->tb_jmp_offset[3] = 0xffff; #endif - return gen_intermediate_code_internal(env, tb, + return gen_intermediate_code_internal(env, tb, tb->tc_ptr, gen_code_size_ptr, 0, NULL); } static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE]; -int cpu_restore_state_copy(TranslationBlock *tb, +int cpu_restore_state_copy(TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc) { @@ -1520,14 +1297,14 @@ int cpu_restore_state_copy(TranslationBlock *tb, if (searched_pc < (unsigned long)tb->tc_ptr) return -1; searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf; - ret = gen_intermediate_code_internal(env, tb, + ret = gen_intermediate_code_internal(env, tb, dummy_gen_code_buf, NULL, 1, (uint8_t *)searched_pc); if (ret < 0) return ret; /* restore all the CPU state from the CPU context from the - signal */ - + signal. The FPU context stays in the host CPU. */ + env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX]; env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX]; env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX]; @@ -1542,3 +1319,5 @@ int cpu_restore_state_copy(TranslationBlock *tb, env->cc_op = CC_OP_EFLAGS; return 0; } + +#endif /* USE_CODE_COPY */