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", | ... | ... |