Commit 056401eae60953822098ff1dc30860364c9681be

Authored by j_mayer
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
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",
... ...