Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

396 lines
11 KiB

  1. subttl emfadd.asm - Addition and Subtraction
  2. page
  3. ;*******************************************************************************
  4. ; Copyright (c) Microsoft Corporation 1991
  5. ; All Rights Reserved
  6. ;
  7. ;emfadd.asm - long double add and subtract
  8. ; by Tim Paterson
  9. ;
  10. ;Purpose:
  11. ; Long double add/subtract.
  12. ;Outputs:
  13. ; Jumps to [RoundMode] to round and store result.
  14. ;
  15. ;Revision History:
  16. ;
  17. ; [] 09/05/91 TP Initial 32-bit version.
  18. ;
  19. ;*******************************************************************************
  20. ;*******************************************************************************
  21. ; Dispatch for Add/Sub/Subr
  22. ;
  23. ; Signs are passed in dx:
  24. ; xor source sign with dl
  25. ; xor dest sign with dh
  26. ;
  27. ;One operand has been loaded into ecx:ebx:esi ("source"), the other is
  28. ;pointed to by edi ("dest").
  29. ;
  30. ;Tag of source is shifted. Tag values are as follows:
  31. .erre TAG_SNGL eq 0 ;SINGLE: low 32 bits are zero
  32. .erre TAG_VALID eq 1
  33. .erre TAG_ZERO eq 2
  34. .erre TAG_SPCL eq 3 ;NAN, Infinity, Denormal, Empty
  35. ;Any special case routines not found in this file are in emarith.asm
  36. tFaddDisp label dword ;Source (reg) Dest (*[di])
  37. dd AddDouble ;single single
  38. dd AddDouble ;single double
  39. dd AddSourceSign ;single zero
  40. dd AddSpclDest ;single special
  41. dd AddDouble ;double single
  42. dd AddDouble ;double double
  43. dd AddSourceSign ;double zero
  44. dd AddSpclDest ;double special
  45. dd AddDestSign ;zero single
  46. dd AddDestSign ;zero double
  47. dd AddZeroZero ;zero zero
  48. dd AddSpclDest ;zero special
  49. dd AddSpclSource ;special single
  50. dd AddSpclSource ;special double
  51. dd AddSpclSource ;special zero
  52. dd TwoOpBothSpcl ;special special
  53. dd AddTwoInf ;Two infinities
  54. EM_ENTRY eFISUB16
  55. eFISUB16:
  56. call Load16Int
  57. mov dx,bSign ;Change sign of source
  58. jmp AddSetResult
  59. EM_ENTRY eFISUBR16
  60. eFISUBR16:
  61. call Load16Int
  62. mov dx,bSign shl 8 ;Change sign of dest
  63. jmp AddSetResult
  64. EM_ENTRY eFIADD16
  65. eFIADD16:
  66. call Load16Int
  67. xor edx,edx ;Both signs positive
  68. jmp AddSetResult
  69. EM_ENTRY eFISUB32
  70. eFISUB32:
  71. call Load32Int
  72. mov dx,bSign ;Change sign of source
  73. jmp AddSetResult
  74. EM_ENTRY eFISUBR32
  75. eFISUBR32:
  76. call Load32Int
  77. mov dx,bSign shl 8 ;Change sign of dest
  78. jmp AddSetResult
  79. EM_ENTRY eFIADD32
  80. eFIADD32:
  81. call Load32Int
  82. xor edx,edx ;Both signs positive
  83. jmp AddSetResult
  84. EM_ENTRY eFSUB32
  85. eFSUB32:
  86. call Load32Real
  87. mov dx,bSign ;Change sign of source
  88. jmp AddSetResult
  89. EM_ENTRY eFSUBR32
  90. eFSUBR32:
  91. call Load32Real
  92. mov dx,bSign shl 8 ;Change sign of dest
  93. jmp AddSetResult
  94. EM_ENTRY eFADD32
  95. eFADD32:
  96. call Load32Real
  97. xor edx,edx ;Both signs positive
  98. jmp AddSetResult
  99. EM_ENTRY eFSUB64
  100. eFSUB64:
  101. call Load64Real
  102. mov dx,bSign ;Change sign of source
  103. jmp AddSetResult
  104. EM_ENTRY eFSUBR64
  105. eFSUBR64:
  106. call Load64Real
  107. mov dx,bSign shl 8 ;Change sign of dest
  108. jmp AddSetResult
  109. EM_ENTRY eFADD64
  110. eFADD64:
  111. call Load64Real
  112. xor edx,edx ;Both signs positive
  113. jmp AddSetResult
  114. PolyAddDouble:
  115. ;This entry point is used by polynomial evaluator.
  116. ;It checks the operand in registers for zero, and doesn't require
  117. ;signs to be set up in dx.
  118. ;
  119. ;op1 mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7, tag in cl
  120. ;edi = pointer to op2 in ds
  121. xor edx,edx ;Addition
  122. cmp cl,bTAG_ZERO ;Adding to zero?
  123. jnz AddDouble
  124. ;Number in registers is zero, so just return value from memory.
  125. mov ecx,EMSEG:[edi].ExpSgn
  126. mov ebx,EMSEG:[edi].lManHi
  127. mov esi,EMSEG:[edi].lManLo
  128. ret
  129. EM_ENTRY eFSUBPreg
  130. eFSUBPreg:
  131. push offset PopWhenDone
  132. EM_ENTRY eFSUBreg
  133. eFSUBreg:
  134. xchg esi,edi
  135. EM_ENTRY eFSUBtop
  136. eFSUBtop:
  137. mov dx,bSign ;Change sign of source
  138. jmp AddHaveSgn
  139. EM_ENTRY eFSUBRPreg
  140. eFSUBRPreg:
  141. push offset PopWhenDone
  142. EM_ENTRY eFSUBRreg
  143. eFSUBRreg:
  144. xchg esi,edi
  145. EM_ENTRY eFSUBRtop
  146. eFSUBRtop:
  147. mov dx,bSign shl 8 ;Change sign of dest
  148. jmp AddHaveSgn
  149. InsignifAdd:
  150. mov eax,1 ;Set sticky bit
  151. shl ch,1 ;Get sign, CY set IFF subtracting mant.
  152. jnc ReturnOp1
  153. sub esi,eax ;Subtract 1 from mantissa
  154. sbb ebx,0
  155. neg eax
  156. ReturnOp1:
  157. ;ebx:esi:eax = normalized unrounded mantissa
  158. ;high half of ecx = exponent
  159. ;high bit of ch = sign
  160. jmp EMSEG:[RoundMode]
  161. EM_ENTRY eFADDPreg
  162. eFADDPreg:
  163. push offset PopWhenDone
  164. EM_ENTRY eFADDreg
  165. eFADDreg:
  166. xchg esi,edi
  167. EM_ENTRY eFADDtop
  168. eFADDtop:
  169. xor edx,edx ;Both signs positive
  170. AddHaveSgn:
  171. mov ecx,EMSEG:[esi].ExpSgn
  172. mov ebx,EMSEG:[esi].lManHi
  173. mov esi,EMSEG:[esi].lManLo
  174. AddSetResult:
  175. mov ebp,offset tFaddDisp
  176. mov EMSEG:[Result],edi ;Save result pointer
  177. mov al,cl
  178. mov ah,EMSEG:[edi].bTag
  179. test ax,ZEROorSPCL * 100H + ZEROorSPCL
  180. jnz TwoOpDispatch
  181. ;.erre AddDouble eq $ ;Fall into AddDouble
  182. ;*********
  183. AddDouble:
  184. ;*********
  185. ;
  186. ;op1 mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7
  187. ;dl = sign change for op1
  188. ;dh = sign change for op2
  189. ;edi = pointer to op2
  190. xor ch,dl ;Flip sign if subtracting
  191. mov eax,EMSEG:[edi].ExpSgn
  192. xor ah,dh ;Flip sign if subtracting
  193. mov edx,EMSEG:[edi].lManHi
  194. mov edi,EMSEG:[edi].lManLo
  195. AddDoubleReg:
  196. ;op1 mantissa in ebx:esi, exponent in high ecx, sign in ch bit 7
  197. ;op2 mantissa in edx:edi, exponent in high eax, sign in ah bit 7
  198. cmp eax,ecx ;Compare exponents
  199. .erre TexpBias eq 0 ;Not biased, use signed jump
  200. jle short HavLg ;op1 is larger, we have the right order
  201. xchg esi,edi
  202. xchg ebx,edx
  203. xchg eax,ecx
  204. HavLg:
  205. ;Larger in ebx:esi. Note that if the exponents were equal, things like
  206. ;the sign bit or tag may have determined which is "larger". It doesn't
  207. ;matter which is which if the exponents are equal, however.
  208. and ah,80H ;Keep sign bit
  209. sar ch,1 ;Extend sign into bit 6 of byte
  210. xor ch,ah ;See if signs are the same
  211. xor ax,ax ;Clear out sign and tag
  212. neg eax ;ax still 0
  213. add eax,ecx ;Get exponent difference
  214. shr eax,16 ;Bring exp. difference down to low end
  215. jz short Aligned
  216. cmp eax,64+1 ;Is difference in range?
  217. ;CONSIDER: tell me again why 1/4 LSB could have effect. It seems like
  218. ;CONSIDER: 1/2 LSB is the limit.
  219. ja short InsignifAdd ; (Even 1/4 LSB could have effect)
  220. mov cl,al ;Shift count to cl
  221. ;High half ecx = exponent
  222. ;ch bit 7 = sign difference
  223. ;ch bit 6 = sign
  224. ;cl = shift count
  225. xor eax,eax ;Prepare to take bits shifted out
  226. cmp cl,32 ;More than a whole word?
  227. jb short ShortShift
  228. xchg eax,edx ;Save bits shifted out in eax
  229. xchg edi,eax
  230. sub cl,32
  231. cmp cl,8 ;Safe to shift this much
  232. jb short ShortSticky
  233. ;Collapse all (sticky) bits of eax into LSB of edi
  234. neg eax ;Sets CY if eax was not zero
  235. sbb eax,eax ;-1 if CY was set, zero otherwise
  236. neg eax ;Sticky bit in LSB only
  237. or di,ax ;Move sticky bit up
  238. cmp cl,32 ;Less than another Dword?
  239. jb short ShortShift
  240. mov eax,edi
  241. xor edi,edi ;edx = edi = 0
  242. ShortSticky:
  243. ;Shift will not be more than 8 bits
  244. or ah,al ;Move up sticky bits
  245. ShortShift:
  246. shrd eax,edi,cl ;Save bits shifted out in eax
  247. shrd edi,edx,cl
  248. shr edx,cl
  249. Aligned:
  250. shl ch,1 ;Were signs the same?
  251. jc short SubMant ;No--go subtract mantissas
  252. ;Add mantissas
  253. add esi,edi
  254. adc ebx,edx
  255. jnc short AddExit
  256. ;Addition of mantissas overflowed. Bump exponent and shift right
  257. shrd eax,esi,1
  258. shrd esi,ebx,1 ;Faster than RCR
  259. sar ebx,1
  260. or ebx,1 shl 31 ;Set MSB
  261. add ecx,1 shl 16
  262. AddExit:
  263. ;ebx:esi:eax = normalized unrounded mantissa
  264. ;high half of ecx = exponent
  265. ;high bit of ch = sign
  266. jmp EMSEG:[RoundMode]
  267. NegMant:
  268. ;To get here, exponents must have been equal and op2 was bigger than op1.
  269. ;Note that this means nothing ever got shifted into eax.
  270. not ch ;Change sign of result
  271. not ebx
  272. neg esi
  273. sbb ebx,-1
  274. js short AddExit ;Already normalized?
  275. test ebx,40000000H ;Only one bit out of normal?
  276. jz short NormalizeAdd
  277. jmp short NormOneBit
  278. SubMant:
  279. ;Subtract mantissas
  280. neg eax ;Pretend minuend is zero extended
  281. sbb esi,edi
  282. sbb ebx,edx
  283. jc short NegMant
  284. js short AddExit ;Already normalized?
  285. NormChk:
  286. test ebx,40000000H ;Only one bit out of normal?
  287. jz short NormalizeAdd
  288. ;One bit normalization
  289. NormOneBit:
  290. sub ecx,1 shl 16 ;Adjust exponent
  291. ShiftOneBit: ;Entry point from emfmul.asm
  292. shld ebx,esi,1
  293. shld esi,eax,1
  294. shl eax,1
  295. jmp EMSEG:[RoundMode]
  296. ;***********
  297. AddZeroZero: ;Entry point for adding two zeros
  298. ;***********
  299. mov ah,EMSEG:[edi].bSgn ;Get sign of op
  300. xor ch,dl ;Possibly subtracting source
  301. xor ah,dh ;Possibly subtracting dest
  302. xor ch,ah ;Do signs match?
  303. js FindZeroSign ;No - use rounding mode to set sign
  304. mov EMSEG:[edi].bSgn,ah ;Correct the sign if subtracting
  305. ret ;Result at [edi] is now correct
  306. ZeroChk:
  307. ;Upper 64 bits were all zero, but there could be 1 bit in the MSB
  308. ;of eax.
  309. or eax,eax
  310. jnz short OneBitLeft
  311. mov ebx,eax
  312. mov esi,eax ;Zero mantissa
  313. FindZeroSign:
  314. ;Round to -0 if "round down" mode, round to +0 otherwise
  315. xor ecx,ecx ;Zero exponent, positive sign
  316. mov dl,EMSEG:[CWcntl] ;Get control word
  317. and dl,RoundControl
  318. cmp dl,RCdown ;Rounding down?
  319. jnz ZeroJmp
  320. mov ch,80H ;Set sign bit
  321. ZeroJmp:
  322. mov cl,bTAG_ZERO
  323. jmp EMSEG:[ZeroVector]
  324. OneBitLeft:
  325. xchg ebx,eax ;Bit now normalized
  326. sub ecx,64 shl 16 ;Adjust exponent
  327. jmp EMSEG:[RoundMode]
  328. NormalizeAdd:
  329. ;Inputs:
  330. ; ebx:esi:eax = 65-bit number
  331. ; ecx high half = exponent
  332. ;
  333. ;Since we are more than 1 bit out of normalization, exponents must have
  334. ;differed by 0 or 1. Thus rounding will not be necessary for 64 bits.
  335. bsr edx,ebx ;Scan for MSB
  336. jnz short ShortNorm
  337. bsr edx,esi
  338. jz short ZeroChk
  339. sub ecx,32 shl 16 ;Adjust exponent
  340. mov ebx,esi ;Push it up 32 bits
  341. mov esi,eax
  342. ShortNorm:
  343. ;Bit number in edx ranges from 0 to 31
  344. mov cl,dl
  345. not cl ;Convert bit number to shift count
  346. shld ebx,esi,cl
  347. shld esi,eax,cl
  348. shl edx,16 ;Move exp. adjustment to high end
  349. lea ecx,[ecx+edx-(31 shl 16)] ;Adjust exponent
  350. xor eax,eax ;No extra bits
  351. jmp EMSEG:[RoundMode]
  352. AddDestSign:
  353. xor EMSEG:[edi].bSgn,dh
  354. ret
  355. AddSourceSign:
  356. xor ch,dl
  357. jmp SaveResult