📄 fp_util.s
字号:
tst.b (-3,%a0) | to -inf jne 1b jra 5f4: tst.b (-3,%a0) | to +inf jeq 1b5: move.w #0x407e,(-2,%a0) move.l #0xffffff00,(%a0)+ clr.l (%a0) jra 2b | zero and denormalizedfp_ns_zero: tst.l (%a0)+ jne 1f tst.l (%a0) jne 1f subq.l #8,%a0 printf PNORM,"%p(",1,%a0 printx PNORM,%a0@ printf PNORM,")\n" rts | zero. nothing to do. | These are not merely subnormal numbers, but true denormals, | i.e. pathologically small (exponent is 2**-16383) numbers. | It is clearly impossible for even a normal extended number | with that exponent to fit into single precision, so just | write these ones off as "too darn small".1: fp_set_sr FPSR_EXC_UNFL | Set UNFL bit clr.l (%a0) clr.l -(%a0) move.w #0x3f81,-(%a0) | i.e. 2**-126 addq.l #6,%a0 moveq #1,%d0 jra fp_ns_round | round. | Infinities or NaNsfp_ns_huge: subq.l #4,%a0 printf PNORM,"%p(",1,%a0 printx PNORM,%a0@ printf PNORM,")\n" rts | fp_normalize_single_fast: | normalize an extended with single (23-bit) precision | this is only used by fsgldiv/fsgdlmul, where the | operand is not completly normalized. | args: %a0 (struct fp_ext *)fp_normalize_single_fast: printf PNORM,"nsf: %p(",1,%a0 printx PNORM,%a0@ printf PNORM,") " addq.l #2,%a0 move.w (%a0)+,%d2 cmp.w #0x7fff,%d2 jeq fp_nsf_huge | NaN / infinitive. move.l (%a0)+,%d0 | get high lword of mantissafp_nsf_round: tst.l (%a0) | check the low lword jeq 1f | Set a sticky bit if it is non-zero. This should only | affect the rounding in what would otherwise be equal- | distance situations, which is what we want it to do. bset #0,%d01: clr.l (%a0) | zap it from memory. | now, round off the low 8 bits of the hi lword. tst.b %d0 | 8 low bits. jne fp_nsf_checkround | Are they non-zero? | nothing to do here subq.l #8,%a0 printf PNORM,"%p(",1,%a0 printx PNORM,%a0@ printf PNORM,")\n" rtsfp_nsf_checkround: fp_set_sr FPSR_EXC_INEX2 | INEX2 bit clr.b -(%a0) | clear low byte of high lword subq.l #3,%a0 move.w (FPD_RND,FPDATA),%d2 | rounding mode jne 2f | %d2 == 0, round to nearest tst.b %d0 | test guard bit jpl 9f | zero is closer btst #8,%d0 | test lsb bit | round to even behaviour, see above. jne fp_nsf_doroundup | round to infinity lsl.b #1,%d0 | check low bits jeq 9f | round to zerofp_nsf_doroundup: | round (the mantissa, that is) towards infinity add.l #0x100,(%a0) jcc 9f | no overflow, good. | Overflow. This means that the %d1 was 0xffffff00, so it | is now zero. We will set the mantissa to reflect this, and | increment the exponent (checking for overflow there too) move.w #0x8000,(%a0) addq.w #1,-(%a0) cmp.w #0x407f,(%a0)+ | exponent now overflown? jeq fp_nsf_large | yes, so make it infinity.9: subq.l #4,%a0 printf PNORM,"%p(",1,%a0 printx PNORM,%a0@ printf PNORM,")\n" rts | check nondefault rounding modes2: subq.w #2,%d2 jcs 9b | %d2 < 2, round to zero jhi 3f | %d2 > 2, round to +infinity tst.b (-3,%a0) | to -inf jne fp_nsf_doroundup | negative, round to infinity jra 9b | positive, round to zero3: tst.b (-3,%a0) | to +inf jeq fp_nsf_doroundup | positive, round to infinity jra 9b | negative, round to zero | Exponent overflow. Just call it infinity.fp_nsf_large: tst.b (3,%a0) jeq 1f fp_set_sr FPSR_EXC_INEX21: fp_set_sr FPSR_EXC_OVFL move.w (FPD_RND,FPDATA),%d2 jne 3f | %d2 = 0 round to nearest1: move.w #0x7fff,(-2,%a0) clr.l (%a0)+ clr.l (%a0)2: subq.l #8,%a0 printf PNORM,"%p(",1,%a0 printx PNORM,%a0@ printf PNORM,")\n" rts3: subq.w #2,%d2 jcs 5f | %d2 < 2, round to zero jhi 4f | %d2 > 2, round to +infinity tst.b (-3,%a0) | to -inf jne 1b jra 5f4: tst.b (-3,%a0) | to +inf jeq 1b5: move.w #0x407e,(-2,%a0) move.l #0xffffff00,(%a0)+ clr.l (%a0) jra 2b | Infinities or NaNsfp_nsf_huge: subq.l #4,%a0 printf PNORM,"%p(",1,%a0 printx PNORM,%a0@ printf PNORM,")\n" rts | conv_ext2int (macro): | Generates a subroutine that converts an extended value to an | integer of a given size, again, with the appropriate type of | rounding. | Macro arguments: | s: size, as given in an assembly instruction. | b: number of bits in that size. | Subroutine arguments: | %a0: source (struct fp_ext *) | Returns the integer in %d0 (like it should).macro conv_ext2int s,b .set inf,(1<<(\b-1))-1 | i.e. MAXINT printf PCONV,"e2i%d: %p(",2,#\b,%a0 printx PCONV,%a0@ printf PCONV,") " addq.l #2,%a0 move.w (%a0)+,%d2 | exponent jeq fp_e2i_zero\b | zero / denorm (== 0, here) cmp.w #0x7fff,%d2 jeq fp_e2i_huge\b | Inf / NaN sub.w #0x3ffe,%d2 jcs fp_e2i_small\b cmp.w #\b,%d2 jhi fp_e2i_large\b move.l (%a0),%d0 move.l %d0,%d1 lsl.l %d2,%d1 jne fp_e2i_round\b tst.l (4,%a0) jne fp_e2i_round\b neg.w %d2 add.w #32,%d2 lsr.l %d2,%d09: tst.w (-4,%a0) jne 1f tst.\s %d0 jmi fp_e2i_large\b printf PCONV,"-> %p\n",1,%d0 rts1: neg.\s %d0 jeq 1f jpl fp_e2i_large\b1: printf PCONV,"-> %p\n",1,%d0 rtsfp_e2i_round\b: fp_set_sr FPSR_EXC_INEX2 | INEX2 bit neg.w %d2 add.w #32,%d2 .if \b>16 jeq 5f .endif lsr.l %d2,%d0 move.w (FPD_RND,FPDATA),%d2 | rounding mode jne 2f | %d2 == 0, round to nearest tst.l %d1 | test guard bit jpl 9b | zero is closer btst %d2,%d0 | test lsb bit (%d2 still 0) jne fp_e2i_doroundup\b lsl.l #1,%d1 | check low bits jne fp_e2i_doroundup\b tst.l (4,%a0) jeq 9bfp_e2i_doroundup\b: addq.l #1,%d0 jra 9b | check nondefault rounding modes2: subq.w #2,%d2 jcs 9b | %d2 < 2, round to zero jhi 3f | %d2 > 2, round to +infinity tst.w (-4,%a0) | to -inf jne fp_e2i_doroundup\b | negative, round to infinity jra 9b | positive, round to zero3: tst.w (-4,%a0) | to +inf jeq fp_e2i_doroundup\b | positive, round to infinity jra 9b | negative, round to zero | we are only want -2**127 get correctly rounded here, | since the guard bit is in the lower lword. | everything else ends up anyway as overflow. .if \b>165: move.w (FPD_RND,FPDATA),%d2 | rounding mode jne 2b | %d2 == 0, round to nearest move.l (4,%a0),%d1 | test guard bit jpl 9b | zero is closer lsl.l #1,%d1 | check low bits jne fp_e2i_doroundup\b jra 9b .endiffp_e2i_zero\b: clr.l %d0 tst.l (%a0)+ jne 1f tst.l (%a0) jeq 3f1: subq.l #4,%a0 fp_clr_sr FPSR_EXC_UNFL | fp_normalize_ext has set this bitfp_e2i_small\b: fp_set_sr FPSR_EXC_INEX2 clr.l %d0 move.w (FPD_RND,FPDATA),%d2 | rounding mode subq.w #2,%d2 jcs 3f | %d2 < 2, round to nearest/zero jhi 2f | %d2 > 2, round to +infinity tst.w (-4,%a0) | to -inf jeq 3f subq.\s #1,%d0 jra 3f2: tst.w (-4,%a0) | to +inf jne 3f addq.\s #1,%d03: printf PCONV,"-> %p\n",1,%d0 rtsfp_e2i_large\b: fp_set_sr FPSR_EXC_OPERR move.\s #inf,%d0 tst.w (-4,%a0) jeq 1f addq.\s #1,%d01: printf PCONV,"-> %p\n",1,%d0 rtsfp_e2i_huge\b: move.\s (%a0),%d0 tst.l (%a0) jne 1f tst.l (%a0) jeq fp_e2i_large\b | fp_normalize_ext has set this bit already | and made the number nonsignaling1: fp_tst_sr FPSR_EXC_SNAN jne 1f fp_set_sr FPSR_EXC_OPERR1: printf PCONV,"-> %p\n",1,%d0 rts.endmfp_conv_ext2long: conv_ext2int l,32fp_conv_ext2short: conv_ext2int w,16fp_conv_ext2byte: conv_ext2int b,8fp_conv_ext2double: jsr fp_normalize_double printf PCONV,"e2d: %p(",1,%a0 printx PCONV,%a0@ printf PCONV,"), " move.l (%a0)+,%d2 cmp.w #0x7fff,%d2 jne 1f move.w #0x7ff,%d2 move.l (%a0)+,%d0 jra 2f1: sub.w #0x3fff-0x3ff,%d2 move.l (%a0)+,%d0 jmi 2f clr.w %d22: lsl.w #5,%d2 lsl.l #7,%d2 lsl.l #8,%d2 move.l %d0,%d1 lsl.l #1,%d0 lsr.l #4,%d0 lsr.l #8,%d0 or.l %d2,%d0 putuser.l %d0,(%a1)+,fp_err_ua2,%a1 moveq #21,%d0 lsl.l %d0,%d1 move.l (%a0),%d0 lsr.l #4,%d0 lsr.l #7,%d0 or.l %d1,%d0 putuser.l %d0,(%a1),fp_err_ua2,%a1#ifdef FPU_EMU_DEBUG getuser.l %a1@(-4),%d0,fp_err_ua2,%a1 getuser.l %a1@(0),%d1,fp_err_ua2,%a1 printf PCONV,"%p(%08x%08x)\n",3,%a1,%d0,%d1#endif rtsfp_conv_ext2single: jsr fp_normalize_single printf PCONV,"e2s: %p(",1,%a0 printx PCONV,%a0@ printf PCONV,"), " move.l (%a0)+,%d1 cmp.w #0x7fff,%d1 jne 1f move.w #0xff,%d1 move.l (%a0)+,%d0 jra 2f1: sub.w #0x3fff-0x7f,%d1 move.l (%a0)+,%d0 jmi 2f clr.w %d12: lsl.w #8,%d1 lsl.l #7,%d1 lsl.l #8,%d1 bclr #31,%d0 lsr.l #8,%d0 or.l %d1,%d0 printf PCONV,"%08x\n",1,%d0 rts | special return addresses for instr that | encode the rounding precision in the opcode | (e.g. fsmove,fdmove)fp_finalrounding_single: addq.l #8,%sp jsr fp_normalize_ext jsr fp_normalize_single jra fp_finaltestfp_finalrounding_single_fast: addq.l #8,%sp jsr fp_normalize_ext jsr fp_normalize_single_fast jra fp_finaltestfp_finalrounding_double: addq.l #8,%sp jsr fp_normalize_ext jsr fp_normalize_double jra fp_finaltest | fp_finaltest: | set the emulated status register based on the outcome of an | emulated instruction.fp_finalrounding: addq.l #8,%sp| printf ,"f: %p\n",1,%a0 jsr fp_normalize_ext move.w (FPD_PREC,FPDATA),%d0 subq.w #1,%d0 jcs fp_finaltest jne 1f jsr fp_normalize_single jra 2f1: jsr fp_normalize_double2:| printf ,"f: %p\n",1,%a0fp_finaltest: | First, we do some of the obvious tests for the exception | status byte and condition code bytes of fp_sr here, so that | they do not have to be handled individually by every | emulated instruction. clr.l %d0 addq.l #1,%a0 tst.b (%a0)+ | sign jeq 1f bset #FPSR_CC_NEG-24,%d0 | N bit1: cmp.w #0x7fff,(%a0)+ | exponent jeq 2f | test for zero moveq #FPSR_CC_Z-24,%d1 tst.l (%a0)+ jne 9f tst.l (%a0) jne 9f jra 8f | infinitiv and NAN2: moveq #FPSR_CC_NAN-24,%d1 move.l (%a0)+,%d2 lsl.l #1,%d2 | ignore high bit jne 8f tst.l (%a0) jne 8f moveq #FPSR_CC_INF-24,%d18: bset %d1,%d09: move.b %d0,(FPD_FPSR+0,FPDATA) | set condition test result | move instructions enter here | Here, we test things in the exception status byte, and set | other things in the accrued exception byte accordingly. | Emulated instructions can set various things in the former, | as defined in fp_emu.h.fp_final: move.l (FPD_FPSR,FPDATA),%d0#if 0 btst #FPSR_EXC_SNAN,%d0 | EXC_SNAN jne 1f btst #FPSR_EXC_OPERR,%d0 | EXC_OPERR jeq 2f1: bset #FPSR_AEXC_IOP,%d0 | set IOP bit2: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL jeq 1f bset #FPSR_AEXC_OVFL,%d0 | set OVFL bit1: btst #FPSR_EXC_UNFL,%d0 | EXC_UNFL jeq 1f btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2 jeq 1f bset #FPSR_AEXC_UNFL,%d0 | set UNFL bit1: btst #FPSR_EXC_DZ,%d0 | EXC_INEX1 jeq 1f bset #FPSR_AEXC_DZ,%d0 | set DZ bit1: btst #FPSR_EXC_OVFL,%d0 | EXC_OVFL jne 1f btst #FPSR_EXC_INEX2,%d0 | EXC_INEX2 jne 1f btst #FPSR_EXC_INEX1,%d0 | EXC_INEX1 jeq 2f1: bset #FPSR_AEXC_INEX,%d0 | set INEX bit2: move.l %d0,(FPD_FPSR,FPDATA)#else | same as above, greatly optimized, but untested (yet) move.l %d0,%d2 lsr.l #5,%d0 move.l %d0,%d1 lsr.l #4,%d1 or.l %d0,%d1 and.b #0x08,%d1 move.l %d2,%d0 lsr.l #6,%d0 or.l %d1,%d0 move.l %d2,%d1 lsr.l #4,%d1 or.b #0xdf,%d1 and.b %d1,%d0 move.l %d2,%d1 lsr.l #7,%d1 and.b #0x80,%d1 or.b %d1,%d0 and.b #0xf8,%d0 or.b %d0,%d2 move.l %d2,(FPD_FPSR,FPDATA)#endif move.b (FPD_FPSR+2,FPDATA),%d0 and.b (FPD_FPCR+2,FPDATA),%d0 jeq 1f printf ,"send signal!!!\n"1: jra fp_end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -