Commit 056401eae60953822098ff1dc30860364c9681be
1 parent
7a51ad82
PowerPC 601 need specific callbacks for its BATs setup.
Implement PowerPC 601 HID0 register, needed for little-endian mode support. As a consequence, we need to merge hflags coming from MSR with other ones. Use little-endian mode from hflags instead of MSR during code translation. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3524 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
136 additions
and
35 deletions
target-ppc/cpu.h
| ... | ... | @@ -651,7 +651,8 @@ struct CPUPPCState { |
| 651 | 651 | /* Those resources are used only in Qemu core */ |
| 652 | 652 | jmp_buf jmp_env; |
| 653 | 653 | int user_mode_only; /* user mode only simulation */ |
| 654 | - target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ | |
| 654 | + target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */ | |
| 655 | + target_ulong hflags_nmsr; /* specific hflags, not comming from MSR */ | |
| 655 | 656 | int mmu_idx; /* precomputed MMU index to speed up mem accesses */ |
| 656 | 657 | |
| 657 | 658 | /* Power management */ |
| ... | ... | @@ -698,6 +699,8 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr); |
| 698 | 699 | target_ulong do_load_dbatl (CPUPPCState *env, int nr); |
| 699 | 700 | void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value); |
| 700 | 701 | void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value); |
| 702 | +void do_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value); | |
| 703 | +void do_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value); | |
| 701 | 704 | target_ulong do_load_sdr1 (CPUPPCState *env); |
| 702 | 705 | void do_store_sdr1 (CPUPPCState *env, target_ulong value); |
| 703 | 706 | #if defined(TARGET_PPC64) | ... | ... |
target-ppc/helper.c
| ... | ... | @@ -482,10 +482,12 @@ static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp, |
| 482 | 482 | int key, pp, valid, prot; |
| 483 | 483 | |
| 484 | 484 | bl = (*BATl & 0x0000003F) << 17; |
| 485 | +#if defined (DEBUG_BATS) | |
| 485 | 486 | if (loglevel != 0) { |
| 486 | 487 | fprintf(logfile, "b %02x ==> bl %08x msk %08x\n", |
| 487 | 488 | *BATl & 0x0000003F, bl, ~bl); |
| 488 | 489 | } |
| 490 | +#endif | |
| 489 | 491 | prot = 0; |
| 490 | 492 | valid = (*BATl >> 6) & 1; |
| 491 | 493 | if (valid) { |
| ... | ... | @@ -1836,6 +1838,76 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) |
| 1836 | 1838 | env->DBAT[1][nr] = value; |
| 1837 | 1839 | } |
| 1838 | 1840 | |
| 1841 | +void do_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value) | |
| 1842 | +{ | |
| 1843 | + target_ulong mask; | |
| 1844 | + int do_inval; | |
| 1845 | + | |
| 1846 | + dump_store_bat(env, 'I', 0, nr, value); | |
| 1847 | + if (env->IBAT[0][nr] != value) { | |
| 1848 | + do_inval = 0; | |
| 1849 | + mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; | |
| 1850 | + if (env->IBAT[1][nr] & 0x40) { | |
| 1851 | + /* Invalidate BAT only if it is valid */ | |
| 1852 | +#if !defined(FLUSH_ALL_TLBS) | |
| 1853 | + do_invalidate_BAT(env, env->IBAT[0][nr], mask); | |
| 1854 | +#else | |
| 1855 | + do_inval = 1; | |
| 1856 | +#endif | |
| 1857 | + } | |
| 1858 | + /* When storing valid upper BAT, mask BEPI and BRPN | |
| 1859 | + * and invalidate all TLBs covered by this BAT | |
| 1860 | + */ | |
| 1861 | + env->IBAT[0][nr] = (value & 0x00001FFFUL) | | |
| 1862 | + (value & ~0x0001FFFFUL & ~mask); | |
| 1863 | + env->DBAT[0][nr] = env->IBAT[0][nr]; | |
| 1864 | + if (env->IBAT[1][nr] & 0x40) { | |
| 1865 | +#if !defined(FLUSH_ALL_TLBS) | |
| 1866 | + do_invalidate_BAT(env, env->IBAT[0][nr], mask); | |
| 1867 | +#else | |
| 1868 | + do_inval = 1; | |
| 1869 | +#endif | |
| 1870 | + } | |
| 1871 | +#if defined(FLUSH_ALL_TLBS) | |
| 1872 | + if (do_inval) | |
| 1873 | + tlb_flush(env, 1); | |
| 1874 | +#endif | |
| 1875 | + } | |
| 1876 | +} | |
| 1877 | + | |
| 1878 | +void do_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value) | |
| 1879 | +{ | |
| 1880 | + target_ulong mask; | |
| 1881 | + int do_inval; | |
| 1882 | + | |
| 1883 | + dump_store_bat(env, 'I', 1, nr, value); | |
| 1884 | + if (env->IBAT[1][nr] != value) { | |
| 1885 | + do_inval = 0; | |
| 1886 | + if (env->IBAT[1][nr] & 0x40) { | |
| 1887 | +#if !defined(FLUSH_ALL_TLBS) | |
| 1888 | + mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL; | |
| 1889 | + do_invalidate_BAT(env, env->IBAT[0][nr], mask); | |
| 1890 | +#else | |
| 1891 | + do_inval = 1; | |
| 1892 | +#endif | |
| 1893 | + } | |
| 1894 | + if (value & 0x40) { | |
| 1895 | +#if !defined(FLUSH_ALL_TLBS) | |
| 1896 | + mask = (value << 17) & 0x0FFE0000UL; | |
| 1897 | + do_invalidate_BAT(env, env->IBAT[0][nr], mask); | |
| 1898 | +#else | |
| 1899 | + do_inval = 1; | |
| 1900 | +#endif | |
| 1901 | + } | |
| 1902 | + env->IBAT[1][nr] = value; | |
| 1903 | + env->DBAT[1][nr] = value; | |
| 1904 | +#if defined(FLUSH_ALL_TLBS) | |
| 1905 | + if (do_inval) | |
| 1906 | + tlb_flush(env, 1); | |
| 1907 | +#endif | |
| 1908 | + } | |
| 1909 | +} | |
| 1910 | + | |
| 1839 | 1911 | /*****************************************************************************/ |
| 1840 | 1912 | /* TLB management */ |
| 1841 | 1913 | void ppc_tlb_invalidate_all (CPUPPCState *env) |
| ... | ... | @@ -2684,6 +2756,7 @@ static always_inline void powerpc_excp (CPUState *env, |
| 2684 | 2756 | * any special case that could occur. Just store MSR and update hflags |
| 2685 | 2757 | */ |
| 2686 | 2758 | env->msr = new_msr; |
| 2759 | + env->hflags_nmsr = 0x00000000; | |
| 2687 | 2760 | hreg_compute_hflags(env); |
| 2688 | 2761 | env->nip = vector; |
| 2689 | 2762 | /* Reset exception state */ | ... | ... |
target-ppc/helper_regs.h
| ... | ... | @@ -58,6 +58,17 @@ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) |
| 58 | 58 | env->tgpr[3] = tmp; |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | +static always_inline void hreg_compute_mem_idx (CPUPPCState *env) | |
| 62 | +{ | |
| 63 | +#if defined (TARGET_PPC64H) | |
| 64 | + /* Precompute MMU index */ | |
| 65 | + if (msr_pr == 0 && msr_hv != 0) | |
| 66 | + env->mmu_idx = 2; | |
| 67 | + else | |
| 68 | +#endif | |
| 69 | + env->mmu_idx = 1 - msr_pr; | |
| 70 | +} | |
| 71 | + | |
| 61 | 72 | static always_inline void hreg_compute_hflags (CPUPPCState *env) |
| 62 | 73 | { |
| 63 | 74 | target_ulong hflags_mask; |
| ... | ... | @@ -70,14 +81,12 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env) |
| 70 | 81 | hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF); |
| 71 | 82 | #if defined (TARGET_PPC64H) |
| 72 | 83 | hflags_mask |= 1ULL << MSR_HV; |
| 73 | - /* Precompute MMU index */ | |
| 74 | - if (msr_pr == 0 && msr_hv != 0) | |
| 75 | - env->mmu_idx = 2; | |
| 76 | - else | |
| 77 | 84 | #endif |
| 78 | 85 | #endif |
| 79 | - env->mmu_idx = 1 - msr_pr; | |
| 86 | + hreg_compute_mem_idx(env); | |
| 80 | 87 | env->hflags = env->msr & hflags_mask; |
| 88 | + /* Merge with hflags coming from other registers */ | |
| 89 | + env->hflags |= env->hflags_nmsr; | |
| 81 | 90 | } |
| 82 | 91 | |
| 83 | 92 | static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) | ... | ... |
target-ppc/op.c
| ... | ... | @@ -2190,30 +2190,27 @@ void OPPROTO op_store_601_rtcu (void) |
| 2190 | 2190 | RETURN(); |
| 2191 | 2191 | } |
| 2192 | 2192 | |
| 2193 | +void OPPROTO op_store_hid0_601 (void) | |
| 2194 | +{ | |
| 2195 | + do_store_hid0_601(); | |
| 2196 | + RETURN(); | |
| 2197 | +} | |
| 2198 | + | |
| 2193 | 2199 | void OPPROTO op_load_601_bat (void) |
| 2194 | 2200 | { |
| 2195 | 2201 | T0 = env->IBAT[PARAM1][PARAM2]; |
| 2196 | 2202 | RETURN(); |
| 2197 | 2203 | } |
| 2198 | -#endif /* !defined(CONFIG_USER_ONLY) */ | |
| 2199 | 2204 | |
| 2200 | -/* 601 unified BATs store. | |
| 2201 | - * To avoid using specific MMU code for 601, we store BATs in | |
| 2202 | - * IBAT and DBAT simultaneously, then emulate unified BATs. | |
| 2203 | - */ | |
| 2204 | -#if !defined(CONFIG_USER_ONLY) | |
| 2205 | 2205 | void OPPROTO op_store_601_batl (void) |
| 2206 | 2206 | { |
| 2207 | - int nr = PARAM1; | |
| 2208 | - | |
| 2209 | - env->IBAT[1][nr] = T0; | |
| 2210 | - env->DBAT[1][nr] = T0; | |
| 2207 | + do_store_ibatl_601(env, PARAM1, T0); | |
| 2211 | 2208 | RETURN(); |
| 2212 | 2209 | } |
| 2213 | 2210 | |
| 2214 | 2211 | void OPPROTO op_store_601_batu (void) |
| 2215 | 2212 | { |
| 2216 | - do_store_601_batu(PARAM1); | |
| 2213 | + do_store_ibatu_601(env, PARAM1, T0); | |
| 2217 | 2214 | RETURN(); |
| 2218 | 2215 | } |
| 2219 | 2216 | #endif /* !defined(CONFIG_USER_ONLY) */ | ... | ... |
target-ppc/op_helper.c
| ... | ... | @@ -1701,12 +1701,23 @@ void do_POWER_rfsvc (void) |
| 1701 | 1701 | __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); |
| 1702 | 1702 | } |
| 1703 | 1703 | |
| 1704 | -/* PowerPC 601 BAT management helper */ | |
| 1705 | -void do_store_601_batu (int nr) | |
| 1704 | +void do_store_hid0_601 (void) | |
| 1706 | 1705 | { |
| 1707 | - do_store_ibatu(env, nr, (uint32_t)T0); | |
| 1708 | - env->DBAT[0][nr] = env->IBAT[0][nr]; | |
| 1709 | - env->DBAT[1][nr] = env->IBAT[1][nr]; | |
| 1706 | + uint32_t hid0; | |
| 1707 | + | |
| 1708 | + hid0 = env->spr[SPR_HID0]; | |
| 1709 | + if ((T0 ^ hid0) & 0x00000008) { | |
| 1710 | + /* Change current endianness */ | |
| 1711 | + env->hflags &= ~(1 << MSR_LE); | |
| 1712 | + env->hflags_nmsr &= ~(1 << MSR_LE); | |
| 1713 | + env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE); | |
| 1714 | + env->hflags |= env->hflags_nmsr; | |
| 1715 | + if (loglevel != 0) { | |
| 1716 | + fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n", | |
| 1717 | + __func__, T0 & 0x8 ? 'l' : 'b', env->hflags); | |
| 1718 | + } | |
| 1719 | + } | |
| 1720 | + env->spr[SPR_HID0] = T0; | |
| 1710 | 1721 | } |
| 1711 | 1722 | #endif |
| 1712 | 1723 | ... | ... |
target-ppc/op_helper.h
| ... | ... | @@ -155,7 +155,6 @@ void do_load_74xx_tlb (int is_code); |
| 155 | 155 | #endif |
| 156 | 156 | |
| 157 | 157 | /* POWER / PowerPC 601 specific helpers */ |
| 158 | -void do_store_601_batu (int nr); | |
| 159 | 158 | void do_POWER_abso (void); |
| 160 | 159 | void do_POWER_clcs (void); |
| 161 | 160 | void do_POWER_div (void); |
| ... | ... | @@ -168,6 +167,7 @@ void do_POWER_mulo (void); |
| 168 | 167 | #if !defined(CONFIG_USER_ONLY) |
| 169 | 168 | void do_POWER_rac (void); |
| 170 | 169 | void do_POWER_rfsvc (void); |
| 170 | +void do_store_hid0_601 (void); | |
| 171 | 171 | #endif |
| 172 | 172 | |
| 173 | 173 | /* PowerPC 602 specific helper */ | ... | ... |
target-ppc/translate.c
| ... | ... | @@ -6801,7 +6801,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, |
| 6801 | 6801 | opc_handler_t **table, *handler; |
| 6802 | 6802 | target_ulong pc_start; |
| 6803 | 6803 | uint16_t *gen_opc_end; |
| 6804 | - int supervisor; | |
| 6804 | + int supervisor, little_endian; | |
| 6805 | 6805 | int single_step, branch_step; |
| 6806 | 6806 | int j, lj = -1; |
| 6807 | 6807 | |
| ... | ... | @@ -6821,11 +6821,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, |
| 6821 | 6821 | #if !defined(CONFIG_USER_ONLY) |
| 6822 | 6822 | ctx.supervisor = supervisor; |
| 6823 | 6823 | #endif |
| 6824 | + little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0; | |
| 6824 | 6825 | #if defined(TARGET_PPC64) |
| 6825 | 6826 | ctx.sf_mode = msr_sf; |
| 6826 | - ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | msr_le; | |
| 6827 | + ctx.mem_idx = (supervisor << 2) | (msr_sf << 1) | little_endian; | |
| 6827 | 6828 | #else |
| 6828 | - ctx.mem_idx = (supervisor << 1) | msr_le; | |
| 6829 | + ctx.mem_idx = (supervisor << 1) | little_endian; | |
| 6829 | 6830 | #endif |
| 6830 | 6831 | ctx.dcache_line_size = env->dcache_line_size; |
| 6831 | 6832 | ctx.fpu_enabled = msr_fp; |
| ... | ... | @@ -6880,18 +6881,16 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, |
| 6880 | 6881 | ctx.nip, supervisor, (int)msr_ir); |
| 6881 | 6882 | } |
| 6882 | 6883 | #endif |
| 6883 | - ctx.opcode = ldl_code(ctx.nip); | |
| 6884 | - if (msr_le) { | |
| 6885 | - ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) | | |
| 6886 | - ((ctx.opcode & 0x00FF0000) >> 8) | | |
| 6887 | - ((ctx.opcode & 0x0000FF00) << 8) | | |
| 6888 | - ((ctx.opcode & 0x000000FF) << 24); | |
| 6884 | + if (unlikely(little_endian)) { | |
| 6885 | + ctx.opcode = bswap32(ldl_code(ctx.nip)); | |
| 6886 | + } else { | |
| 6887 | + ctx.opcode = ldl_code(ctx.nip); | |
| 6889 | 6888 | } |
| 6890 | 6889 | #if defined PPC_DEBUG_DISAS |
| 6891 | 6890 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 6892 | 6891 | fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n", |
| 6893 | 6892 | ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), |
| 6894 | - opc3(ctx.opcode), msr_le ? "little" : "big"); | |
| 6893 | + opc3(ctx.opcode), little_endian ? "little" : "big"); | |
| 6895 | 6894 | } |
| 6896 | 6895 | #endif |
| 6897 | 6896 | ctx.nip += 4; |
| ... | ... | @@ -6986,7 +6985,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, |
| 6986 | 6985 | if (loglevel & CPU_LOG_TB_IN_ASM) { |
| 6987 | 6986 | int flags; |
| 6988 | 6987 | flags = env->bfd_mach; |
| 6989 | - flags |= msr_le << 16; | |
| 6988 | + flags |= little_endian << 16; | |
| 6990 | 6989 | fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); |
| 6991 | 6990 | target_disas(logfile, pc_start, ctx.nip - pc_start, flags); |
| 6992 | 6991 | fprintf(logfile, "\n"); | ... | ... |
target-ppc/translate_init.c
| ... | ... | @@ -314,6 +314,15 @@ static void spr_write_601_rtcl (void *opaque, int sprn) |
| 314 | 314 | { |
| 315 | 315 | gen_op_store_601_rtcl(); |
| 316 | 316 | } |
| 317 | + | |
| 318 | +static void spr_write_hid0_601 (void *opaque, int sprn) | |
| 319 | +{ | |
| 320 | + DisasContext *ctx = opaque; | |
| 321 | + | |
| 322 | + gen_op_store_hid0_601(); | |
| 323 | + /* Must stop the translation as endianness may have changed */ | |
| 324 | + GEN_STOP(ctx); | |
| 325 | +} | |
| 317 | 326 | #endif |
| 318 | 327 | |
| 319 | 328 | /* Unified bats */ |
| ... | ... | @@ -3259,7 +3268,7 @@ static void init_proc_601 (CPUPPCState *env) |
| 3259 | 3268 | /* XXX : not implemented */ |
| 3260 | 3269 | spr_register(env, SPR_HID0, "HID0", |
| 3261 | 3270 | SPR_NOACCESS, SPR_NOACCESS, |
| 3262 | - &spr_read_generic, &spr_write_generic, | |
| 3271 | + &spr_read_generic, &spr_write_hid0_601, | |
| 3263 | 3272 | 0x80010080); |
| 3264 | 3273 | /* XXX : not implemented */ |
| 3265 | 3274 | spr_register(env, SPR_HID1, "HID1", | ... | ... |