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,7 +651,8 @@ struct CPUPPCState {
651 /* Those resources are used only in Qemu core */ 651 /* Those resources are used only in Qemu core */
652 jmp_buf jmp_env; 652 jmp_buf jmp_env;
653 int user_mode_only; /* user mode only simulation */ 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 int mmu_idx; /* precomputed MMU index to speed up mem accesses */ 656 int mmu_idx; /* precomputed MMU index to speed up mem accesses */
656 657
657 /* Power management */ 658 /* Power management */
@@ -698,6 +699,8 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr); @@ -698,6 +699,8 @@ target_ulong do_load_dbatu (CPUPPCState *env, int nr);
698 target_ulong do_load_dbatl (CPUPPCState *env, int nr); 699 target_ulong do_load_dbatl (CPUPPCState *env, int nr);
699 void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value); 700 void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
700 void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value); 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 target_ulong do_load_sdr1 (CPUPPCState *env); 704 target_ulong do_load_sdr1 (CPUPPCState *env);
702 void do_store_sdr1 (CPUPPCState *env, target_ulong value); 705 void do_store_sdr1 (CPUPPCState *env, target_ulong value);
703 #if defined(TARGET_PPC64) 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,10 +482,12 @@ static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp,
482 int key, pp, valid, prot; 482 int key, pp, valid, prot;
483 483
484 bl = (*BATl & 0x0000003F) << 17; 484 bl = (*BATl & 0x0000003F) << 17;
  485 +#if defined (DEBUG_BATS)
485 if (loglevel != 0) { 486 if (loglevel != 0) {
486 fprintf(logfile, "b %02x ==> bl %08x msk %08x\n", 487 fprintf(logfile, "b %02x ==> bl %08x msk %08x\n",
487 *BATl & 0x0000003F, bl, ~bl); 488 *BATl & 0x0000003F, bl, ~bl);
488 } 489 }
  490 +#endif
489 prot = 0; 491 prot = 0;
490 valid = (*BATl >> 6) & 1; 492 valid = (*BATl >> 6) & 1;
491 if (valid) { 493 if (valid) {
@@ -1836,6 +1838,76 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value) @@ -1836,6 +1838,76 @@ void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
1836 env->DBAT[1][nr] = value; 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 /* TLB management */ 1912 /* TLB management */
1841 void ppc_tlb_invalidate_all (CPUPPCState *env) 1913 void ppc_tlb_invalidate_all (CPUPPCState *env)
@@ -2684,6 +2756,7 @@ static always_inline void powerpc_excp (CPUState *env, @@ -2684,6 +2756,7 @@ static always_inline void powerpc_excp (CPUState *env,
2684 * any special case that could occur. Just store MSR and update hflags 2756 * any special case that could occur. Just store MSR and update hflags
2685 */ 2757 */
2686 env->msr = new_msr; 2758 env->msr = new_msr;
  2759 + env->hflags_nmsr = 0x00000000;
2687 hreg_compute_hflags(env); 2760 hreg_compute_hflags(env);
2688 env->nip = vector; 2761 env->nip = vector;
2689 /* Reset exception state */ 2762 /* Reset exception state */
target-ppc/helper_regs.h
@@ -58,6 +58,17 @@ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env) @@ -58,6 +58,17 @@ static always_inline void hreg_swap_gpr_tgpr (CPUPPCState *env)
58 env->tgpr[3] = tmp; 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 static always_inline void hreg_compute_hflags (CPUPPCState *env) 72 static always_inline void hreg_compute_hflags (CPUPPCState *env)
62 { 73 {
63 target_ulong hflags_mask; 74 target_ulong hflags_mask;
@@ -70,14 +81,12 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env) @@ -70,14 +81,12 @@ static always_inline void hreg_compute_hflags (CPUPPCState *env)
70 hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF); 81 hflags_mask |= (1ULL << MSR_CM) | (1ULL << MSR_SF);
71 #if defined (TARGET_PPC64H) 82 #if defined (TARGET_PPC64H)
72 hflags_mask |= 1ULL << MSR_HV; 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 #endif 84 #endif
78 #endif 85 #endif
79 - env->mmu_idx = 1 - msr_pr; 86 + hreg_compute_mem_idx(env);
80 env->hflags = env->msr & hflags_mask; 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 static always_inline int hreg_store_msr (CPUPPCState *env, target_ulong value) 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,30 +2190,27 @@ void OPPROTO op_store_601_rtcu (void)
2190 RETURN(); 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 void OPPROTO op_load_601_bat (void) 2199 void OPPROTO op_load_601_bat (void)
2194 { 2200 {
2195 T0 = env->IBAT[PARAM1][PARAM2]; 2201 T0 = env->IBAT[PARAM1][PARAM2];
2196 RETURN(); 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 void OPPROTO op_store_601_batl (void) 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 RETURN(); 2208 RETURN();
2212 } 2209 }
2213 2210
2214 void OPPROTO op_store_601_batu (void) 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 RETURN(); 2214 RETURN();
2218 } 2215 }
2219 #endif /* !defined(CONFIG_USER_ONLY) */ 2216 #endif /* !defined(CONFIG_USER_ONLY) */
target-ppc/op_helper.c
@@ -1701,12 +1701,23 @@ void do_POWER_rfsvc (void) @@ -1701,12 +1701,23 @@ void do_POWER_rfsvc (void)
1701 __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0); 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 #endif 1722 #endif
1712 1723
target-ppc/op_helper.h
@@ -155,7 +155,6 @@ void do_load_74xx_tlb (int is_code); @@ -155,7 +155,6 @@ void do_load_74xx_tlb (int is_code);
155 #endif 155 #endif
156 156
157 /* POWER / PowerPC 601 specific helpers */ 157 /* POWER / PowerPC 601 specific helpers */
158 -void do_store_601_batu (int nr);  
159 void do_POWER_abso (void); 158 void do_POWER_abso (void);
160 void do_POWER_clcs (void); 159 void do_POWER_clcs (void);
161 void do_POWER_div (void); 160 void do_POWER_div (void);
@@ -168,6 +167,7 @@ void do_POWER_mulo (void); @@ -168,6 +167,7 @@ void do_POWER_mulo (void);
168 #if !defined(CONFIG_USER_ONLY) 167 #if !defined(CONFIG_USER_ONLY)
169 void do_POWER_rac (void); 168 void do_POWER_rac (void);
170 void do_POWER_rfsvc (void); 169 void do_POWER_rfsvc (void);
  170 +void do_store_hid0_601 (void);
171 #endif 171 #endif
172 172
173 /* PowerPC 602 specific helper */ 173 /* PowerPC 602 specific helper */
target-ppc/translate.c
@@ -6801,7 +6801,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, @@ -6801,7 +6801,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
6801 opc_handler_t **table, *handler; 6801 opc_handler_t **table, *handler;
6802 target_ulong pc_start; 6802 target_ulong pc_start;
6803 uint16_t *gen_opc_end; 6803 uint16_t *gen_opc_end;
6804 - int supervisor; 6804 + int supervisor, little_endian;
6805 int single_step, branch_step; 6805 int single_step, branch_step;
6806 int j, lj = -1; 6806 int j, lj = -1;
6807 6807
@@ -6821,11 +6821,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, @@ -6821,11 +6821,12 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
6821 #if !defined(CONFIG_USER_ONLY) 6821 #if !defined(CONFIG_USER_ONLY)
6822 ctx.supervisor = supervisor; 6822 ctx.supervisor = supervisor;
6823 #endif 6823 #endif
  6824 + little_endian = env->hflags & (1 << MSR_LE) ? 1 : 0;
6824 #if defined(TARGET_PPC64) 6825 #if defined(TARGET_PPC64)
6825 ctx.sf_mode = msr_sf; 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 #else 6828 #else
6828 - ctx.mem_idx = (supervisor << 1) | msr_le; 6829 + ctx.mem_idx = (supervisor << 1) | little_endian;
6829 #endif 6830 #endif
6830 ctx.dcache_line_size = env->dcache_line_size; 6831 ctx.dcache_line_size = env->dcache_line_size;
6831 ctx.fpu_enabled = msr_fp; 6832 ctx.fpu_enabled = msr_fp;
@@ -6880,18 +6881,16 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, @@ -6880,18 +6881,16 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
6880 ctx.nip, supervisor, (int)msr_ir); 6881 ctx.nip, supervisor, (int)msr_ir);
6881 } 6882 }
6882 #endif 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 #if defined PPC_DEBUG_DISAS 6889 #if defined PPC_DEBUG_DISAS
6891 if (loglevel & CPU_LOG_TB_IN_ASM) { 6890 if (loglevel & CPU_LOG_TB_IN_ASM) {
6892 fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n", 6891 fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
6893 ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), 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 #endif 6895 #endif
6897 ctx.nip += 4; 6896 ctx.nip += 4;
@@ -6986,7 +6985,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env, @@ -6986,7 +6985,7 @@ static always_inline int gen_intermediate_code_internal (CPUState *env,
6986 if (loglevel & CPU_LOG_TB_IN_ASM) { 6985 if (loglevel & CPU_LOG_TB_IN_ASM) {
6987 int flags; 6986 int flags;
6988 flags = env->bfd_mach; 6987 flags = env->bfd_mach;
6989 - flags |= msr_le << 16; 6988 + flags |= little_endian << 16;
6990 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start)); 6989 fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
6991 target_disas(logfile, pc_start, ctx.nip - pc_start, flags); 6990 target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
6992 fprintf(logfile, "\n"); 6991 fprintf(logfile, "\n");
target-ppc/translate_init.c
@@ -314,6 +314,15 @@ static void spr_write_601_rtcl (void *opaque, int sprn) @@ -314,6 +314,15 @@ static void spr_write_601_rtcl (void *opaque, int sprn)
314 { 314 {
315 gen_op_store_601_rtcl(); 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 #endif 326 #endif
318 327
319 /* Unified bats */ 328 /* Unified bats */
@@ -3259,7 +3268,7 @@ static void init_proc_601 (CPUPPCState *env) @@ -3259,7 +3268,7 @@ static void init_proc_601 (CPUPPCState *env)
3259 /* XXX : not implemented */ 3268 /* XXX : not implemented */
3260 spr_register(env, SPR_HID0, "HID0", 3269 spr_register(env, SPR_HID0, "HID0",
3261 SPR_NOACCESS, SPR_NOACCESS, 3270 SPR_NOACCESS, SPR_NOACCESS,
3262 - &spr_read_generic, &spr_write_generic, 3271 + &spr_read_generic, &spr_write_hid0_601,
3263 0x80010080); 3272 0x80010080);
3264 /* XXX : not implemented */ 3273 /* XXX : not implemented */
3265 spr_register(env, SPR_HID1, "HID1", 3274 spr_register(env, SPR_HID1, "HID1",