1 /* 2 * Software MMU support 3 * 4 * Copyright (c) 2003 Fabrice Bellard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 #if DATA_SIZE == 8 20 #define SUFFIX q 21 #define USUFFIX q 22 #define DATA_TYPE uint64_t 23 #elif DATA_SIZE == 4 24 #define SUFFIX l 25 #define USUFFIX l 26 #define DATA_TYPE uint32_t 27 #elif DATA_SIZE == 2 28 #define SUFFIX w 29 #define USUFFIX uw 30 #define DATA_TYPE uint16_t 31 #define DATA_STYPE int16_t 32 #elif DATA_SIZE == 1 33 #define SUFFIX b 34 #define USUFFIX ub 35 #define DATA_TYPE uint8_t 36 #define DATA_STYPE int8_t 37 #else 38 #error unsupported data size 39 #endif 40 41 #if ACCESS_TYPE < (NB_MMU_MODES) 42 43 #if defined(OUTSIDE_JIT) 44 /* Dispatch calls to __ldx_outside_jit / __stx_outside_jit, which don't 45 * expect CPU environment. to be cached in ebp register, but rather uses 46 * cpu_single_env variable for that purpose. 47 */ 48 #define MMUSUFFIX _outside_jit 49 #else // OUTSIDE_JIT 50 #define MMUSUFFIX _mmu 51 #endif // OUTSIDE_JIT 52 #define CPU_MMU_INDEX ACCESS_TYPE 53 54 #elif ACCESS_TYPE == (NB_MMU_MODES) 55 56 #define CPU_MMU_INDEX (cpu_mmu_index(env)) 57 #define MMUSUFFIX _mmu 58 59 #elif ACCESS_TYPE == (NB_MMU_MODES + 1) 60 61 #define CPU_MMU_INDEX (cpu_mmu_index(env)) 62 #define MMUSUFFIX _cmmu 63 64 #else 65 #error invalid ACCESS_TYPE 66 #endif 67 68 #if DATA_SIZE == 8 69 #define RES_TYPE uint64_t 70 #else 71 #define RES_TYPE uint32_t 72 #endif 73 74 #if ACCESS_TYPE == (NB_MMU_MODES + 1) 75 #define ADDR_READ addr_code 76 #else 77 #define ADDR_READ addr_read 78 #endif 79 80 /* generic load/store macros */ 81 82 static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr) 83 { 84 int page_index; 85 RES_TYPE res; 86 target_ulong addr; 87 unsigned long physaddr; 88 int mmu_idx; 89 90 addr = ptr; 91 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 92 mmu_idx = CPU_MMU_INDEX; 93 if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != 94 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { 95 res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); 96 } else { 97 physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; 98 res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); 99 } 100 return res; 101 } 102 103 #if DATA_SIZE <= 2 104 static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr) 105 { 106 int res, page_index; 107 target_ulong addr; 108 unsigned long physaddr; 109 int mmu_idx; 110 111 addr = ptr; 112 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 113 mmu_idx = CPU_MMU_INDEX; 114 if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != 115 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { 116 res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, mmu_idx); 117 } else { 118 physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; 119 res = glue(glue(lds, SUFFIX), _raw)((uint8_t *)physaddr); 120 } 121 return res; 122 } 123 #endif 124 125 #if ACCESS_TYPE != (NB_MMU_MODES + 1) 126 127 /* generic store macro */ 128 129 static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v) 130 { 131 int page_index; 132 target_ulong addr; 133 unsigned long physaddr; 134 int mmu_idx; 135 136 addr = ptr; 137 page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 138 mmu_idx = CPU_MMU_INDEX; 139 if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write != 140 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { 141 glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, mmu_idx); 142 } else { 143 physaddr = addr + env->tlb_table[mmu_idx][page_index].addend; 144 glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, v); 145 } 146 } 147 148 #endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ 149 150 #if ACCESS_TYPE != (NB_MMU_MODES + 1) 151 152 #if DATA_SIZE == 8 153 static inline float64 glue(ldfq, MEMSUFFIX)(target_ulong ptr) 154 { 155 union { 156 float64 d; 157 uint64_t i; 158 } u; 159 u.i = glue(ldq, MEMSUFFIX)(ptr); 160 return u.d; 161 } 162 163 static inline void glue(stfq, MEMSUFFIX)(target_ulong ptr, float64 v) 164 { 165 union { 166 float64 d; 167 uint64_t i; 168 } u; 169 u.d = v; 170 glue(stq, MEMSUFFIX)(ptr, u.i); 171 } 172 #endif /* DATA_SIZE == 8 */ 173 174 #if DATA_SIZE == 4 175 static inline float32 glue(ldfl, MEMSUFFIX)(target_ulong ptr) 176 { 177 union { 178 float32 f; 179 uint32_t i; 180 } u; 181 u.i = glue(ldl, MEMSUFFIX)(ptr); 182 return u.f; 183 } 184 185 static inline void glue(stfl, MEMSUFFIX)(target_ulong ptr, float32 v) 186 { 187 union { 188 float32 f; 189 uint32_t i; 190 } u; 191 u.f = v; 192 glue(stl, MEMSUFFIX)(ptr, u.i); 193 } 194 #endif /* DATA_SIZE == 4 */ 195 196 #endif /* ACCESS_TYPE != (NB_MMU_MODES + 1) */ 197 198 #undef RES_TYPE 199 #undef DATA_TYPE 200 #undef DATA_STYPE 201 #undef SUFFIX 202 #undef USUFFIX 203 #undef DATA_SIZE 204 #undef CPU_MMU_INDEX 205 #undef MMUSUFFIX 206 #undef ADDR_READ 207