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,19 +378,68 @@ void cpu_loop(CPUARMState *env) | ||
378 | { | 378 | { |
379 | TaskState *ts = env->opaque; | 379 | TaskState *ts = env->opaque; |
380 | uint32_t opcode; | 380 | uint32_t opcode; |
381 | + int rc; | ||
381 | 382 | ||
382 | /* we handle the FPU emulation here, as Linux */ | 383 | /* we handle the FPU emulation here, as Linux */ |
383 | /* we get the opcode */ | 384 | /* we get the opcode */ |
384 | /* FIXME - what to do if get_user() fails? */ | 385 | /* FIXME - what to do if get_user() fails? */ |
385 | get_user_u32(opcode, env->regs[15]); | 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 | info.si_signo = SIGILL; | 390 | info.si_signo = SIGILL; |
389 | info.si_errno = 0; | 391 | info.si_errno = 0; |
390 | info.si_code = TARGET_ILL_ILLOPN; | 392 | info.si_code = TARGET_ILL_ILLOPN; |
391 | info._sifields._sigfault._addr = env->regs[15]; | 393 | info._sifields._sigfault._addr = env->regs[15]; |
392 | queue_signal(info.si_signo, &info); | 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 | /* increment PC */ | 443 | /* increment PC */ |
395 | env->regs[15] += 4; | 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,6 +162,8 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) | ||
162 | fpa11->initflag = 1; | 162 | fpa11->initflag = 1; |
163 | } | 163 | } |
164 | 164 | ||
165 | + set_float_exception_flags(0, &fpa11->fp_status); | ||
166 | + | ||
165 | if (TEST_OPCODE(opcode,MASK_CPRT)) | 167 | if (TEST_OPCODE(opcode,MASK_CPRT)) |
166 | { | 168 | { |
167 | //fprintf(stderr,"emulating CPRT\n"); | 169 | //fprintf(stderr,"emulating CPRT\n"); |
@@ -191,6 +193,11 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) | @@ -191,6 +193,11 @@ unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) | ||
191 | } | 193 | } |
192 | 194 | ||
193 | // restore_flags(flags); | 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 | //printf("returning %d\n",nRc); | 202 | //printf("returning %d\n",nRc); |
196 | return(nRc); | 203 | return(nRc); |