| 21 |
|
|
| 22 |
#if DATA_SIZE == 8 |
#if DATA_SIZE == 8 |
| 23 |
#define SUFFIX q |
#define SUFFIX q |
| 24 |
|
#define USUFFIX q |
| 25 |
#define DATA_TYPE uint64_t |
#define DATA_TYPE uint64_t |
| 26 |
#elif DATA_SIZE == 4 |
#elif DATA_SIZE == 4 |
| 27 |
#define SUFFIX l |
#define SUFFIX l |
| 28 |
|
#define USUFFIX l |
| 29 |
#define DATA_TYPE uint32_t |
#define DATA_TYPE uint32_t |
| 30 |
#elif DATA_SIZE == 2 |
#elif DATA_SIZE == 2 |
| 31 |
#define SUFFIX w |
#define SUFFIX w |
| 32 |
|
#define USUFFIX uw |
| 33 |
#define DATA_TYPE uint16_t |
#define DATA_TYPE uint16_t |
| 34 |
#elif DATA_SIZE == 1 |
#elif DATA_SIZE == 1 |
| 35 |
#define SUFFIX b |
#define SUFFIX b |
| 36 |
|
#define USUFFIX ub |
| 37 |
#define DATA_TYPE uint8_t |
#define DATA_TYPE uint8_t |
| 38 |
#else |
#else |
| 39 |
#error unsupported data size |
#error unsupported data size |
| 40 |
#endif |
#endif |
| 41 |
|
|
| 42 |
static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr); |
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, |
| 43 |
static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, |
int is_user, |
| 44 |
void *retaddr); |
void *retaddr); |
| 45 |
|
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, |
| 46 |
|
DATA_TYPE val, |
| 47 |
|
int is_user, |
| 48 |
|
void *retaddr); |
| 49 |
|
|
| 50 |
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, |
static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr, |
| 51 |
unsigned long tlb_addr) |
unsigned long tlb_addr) |
| 89 |
} |
} |
| 90 |
|
|
| 91 |
/* handle all cases except unaligned access which span two pages */ |
/* handle all cases except unaligned access which span two pages */ |
| 92 |
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), _mmu)(unsigned long addr) |
DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(unsigned long addr, |
| 93 |
|
int is_user) |
| 94 |
{ |
{ |
| 95 |
DATA_TYPE res; |
DATA_TYPE res; |
| 96 |
int is_user, index; |
int index; |
| 97 |
unsigned long physaddr, tlb_addr; |
unsigned long physaddr, tlb_addr; |
| 98 |
void *retaddr; |
void *retaddr; |
| 99 |
|
|
| 100 |
/* test if there is match for unaligned or IO access */ |
/* test if there is match for unaligned or IO access */ |
| 101 |
/* XXX: could done more in memory macro in a non portable way */ |
/* XXX: could done more in memory macro in a non portable way */ |
|
is_user = ((env->hflags & HF_CPL_MASK) == 3); |
|
| 102 |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
| 103 |
redo: |
redo: |
| 104 |
tlb_addr = env->tlb_read[is_user][index].address; |
tlb_addr = env->tlb_read[is_user][index].address; |
| 112 |
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { |
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { |
| 113 |
/* slow unaligned access (it spans two pages or IO) */ |
/* slow unaligned access (it spans two pages or IO) */ |
| 114 |
do_unaligned_access: |
do_unaligned_access: |
| 115 |
retaddr = __builtin_return_address(0); |
retaddr = GETPC(); |
| 116 |
res = glue(slow_ld, SUFFIX)(addr, retaddr); |
res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, |
| 117 |
|
is_user, retaddr); |
| 118 |
} else { |
} else { |
| 119 |
/* unaligned access in the same page */ |
/* unaligned access in the same page */ |
| 120 |
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); |
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); |
| 121 |
} |
} |
| 122 |
} else { |
} else { |
| 123 |
/* the page is not in the TLB : fill it */ |
/* the page is not in the TLB : fill it */ |
| 124 |
retaddr = __builtin_return_address(0); |
retaddr = GETPC(); |
| 125 |
tlb_fill(addr, 0, retaddr); |
tlb_fill(addr, 0, is_user, retaddr); |
| 126 |
goto redo; |
goto redo; |
| 127 |
} |
} |
| 128 |
return res; |
return res; |
| 129 |
} |
} |
| 130 |
|
|
| 131 |
/* handle all unaligned cases */ |
/* handle all unaligned cases */ |
| 132 |
static DATA_TYPE glue(slow_ld, SUFFIX)(unsigned long addr, void *retaddr) |
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(unsigned long addr, |
| 133 |
|
int is_user, |
| 134 |
|
void *retaddr) |
| 135 |
{ |
{ |
| 136 |
DATA_TYPE res, res1, res2; |
DATA_TYPE res, res1, res2; |
| 137 |
int is_user, index, shift; |
int index, shift; |
| 138 |
unsigned long physaddr, tlb_addr, addr1, addr2; |
unsigned long physaddr, tlb_addr, addr1, addr2; |
| 139 |
|
|
|
is_user = ((env->hflags & HF_CPL_MASK) == 3); |
|
| 140 |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
| 141 |
redo: |
redo: |
| 142 |
tlb_addr = env->tlb_read[is_user][index].address; |
tlb_addr = env->tlb_read[is_user][index].address; |
| 152 |
/* slow unaligned access (it spans two pages) */ |
/* slow unaligned access (it spans two pages) */ |
| 153 |
addr1 = addr & ~(DATA_SIZE - 1); |
addr1 = addr & ~(DATA_SIZE - 1); |
| 154 |
addr2 = addr1 + DATA_SIZE; |
addr2 = addr1 + DATA_SIZE; |
| 155 |
res1 = glue(slow_ld, SUFFIX)(addr1, retaddr); |
res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, |
| 156 |
res2 = glue(slow_ld, SUFFIX)(addr2, retaddr); |
is_user, retaddr); |
| 157 |
|
res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, |
| 158 |
|
is_user, retaddr); |
| 159 |
shift = (addr & (DATA_SIZE - 1)) * 8; |
shift = (addr & (DATA_SIZE - 1)) * 8; |
| 160 |
#ifdef TARGET_WORDS_BIGENDIAN |
#ifdef TARGET_WORDS_BIGENDIAN |
| 161 |
res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); |
res = (res1 << shift) | (res2 >> ((DATA_SIZE * 8) - shift)); |
| 164 |
#endif |
#endif |
| 165 |
} else { |
} else { |
| 166 |
/* unaligned/aligned access in the same page */ |
/* unaligned/aligned access in the same page */ |
| 167 |
res = glue(glue(ldu, SUFFIX), _raw)((uint8_t *)physaddr); |
res = glue(glue(ld, USUFFIX), _raw)((uint8_t *)physaddr); |
| 168 |
} |
} |
| 169 |
} else { |
} else { |
| 170 |
/* the page is not in the TLB : fill it */ |
/* the page is not in the TLB : fill it */ |
| 171 |
tlb_fill(addr, 0, retaddr); |
tlb_fill(addr, 0, is_user, retaddr); |
| 172 |
goto redo; |
goto redo; |
| 173 |
} |
} |
| 174 |
return res; |
return res; |
| 175 |
} |
} |
| 176 |
|
|
| 177 |
|
|
| 178 |
void REGPARM(2) glue(glue(__st, SUFFIX), _mmu)(unsigned long addr, DATA_TYPE val) |
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr, |
| 179 |
|
DATA_TYPE val, |
| 180 |
|
int is_user) |
| 181 |
{ |
{ |
| 182 |
unsigned long physaddr, tlb_addr; |
unsigned long physaddr, tlb_addr; |
| 183 |
void *retaddr; |
void *retaddr; |
| 184 |
int is_user, index; |
int index; |
| 185 |
|
|
|
is_user = ((env->hflags & HF_CPL_MASK) == 3); |
|
| 186 |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
| 187 |
redo: |
redo: |
| 188 |
tlb_addr = env->tlb_write[is_user][index].address; |
tlb_addr = env->tlb_write[is_user][index].address; |
| 195 |
glue(io_write, SUFFIX)(physaddr, val, tlb_addr); |
glue(io_write, SUFFIX)(physaddr, val, tlb_addr); |
| 196 |
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { |
} else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { |
| 197 |
do_unaligned_access: |
do_unaligned_access: |
| 198 |
retaddr = __builtin_return_address(0); |
retaddr = GETPC(); |
| 199 |
glue(slow_st, SUFFIX)(addr, val, retaddr); |
glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, |
| 200 |
|
is_user, retaddr); |
| 201 |
} else { |
} else { |
| 202 |
/* aligned/unaligned access in the same page */ |
/* aligned/unaligned access in the same page */ |
| 203 |
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val); |
glue(glue(st, SUFFIX), _raw)((uint8_t *)physaddr, val); |
| 204 |
} |
} |
| 205 |
} else { |
} else { |
| 206 |
/* the page is not in the TLB : fill it */ |
/* the page is not in the TLB : fill it */ |
| 207 |
retaddr = __builtin_return_address(0); |
retaddr = GETPC(); |
| 208 |
tlb_fill(addr, 1, retaddr); |
tlb_fill(addr, 1, is_user, retaddr); |
| 209 |
goto redo; |
goto redo; |
| 210 |
} |
} |
| 211 |
} |
} |
| 212 |
|
|
| 213 |
/* handles all unaligned cases */ |
/* handles all unaligned cases */ |
| 214 |
static void glue(slow_st, SUFFIX)(unsigned long addr, DATA_TYPE val, |
static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr, |
| 215 |
void *retaddr) |
DATA_TYPE val, |
| 216 |
|
int is_user, |
| 217 |
|
void *retaddr) |
| 218 |
{ |
{ |
| 219 |
unsigned long physaddr, tlb_addr; |
unsigned long physaddr, tlb_addr; |
| 220 |
int is_user, index, i; |
int index, i; |
| 221 |
|
|
|
is_user = ((env->hflags & HF_CPL_MASK) == 3); |
|
| 222 |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); |
| 223 |
redo: |
redo: |
| 224 |
tlb_addr = env->tlb_write[is_user][index].address; |
tlb_addr = env->tlb_write[is_user][index].address; |
| 234 |
/* XXX: not efficient, but simple */ |
/* XXX: not efficient, but simple */ |
| 235 |
for(i = 0;i < DATA_SIZE; i++) { |
for(i = 0;i < DATA_SIZE; i++) { |
| 236 |
#ifdef TARGET_WORDS_BIGENDIAN |
#ifdef TARGET_WORDS_BIGENDIAN |
| 237 |
slow_stb(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), retaddr); |
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), |
| 238 |
|
is_user, retaddr); |
| 239 |
#else |
#else |
| 240 |
slow_stb(addr + i, val >> (i * 8), retaddr); |
glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), |
| 241 |
|
is_user, retaddr); |
| 242 |
#endif |
#endif |
| 243 |
} |
} |
| 244 |
} else { |
} else { |
| 247 |
} |
} |
| 248 |
} else { |
} else { |
| 249 |
/* the page is not in the TLB : fill it */ |
/* the page is not in the TLB : fill it */ |
| 250 |
tlb_fill(addr, 1, retaddr); |
tlb_fill(addr, 1, is_user, retaddr); |
| 251 |
goto redo; |
goto redo; |
| 252 |
} |
} |
| 253 |
} |
} |
| 255 |
#undef SHIFT |
#undef SHIFT |
| 256 |
#undef DATA_TYPE |
#undef DATA_TYPE |
| 257 |
#undef SUFFIX |
#undef SUFFIX |
| 258 |
|
#undef USUFFIX |
| 259 |
#undef DATA_SIZE |
#undef DATA_SIZE |