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 |