Commit 5eb7995e34ebf8cf9a3fc43ed2c7af93149d1b0d
1 parent
1527c87e
Code provision for PowerPC BookE MMU model support.
Better MSR flags initialisation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3189 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
365 additions
and
14 deletions
target-ppc/helper.c
... | ... | @@ -1013,6 +1013,52 @@ void store_40x_sler (CPUPPCState *env, uint32_t val) |
1013 | 1013 | env->spr[SPR_405_SLER] = val; |
1014 | 1014 | } |
1015 | 1015 | |
1016 | +int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx, | |
1017 | + target_ulong address, int rw, | |
1018 | + int access_type) | |
1019 | +{ | |
1020 | + ppcemb_tlb_t *tlb; | |
1021 | + target_phys_addr_t raddr; | |
1022 | + int i, prot, ret; | |
1023 | + | |
1024 | + ret = -1; | |
1025 | + raddr = -1; | |
1026 | + for (i = 0; i < env->nb_tlb; i++) { | |
1027 | + tlb = &env->tlb[i].tlbe; | |
1028 | + if (ppcemb_tlb_check(env, tlb, &raddr, address, | |
1029 | + env->spr[SPR_BOOKE_PID], 1, i) < 0) | |
1030 | + continue; | |
1031 | + if (msr_pr) | |
1032 | + prot = tlb->prot & 0xF; | |
1033 | + else | |
1034 | + prot = (tlb->prot >> 4) & 0xF; | |
1035 | + /* Check the address space */ | |
1036 | + if (access_type == ACCESS_CODE) { | |
1037 | + if (msr_is != (tlb->attr & 1)) | |
1038 | + continue; | |
1039 | + ctx->prot = prot; | |
1040 | + if (prot & PAGE_EXEC) { | |
1041 | + ret = 0; | |
1042 | + break; | |
1043 | + } | |
1044 | + ret = -3; | |
1045 | + } else { | |
1046 | + if (msr_ds != (tlb->attr & 1)) | |
1047 | + continue; | |
1048 | + ctx->prot = prot; | |
1049 | + if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) { | |
1050 | + ret = 0; | |
1051 | + break; | |
1052 | + } | |
1053 | + ret = -2; | |
1054 | + } | |
1055 | + } | |
1056 | + if (ret >= 0) | |
1057 | + ctx->raddr = raddr; | |
1058 | + | |
1059 | + return ret; | |
1060 | +} | |
1061 | + | |
1016 | 1062 | static int check_physical (CPUState *env, mmu_ctx_t *ctx, |
1017 | 1063 | target_ulong eaddr, int rw) |
1018 | 1064 | { |
... | ... | @@ -1115,9 +1161,9 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr, |
1115 | 1161 | cpu_abort(env, "601 MMU model not implemented\n"); |
1116 | 1162 | return -1; |
1117 | 1163 | case PPC_FLAGS_MMU_BOOKE: |
1118 | - /* XXX: TODO */ | |
1119 | - cpu_abort(env, "BookeE MMU model not implemented\n"); | |
1120 | - return -1; | |
1164 | + ret = mmubooke_get_physical_address(env, ctx, eaddr, | |
1165 | + rw, access_type); | |
1166 | + break; | |
1121 | 1167 | case PPC_FLAGS_MMU_BOOKE_FSL: |
1122 | 1168 | /* XXX: TODO */ |
1123 | 1169 | cpu_abort(env, "BookE FSL MMU model not implemented\n"); |
... | ... | @@ -1950,7 +1996,7 @@ void do_interrupt (CPUState *env) |
1950 | 1996 | cpu_abort(env, "Floating point assist exception " |
1951 | 1997 | "is not implemented yet !\n"); |
1952 | 1998 | goto store_next; |
1953 | - /* 64 bits PowerPC exceptions */ | |
1999 | + /* 64 bits PowerPC exceptions */ | |
1954 | 2000 | case EXCP_DSEG: /* 0x0380 */ |
1955 | 2001 | /* XXX: TODO */ |
1956 | 2002 | cpu_abort(env, "Data segment exception is not implemented yet !\n"); |
... | ... | @@ -2446,28 +2492,39 @@ void cpu_dump_rfi (target_ulong RA, target_ulong msr) |
2446 | 2492 | void cpu_ppc_reset (void *opaque) |
2447 | 2493 | { |
2448 | 2494 | CPUPPCState *env; |
2495 | + int i; | |
2449 | 2496 | |
2450 | 2497 | env = opaque; |
2498 | + /* XXX: some of those flags initialisation values could depend | |
2499 | + * on the actual PowerPC implementation | |
2500 | + */ | |
2501 | + for (i = 0; i < 63; i++) | |
2502 | + env->msr[i] = 0; | |
2503 | +#if defined(TARGET_PPC64) | |
2504 | + msr_hv = 0; /* Should be 1... */ | |
2505 | +#endif | |
2506 | + msr_ap = 0; /* TO BE CHECKED */ | |
2507 | + msr_sa = 0; /* TO BE CHECKED */ | |
2508 | + msr_ip = 0; /* TO BE CHECKED */ | |
2451 | 2509 | #if defined (DO_SINGLE_STEP) && 0 |
2452 | 2510 | /* Single step trace mode */ |
2453 | 2511 | msr_se = 1; |
2454 | 2512 | msr_be = 1; |
2455 | 2513 | #endif |
2456 | - msr_fp = 1; /* Allow floating point exceptions */ | |
2457 | - msr_me = 1; /* Allow machine check exceptions */ | |
2458 | -#if defined(TARGET_PPC64) | |
2459 | - msr_sf = 0; /* Boot in 32 bits mode */ | |
2460 | - msr_cm = 0; | |
2461 | -#endif | |
2462 | 2514 | #if defined(CONFIG_USER_ONLY) |
2515 | + msr_fp = 1; /* Allow floating point exceptions */ | |
2463 | 2516 | msr_pr = 1; |
2464 | - tlb_flush(env, 1); | |
2465 | 2517 | #else |
2466 | 2518 | env->nip = 0xFFFFFFFC; |
2467 | 2519 | ppc_tlb_invalidate_all(env); |
2468 | 2520 | #endif |
2469 | 2521 | do_compute_hflags(env); |
2470 | 2522 | env->reserve = -1; |
2523 | + /* Be sure no exception or interrupt is pending */ | |
2524 | + env->pending_interrupts = 0; | |
2525 | + env->exception_index = EXCP_NONE; | |
2526 | + /* Flush all TLBs */ | |
2527 | + tlb_flush(env, 1); | |
2471 | 2528 | } |
2472 | 2529 | |
2473 | 2530 | CPUPPCState *cpu_ppc_init (void) | ... | ... |
target-ppc/op.c
... | ... | @@ -2365,6 +2365,54 @@ void OPPROTO op_wrte (void) |
2365 | 2365 | RETURN(); |
2366 | 2366 | } |
2367 | 2367 | |
2368 | +void OPPROTO op_booke_tlbre0 (void) | |
2369 | +{ | |
2370 | + do_booke_tlbre0(); | |
2371 | + RETURN(); | |
2372 | +} | |
2373 | + | |
2374 | +void OPPROTO op_booke_tlbre1 (void) | |
2375 | +{ | |
2376 | + do_booke_tlbre1(); | |
2377 | + RETURN(); | |
2378 | +} | |
2379 | + | |
2380 | +void OPPROTO op_booke_tlbre2 (void) | |
2381 | +{ | |
2382 | + do_booke_tlbre2(); | |
2383 | + RETURN(); | |
2384 | +} | |
2385 | + | |
2386 | +void OPPROTO op_booke_tlbsx (void) | |
2387 | +{ | |
2388 | + do_booke_tlbsx(); | |
2389 | + RETURN(); | |
2390 | +} | |
2391 | + | |
2392 | +void OPPROTO op_booke_tlbsx_ (void) | |
2393 | +{ | |
2394 | + do_booke_tlbsx_(); | |
2395 | + RETURN(); | |
2396 | +} | |
2397 | + | |
2398 | +void OPPROTO op_booke_tlbwe0 (void) | |
2399 | +{ | |
2400 | + do_booke_tlbwe0(); | |
2401 | + RETURN(); | |
2402 | +} | |
2403 | + | |
2404 | +void OPPROTO op_booke_tlbwe1 (void) | |
2405 | +{ | |
2406 | + do_booke_tlbwe1(); | |
2407 | + RETURN(); | |
2408 | +} | |
2409 | + | |
2410 | +void OPPROTO op_booke_tlbwe2 (void) | |
2411 | +{ | |
2412 | + do_booke_tlbwe2(); | |
2413 | + RETURN(); | |
2414 | +} | |
2415 | + | |
2368 | 2416 | void OPPROTO op_4xx_tlbre_lo (void) |
2369 | 2417 | { |
2370 | 2418 | do_4xx_tlbre_lo(); | ... | ... |
target-ppc/op_helper.c
... | ... | @@ -2605,4 +2605,151 @@ void do_4xx_tlbwe_lo (void) |
2605 | 2605 | } |
2606 | 2606 | #endif |
2607 | 2607 | } |
2608 | + | |
2609 | +/* BookE TLB management */ | |
2610 | +void do_booke_tlbwe0 (void) | |
2611 | +{ | |
2612 | + ppcemb_tlb_t *tlb; | |
2613 | + target_ulong EPN, size; | |
2614 | + int do_flush_tlbs; | |
2615 | + | |
2616 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2617 | + if (loglevel != 0) { | |
2618 | + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); | |
2619 | + } | |
2620 | +#endif | |
2621 | + do_flush_tlbs = 0; | |
2622 | + T0 &= 0x3F; | |
2623 | + tlb = &env->tlb[T0].tlbe; | |
2624 | + EPN = T1 & 0xFFFFFC00; | |
2625 | + if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) | |
2626 | + do_flush_tlbs = 1; | |
2627 | + tlb->EPN = EPN; | |
2628 | + size = booke_tlb_to_page_size((T1 >> 4) & 0xF); | |
2629 | + if ((tlb->prot & PAGE_VALID) && tlb->size < size) | |
2630 | + do_flush_tlbs = 1; | |
2631 | + tlb->size = size; | |
2632 | + tlb->attr &= ~0x1; | |
2633 | + tlb->attr |= (T1 >> 8) & 1; | |
2634 | + if (T1 & 0x200) { | |
2635 | + tlb->prot |= PAGE_VALID; | |
2636 | + } else { | |
2637 | + if (tlb->prot & PAGE_VALID) { | |
2638 | + tlb->prot &= ~PAGE_VALID; | |
2639 | + do_flush_tlbs = 1; | |
2640 | + } | |
2641 | + } | |
2642 | + tlb->PID = env->spr[SPR_BOOKE_PID]; | |
2643 | + if (do_flush_tlbs) | |
2644 | + tlb_flush(env, 1); | |
2645 | +} | |
2646 | + | |
2647 | +void do_booke_tlbwe1 (void) | |
2648 | +{ | |
2649 | + ppcemb_tlb_t *tlb; | |
2650 | + target_phys_addr_t RPN; | |
2651 | + | |
2652 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2653 | + if (loglevel != 0) { | |
2654 | + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); | |
2655 | + } | |
2656 | +#endif | |
2657 | + T0 &= 0x3F; | |
2658 | + tlb = &env->tlb[T0].tlbe; | |
2659 | + RPN = T1 & 0xFFFFFC0F; | |
2660 | + if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) | |
2661 | + tlb_flush(env, 1); | |
2662 | + tlb->RPN = RPN; | |
2663 | +} | |
2664 | + | |
2665 | +void do_booke_tlbwe2 (void) | |
2666 | +{ | |
2667 | + ppcemb_tlb_t *tlb; | |
2668 | + | |
2669 | +#if defined (DEBUG_SOFTWARE_TLB) | |
2670 | + if (loglevel != 0) { | |
2671 | + fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1); | |
2672 | + } | |
2673 | +#endif | |
2674 | + T0 &= 0x3F; | |
2675 | + tlb = &env->tlb[T0].tlbe; | |
2676 | + tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00); | |
2677 | + tlb->prot = tlb->prot & PAGE_VALID; | |
2678 | + if (T1 & 0x1) | |
2679 | + tlb->prot |= PAGE_READ << 4; | |
2680 | + if (T1 & 0x2) | |
2681 | + tlb->prot |= PAGE_WRITE << 4; | |
2682 | + if (T1 & 0x4) | |
2683 | + tlb->prot |= PAGE_EXEC << 4; | |
2684 | + if (T1 & 0x8) | |
2685 | + tlb->prot |= PAGE_READ; | |
2686 | + if (T1 & 0x10) | |
2687 | + tlb->prot |= PAGE_WRITE; | |
2688 | + if (T1 & 0x20) | |
2689 | + tlb->prot |= PAGE_EXEC; | |
2690 | +} | |
2691 | + | |
2692 | +void do_booke_tlbsx (void) | |
2693 | +{ | |
2694 | + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); | |
2695 | +} | |
2696 | + | |
2697 | +void do_booke_tlbsx_ (void) | |
2698 | +{ | |
2699 | + int tmp = xer_so; | |
2700 | + | |
2701 | + T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR]); | |
2702 | + if (T0 != -1) | |
2703 | + tmp |= 0x02; | |
2704 | + env->crf[0] = tmp; | |
2705 | +} | |
2706 | + | |
2707 | +void do_booke_tlbre0 (void) | |
2708 | +{ | |
2709 | + ppcemb_tlb_t *tlb; | |
2710 | + int size; | |
2711 | + | |
2712 | + T0 &= 0x3F; | |
2713 | + tlb = &env->tlb[T0].tlbe; | |
2714 | + T0 = tlb->EPN; | |
2715 | + size = booke_page_size_to_tlb(tlb->size); | |
2716 | + if (size < 0 || size > 0xF) | |
2717 | + size = 1; | |
2718 | + T0 |= size << 4; | |
2719 | + if (tlb->attr & 0x1) | |
2720 | + T0 |= 0x100; | |
2721 | + if (tlb->prot & PAGE_VALID) | |
2722 | + T0 |= 0x200; | |
2723 | + env->spr[SPR_BOOKE_PID] = tlb->PID; | |
2724 | +} | |
2725 | + | |
2726 | +void do_booke_tlbre1 (void) | |
2727 | +{ | |
2728 | + ppcemb_tlb_t *tlb; | |
2729 | + | |
2730 | + T0 &= 0x3F; | |
2731 | + tlb = &env->tlb[T0].tlbe; | |
2732 | + T0 = tlb->RPN; | |
2733 | +} | |
2734 | + | |
2735 | +void do_booke_tlbre2 (void) | |
2736 | +{ | |
2737 | + ppcemb_tlb_t *tlb; | |
2738 | + | |
2739 | + T0 &= 0x3F; | |
2740 | + tlb = &env->tlb[T0].tlbe; | |
2741 | + T0 = tlb->attr & ~0x1; | |
2742 | + if (tlb->prot & (PAGE_READ << 4)) | |
2743 | + T0 |= 0x1; | |
2744 | + if (tlb->prot & (PAGE_WRITE << 4)) | |
2745 | + T0 |= 0x2; | |
2746 | + if (tlb->prot & (PAGE_EXEC << 4)) | |
2747 | + T0 |= 0x4; | |
2748 | + if (tlb->prot & PAGE_READ) | |
2749 | + T0 |= 0x8; | |
2750 | + if (tlb->prot & PAGE_WRITE) | |
2751 | + T0 |= 0x10; | |
2752 | + if (tlb->prot & PAGE_EXEC) | |
2753 | + T0 |= 0x20; | |
2754 | +} | |
2608 | 2755 | #endif /* !CONFIG_USER_ONLY */ | ... | ... |
target-ppc/op_helper.h
... | ... | @@ -156,6 +156,18 @@ void do_POWER_rfsvc (void); |
156 | 156 | void do_op_602_mfrom (void); |
157 | 157 | #endif |
158 | 158 | |
159 | +/* PowerPC BookE specific helpers */ | |
160 | +#if !defined(CONFIG_USER_ONLY) | |
161 | +void do_booke_tlbre0 (void); | |
162 | +void do_booke_tlbre1 (void); | |
163 | +void do_booke_tlbre2 (void); | |
164 | +void do_booke_tlbsx (void); | |
165 | +void do_booke_tlbsx_ (void); | |
166 | +void do_booke_tlbwe0 (void); | |
167 | +void do_booke_tlbwe1 (void); | |
168 | +void do_booke_tlbwe2 (void); | |
169 | +#endif | |
170 | + | |
159 | 171 | /* PowerPC 4xx specific helpers */ |
160 | 172 | void do_405_check_ov (void); |
161 | 173 | void do_405_check_sat (void); | ... | ... |
target-ppc/translate.c
... | ... | @@ -4618,9 +4618,10 @@ GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE) |
4618 | 4618 | RET_CHG_FLOW(ctx); |
4619 | 4619 | #endif |
4620 | 4620 | } |
4621 | + | |
4621 | 4622 | /* TLB management - PowerPC 405 implementation */ |
4622 | 4623 | /* tlbre */ |
4623 | -GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) | |
4624 | +GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) | |
4624 | 4625 | { |
4625 | 4626 | #if defined(CONFIG_USER_ONLY) |
4626 | 4627 | RET_PRIVOPC(ctx); |
... | ... | @@ -4648,7 +4649,7 @@ GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC) |
4648 | 4649 | } |
4649 | 4650 | |
4650 | 4651 | /* tlbsx - tlbsx. */ |
4651 | -GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) | |
4652 | +GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) | |
4652 | 4653 | { |
4653 | 4654 | #if defined(CONFIG_USER_ONLY) |
4654 | 4655 | RET_PRIVOPC(ctx); |
... | ... | @@ -4667,7 +4668,7 @@ GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC) |
4667 | 4668 | } |
4668 | 4669 | |
4669 | 4670 | /* tlbwe */ |
4670 | -GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) | |
4671 | +GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) | |
4671 | 4672 | { |
4672 | 4673 | #if defined(CONFIG_USER_ONLY) |
4673 | 4674 | RET_PRIVOPC(ctx); |
... | ... | @@ -4694,6 +4695,92 @@ GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC) |
4694 | 4695 | #endif |
4695 | 4696 | } |
4696 | 4697 | |
4698 | +/* TLB management - PowerPC BookE implementation */ | |
4699 | +/* tlbre */ | |
4700 | +GEN_HANDLER(tlbre_booke, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE) | |
4701 | +{ | |
4702 | +#if defined(CONFIG_USER_ONLY) | |
4703 | + RET_PRIVOPC(ctx); | |
4704 | +#else | |
4705 | + if (unlikely(!ctx->supervisor)) { | |
4706 | + RET_PRIVOPC(ctx); | |
4707 | + return; | |
4708 | + } | |
4709 | + switch (rB(ctx->opcode)) { | |
4710 | + case 0: | |
4711 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
4712 | + gen_op_booke_tlbre0(); | |
4713 | + gen_op_store_T0_gpr(rD(ctx->opcode)); | |
4714 | + break; | |
4715 | + case 1: | |
4716 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
4717 | + gen_op_booke_tlbre1(); | |
4718 | + gen_op_store_T0_gpr(rD(ctx->opcode)); | |
4719 | + break; | |
4720 | + case 2: | |
4721 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
4722 | + gen_op_booke_tlbre2(); | |
4723 | + gen_op_store_T0_gpr(rD(ctx->opcode)); | |
4724 | + break; | |
4725 | + default: | |
4726 | + RET_INVAL(ctx); | |
4727 | + break; | |
4728 | + } | |
4729 | +#endif | |
4730 | +} | |
4731 | + | |
4732 | +/* tlbsx - tlbsx. */ | |
4733 | +GEN_HANDLER(tlbsx_booke, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE) | |
4734 | +{ | |
4735 | +#if defined(CONFIG_USER_ONLY) | |
4736 | + RET_PRIVOPC(ctx); | |
4737 | +#else | |
4738 | + if (unlikely(!ctx->supervisor)) { | |
4739 | + RET_PRIVOPC(ctx); | |
4740 | + return; | |
4741 | + } | |
4742 | + gen_addr_reg_index(ctx); | |
4743 | + if (Rc(ctx->opcode)) | |
4744 | + gen_op_booke_tlbsx_(); | |
4745 | + else | |
4746 | + gen_op_booke_tlbsx(); | |
4747 | + gen_op_store_T0_gpr(rD(ctx->opcode)); | |
4748 | +#endif | |
4749 | +} | |
4750 | + | |
4751 | +/* tlbwe */ | |
4752 | +GEN_HANDLER(tlbwe_booke, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE) | |
4753 | +{ | |
4754 | +#if defined(CONFIG_USER_ONLY) | |
4755 | + RET_PRIVOPC(ctx); | |
4756 | +#else | |
4757 | + if (unlikely(!ctx->supervisor)) { | |
4758 | + RET_PRIVOPC(ctx); | |
4759 | + return; | |
4760 | + } | |
4761 | + switch (rB(ctx->opcode)) { | |
4762 | + case 0: | |
4763 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
4764 | + gen_op_load_gpr_T1(rS(ctx->opcode)); | |
4765 | + gen_op_booke_tlbwe0(); | |
4766 | + break; | |
4767 | + case 1: | |
4768 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
4769 | + gen_op_load_gpr_T1(rS(ctx->opcode)); | |
4770 | + gen_op_booke_tlbwe1(); | |
4771 | + break; | |
4772 | + case 2: | |
4773 | + gen_op_load_gpr_T0(rA(ctx->opcode)); | |
4774 | + gen_op_load_gpr_T1(rS(ctx->opcode)); | |
4775 | + gen_op_booke_tlbwe2(); | |
4776 | + break; | |
4777 | + default: | |
4778 | + RET_INVAL(ctx); | |
4779 | + break; | |
4780 | + } | |
4781 | +#endif | |
4782 | +} | |
4783 | + | |
4697 | 4784 | /* wrtee */ |
4698 | 4785 | GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON) |
4699 | 4786 | { | ... | ... |