Commit 6d9a42be17f1961f05dd247d5277747b9cea631e
1 parent
26fb5e48
Implement ARM floating point exception emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4166 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
58 additions
and
2 deletions
linux-user/main.c
... | ... | @@ -378,19 +378,68 @@ void cpu_loop(CPUARMState *env) |
378 | 378 | { |
379 | 379 | TaskState *ts = env->opaque; |
380 | 380 | uint32_t opcode; |
381 | + int rc; | |
381 | 382 | |
382 | 383 | /* we handle the FPU emulation here, as Linux */ |
383 | 384 | /* we get the opcode */ |
384 | 385 | /* FIXME - what to do if get_user() fails? */ |
385 | 386 | get_user_u32(opcode, env->regs[15]); |
386 | 387 | |
387 | - if (EmulateAll(opcode, &ts->fpa, env) == 0) { | |
388 | + rc = EmulateAll(opcode, &ts->fpa, env); | |
389 | + if (rc == 0) { /* illegal instruction */ | |
388 | 390 | info.si_signo = SIGILL; |
389 | 391 | info.si_errno = 0; |
390 | 392 | info.si_code = TARGET_ILL_ILLOPN; |
391 | 393 | info._sifields._sigfault._addr = env->regs[15]; |
392 | 394 | queue_signal(info.si_signo, &info); |
393 | - } else { | |
395 | + } else if (rc < 0) { /* FP exception */ | |
396 | + int arm_fpe=0; | |
397 | + | |
398 | + /* translate softfloat flags to FPSR flags */ | |
399 | + if (-rc & float_flag_invalid) | |
400 | + arm_fpe |= BIT_IOC; | |
401 | + if (-rc & float_flag_divbyzero) | |
402 | + arm_fpe |= BIT_DZC; | |
403 | + if (-rc & float_flag_overflow) | |
404 | + arm_fpe |= BIT_OFC; | |
405 | + if (-rc & float_flag_underflow) | |
406 | + arm_fpe |= BIT_UFC; | |
407 | + if (-rc & float_flag_inexact) | |
408 | + arm_fpe |= BIT_IXC; | |
409 | + | |
410 | + FPSR fpsr = ts->fpa.fpsr; | |
411 | + //printf("fpsr 0x%x, arm_fpe 0x%x\n",fpsr,arm_fpe); | |
412 | + | |
413 | + if (fpsr & (arm_fpe << 16)) { /* exception enabled? */ | |
414 | + info.si_signo = SIGFPE; | |
415 | + info.si_errno = 0; | |
416 | + | |
417 | + /* ordered by priority, least first */ | |
418 | + if (arm_fpe & BIT_IXC) info.si_code = TARGET_FPE_FLTRES; | |
419 | + if (arm_fpe & BIT_UFC) info.si_code = TARGET_FPE_FLTUND; | |
420 | + if (arm_fpe & BIT_OFC) info.si_code = TARGET_FPE_FLTOVF; | |
421 | + if (arm_fpe & BIT_DZC) info.si_code = TARGET_FPE_FLTDIV; | |
422 | + if (arm_fpe & BIT_IOC) info.si_code = TARGET_FPE_FLTINV; | |
423 | + | |
424 | + info._sifields._sigfault._addr = env->regs[15]; | |
425 | + queue_signal(info.si_signo, &info); | |
426 | + } else { | |
427 | + env->regs[15] += 4; | |
428 | + } | |
429 | + | |
430 | + /* accumulate unenabled exceptions */ | |
431 | + if ((!(fpsr & BIT_IXE)) && (arm_fpe & BIT_IXC)) | |
432 | + fpsr |= BIT_IXC; | |
433 | + if ((!(fpsr & BIT_UFE)) && (arm_fpe & BIT_UFC)) | |
434 | + fpsr |= BIT_UFC; | |
435 | + if ((!(fpsr & BIT_OFE)) && (arm_fpe & BIT_OFC)) | |
436 | + fpsr |= BIT_OFC; | |
437 | + if ((!(fpsr & BIT_DZE)) && (arm_fpe & BIT_DZC)) | |
438 | + fpsr |= BIT_DZC; | |
439 | + if ((!(fpsr & BIT_IOE)) && (arm_fpe & BIT_IOC)) | |
440 | + fpsr |= BIT_IOC; | |
441 | + ts->fpa.fpsr=fpsr; | |
442 | + } else { /* everything OK */ | |
394 | 443 | /* increment PC */ |
395 | 444 | env->regs[15] += 4; |
396 | 445 | } | ... | ... |
target-arm/nwfpe/fpa11.c
... | ... | @@ -162,6 +162,8 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) |
162 | 162 | fpa11->initflag = 1; |
163 | 163 | } |
164 | 164 | |
165 | + set_float_exception_flags(0, &fpa11->fp_status); | |
166 | + | |
165 | 167 | if (TEST_OPCODE(opcode,MASK_CPRT)) |
166 | 168 | { |
167 | 169 | //fprintf(stderr,"emulating CPRT\n"); |
... | ... | @@ -191,6 +193,11 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) |
191 | 193 | } |
192 | 194 | |
193 | 195 | // restore_flags(flags); |
196 | + if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status)) | |
197 | + { | |
198 | + //printf("fef 0x%x\n",float_exception_flags); | |
199 | + nRc=-get_float_exception_flags(&fpa11->fp_status); | |
200 | + } | |
194 | 201 | |
195 | 202 | //printf("returning %d\n",nRc); |
196 | 203 | return(nRc); | ... | ... |