root / target-sparc / op_helper.c @ 6f7e9aec
History | View | Annotate | Download (5.6 kB)
1 |
#include <math.h> |
---|---|
2 |
#include <fenv.h> |
3 |
#include "exec.h" |
4 |
|
5 |
//#define DEBUG_MMU
|
6 |
|
7 |
void raise_exception(int tt) |
8 |
{ |
9 |
env->exception_index = tt; |
10 |
cpu_loop_exit(); |
11 |
} |
12 |
|
13 |
#ifdef USE_INT_TO_FLOAT_HELPERS
|
14 |
void do_fitos(void) |
15 |
{ |
16 |
FT0 = (float) *((int32_t *)&FT1);
|
17 |
} |
18 |
|
19 |
void do_fitod(void) |
20 |
{ |
21 |
DT0 = (double) *((int32_t *)&FT1);
|
22 |
} |
23 |
#endif
|
24 |
|
25 |
void do_fabss(void) |
26 |
{ |
27 |
FT0 = fabsf(FT1); |
28 |
} |
29 |
|
30 |
void do_fsqrts(void) |
31 |
{ |
32 |
FT0 = sqrtf(FT1); |
33 |
} |
34 |
|
35 |
void do_fsqrtd(void) |
36 |
{ |
37 |
DT0 = sqrt(DT1); |
38 |
} |
39 |
|
40 |
void do_fcmps (void) |
41 |
{ |
42 |
if (isnan(FT0) || isnan(FT1)) {
|
43 |
T0 = FSR_FCC1 | FSR_FCC0; |
44 |
env->fsr &= ~(FSR_FCC1 | FSR_FCC0); |
45 |
env->fsr |= T0; |
46 |
if (env->fsr & FSR_NVM) {
|
47 |
raise_exception(TT_FP_EXCP); |
48 |
} else {
|
49 |
env->fsr |= FSR_NVA; |
50 |
} |
51 |
} else if (FT0 < FT1) { |
52 |
T0 = FSR_FCC0; |
53 |
} else if (FT0 > FT1) { |
54 |
T0 = FSR_FCC1; |
55 |
} else {
|
56 |
T0 = 0;
|
57 |
} |
58 |
env->fsr = T0; |
59 |
} |
60 |
|
61 |
void do_fcmpd (void) |
62 |
{ |
63 |
if (isnan(DT0) || isnan(DT1)) {
|
64 |
T0 = FSR_FCC1 | FSR_FCC0; |
65 |
env->fsr &= ~(FSR_FCC1 | FSR_FCC0); |
66 |
env->fsr |= T0; |
67 |
if (env->fsr & FSR_NVM) {
|
68 |
raise_exception(TT_FP_EXCP); |
69 |
} else {
|
70 |
env->fsr |= FSR_NVA; |
71 |
} |
72 |
} else if (DT0 < DT1) { |
73 |
T0 = FSR_FCC0; |
74 |
} else if (DT0 > DT1) { |
75 |
T0 = FSR_FCC1; |
76 |
} else {
|
77 |
T0 = 0;
|
78 |
} |
79 |
env->fsr = T0; |
80 |
} |
81 |
|
82 |
void helper_ld_asi(int asi, int size, int sign) |
83 |
{ |
84 |
uint32_t ret; |
85 |
|
86 |
switch (asi) {
|
87 |
case 3: /* MMU probe */ |
88 |
{ |
89 |
int mmulev;
|
90 |
|
91 |
mmulev = (T0 >> 8) & 15; |
92 |
if (mmulev > 4) |
93 |
ret = 0;
|
94 |
else {
|
95 |
ret = mmu_probe(T0, mmulev); |
96 |
//bswap32s(&ret);
|
97 |
} |
98 |
#ifdef DEBUG_MMU
|
99 |
printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
|
100 |
#endif
|
101 |
} |
102 |
break;
|
103 |
case 4: /* read MMU regs */ |
104 |
{ |
105 |
int reg = (T0 >> 8) & 0xf; |
106 |
|
107 |
ret = env->mmuregs[reg]; |
108 |
if (reg == 3) /* Fault status cleared on read */ |
109 |
env->mmuregs[reg] = 0;
|
110 |
#ifdef DEBUG_MMU
|
111 |
printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
|
112 |
#endif
|
113 |
} |
114 |
break;
|
115 |
case 0x20 ... 0x2f: /* MMU passthrough */ |
116 |
cpu_physical_memory_read(T0, (void *) &ret, size);
|
117 |
if (size == 4) |
118 |
tswap32s(&ret); |
119 |
else if (size == 2) |
120 |
tswap16s((uint16_t *)&ret); |
121 |
break;
|
122 |
default:
|
123 |
ret = 0;
|
124 |
break;
|
125 |
} |
126 |
T1 = ret; |
127 |
} |
128 |
|
129 |
void helper_st_asi(int asi, int size, int sign) |
130 |
{ |
131 |
switch(asi) {
|
132 |
case 3: /* MMU flush */ |
133 |
{ |
134 |
int mmulev;
|
135 |
|
136 |
mmulev = (T0 >> 8) & 15; |
137 |
#ifdef DEBUG_MMU
|
138 |
printf("mmu flush level %d\n", mmulev);
|
139 |
#endif
|
140 |
switch (mmulev) {
|
141 |
case 0: // flush page |
142 |
tlb_flush_page(env, T0 & 0xfffff000);
|
143 |
break;
|
144 |
case 1: // flush segment (256k) |
145 |
case 2: // flush region (16M) |
146 |
case 3: // flush context (4G) |
147 |
case 4: // flush entire |
148 |
tlb_flush(env, 1);
|
149 |
break;
|
150 |
default:
|
151 |
break;
|
152 |
} |
153 |
#ifdef DEBUG_MMU
|
154 |
dump_mmu(); |
155 |
#endif
|
156 |
return;
|
157 |
} |
158 |
case 4: /* write MMU regs */ |
159 |
{ |
160 |
int reg = (T0 >> 8) & 0xf, oldreg; |
161 |
|
162 |
oldreg = env->mmuregs[reg]; |
163 |
switch(reg) {
|
164 |
case 0: |
165 |
env->mmuregs[reg] &= ~(MMU_E | MMU_NF); |
166 |
env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); |
167 |
// Mappings generated during no-fault mode or MMU
|
168 |
// disabled mode are invalid in normal mode
|
169 |
if (oldreg != env->mmuregs[reg])
|
170 |
tlb_flush(env, 1);
|
171 |
break;
|
172 |
case 2: |
173 |
env->mmuregs[reg] = T1; |
174 |
if (oldreg != env->mmuregs[reg]) {
|
175 |
/* we flush when the MMU context changes because
|
176 |
QEMU has no MMU context support */
|
177 |
tlb_flush(env, 1);
|
178 |
} |
179 |
break;
|
180 |
case 3: |
181 |
case 4: |
182 |
break;
|
183 |
default:
|
184 |
env->mmuregs[reg] = T1; |
185 |
break;
|
186 |
} |
187 |
#ifdef DEBUG_MMU
|
188 |
if (oldreg != env->mmuregs[reg]) {
|
189 |
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
|
190 |
} |
191 |
dump_mmu(); |
192 |
#endif
|
193 |
return;
|
194 |
} |
195 |
case 0x17: /* Block copy, sta access */ |
196 |
{ |
197 |
// value (T1) = src
|
198 |
// address (T0) = dst
|
199 |
// copy 32 bytes
|
200 |
int src = T1, dst = T0;
|
201 |
uint8_t temp[32];
|
202 |
|
203 |
tswap32s(&src); |
204 |
|
205 |
cpu_physical_memory_read(src, (void *) &temp, 32); |
206 |
cpu_physical_memory_write(dst, (void *) &temp, 32); |
207 |
} |
208 |
return;
|
209 |
case 0x1f: /* Block fill, stda access */ |
210 |
{ |
211 |
// value (T1, T2)
|
212 |
// address (T0) = dst
|
213 |
// fill 32 bytes
|
214 |
int i, dst = T0;
|
215 |
uint64_t val; |
216 |
|
217 |
val = (((uint64_t)T1) << 32) | T2;
|
218 |
tswap64s(&val); |
219 |
|
220 |
for (i = 0; i < 32; i += 8, dst += 8) { |
221 |
cpu_physical_memory_write(dst, (void *) &val, 8); |
222 |
} |
223 |
} |
224 |
return;
|
225 |
case 0x20 ... 0x2f: /* MMU passthrough */ |
226 |
{ |
227 |
int temp = T1;
|
228 |
if (size == 4) |
229 |
tswap32s(&temp); |
230 |
else if (size == 2) |
231 |
tswap16s((uint16_t *)&temp); |
232 |
cpu_physical_memory_write(T0, (void *) &temp, size);
|
233 |
} |
234 |
return;
|
235 |
default:
|
236 |
return;
|
237 |
} |
238 |
} |
239 |
|
240 |
void helper_rett()
|
241 |
{ |
242 |
unsigned int cwp; |
243 |
|
244 |
env->psret = 1;
|
245 |
cwp = (env->cwp + 1) & (NWINDOWS - 1); |
246 |
if (env->wim & (1 << cwp)) { |
247 |
raise_exception(TT_WIN_UNF); |
248 |
} |
249 |
set_cwp(cwp); |
250 |
env->psrs = env->psrps; |
251 |
} |
252 |
|
253 |
void helper_ldfsr(void) |
254 |
{ |
255 |
switch (env->fsr & FSR_RD_MASK) {
|
256 |
case FSR_RD_NEAREST:
|
257 |
fesetround(FE_TONEAREST); |
258 |
break;
|
259 |
case FSR_RD_ZERO:
|
260 |
fesetround(FE_TOWARDZERO); |
261 |
break;
|
262 |
case FSR_RD_POS:
|
263 |
fesetround(FE_UPWARD); |
264 |
break;
|
265 |
case FSR_RD_NEG:
|
266 |
fesetround(FE_DOWNWARD); |
267 |
break;
|
268 |
} |
269 |
} |
270 |
|
271 |
void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f) |
272 |
{ |
273 |
int exptemp;
|
274 |
|
275 |
*pmant = ldexp(frexp(f, &exptemp), 53);
|
276 |
*pexp = exptemp; |
277 |
} |
278 |
|
279 |
double cpu_put_fp64(uint64_t mant, uint16_t exp)
|
280 |
{ |
281 |
return ldexp((double) mant, exp - 53); |
282 |
} |
283 |
|
284 |
void helper_debug()
|
285 |
{ |
286 |
env->exception_index = EXCP_DEBUG; |
287 |
cpu_loop_exit(); |
288 |
} |
289 |
|
290 |
void do_wrpsr()
|
291 |
{ |
292 |
PUT_PSR(env, T0); |
293 |
} |
294 |
|
295 |
void do_rdpsr()
|
296 |
{ |
297 |
T0 = GET_PSR(env); |
298 |
} |