res_func.S 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040
  1. |
  2. | res_func.sa 3.9 7/29/91
  3. |
  4. | Normalizes denormalized numbers if necessary and updates the
  5. | stack frame. The function is then restored back into the
  6. | machine and the 040 completes the operation. This routine
  7. | is only used by the unsupported data type/format handler.
  8. | (Exception vector 55).
  9. |
  10. | For packed move out (fmove.p fpm,<ea>) the operation is
  11. | completed here; data is packed and moved to user memory.
  12. | The stack is restored to the 040 only in the case of a
  13. | reportable exception in the conversion.
  14. |
  15. |
  16. | Copyright (C) Motorola, Inc. 1990
  17. | All Rights Reserved
  18. |
  19. | THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MOTOROLA
  20. | The copyright notice above does not evidence any
  21. | actual or intended publication of such source code.
  22. RES_FUNC: |idnt 2,1 | Motorola 040 Floating Point Software Package
  23. |section 8
  24. #include "fpsp.h"
  25. sp_bnds: .short 0x3f81,0x407e
  26. .short 0x3f6a,0x0000
  27. dp_bnds: .short 0x3c01,0x43fe
  28. .short 0x3bcd,0x0000
  29. |xref mem_write
  30. |xref bindec
  31. |xref get_fline
  32. |xref round
  33. |xref denorm
  34. |xref dest_ext
  35. |xref dest_dbl
  36. |xref dest_sgl
  37. |xref unf_sub
  38. |xref nrm_set
  39. |xref dnrm_lp
  40. |xref ovf_res
  41. |xref reg_dest
  42. |xref t_ovfl
  43. |xref t_unfl
  44. .global res_func
  45. .global p_move
  46. res_func:
  47. clrb DNRM_FLG(%a6)
  48. clrb RES_FLG(%a6)
  49. clrb CU_ONLY(%a6)
  50. tstb DY_MO_FLG(%a6)
  51. beqs monadic
  52. dyadic:
  53. btstb #7,DTAG(%a6) |if dop = norm=000, zero=001,
  54. | ;inf=010 or nan=011
  55. beqs monadic |then branch
  56. | ;else denorm
  57. | HANDLE DESTINATION DENORM HERE
  58. | ;set dtag to norm
  59. | ;write the tag & fpte15 to the fstack
  60. leal FPTEMP(%a6),%a0
  61. bclrb #sign_bit,LOCAL_EX(%a0)
  62. sne LOCAL_SGN(%a0)
  63. bsr nrm_set |normalize number (exp will go negative)
  64. bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
  65. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  66. beqs dpos
  67. bsetb #sign_bit,LOCAL_EX(%a0)
  68. dpos:
  69. bfclr DTAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
  70. bsetb #4,DTAG(%a6) |set FPTE15
  71. orb #0x0f,DNRM_FLG(%a6)
  72. monadic:
  73. leal ETEMP(%a6),%a0
  74. btstb #direction_bit,CMDREG1B(%a6) |check direction
  75. bne opclass3 |it is a mv out
  76. |
  77. | At this point, only opclass 0 and 2 possible
  78. |
  79. btstb #7,STAG(%a6) |if sop = norm=000, zero=001,
  80. | ;inf=010 or nan=011
  81. bne mon_dnrm |else denorm
  82. tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
  83. bne normal |require normalization of denorm
  84. | At this point:
  85. | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
  86. | fmove = $00 fsmove = $40 fdmove = $44
  87. | fsqrt = $05* fssqrt = $41 fdsqrt = $45
  88. | (*fsqrt reencoded to $05)
  89. |
  90. movew CMDREG1B(%a6),%d0 |get command register
  91. andil #0x7f,%d0 |strip to only command word
  92. |
  93. | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
  94. | fdsqrt are possible.
  95. | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
  96. | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
  97. |
  98. btstl #0,%d0
  99. bne normal |weed out fsqrt instructions
  100. |
  101. | cu_norm handles fmove in instructions with normalized inputs.
  102. | The routine round is used to correctly round the input for the
  103. | destination precision and mode.
  104. |
  105. cu_norm:
  106. st CU_ONLY(%a6) |set cu-only inst flag
  107. movew CMDREG1B(%a6),%d0
  108. andib #0x3b,%d0 |isolate bits to select inst
  109. tstb %d0
  110. beql cu_nmove |if zero, it is an fmove
  111. cmpib #0x18,%d0
  112. beql cu_nabs |if $18, it is fabs
  113. cmpib #0x1a,%d0
  114. beql cu_nneg |if $1a, it is fneg
  115. |
  116. | Inst is ftst. Check the source operand and set the cc's accordingly.
  117. | No write is done, so simply rts.
  118. |
  119. cu_ntst:
  120. movew LOCAL_EX(%a0),%d0
  121. bclrl #15,%d0
  122. sne LOCAL_SGN(%a0)
  123. beqs cu_ntpo
  124. orl #neg_mask,USER_FPSR(%a6) |set N
  125. cu_ntpo:
  126. cmpiw #0x7fff,%d0 |test for inf/nan
  127. bnes cu_ntcz
  128. tstl LOCAL_HI(%a0)
  129. bnes cu_ntn
  130. tstl LOCAL_LO(%a0)
  131. bnes cu_ntn
  132. orl #inf_mask,USER_FPSR(%a6)
  133. rts
  134. cu_ntn:
  135. orl #nan_mask,USER_FPSR(%a6)
  136. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  137. | ;snan handler
  138. rts
  139. cu_ntcz:
  140. tstl LOCAL_HI(%a0)
  141. bnel cu_ntsx
  142. tstl LOCAL_LO(%a0)
  143. bnel cu_ntsx
  144. orl #z_mask,USER_FPSR(%a6)
  145. cu_ntsx:
  146. rts
  147. |
  148. | Inst is fabs. Execute the absolute value function on the input.
  149. | Branch to the fmove code. If the operand is NaN, do nothing.
  150. |
  151. cu_nabs:
  152. moveb STAG(%a6),%d0
  153. btstl #5,%d0 |test for NaN or zero
  154. bne wr_etemp |if either, simply write it
  155. bclrb #7,LOCAL_EX(%a0) |do abs
  156. bras cu_nmove |fmove code will finish
  157. |
  158. | Inst is fneg. Execute the negate value function on the input.
  159. | Fall though to the fmove code. If the operand is NaN, do nothing.
  160. |
  161. cu_nneg:
  162. moveb STAG(%a6),%d0
  163. btstl #5,%d0 |test for NaN or zero
  164. bne wr_etemp |if either, simply write it
  165. bchgb #7,LOCAL_EX(%a0) |do neg
  166. |
  167. | Inst is fmove. This code also handles all result writes.
  168. | If bit 2 is set, round is forced to double. If it is clear,
  169. | and bit 6 is set, round is forced to single. If both are clear,
  170. | the round precision is found in the fpcr. If the rounding precision
  171. | is double or single, round the result before the write.
  172. |
  173. cu_nmove:
  174. moveb STAG(%a6),%d0
  175. andib #0xe0,%d0 |isolate stag bits
  176. bne wr_etemp |if not norm, simply write it
  177. btstb #2,CMDREG1B+1(%a6) |check for rd
  178. bne cu_nmrd
  179. btstb #6,CMDREG1B+1(%a6) |check for rs
  180. bne cu_nmrs
  181. |
  182. | The move or operation is not with forced precision. Test for
  183. | nan or inf as the input; if so, simply write it to FPn. Use the
  184. | FPCR_MODE byte to get rounding on norms and zeros.
  185. |
  186. cu_nmnr:
  187. bfextu FPCR_MODE(%a6){#0:#2},%d0
  188. tstb %d0 |check for extended
  189. beq cu_wrexn |if so, just write result
  190. cmpib #1,%d0 |check for single
  191. beq cu_nmrs |fall through to double
  192. |
  193. | The move is fdmove or round precision is double.
  194. |
  195. cu_nmrd:
  196. movel #2,%d0 |set up the size for denorm
  197. movew LOCAL_EX(%a0),%d1 |compare exponent to double threshold
  198. andw #0x7fff,%d1
  199. cmpw #0x3c01,%d1
  200. bls cu_nunfl
  201. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  202. orl #0x00020000,%d1 |or in rprec (double)
  203. clrl %d0 |clear g,r,s for round
  204. bclrb #sign_bit,LOCAL_EX(%a0) |convert to internal format
  205. sne LOCAL_SGN(%a0)
  206. bsrl round
  207. bfclr LOCAL_SGN(%a0){#0:#8}
  208. beqs cu_nmrdc
  209. bsetb #sign_bit,LOCAL_EX(%a0)
  210. cu_nmrdc:
  211. movew LOCAL_EX(%a0),%d1 |check for overflow
  212. andw #0x7fff,%d1
  213. cmpw #0x43ff,%d1
  214. bge cu_novfl |take care of overflow case
  215. bra cu_wrexn
  216. |
  217. | The move is fsmove or round precision is single.
  218. |
  219. cu_nmrs:
  220. movel #1,%d0
  221. movew LOCAL_EX(%a0),%d1
  222. andw #0x7fff,%d1
  223. cmpw #0x3f81,%d1
  224. bls cu_nunfl
  225. bfextu FPCR_MODE(%a6){#2:#2},%d1
  226. orl #0x00010000,%d1
  227. clrl %d0
  228. bclrb #sign_bit,LOCAL_EX(%a0)
  229. sne LOCAL_SGN(%a0)
  230. bsrl round
  231. bfclr LOCAL_SGN(%a0){#0:#8}
  232. beqs cu_nmrsc
  233. bsetb #sign_bit,LOCAL_EX(%a0)
  234. cu_nmrsc:
  235. movew LOCAL_EX(%a0),%d1
  236. andw #0x7FFF,%d1
  237. cmpw #0x407f,%d1
  238. blt cu_wrexn
  239. |
  240. | The operand is above precision boundaries. Use t_ovfl to
  241. | generate the correct value.
  242. |
  243. cu_novfl:
  244. bsr t_ovfl
  245. bra cu_wrexn
  246. |
  247. | The operand is below precision boundaries. Use denorm to
  248. | generate the correct value.
  249. |
  250. cu_nunfl:
  251. bclrb #sign_bit,LOCAL_EX(%a0)
  252. sne LOCAL_SGN(%a0)
  253. bsr denorm
  254. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  255. beqs cu_nucont
  256. bsetb #sign_bit,LOCAL_EX(%a0)
  257. cu_nucont:
  258. bfextu FPCR_MODE(%a6){#2:#2},%d1
  259. btstb #2,CMDREG1B+1(%a6) |check for rd
  260. bne inst_d
  261. btstb #6,CMDREG1B+1(%a6) |check for rs
  262. bne inst_s
  263. swap %d1
  264. moveb FPCR_MODE(%a6),%d1
  265. lsrb #6,%d1
  266. swap %d1
  267. bra inst_sd
  268. inst_d:
  269. orl #0x00020000,%d1
  270. bra inst_sd
  271. inst_s:
  272. orl #0x00010000,%d1
  273. inst_sd:
  274. bclrb #sign_bit,LOCAL_EX(%a0)
  275. sne LOCAL_SGN(%a0)
  276. bsrl round
  277. bfclr LOCAL_SGN(%a0){#0:#8}
  278. beqs cu_nuflp
  279. bsetb #sign_bit,LOCAL_EX(%a0)
  280. cu_nuflp:
  281. btstb #inex2_bit,FPSR_EXCEPT(%a6)
  282. beqs cu_nuninx
  283. orl #aunfl_mask,USER_FPSR(%a6) |if the round was inex, set AUNFL
  284. cu_nuninx:
  285. tstl LOCAL_HI(%a0) |test for zero
  286. bnes cu_nunzro
  287. tstl LOCAL_LO(%a0)
  288. bnes cu_nunzro
  289. |
  290. | The mantissa is zero from the denorm loop. Check sign and rmode
  291. | to see if rounding should have occurred which would leave the lsb.
  292. |
  293. movel USER_FPCR(%a6),%d0
  294. andil #0x30,%d0 |isolate rmode
  295. cmpil #0x20,%d0
  296. blts cu_nzro
  297. bnes cu_nrp
  298. cu_nrm:
  299. tstw LOCAL_EX(%a0) |if positive, set lsb
  300. bges cu_nzro
  301. btstb #7,FPCR_MODE(%a6) |check for double
  302. beqs cu_nincs
  303. bras cu_nincd
  304. cu_nrp:
  305. tstw LOCAL_EX(%a0) |if positive, set lsb
  306. blts cu_nzro
  307. btstb #7,FPCR_MODE(%a6) |check for double
  308. beqs cu_nincs
  309. cu_nincd:
  310. orl #0x800,LOCAL_LO(%a0) |inc for double
  311. bra cu_nunzro
  312. cu_nincs:
  313. orl #0x100,LOCAL_HI(%a0) |inc for single
  314. bra cu_nunzro
  315. cu_nzro:
  316. orl #z_mask,USER_FPSR(%a6)
  317. moveb STAG(%a6),%d0
  318. andib #0xe0,%d0
  319. cmpib #0x40,%d0 |check if input was tagged zero
  320. beqs cu_numv
  321. cu_nunzro:
  322. orl #unfl_mask,USER_FPSR(%a6) |set unfl
  323. cu_numv:
  324. movel (%a0),ETEMP(%a6)
  325. movel 4(%a0),ETEMP_HI(%a6)
  326. movel 8(%a0),ETEMP_LO(%a6)
  327. |
  328. | Write the result to memory, setting the fpsr cc bits. NaN and Inf
  329. | bypass cu_wrexn.
  330. |
  331. cu_wrexn:
  332. tstw LOCAL_EX(%a0) |test for zero
  333. beqs cu_wrzero
  334. cmpw #0x8000,LOCAL_EX(%a0) |test for zero
  335. bnes cu_wreon
  336. cu_wrzero:
  337. orl #z_mask,USER_FPSR(%a6) |set Z bit
  338. cu_wreon:
  339. tstw LOCAL_EX(%a0)
  340. bpl wr_etemp
  341. orl #neg_mask,USER_FPSR(%a6)
  342. bra wr_etemp
  343. |
  344. | HANDLE SOURCE DENORM HERE
  345. |
  346. | ;clear denorm stag to norm
  347. | ;write the new tag & ete15 to the fstack
  348. mon_dnrm:
  349. |
  350. | At this point, check for the cases in which normalizing the
  351. | denorm produces incorrect results.
  352. |
  353. tstb DY_MO_FLG(%a6) |all cases of dyadic instructions would
  354. bnes nrm_src |require normalization of denorm
  355. | At this point:
  356. | monadic instructions: fabs = $18 fneg = $1a ftst = $3a
  357. | fmove = $00 fsmove = $40 fdmove = $44
  358. | fsqrt = $05* fssqrt = $41 fdsqrt = $45
  359. | (*fsqrt reencoded to $05)
  360. |
  361. movew CMDREG1B(%a6),%d0 |get command register
  362. andil #0x7f,%d0 |strip to only command word
  363. |
  364. | At this point, fabs, fneg, fsmove, fdmove, ftst, fsqrt, fssqrt, and
  365. | fdsqrt are possible.
  366. | For cases fabs, fneg, fsmove, and fdmove goto spos (do not normalize)
  367. | For cases fsqrt, fssqrt, and fdsqrt goto nrm_src (do normalize)
  368. |
  369. btstl #0,%d0
  370. bnes nrm_src |weed out fsqrt instructions
  371. st CU_ONLY(%a6) |set cu-only inst flag
  372. bra cu_dnrm |fmove, fabs, fneg, ftst
  373. | ;cases go to cu_dnrm
  374. nrm_src:
  375. bclrb #sign_bit,LOCAL_EX(%a0)
  376. sne LOCAL_SGN(%a0)
  377. bsr nrm_set |normalize number (exponent will go
  378. | ; negative)
  379. bclrb #sign_bit,LOCAL_EX(%a0) |get rid of false sign
  380. bfclr LOCAL_SGN(%a0){#0:#8} |change back to IEEE ext format
  381. beqs spos
  382. bsetb #sign_bit,LOCAL_EX(%a0)
  383. spos:
  384. bfclr STAG(%a6){#0:#4} |set tag to normalized, FPTE15 = 0
  385. bsetb #4,STAG(%a6) |set ETE15
  386. orb #0xf0,DNRM_FLG(%a6)
  387. normal:
  388. tstb DNRM_FLG(%a6) |check if any of the ops were denorms
  389. bne ck_wrap |if so, check if it is a potential
  390. | ;wrap-around case
  391. fix_stk:
  392. moveb #0xfe,CU_SAVEPC(%a6)
  393. bclrb #E1,E_BYTE(%a6)
  394. clrw NMNEXC(%a6)
  395. st RES_FLG(%a6) |indicate that a restore is needed
  396. rts
  397. |
  398. | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and
  399. | ftst) completely in software without an frestore to the 040.
  400. |
  401. cu_dnrm:
  402. st CU_ONLY(%a6)
  403. movew CMDREG1B(%a6),%d0
  404. andib #0x3b,%d0 |isolate bits to select inst
  405. tstb %d0
  406. beql cu_dmove |if zero, it is an fmove
  407. cmpib #0x18,%d0
  408. beql cu_dabs |if $18, it is fabs
  409. cmpib #0x1a,%d0
  410. beql cu_dneg |if $1a, it is fneg
  411. |
  412. | Inst is ftst. Check the source operand and set the cc's accordingly.
  413. | No write is done, so simply rts.
  414. |
  415. cu_dtst:
  416. movew LOCAL_EX(%a0),%d0
  417. bclrl #15,%d0
  418. sne LOCAL_SGN(%a0)
  419. beqs cu_dtpo
  420. orl #neg_mask,USER_FPSR(%a6) |set N
  421. cu_dtpo:
  422. cmpiw #0x7fff,%d0 |test for inf/nan
  423. bnes cu_dtcz
  424. tstl LOCAL_HI(%a0)
  425. bnes cu_dtn
  426. tstl LOCAL_LO(%a0)
  427. bnes cu_dtn
  428. orl #inf_mask,USER_FPSR(%a6)
  429. rts
  430. cu_dtn:
  431. orl #nan_mask,USER_FPSR(%a6)
  432. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  433. | ;snan handler
  434. rts
  435. cu_dtcz:
  436. tstl LOCAL_HI(%a0)
  437. bnel cu_dtsx
  438. tstl LOCAL_LO(%a0)
  439. bnel cu_dtsx
  440. orl #z_mask,USER_FPSR(%a6)
  441. cu_dtsx:
  442. rts
  443. |
  444. | Inst is fabs. Execute the absolute value function on the input.
  445. | Branch to the fmove code.
  446. |
  447. cu_dabs:
  448. bclrb #7,LOCAL_EX(%a0) |do abs
  449. bras cu_dmove |fmove code will finish
  450. |
  451. | Inst is fneg. Execute the negate value function on the input.
  452. | Fall though to the fmove code.
  453. |
  454. cu_dneg:
  455. bchgb #7,LOCAL_EX(%a0) |do neg
  456. |
  457. | Inst is fmove. This code also handles all result writes.
  458. | If bit 2 is set, round is forced to double. If it is clear,
  459. | and bit 6 is set, round is forced to single. If both are clear,
  460. | the round precision is found in the fpcr. If the rounding precision
  461. | is double or single, the result is zero, and the mode is checked
  462. | to determine if the lsb of the result should be set.
  463. |
  464. cu_dmove:
  465. btstb #2,CMDREG1B+1(%a6) |check for rd
  466. bne cu_dmrd
  467. btstb #6,CMDREG1B+1(%a6) |check for rs
  468. bne cu_dmrs
  469. |
  470. | The move or operation is not with forced precision. Use the
  471. | FPCR_MODE byte to get rounding.
  472. |
  473. cu_dmnr:
  474. bfextu FPCR_MODE(%a6){#0:#2},%d0
  475. tstb %d0 |check for extended
  476. beq cu_wrexd |if so, just write result
  477. cmpib #1,%d0 |check for single
  478. beq cu_dmrs |fall through to double
  479. |
  480. | The move is fdmove or round precision is double. Result is zero.
  481. | Check rmode for rp or rm and set lsb accordingly.
  482. |
  483. cu_dmrd:
  484. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  485. tstw LOCAL_EX(%a0) |check sign
  486. blts cu_dmdn
  487. cmpib #3,%d1 |check for rp
  488. bne cu_dpd |load double pos zero
  489. bra cu_dpdr |load double pos zero w/lsb
  490. cu_dmdn:
  491. cmpib #2,%d1 |check for rm
  492. bne cu_dnd |load double neg zero
  493. bra cu_dndr |load double neg zero w/lsb
  494. |
  495. | The move is fsmove or round precision is single. Result is zero.
  496. | Check for rp or rm and set lsb accordingly.
  497. |
  498. cu_dmrs:
  499. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rmode
  500. tstw LOCAL_EX(%a0) |check sign
  501. blts cu_dmsn
  502. cmpib #3,%d1 |check for rp
  503. bne cu_spd |load single pos zero
  504. bra cu_spdr |load single pos zero w/lsb
  505. cu_dmsn:
  506. cmpib #2,%d1 |check for rm
  507. bne cu_snd |load single neg zero
  508. bra cu_sndr |load single neg zero w/lsb
  509. |
  510. | The precision is extended, so the result in etemp is correct.
  511. | Simply set unfl (not inex2 or aunfl) and write the result to
  512. | the correct fp register.
  513. cu_wrexd:
  514. orl #unfl_mask,USER_FPSR(%a6)
  515. tstw LOCAL_EX(%a0)
  516. beq wr_etemp
  517. orl #neg_mask,USER_FPSR(%a6)
  518. bra wr_etemp
  519. |
  520. | These routines write +/- zero in double format. The routines
  521. | cu_dpdr and cu_dndr set the double lsb.
  522. |
  523. cu_dpd:
  524. movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
  525. clrl LOCAL_HI(%a0)
  526. clrl LOCAL_LO(%a0)
  527. orl #z_mask,USER_FPSR(%a6)
  528. orl #unfinx_mask,USER_FPSR(%a6)
  529. bra wr_etemp
  530. cu_dpdr:
  531. movel #0x3c010000,LOCAL_EX(%a0) |force pos double zero
  532. clrl LOCAL_HI(%a0)
  533. movel #0x800,LOCAL_LO(%a0) |with lsb set
  534. orl #unfinx_mask,USER_FPSR(%a6)
  535. bra wr_etemp
  536. cu_dnd:
  537. movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
  538. clrl LOCAL_HI(%a0)
  539. clrl LOCAL_LO(%a0)
  540. orl #z_mask,USER_FPSR(%a6)
  541. orl #neg_mask,USER_FPSR(%a6)
  542. orl #unfinx_mask,USER_FPSR(%a6)
  543. bra wr_etemp
  544. cu_dndr:
  545. movel #0xbc010000,LOCAL_EX(%a0) |force pos double zero
  546. clrl LOCAL_HI(%a0)
  547. movel #0x800,LOCAL_LO(%a0) |with lsb set
  548. orl #neg_mask,USER_FPSR(%a6)
  549. orl #unfinx_mask,USER_FPSR(%a6)
  550. bra wr_etemp
  551. |
  552. | These routines write +/- zero in single format. The routines
  553. | cu_dpdr and cu_dndr set the single lsb.
  554. |
  555. cu_spd:
  556. movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
  557. clrl LOCAL_HI(%a0)
  558. clrl LOCAL_LO(%a0)
  559. orl #z_mask,USER_FPSR(%a6)
  560. orl #unfinx_mask,USER_FPSR(%a6)
  561. bra wr_etemp
  562. cu_spdr:
  563. movel #0x3f810000,LOCAL_EX(%a0) |force pos single zero
  564. movel #0x100,LOCAL_HI(%a0) |with lsb set
  565. clrl LOCAL_LO(%a0)
  566. orl #unfinx_mask,USER_FPSR(%a6)
  567. bra wr_etemp
  568. cu_snd:
  569. movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
  570. clrl LOCAL_HI(%a0)
  571. clrl LOCAL_LO(%a0)
  572. orl #z_mask,USER_FPSR(%a6)
  573. orl #neg_mask,USER_FPSR(%a6)
  574. orl #unfinx_mask,USER_FPSR(%a6)
  575. bra wr_etemp
  576. cu_sndr:
  577. movel #0xbf810000,LOCAL_EX(%a0) |force pos single zero
  578. movel #0x100,LOCAL_HI(%a0) |with lsb set
  579. clrl LOCAL_LO(%a0)
  580. orl #neg_mask,USER_FPSR(%a6)
  581. orl #unfinx_mask,USER_FPSR(%a6)
  582. bra wr_etemp
  583. |
  584. | This code checks for 16-bit overflow conditions on dyadic
  585. | operations which are not restorable into the floating-point
  586. | unit and must be completed in software. Basically, this
  587. | condition exists with a very large norm and a denorm. One
  588. | of the operands must be denormalized to enter this code.
  589. |
  590. | Flags used:
  591. | DY_MO_FLG contains 0 for monadic op, $ff for dyadic
  592. | DNRM_FLG contains $00 for neither op denormalized
  593. | $0f for the destination op denormalized
  594. | $f0 for the source op denormalized
  595. | $ff for both ops denormalized
  596. |
  597. | The wrap-around condition occurs for add, sub, div, and cmp
  598. | when
  599. |
  600. | abs(dest_exp - src_exp) >= $8000
  601. |
  602. | and for mul when
  603. |
  604. | (dest_exp + src_exp) < $0
  605. |
  606. | we must process the operation here if this case is true.
  607. |
  608. | The rts following the frcfpn routine is the exit from res_func
  609. | for this condition. The restore flag (RES_FLG) is left clear.
  610. | No frestore is done unless an exception is to be reported.
  611. |
  612. | For fadd:
  613. | if(sign_of(dest) != sign_of(src))
  614. | replace exponent of src with $3fff (keep sign)
  615. | use fpu to perform dest+new_src (user's rmode and X)
  616. | clr sticky
  617. | else
  618. | set sticky
  619. | call round with user's precision and mode
  620. | move result to fpn and wbtemp
  621. |
  622. | For fsub:
  623. | if(sign_of(dest) == sign_of(src))
  624. | replace exponent of src with $3fff (keep sign)
  625. | use fpu to perform dest+new_src (user's rmode and X)
  626. | clr sticky
  627. | else
  628. | set sticky
  629. | call round with user's precision and mode
  630. | move result to fpn and wbtemp
  631. |
  632. | For fdiv/fsgldiv:
  633. | if(both operands are denorm)
  634. | restore_to_fpu;
  635. | if(dest is norm)
  636. | force_ovf;
  637. | else(dest is denorm)
  638. | force_unf:
  639. |
  640. | For fcmp:
  641. | if(dest is norm)
  642. | N = sign_of(dest);
  643. | else(dest is denorm)
  644. | N = sign_of(src);
  645. |
  646. | For fmul:
  647. | if(both operands are denorm)
  648. | force_unf;
  649. | if((dest_exp + src_exp) < 0)
  650. | force_unf:
  651. | else
  652. | restore_to_fpu;
  653. |
  654. | local equates:
  655. .set addcode,0x22
  656. .set subcode,0x28
  657. .set mulcode,0x23
  658. .set divcode,0x20
  659. .set cmpcode,0x38
  660. ck_wrap:
  661. | tstb DY_MO_FLG(%a6) ;check for fsqrt
  662. beq fix_stk |if zero, it is fsqrt
  663. movew CMDREG1B(%a6),%d0
  664. andiw #0x3b,%d0 |strip to command bits
  665. cmpiw #addcode,%d0
  666. beq wrap_add
  667. cmpiw #subcode,%d0
  668. beq wrap_sub
  669. cmpiw #mulcode,%d0
  670. beq wrap_mul
  671. cmpiw #cmpcode,%d0
  672. beq wrap_cmp
  673. |
  674. | Inst is fdiv.
  675. |
  676. wrap_div:
  677. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  678. beq fix_stk |restore to fpu
  679. |
  680. | One of the ops is denormalized. Test for wrap condition
  681. | and force the result.
  682. |
  683. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  684. bnes div_srcd
  685. div_destd:
  686. bsrl ckinf_ns
  687. bne fix_stk
  688. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  689. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  690. subl %d1,%d0 |subtract dest from src
  691. cmpl #0x7fff,%d0
  692. blt fix_stk |if less, not wrap case
  693. clrb WBTEMP_SGN(%a6)
  694. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  695. movew FPTEMP_EX(%a6),%d1
  696. eorw %d1,%d0
  697. andiw #0x8000,%d0
  698. beq force_unf
  699. st WBTEMP_SGN(%a6)
  700. bra force_unf
  701. ckinf_ns:
  702. moveb STAG(%a6),%d0 |check source tag for inf or nan
  703. bra ck_in_com
  704. ckinf_nd:
  705. moveb DTAG(%a6),%d0 |check destination tag for inf or nan
  706. ck_in_com:
  707. andib #0x60,%d0 |isolate tag bits
  708. cmpb #0x40,%d0 |is it inf?
  709. beq nan_or_inf |not wrap case
  710. cmpb #0x60,%d0 |is it nan?
  711. beq nan_or_inf |yes, not wrap case?
  712. cmpb #0x20,%d0 |is it a zero?
  713. beq nan_or_inf |yes
  714. clrl %d0
  715. rts |then ; it is either a zero of norm,
  716. | ;check wrap case
  717. nan_or_inf:
  718. moveql #-1,%d0
  719. rts
  720. div_srcd:
  721. bsrl ckinf_nd
  722. bne fix_stk
  723. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  724. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  725. subl %d1,%d0 |subtract src from dest
  726. cmpl #0x8000,%d0
  727. blt fix_stk |if less, not wrap case
  728. clrb WBTEMP_SGN(%a6)
  729. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  730. movew FPTEMP_EX(%a6),%d1
  731. eorw %d1,%d0
  732. andiw #0x8000,%d0
  733. beqs force_ovf
  734. st WBTEMP_SGN(%a6)
  735. |
  736. | This code handles the case of the instruction resulting in
  737. | an overflow condition.
  738. |
  739. force_ovf:
  740. bclrb #E1,E_BYTE(%a6)
  741. orl #ovfl_inx_mask,USER_FPSR(%a6)
  742. clrw NMNEXC(%a6)
  743. leal WBTEMP(%a6),%a0 |point a0 to memory location
  744. movew CMDREG1B(%a6),%d0
  745. btstl #6,%d0 |test for forced precision
  746. beqs frcovf_fpcr
  747. btstl #2,%d0 |check for double
  748. bnes frcovf_dbl
  749. movel #0x1,%d0 |inst is forced single
  750. bras frcovf_rnd
  751. frcovf_dbl:
  752. movel #0x2,%d0 |inst is forced double
  753. bras frcovf_rnd
  754. frcovf_fpcr:
  755. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  756. frcovf_rnd:
  757. | The 881/882 does not set inex2 for the following case, so the
  758. | line is commented out to be compatible with 881/882
  759. | tst.b %d0
  760. | beq.b frcovf_x
  761. | or.l #inex2_mask,USER_FPSR(%a6) ;if prec is s or d, set inex2
  762. |frcovf_x:
  763. bsrl ovf_res |get correct result based on
  764. | ;round precision/mode. This
  765. | ;sets FPSR_CC correctly
  766. | ;returns in external format
  767. bfclr WBTEMP_SGN(%a6){#0:#8}
  768. beq frcfpn
  769. bsetb #sign_bit,WBTEMP_EX(%a6)
  770. bra frcfpn
  771. |
  772. | Inst is fadd.
  773. |
  774. wrap_add:
  775. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  776. beq fix_stk |restore to fpu
  777. |
  778. | One of the ops is denormalized. Test for wrap condition
  779. | and complete the instruction.
  780. |
  781. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  782. bnes add_srcd
  783. add_destd:
  784. bsrl ckinf_ns
  785. bne fix_stk
  786. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  787. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  788. subl %d1,%d0 |subtract dest from src
  789. cmpl #0x8000,%d0
  790. blt fix_stk |if less, not wrap case
  791. bra add_wrap
  792. add_srcd:
  793. bsrl ckinf_nd
  794. bne fix_stk
  795. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  796. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  797. subl %d1,%d0 |subtract src from dest
  798. cmpl #0x8000,%d0
  799. blt fix_stk |if less, not wrap case
  800. |
  801. | Check the signs of the operands. If they are unlike, the fpu
  802. | can be used to add the norm and 1.0 with the sign of the
  803. | denorm and it will correctly generate the result in extended
  804. | precision. We can then call round with no sticky and the result
  805. | will be correct for the user's rounding mode and precision. If
  806. | the signs are the same, we call round with the sticky bit set
  807. | and the result will be correct for the user's rounding mode and
  808. | precision.
  809. |
  810. add_wrap:
  811. movew ETEMP_EX(%a6),%d0
  812. movew FPTEMP_EX(%a6),%d1
  813. eorw %d1,%d0
  814. andiw #0x8000,%d0
  815. beq add_same
  816. |
  817. | The signs are unlike.
  818. |
  819. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  820. bnes add_u_srcd
  821. movew FPTEMP_EX(%a6),%d0
  822. andiw #0x8000,%d0
  823. orw #0x3fff,%d0 |force the exponent to +/- 1
  824. movew %d0,FPTEMP_EX(%a6) |in the denorm
  825. movel USER_FPCR(%a6),%d0
  826. andil #0x30,%d0
  827. fmovel %d0,%fpcr |set up users rmode and X
  828. fmovex ETEMP(%a6),%fp0
  829. faddx FPTEMP(%a6),%fp0
  830. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  831. fmovel %fpsr,%d1
  832. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  833. fmovex %fp0,WBTEMP(%a6) |write result to memory
  834. lsrl #4,%d0 |put rmode in lower 2 bits
  835. movel USER_FPCR(%a6),%d1
  836. andil #0xc0,%d1
  837. lsrl #6,%d1 |put precision in upper word
  838. swap %d1
  839. orl %d0,%d1 |set up for round call
  840. clrl %d0 |force sticky to zero
  841. bclrb #sign_bit,WBTEMP_EX(%a6)
  842. sne WBTEMP_SGN(%a6)
  843. bsrl round |round result to users rmode & prec
  844. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  845. beq frcfpnr
  846. bsetb #sign_bit,WBTEMP_EX(%a6)
  847. bra frcfpnr
  848. add_u_srcd:
  849. movew ETEMP_EX(%a6),%d0
  850. andiw #0x8000,%d0
  851. orw #0x3fff,%d0 |force the exponent to +/- 1
  852. movew %d0,ETEMP_EX(%a6) |in the denorm
  853. movel USER_FPCR(%a6),%d0
  854. andil #0x30,%d0
  855. fmovel %d0,%fpcr |set up users rmode and X
  856. fmovex ETEMP(%a6),%fp0
  857. faddx FPTEMP(%a6),%fp0
  858. fmovel %fpsr,%d1
  859. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  860. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  861. fmovex %fp0,WBTEMP(%a6) |write result to memory
  862. lsrl #4,%d0 |put rmode in lower 2 bits
  863. movel USER_FPCR(%a6),%d1
  864. andil #0xc0,%d1
  865. lsrl #6,%d1 |put precision in upper word
  866. swap %d1
  867. orl %d0,%d1 |set up for round call
  868. clrl %d0 |force sticky to zero
  869. bclrb #sign_bit,WBTEMP_EX(%a6)
  870. sne WBTEMP_SGN(%a6) |use internal format for round
  871. bsrl round |round result to users rmode & prec
  872. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  873. beq frcfpnr
  874. bsetb #sign_bit,WBTEMP_EX(%a6)
  875. bra frcfpnr
  876. |
  877. | Signs are alike:
  878. |
  879. add_same:
  880. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  881. bnes add_s_srcd
  882. add_s_destd:
  883. leal ETEMP(%a6),%a0
  884. movel USER_FPCR(%a6),%d0
  885. andil #0x30,%d0
  886. lsrl #4,%d0 |put rmode in lower 2 bits
  887. movel USER_FPCR(%a6),%d1
  888. andil #0xc0,%d1
  889. lsrl #6,%d1 |put precision in upper word
  890. swap %d1
  891. orl %d0,%d1 |set up for round call
  892. movel #0x20000000,%d0 |set sticky for round
  893. bclrb #sign_bit,ETEMP_EX(%a6)
  894. sne ETEMP_SGN(%a6)
  895. bsrl round |round result to users rmode & prec
  896. bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  897. beqs add_s_dclr
  898. bsetb #sign_bit,ETEMP_EX(%a6)
  899. add_s_dclr:
  900. leal WBTEMP(%a6),%a0
  901. movel ETEMP(%a6),(%a0) |write result to wbtemp
  902. movel ETEMP_HI(%a6),4(%a0)
  903. movel ETEMP_LO(%a6),8(%a0)
  904. tstw ETEMP_EX(%a6)
  905. bgt add_ckovf
  906. orl #neg_mask,USER_FPSR(%a6)
  907. bra add_ckovf
  908. add_s_srcd:
  909. leal FPTEMP(%a6),%a0
  910. movel USER_FPCR(%a6),%d0
  911. andil #0x30,%d0
  912. lsrl #4,%d0 |put rmode in lower 2 bits
  913. movel USER_FPCR(%a6),%d1
  914. andil #0xc0,%d1
  915. lsrl #6,%d1 |put precision in upper word
  916. swap %d1
  917. orl %d0,%d1 |set up for round call
  918. movel #0x20000000,%d0 |set sticky for round
  919. bclrb #sign_bit,FPTEMP_EX(%a6)
  920. sne FPTEMP_SGN(%a6)
  921. bsrl round |round result to users rmode & prec
  922. bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  923. beqs add_s_sclr
  924. bsetb #sign_bit,FPTEMP_EX(%a6)
  925. add_s_sclr:
  926. leal WBTEMP(%a6),%a0
  927. movel FPTEMP(%a6),(%a0) |write result to wbtemp
  928. movel FPTEMP_HI(%a6),4(%a0)
  929. movel FPTEMP_LO(%a6),8(%a0)
  930. tstw FPTEMP_EX(%a6)
  931. bgt add_ckovf
  932. orl #neg_mask,USER_FPSR(%a6)
  933. add_ckovf:
  934. movew WBTEMP_EX(%a6),%d0
  935. andiw #0x7fff,%d0
  936. cmpiw #0x7fff,%d0
  937. bne frcfpnr
  938. |
  939. | The result has overflowed to $7fff exponent. Set I, ovfl,
  940. | and aovfl, and clr the mantissa (incorrectly set by the
  941. | round routine.)
  942. |
  943. orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
  944. clrl 4(%a0)
  945. bra frcfpnr
  946. |
  947. | Inst is fsub.
  948. |
  949. wrap_sub:
  950. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  951. beq fix_stk |restore to fpu
  952. |
  953. | One of the ops is denormalized. Test for wrap condition
  954. | and complete the instruction.
  955. |
  956. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  957. bnes sub_srcd
  958. sub_destd:
  959. bsrl ckinf_ns
  960. bne fix_stk
  961. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  962. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  963. subl %d1,%d0 |subtract src from dest
  964. cmpl #0x8000,%d0
  965. blt fix_stk |if less, not wrap case
  966. bra sub_wrap
  967. sub_srcd:
  968. bsrl ckinf_nd
  969. bne fix_stk
  970. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  971. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  972. subl %d1,%d0 |subtract dest from src
  973. cmpl #0x8000,%d0
  974. blt fix_stk |if less, not wrap case
  975. |
  976. | Check the signs of the operands. If they are alike, the fpu
  977. | can be used to subtract from the norm 1.0 with the sign of the
  978. | denorm and it will correctly generate the result in extended
  979. | precision. We can then call round with no sticky and the result
  980. | will be correct for the user's rounding mode and precision. If
  981. | the signs are unlike, we call round with the sticky bit set
  982. | and the result will be correct for the user's rounding mode and
  983. | precision.
  984. |
  985. sub_wrap:
  986. movew ETEMP_EX(%a6),%d0
  987. movew FPTEMP_EX(%a6),%d1
  988. eorw %d1,%d0
  989. andiw #0x8000,%d0
  990. bne sub_diff
  991. |
  992. | The signs are alike.
  993. |
  994. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  995. bnes sub_u_srcd
  996. movew FPTEMP_EX(%a6),%d0
  997. andiw #0x8000,%d0
  998. orw #0x3fff,%d0 |force the exponent to +/- 1
  999. movew %d0,FPTEMP_EX(%a6) |in the denorm
  1000. movel USER_FPCR(%a6),%d0
  1001. andil #0x30,%d0
  1002. fmovel %d0,%fpcr |set up users rmode and X
  1003. fmovex FPTEMP(%a6),%fp0
  1004. fsubx ETEMP(%a6),%fp0
  1005. fmovel %fpsr,%d1
  1006. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  1007. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  1008. fmovex %fp0,WBTEMP(%a6) |write result to memory
  1009. lsrl #4,%d0 |put rmode in lower 2 bits
  1010. movel USER_FPCR(%a6),%d1
  1011. andil #0xc0,%d1
  1012. lsrl #6,%d1 |put precision in upper word
  1013. swap %d1
  1014. orl %d0,%d1 |set up for round call
  1015. clrl %d0 |force sticky to zero
  1016. bclrb #sign_bit,WBTEMP_EX(%a6)
  1017. sne WBTEMP_SGN(%a6)
  1018. bsrl round |round result to users rmode & prec
  1019. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1020. beq frcfpnr
  1021. bsetb #sign_bit,WBTEMP_EX(%a6)
  1022. bra frcfpnr
  1023. sub_u_srcd:
  1024. movew ETEMP_EX(%a6),%d0
  1025. andiw #0x8000,%d0
  1026. orw #0x3fff,%d0 |force the exponent to +/- 1
  1027. movew %d0,ETEMP_EX(%a6) |in the denorm
  1028. movel USER_FPCR(%a6),%d0
  1029. andil #0x30,%d0
  1030. fmovel %d0,%fpcr |set up users rmode and X
  1031. fmovex FPTEMP(%a6),%fp0
  1032. fsubx ETEMP(%a6),%fp0
  1033. fmovel %fpsr,%d1
  1034. orl %d1,USER_FPSR(%a6) |capture cc's and inex from fadd
  1035. leal WBTEMP(%a6),%a0 |point a0 to wbtemp in frame
  1036. fmovex %fp0,WBTEMP(%a6) |write result to memory
  1037. lsrl #4,%d0 |put rmode in lower 2 bits
  1038. movel USER_FPCR(%a6),%d1
  1039. andil #0xc0,%d1
  1040. lsrl #6,%d1 |put precision in upper word
  1041. swap %d1
  1042. orl %d0,%d1 |set up for round call
  1043. clrl %d0 |force sticky to zero
  1044. bclrb #sign_bit,WBTEMP_EX(%a6)
  1045. sne WBTEMP_SGN(%a6)
  1046. bsrl round |round result to users rmode & prec
  1047. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1048. beq frcfpnr
  1049. bsetb #sign_bit,WBTEMP_EX(%a6)
  1050. bra frcfpnr
  1051. |
  1052. | Signs are unlike:
  1053. |
  1054. sub_diff:
  1055. cmpb #0x0f,DNRM_FLG(%a6) |is dest the denorm?
  1056. bnes sub_s_srcd
  1057. sub_s_destd:
  1058. leal ETEMP(%a6),%a0
  1059. movel USER_FPCR(%a6),%d0
  1060. andil #0x30,%d0
  1061. lsrl #4,%d0 |put rmode in lower 2 bits
  1062. movel USER_FPCR(%a6),%d1
  1063. andil #0xc0,%d1
  1064. lsrl #6,%d1 |put precision in upper word
  1065. swap %d1
  1066. orl %d0,%d1 |set up for round call
  1067. movel #0x20000000,%d0 |set sticky for round
  1068. |
  1069. | Since the dest is the denorm, the sign is the opposite of the
  1070. | norm sign.
  1071. |
  1072. eoriw #0x8000,ETEMP_EX(%a6) |flip sign on result
  1073. tstw ETEMP_EX(%a6)
  1074. bgts sub_s_dwr
  1075. orl #neg_mask,USER_FPSR(%a6)
  1076. sub_s_dwr:
  1077. bclrb #sign_bit,ETEMP_EX(%a6)
  1078. sne ETEMP_SGN(%a6)
  1079. bsrl round |round result to users rmode & prec
  1080. bfclr ETEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1081. beqs sub_s_dclr
  1082. bsetb #sign_bit,ETEMP_EX(%a6)
  1083. sub_s_dclr:
  1084. leal WBTEMP(%a6),%a0
  1085. movel ETEMP(%a6),(%a0) |write result to wbtemp
  1086. movel ETEMP_HI(%a6),4(%a0)
  1087. movel ETEMP_LO(%a6),8(%a0)
  1088. bra sub_ckovf
  1089. sub_s_srcd:
  1090. leal FPTEMP(%a6),%a0
  1091. movel USER_FPCR(%a6),%d0
  1092. andil #0x30,%d0
  1093. lsrl #4,%d0 |put rmode in lower 2 bits
  1094. movel USER_FPCR(%a6),%d1
  1095. andil #0xc0,%d1
  1096. lsrl #6,%d1 |put precision in upper word
  1097. swap %d1
  1098. orl %d0,%d1 |set up for round call
  1099. movel #0x20000000,%d0 |set sticky for round
  1100. bclrb #sign_bit,FPTEMP_EX(%a6)
  1101. sne FPTEMP_SGN(%a6)
  1102. bsrl round |round result to users rmode & prec
  1103. bfclr FPTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1104. beqs sub_s_sclr
  1105. bsetb #sign_bit,FPTEMP_EX(%a6)
  1106. sub_s_sclr:
  1107. leal WBTEMP(%a6),%a0
  1108. movel FPTEMP(%a6),(%a0) |write result to wbtemp
  1109. movel FPTEMP_HI(%a6),4(%a0)
  1110. movel FPTEMP_LO(%a6),8(%a0)
  1111. tstw FPTEMP_EX(%a6)
  1112. bgt sub_ckovf
  1113. orl #neg_mask,USER_FPSR(%a6)
  1114. sub_ckovf:
  1115. movew WBTEMP_EX(%a6),%d0
  1116. andiw #0x7fff,%d0
  1117. cmpiw #0x7fff,%d0
  1118. bne frcfpnr
  1119. |
  1120. | The result has overflowed to $7fff exponent. Set I, ovfl,
  1121. | and aovfl, and clr the mantissa (incorrectly set by the
  1122. | round routine.)
  1123. |
  1124. orl #inf_mask+ovfl_inx_mask,USER_FPSR(%a6)
  1125. clrl 4(%a0)
  1126. bra frcfpnr
  1127. |
  1128. | Inst is fcmp.
  1129. |
  1130. wrap_cmp:
  1131. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  1132. beq fix_stk |restore to fpu
  1133. |
  1134. | One of the ops is denormalized. Test for wrap condition
  1135. | and complete the instruction.
  1136. |
  1137. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  1138. bnes cmp_srcd
  1139. cmp_destd:
  1140. bsrl ckinf_ns
  1141. bne fix_stk
  1142. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  1143. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  1144. subl %d1,%d0 |subtract dest from src
  1145. cmpl #0x8000,%d0
  1146. blt fix_stk |if less, not wrap case
  1147. tstw ETEMP_EX(%a6) |set N to ~sign_of(src)
  1148. bge cmp_setn
  1149. rts
  1150. cmp_srcd:
  1151. bsrl ckinf_nd
  1152. bne fix_stk
  1153. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  1154. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  1155. subl %d1,%d0 |subtract src from dest
  1156. cmpl #0x8000,%d0
  1157. blt fix_stk |if less, not wrap case
  1158. tstw FPTEMP_EX(%a6) |set N to sign_of(dest)
  1159. blt cmp_setn
  1160. rts
  1161. cmp_setn:
  1162. orl #neg_mask,USER_FPSR(%a6)
  1163. rts
  1164. |
  1165. | Inst is fmul.
  1166. |
  1167. wrap_mul:
  1168. cmpb #0xff,DNRM_FLG(%a6) |if both ops denorm,
  1169. beq force_unf |force an underflow (really!)
  1170. |
  1171. | One of the ops is denormalized. Test for wrap condition
  1172. | and complete the instruction.
  1173. |
  1174. cmpb #0x0f,DNRM_FLG(%a6) |check for dest denorm
  1175. bnes mul_srcd
  1176. mul_destd:
  1177. bsrl ckinf_ns
  1178. bne fix_stk
  1179. bfextu ETEMP_EX(%a6){#1:#15},%d0 |get src exp (always pos)
  1180. bfexts FPTEMP_EX(%a6){#1:#15},%d1 |get dest exp (always neg)
  1181. addl %d1,%d0 |subtract dest from src
  1182. bgt fix_stk
  1183. bra force_unf
  1184. mul_srcd:
  1185. bsrl ckinf_nd
  1186. bne fix_stk
  1187. bfextu FPTEMP_EX(%a6){#1:#15},%d0 |get dest exp (always pos)
  1188. bfexts ETEMP_EX(%a6){#1:#15},%d1 |get src exp (always neg)
  1189. addl %d1,%d0 |subtract src from dest
  1190. bgt fix_stk
  1191. |
  1192. | This code handles the case of the instruction resulting in
  1193. | an underflow condition.
  1194. |
  1195. force_unf:
  1196. bclrb #E1,E_BYTE(%a6)
  1197. orl #unfinx_mask,USER_FPSR(%a6)
  1198. clrw NMNEXC(%a6)
  1199. clrb WBTEMP_SGN(%a6)
  1200. movew ETEMP_EX(%a6),%d0 |find the sign of the result
  1201. movew FPTEMP_EX(%a6),%d1
  1202. eorw %d1,%d0
  1203. andiw #0x8000,%d0
  1204. beqs frcunfcont
  1205. st WBTEMP_SGN(%a6)
  1206. frcunfcont:
  1207. lea WBTEMP(%a6),%a0 |point a0 to memory location
  1208. movew CMDREG1B(%a6),%d0
  1209. btstl #6,%d0 |test for forced precision
  1210. beqs frcunf_fpcr
  1211. btstl #2,%d0 |check for double
  1212. bnes frcunf_dbl
  1213. movel #0x1,%d0 |inst is forced single
  1214. bras frcunf_rnd
  1215. frcunf_dbl:
  1216. movel #0x2,%d0 |inst is forced double
  1217. bras frcunf_rnd
  1218. frcunf_fpcr:
  1219. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  1220. frcunf_rnd:
  1221. bsrl unf_sub |get correct result based on
  1222. | ;round precision/mode. This
  1223. | ;sets FPSR_CC correctly
  1224. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1225. beqs frcfpn
  1226. bsetb #sign_bit,WBTEMP_EX(%a6)
  1227. bra frcfpn
  1228. |
  1229. | Write the result to the user's fpn. All results must be HUGE to be
  1230. | written; otherwise the results would have overflowed or underflowed.
  1231. | If the rounding precision is single or double, the ovf_res routine
  1232. | is needed to correctly supply the max value.
  1233. |
  1234. frcfpnr:
  1235. movew CMDREG1B(%a6),%d0
  1236. btstl #6,%d0 |test for forced precision
  1237. beqs frcfpn_fpcr
  1238. btstl #2,%d0 |check for double
  1239. bnes frcfpn_dbl
  1240. movel #0x1,%d0 |inst is forced single
  1241. bras frcfpn_rnd
  1242. frcfpn_dbl:
  1243. movel #0x2,%d0 |inst is forced double
  1244. bras frcfpn_rnd
  1245. frcfpn_fpcr:
  1246. bfextu FPCR_MODE(%a6){#0:#2},%d0 |inst not forced - use fpcr prec
  1247. tstb %d0
  1248. beqs frcfpn |if extended, write what you got
  1249. frcfpn_rnd:
  1250. bclrb #sign_bit,WBTEMP_EX(%a6)
  1251. sne WBTEMP_SGN(%a6)
  1252. bsrl ovf_res |get correct result based on
  1253. | ;round precision/mode. This
  1254. | ;sets FPSR_CC correctly
  1255. bfclr WBTEMP_SGN(%a6){#0:#8} |convert back to IEEE ext format
  1256. beqs frcfpn_clr
  1257. bsetb #sign_bit,WBTEMP_EX(%a6)
  1258. frcfpn_clr:
  1259. orl #ovfinx_mask,USER_FPSR(%a6)
  1260. |
  1261. | Perform the write.
  1262. |
  1263. frcfpn:
  1264. bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
  1265. cmpib #3,%d0
  1266. bles frc0123 |check if dest is fp0-fp3
  1267. movel #7,%d1
  1268. subl %d0,%d1
  1269. clrl %d0
  1270. bsetl %d1,%d0
  1271. fmovemx WBTEMP(%a6),%d0
  1272. rts
  1273. frc0123:
  1274. cmpib #0,%d0
  1275. beqs frc0_dst
  1276. cmpib #1,%d0
  1277. beqs frc1_dst
  1278. cmpib #2,%d0
  1279. beqs frc2_dst
  1280. frc3_dst:
  1281. movel WBTEMP_EX(%a6),USER_FP3(%a6)
  1282. movel WBTEMP_HI(%a6),USER_FP3+4(%a6)
  1283. movel WBTEMP_LO(%a6),USER_FP3+8(%a6)
  1284. rts
  1285. frc2_dst:
  1286. movel WBTEMP_EX(%a6),USER_FP2(%a6)
  1287. movel WBTEMP_HI(%a6),USER_FP2+4(%a6)
  1288. movel WBTEMP_LO(%a6),USER_FP2+8(%a6)
  1289. rts
  1290. frc1_dst:
  1291. movel WBTEMP_EX(%a6),USER_FP1(%a6)
  1292. movel WBTEMP_HI(%a6),USER_FP1+4(%a6)
  1293. movel WBTEMP_LO(%a6),USER_FP1+8(%a6)
  1294. rts
  1295. frc0_dst:
  1296. movel WBTEMP_EX(%a6),USER_FP0(%a6)
  1297. movel WBTEMP_HI(%a6),USER_FP0+4(%a6)
  1298. movel WBTEMP_LO(%a6),USER_FP0+8(%a6)
  1299. rts
  1300. |
  1301. | Write etemp to fpn.
  1302. | A check is made on enabled and signalled snan exceptions,
  1303. | and the destination is not overwritten if this condition exists.
  1304. | This code is designed to make fmoveins of unsupported data types
  1305. | faster.
  1306. |
  1307. wr_etemp:
  1308. btstb #snan_bit,FPSR_EXCEPT(%a6) |if snan is set, and
  1309. beqs fmoveinc |enabled, force restore
  1310. btstb #snan_bit,FPCR_ENABLE(%a6) |and don't overwrite
  1311. beqs fmoveinc |the dest
  1312. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  1313. | ;snan handler
  1314. tstb ETEMP(%a6) |check for negative
  1315. blts snan_neg
  1316. rts
  1317. snan_neg:
  1318. orl #neg_bit,USER_FPSR(%a6) |snan is negative; set N
  1319. rts
  1320. fmoveinc:
  1321. clrw NMNEXC(%a6)
  1322. bclrb #E1,E_BYTE(%a6)
  1323. moveb STAG(%a6),%d0 |check if stag is inf
  1324. andib #0xe0,%d0
  1325. cmpib #0x40,%d0
  1326. bnes fminc_cnan
  1327. orl #inf_mask,USER_FPSR(%a6) |if inf, nothing yet has set I
  1328. tstw LOCAL_EX(%a0) |check sign
  1329. bges fminc_con
  1330. orl #neg_mask,USER_FPSR(%a6)
  1331. bra fminc_con
  1332. fminc_cnan:
  1333. cmpib #0x60,%d0 |check if stag is NaN
  1334. bnes fminc_czero
  1335. orl #nan_mask,USER_FPSR(%a6) |if nan, nothing yet has set NaN
  1336. movel ETEMP_EX(%a6),FPTEMP_EX(%a6) |set up fptemp sign for
  1337. | ;snan handler
  1338. tstw LOCAL_EX(%a0) |check sign
  1339. bges fminc_con
  1340. orl #neg_mask,USER_FPSR(%a6)
  1341. bra fminc_con
  1342. fminc_czero:
  1343. cmpib #0x20,%d0 |check if zero
  1344. bnes fminc_con
  1345. orl #z_mask,USER_FPSR(%a6) |if zero, set Z
  1346. tstw LOCAL_EX(%a0) |check sign
  1347. bges fminc_con
  1348. orl #neg_mask,USER_FPSR(%a6)
  1349. fminc_con:
  1350. bfextu CMDREG1B(%a6){#6:#3},%d0 |extract fp destination register
  1351. cmpib #3,%d0
  1352. bles fp0123 |check if dest is fp0-fp3
  1353. movel #7,%d1
  1354. subl %d0,%d1
  1355. clrl %d0
  1356. bsetl %d1,%d0
  1357. fmovemx ETEMP(%a6),%d0
  1358. rts
  1359. fp0123:
  1360. cmpib #0,%d0
  1361. beqs fp0_dst
  1362. cmpib #1,%d0
  1363. beqs fp1_dst
  1364. cmpib #2,%d0
  1365. beqs fp2_dst
  1366. fp3_dst:
  1367. movel ETEMP_EX(%a6),USER_FP3(%a6)
  1368. movel ETEMP_HI(%a6),USER_FP3+4(%a6)
  1369. movel ETEMP_LO(%a6),USER_FP3+8(%a6)
  1370. rts
  1371. fp2_dst:
  1372. movel ETEMP_EX(%a6),USER_FP2(%a6)
  1373. movel ETEMP_HI(%a6),USER_FP2+4(%a6)
  1374. movel ETEMP_LO(%a6),USER_FP2+8(%a6)
  1375. rts
  1376. fp1_dst:
  1377. movel ETEMP_EX(%a6),USER_FP1(%a6)
  1378. movel ETEMP_HI(%a6),USER_FP1+4(%a6)
  1379. movel ETEMP_LO(%a6),USER_FP1+8(%a6)
  1380. rts
  1381. fp0_dst:
  1382. movel ETEMP_EX(%a6),USER_FP0(%a6)
  1383. movel ETEMP_HI(%a6),USER_FP0+4(%a6)
  1384. movel ETEMP_LO(%a6),USER_FP0+8(%a6)
  1385. rts
  1386. opclass3:
  1387. st CU_ONLY(%a6)
  1388. movew CMDREG1B(%a6),%d0 |check if packed moveout
  1389. andiw #0x0c00,%d0 |isolate last 2 bits of size field
  1390. cmpiw #0x0c00,%d0 |if size is 011 or 111, it is packed
  1391. beq pack_out |else it is norm or denorm
  1392. bra mv_out
  1393. |
  1394. | MOVE OUT
  1395. |
  1396. mv_tbl:
  1397. .long li
  1398. .long sgp
  1399. .long xp
  1400. .long mvout_end |should never be taken
  1401. .long wi
  1402. .long dp
  1403. .long bi
  1404. .long mvout_end |should never be taken
  1405. mv_out:
  1406. bfextu CMDREG1B(%a6){#3:#3},%d1 |put source specifier in d1
  1407. leal mv_tbl,%a0
  1408. movel %a0@(%d1:l:4),%a0
  1409. jmp (%a0)
  1410. |
  1411. | This exit is for move-out to memory. The aunfl bit is
  1412. | set if the result is inex and unfl is signalled.
  1413. |
  1414. mvout_end:
  1415. btstb #inex2_bit,FPSR_EXCEPT(%a6)
  1416. beqs no_aufl
  1417. btstb #unfl_bit,FPSR_EXCEPT(%a6)
  1418. beqs no_aufl
  1419. bsetb #aunfl_bit,FPSR_AEXCEPT(%a6)
  1420. no_aufl:
  1421. clrw NMNEXC(%a6)
  1422. bclrb #E1,E_BYTE(%a6)
  1423. fmovel #0,%FPSR |clear any cc bits from res_func
  1424. |
  1425. | Return ETEMP to extended format from internal extended format so
  1426. | that gen_except will have a correctly signed value for ovfl/unfl
  1427. | handlers.
  1428. |
  1429. bfclr ETEMP_SGN(%a6){#0:#8}
  1430. beqs mvout_con
  1431. bsetb #sign_bit,ETEMP_EX(%a6)
  1432. mvout_con:
  1433. rts
  1434. |
  1435. | This exit is for move-out to int register. The aunfl bit is
  1436. | not set in any case for this move.
  1437. |
  1438. mvouti_end:
  1439. clrw NMNEXC(%a6)
  1440. bclrb #E1,E_BYTE(%a6)
  1441. fmovel #0,%FPSR |clear any cc bits from res_func
  1442. |
  1443. | Return ETEMP to extended format from internal extended format so
  1444. | that gen_except will have a correctly signed value for ovfl/unfl
  1445. | handlers.
  1446. |
  1447. bfclr ETEMP_SGN(%a6){#0:#8}
  1448. beqs mvouti_con
  1449. bsetb #sign_bit,ETEMP_EX(%a6)
  1450. mvouti_con:
  1451. rts
  1452. |
  1453. | li is used to handle a long integer source specifier
  1454. |
  1455. li:
  1456. moveql #4,%d0 |set byte count
  1457. btstb #7,STAG(%a6) |check for extended denorm
  1458. bne int_dnrm |if so, branch
  1459. fmovemx ETEMP(%a6),%fp0-%fp0
  1460. fcmpd #0x41dfffffffc00000,%fp0
  1461. | 41dfffffffc00000 in dbl prec = 401d0000fffffffe00000000 in ext prec
  1462. fbge lo_plrg
  1463. fcmpd #0xc1e0000000000000,%fp0
  1464. | c1e0000000000000 in dbl prec = c01e00008000000000000000 in ext prec
  1465. fble lo_nlrg
  1466. |
  1467. | at this point, the answer is between the largest pos and neg values
  1468. |
  1469. movel USER_FPCR(%a6),%d1 |use user's rounding mode
  1470. andil #0x30,%d1
  1471. fmovel %d1,%fpcr
  1472. fmovel %fp0,L_SCR1(%a6) |let the 040 perform conversion
  1473. fmovel %fpsr,%d1
  1474. orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
  1475. bra int_wrt
  1476. lo_plrg:
  1477. movel #0x7fffffff,L_SCR1(%a6) |answer is largest positive int
  1478. fbeq int_wrt |exact answer
  1479. fcmpd #0x41dfffffffe00000,%fp0
  1480. | 41dfffffffe00000 in dbl prec = 401d0000ffffffff00000000 in ext prec
  1481. fbge int_operr |set operr
  1482. bra int_inx |set inexact
  1483. lo_nlrg:
  1484. movel #0x80000000,L_SCR1(%a6)
  1485. fbeq int_wrt |exact answer
  1486. fcmpd #0xc1e0000000100000,%fp0
  1487. | c1e0000000100000 in dbl prec = c01e00008000000080000000 in ext prec
  1488. fblt int_operr |set operr
  1489. bra int_inx |set inexact
  1490. |
  1491. | wi is used to handle a word integer source specifier
  1492. |
  1493. wi:
  1494. moveql #2,%d0 |set byte count
  1495. btstb #7,STAG(%a6) |check for extended denorm
  1496. bne int_dnrm |branch if so
  1497. fmovemx ETEMP(%a6),%fp0-%fp0
  1498. fcmps #0x46fffe00,%fp0
  1499. | 46fffe00 in sgl prec = 400d0000fffe000000000000 in ext prec
  1500. fbge wo_plrg
  1501. fcmps #0xc7000000,%fp0
  1502. | c7000000 in sgl prec = c00e00008000000000000000 in ext prec
  1503. fble wo_nlrg
  1504. |
  1505. | at this point, the answer is between the largest pos and neg values
  1506. |
  1507. movel USER_FPCR(%a6),%d1 |use user's rounding mode
  1508. andil #0x30,%d1
  1509. fmovel %d1,%fpcr
  1510. fmovew %fp0,L_SCR1(%a6) |let the 040 perform conversion
  1511. fmovel %fpsr,%d1
  1512. orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
  1513. bra int_wrt
  1514. wo_plrg:
  1515. movew #0x7fff,L_SCR1(%a6) |answer is largest positive int
  1516. fbeq int_wrt |exact answer
  1517. fcmps #0x46ffff00,%fp0
  1518. | 46ffff00 in sgl prec = 400d0000ffff000000000000 in ext prec
  1519. fbge int_operr |set operr
  1520. bra int_inx |set inexact
  1521. wo_nlrg:
  1522. movew #0x8000,L_SCR1(%a6)
  1523. fbeq int_wrt |exact answer
  1524. fcmps #0xc7000080,%fp0
  1525. | c7000080 in sgl prec = c00e00008000800000000000 in ext prec
  1526. fblt int_operr |set operr
  1527. bra int_inx |set inexact
  1528. |
  1529. | bi is used to handle a byte integer source specifier
  1530. |
  1531. bi:
  1532. moveql #1,%d0 |set byte count
  1533. btstb #7,STAG(%a6) |check for extended denorm
  1534. bne int_dnrm |branch if so
  1535. fmovemx ETEMP(%a6),%fp0-%fp0
  1536. fcmps #0x42fe0000,%fp0
  1537. | 42fe0000 in sgl prec = 40050000fe00000000000000 in ext prec
  1538. fbge by_plrg
  1539. fcmps #0xc3000000,%fp0
  1540. | c3000000 in sgl prec = c00600008000000000000000 in ext prec
  1541. fble by_nlrg
  1542. |
  1543. | at this point, the answer is between the largest pos and neg values
  1544. |
  1545. movel USER_FPCR(%a6),%d1 |use user's rounding mode
  1546. andil #0x30,%d1
  1547. fmovel %d1,%fpcr
  1548. fmoveb %fp0,L_SCR1(%a6) |let the 040 perform conversion
  1549. fmovel %fpsr,%d1
  1550. orl %d1,USER_FPSR(%a6) |capture inex2/ainex if set
  1551. bra int_wrt
  1552. by_plrg:
  1553. moveb #0x7f,L_SCR1(%a6) |answer is largest positive int
  1554. fbeq int_wrt |exact answer
  1555. fcmps #0x42ff0000,%fp0
  1556. | 42ff0000 in sgl prec = 40050000ff00000000000000 in ext prec
  1557. fbge int_operr |set operr
  1558. bra int_inx |set inexact
  1559. by_nlrg:
  1560. moveb #0x80,L_SCR1(%a6)
  1561. fbeq int_wrt |exact answer
  1562. fcmps #0xc3008000,%fp0
  1563. | c3008000 in sgl prec = c00600008080000000000000 in ext prec
  1564. fblt int_operr |set operr
  1565. bra int_inx |set inexact
  1566. |
  1567. | Common integer routines
  1568. |
  1569. | int_drnrm---account for possible nonzero result for round up with positive
  1570. | operand and round down for negative answer. In the first case (result = 1)
  1571. | byte-width (store in d0) of result must be honored. In the second case,
  1572. | -1 in L_SCR1(a6) will cover all contingencies (FMOVE.B/W/L out).
  1573. int_dnrm:
  1574. movel #0,L_SCR1(%a6) | initialize result to 0
  1575. bfextu FPCR_MODE(%a6){#2:#2},%d1 | d1 is the rounding mode
  1576. cmpb #2,%d1
  1577. bmis int_inx | if RN or RZ, done
  1578. bnes int_rp | if RP, continue below
  1579. tstw ETEMP(%a6) | RM: store -1 in L_SCR1 if src is negative
  1580. bpls int_inx | otherwise result is 0
  1581. movel #-1,L_SCR1(%a6)
  1582. bras int_inx
  1583. int_rp:
  1584. tstw ETEMP(%a6) | RP: store +1 of proper width in L_SCR1 if
  1585. | ; source is greater than 0
  1586. bmis int_inx | otherwise, result is 0
  1587. lea L_SCR1(%a6),%a1 | a1 is address of L_SCR1
  1588. addal %d0,%a1 | offset by destination width -1
  1589. subal #1,%a1
  1590. bsetb #0,(%a1) | set low bit at a1 address
  1591. int_inx:
  1592. oril #inx2a_mask,USER_FPSR(%a6)
  1593. bras int_wrt
  1594. int_operr:
  1595. fmovemx %fp0-%fp0,FPTEMP(%a6) |FPTEMP must contain the extended
  1596. | ;precision source that needs to be
  1597. | ;converted to integer this is required
  1598. | ;if the operr exception is enabled.
  1599. | ;set operr/aiop (no inex2 on int ovfl)
  1600. oril #opaop_mask,USER_FPSR(%a6)
  1601. | ;fall through to perform int_wrt
  1602. int_wrt:
  1603. movel EXC_EA(%a6),%a1 |load destination address
  1604. tstl %a1 |check to see if it is a dest register
  1605. beqs wrt_dn |write data register
  1606. lea L_SCR1(%a6),%a0 |point to supervisor source address
  1607. bsrl mem_write
  1608. bra mvouti_end
  1609. wrt_dn:
  1610. movel %d0,-(%sp) |d0 currently contains the size to write
  1611. bsrl get_fline |get_fline returns Dn in d0
  1612. andiw #0x7,%d0 |isolate register
  1613. movel (%sp)+,%d1 |get size
  1614. cmpil #4,%d1 |most frequent case
  1615. beqs sz_long
  1616. cmpil #2,%d1
  1617. bnes sz_con
  1618. orl #8,%d0 |add 'word' size to register#
  1619. bras sz_con
  1620. sz_long:
  1621. orl #0x10,%d0 |add 'long' size to register#
  1622. sz_con:
  1623. movel %d0,%d1 |reg_dest expects size:reg in d1
  1624. bsrl reg_dest |load proper data register
  1625. bra mvouti_end
  1626. xp:
  1627. lea ETEMP(%a6),%a0
  1628. bclrb #sign_bit,LOCAL_EX(%a0)
  1629. sne LOCAL_SGN(%a0)
  1630. btstb #7,STAG(%a6) |check for extended denorm
  1631. bne xdnrm
  1632. clrl %d0
  1633. bras do_fp |do normal case
  1634. sgp:
  1635. lea ETEMP(%a6),%a0
  1636. bclrb #sign_bit,LOCAL_EX(%a0)
  1637. sne LOCAL_SGN(%a0)
  1638. btstb #7,STAG(%a6) |check for extended denorm
  1639. bne sp_catas |branch if so
  1640. movew LOCAL_EX(%a0),%d0
  1641. lea sp_bnds,%a1
  1642. cmpw (%a1),%d0
  1643. blt sp_under
  1644. cmpw 2(%a1),%d0
  1645. bgt sp_over
  1646. movel #1,%d0 |set destination format to single
  1647. bras do_fp |do normal case
  1648. dp:
  1649. lea ETEMP(%a6),%a0
  1650. bclrb #sign_bit,LOCAL_EX(%a0)
  1651. sne LOCAL_SGN(%a0)
  1652. btstb #7,STAG(%a6) |check for extended denorm
  1653. bne dp_catas |branch if so
  1654. movew LOCAL_EX(%a0),%d0
  1655. lea dp_bnds,%a1
  1656. cmpw (%a1),%d0
  1657. blt dp_under
  1658. cmpw 2(%a1),%d0
  1659. bgt dp_over
  1660. movel #2,%d0 |set destination format to double
  1661. | ;fall through to do_fp
  1662. |
  1663. do_fp:
  1664. bfextu FPCR_MODE(%a6){#2:#2},%d1 |rnd mode in d1
  1665. swap %d0 |rnd prec in upper word
  1666. addl %d0,%d1 |d1 has PREC/MODE info
  1667. clrl %d0 |clear g,r,s
  1668. bsrl round |round
  1669. movel %a0,%a1
  1670. movel EXC_EA(%a6),%a0
  1671. bfextu CMDREG1B(%a6){#3:#3},%d1 |extract destination format
  1672. | ;at this point only the dest
  1673. | ;formats sgl, dbl, ext are
  1674. | ;possible
  1675. cmpb #2,%d1
  1676. bgts ddbl |double=5, extended=2, single=1
  1677. bnes dsgl
  1678. | ;fall through to dext
  1679. dext:
  1680. bsrl dest_ext
  1681. bra mvout_end
  1682. dsgl:
  1683. bsrl dest_sgl
  1684. bra mvout_end
  1685. ddbl:
  1686. bsrl dest_dbl
  1687. bra mvout_end
  1688. |
  1689. | Handle possible denorm or catastrophic underflow cases here
  1690. |
  1691. xdnrm:
  1692. bsr set_xop |initialize WBTEMP
  1693. bsetb #wbtemp15_bit,WB_BYTE(%a6) |set wbtemp15
  1694. movel %a0,%a1
  1695. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1696. bsrl dest_ext |store to memory
  1697. bsetb #unfl_bit,FPSR_EXCEPT(%a6)
  1698. bra mvout_end
  1699. sp_under:
  1700. bsetb #etemp15_bit,STAG(%a6)
  1701. cmpw 4(%a1),%d0
  1702. blts sp_catas |catastrophic underflow case
  1703. movel #1,%d0 |load in round precision
  1704. movel #sgl_thresh,%d1 |load in single denorm threshold
  1705. bsrl dpspdnrm |expects d1 to have the proper
  1706. | ;denorm threshold
  1707. bsrl dest_sgl |stores value to destination
  1708. bsetb #unfl_bit,FPSR_EXCEPT(%a6)
  1709. bra mvout_end |exit
  1710. dp_under:
  1711. bsetb #etemp15_bit,STAG(%a6)
  1712. cmpw 4(%a1),%d0
  1713. blts dp_catas |catastrophic underflow case
  1714. movel #dbl_thresh,%d1 |load in double precision threshold
  1715. movel #2,%d0
  1716. bsrl dpspdnrm |expects d1 to have proper
  1717. | ;denorm threshold
  1718. | ;expects d0 to have round precision
  1719. bsrl dest_dbl |store value to destination
  1720. bsetb #unfl_bit,FPSR_EXCEPT(%a6)
  1721. bra mvout_end |exit
  1722. |
  1723. | Handle catastrophic underflow cases here
  1724. |
  1725. sp_catas:
  1726. | Temp fix for z bit set in unf_sub
  1727. movel USER_FPSR(%a6),-(%a7)
  1728. movel #1,%d0 |set round precision to sgl
  1729. bsrl unf_sub |a0 points to result
  1730. movel (%a7)+,USER_FPSR(%a6)
  1731. movel #1,%d0
  1732. subw %d0,LOCAL_EX(%a0) |account for difference between
  1733. | ;denorm/norm bias
  1734. movel %a0,%a1 |a1 has the operand input
  1735. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1736. bsrl dest_sgl |store the result
  1737. oril #unfinx_mask,USER_FPSR(%a6)
  1738. bra mvout_end
  1739. dp_catas:
  1740. | Temp fix for z bit set in unf_sub
  1741. movel USER_FPSR(%a6),-(%a7)
  1742. movel #2,%d0 |set round precision to dbl
  1743. bsrl unf_sub |a0 points to result
  1744. movel (%a7)+,USER_FPSR(%a6)
  1745. movel #1,%d0
  1746. subw %d0,LOCAL_EX(%a0) |account for difference between
  1747. | ;denorm/norm bias
  1748. movel %a0,%a1 |a1 has the operand input
  1749. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1750. bsrl dest_dbl |store the result
  1751. oril #unfinx_mask,USER_FPSR(%a6)
  1752. bra mvout_end
  1753. |
  1754. | Handle catastrophic overflow cases here
  1755. |
  1756. sp_over:
  1757. | Temp fix for z bit set in unf_sub
  1758. movel USER_FPSR(%a6),-(%a7)
  1759. movel #1,%d0
  1760. leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
  1761. movel ETEMP_EX(%a6),(%a0)
  1762. movel ETEMP_HI(%a6),4(%a0)
  1763. movel ETEMP_LO(%a6),8(%a0)
  1764. bsrl ovf_res
  1765. movel (%a7)+,USER_FPSR(%a6)
  1766. movel %a0,%a1
  1767. movel EXC_EA(%a6),%a0
  1768. bsrl dest_sgl
  1769. orl #ovfinx_mask,USER_FPSR(%a6)
  1770. bra mvout_end
  1771. dp_over:
  1772. | Temp fix for z bit set in ovf_res
  1773. movel USER_FPSR(%a6),-(%a7)
  1774. movel #2,%d0
  1775. leal FP_SCR1(%a6),%a0 |use FP_SCR1 for creating result
  1776. movel ETEMP_EX(%a6),(%a0)
  1777. movel ETEMP_HI(%a6),4(%a0)
  1778. movel ETEMP_LO(%a6),8(%a0)
  1779. bsrl ovf_res
  1780. movel (%a7)+,USER_FPSR(%a6)
  1781. movel %a0,%a1
  1782. movel EXC_EA(%a6),%a0
  1783. bsrl dest_dbl
  1784. orl #ovfinx_mask,USER_FPSR(%a6)
  1785. bra mvout_end
  1786. |
  1787. | DPSPDNRM
  1788. |
  1789. | This subroutine takes an extended normalized number and denormalizes
  1790. | it to the given round precision. This subroutine also decrements
  1791. | the input operand's exponent by 1 to account for the fact that
  1792. | dest_sgl or dest_dbl expects a normalized number's bias.
  1793. |
  1794. | Input: a0 points to a normalized number in internal extended format
  1795. | d0 is the round precision (=1 for sgl; =2 for dbl)
  1796. | d1 is the single precision or double precision
  1797. | denorm threshold
  1798. |
  1799. | Output: (In the format for dest_sgl or dest_dbl)
  1800. | a0 points to the destination
  1801. | a1 points to the operand
  1802. |
  1803. | Exceptions: Reports inexact 2 exception by setting USER_FPSR bits
  1804. |
  1805. dpspdnrm:
  1806. movel %d0,-(%a7) |save round precision
  1807. clrl %d0 |clear initial g,r,s
  1808. bsrl dnrm_lp |careful with d0, it's needed by round
  1809. bfextu FPCR_MODE(%a6){#2:#2},%d1 |get rounding mode
  1810. swap %d1
  1811. movew 2(%a7),%d1 |set rounding precision
  1812. swap %d1 |at this point d1 has PREC/MODE info
  1813. bsrl round |round result, sets the inex bit in
  1814. | ;USER_FPSR if needed
  1815. movew #1,%d0
  1816. subw %d0,LOCAL_EX(%a0) |account for difference in denorm
  1817. | ;vs norm bias
  1818. movel %a0,%a1 |a1 has the operand input
  1819. movel EXC_EA(%a6),%a0 |a0 has the destination pointer
  1820. addw #4,%a7 |pop stack
  1821. rts
  1822. |
  1823. | SET_XOP initialized WBTEMP with the value pointed to by a0
  1824. | input: a0 points to input operand in the internal extended format
  1825. |
  1826. set_xop:
  1827. movel LOCAL_EX(%a0),WBTEMP_EX(%a6)
  1828. movel LOCAL_HI(%a0),WBTEMP_HI(%a6)
  1829. movel LOCAL_LO(%a0),WBTEMP_LO(%a6)
  1830. bfclr WBTEMP_SGN(%a6){#0:#8}
  1831. beqs sxop
  1832. bsetb #sign_bit,WBTEMP_EX(%a6)
  1833. sxop:
  1834. bfclr STAG(%a6){#5:#4} |clear wbtm66,wbtm1,wbtm0,sbit
  1835. rts
  1836. |
  1837. | P_MOVE
  1838. |
  1839. p_movet:
  1840. .long p_move
  1841. .long p_movez
  1842. .long p_movei
  1843. .long p_moven
  1844. .long p_move
  1845. p_regd:
  1846. .long p_dyd0
  1847. .long p_dyd1
  1848. .long p_dyd2
  1849. .long p_dyd3
  1850. .long p_dyd4
  1851. .long p_dyd5
  1852. .long p_dyd6
  1853. .long p_dyd7
  1854. pack_out:
  1855. leal p_movet,%a0 |load jmp table address
  1856. movew STAG(%a6),%d0 |get source tag
  1857. bfextu %d0{#16:#3},%d0 |isolate source bits
  1858. movel (%a0,%d0.w*4),%a0 |load a0 with routine label for tag
  1859. jmp (%a0) |go to the routine
  1860. p_write:
  1861. movel #0x0c,%d0 |get byte count
  1862. movel EXC_EA(%a6),%a1 |get the destination address
  1863. bsr mem_write |write the user's destination
  1864. moveb #0,CU_SAVEPC(%a6) |set the cu save pc to all 0's
  1865. |
  1866. | Also note that the dtag must be set to norm here - this is because
  1867. | the 040 uses the dtag to execute the correct microcode.
  1868. |
  1869. bfclr DTAG(%a6){#0:#3} |set dtag to norm
  1870. rts
  1871. | Notes on handling of special case (zero, inf, and nan) inputs:
  1872. | 1. Operr is not signalled if the k-factor is greater than 18.
  1873. | 2. Per the manual, status bits are not set.
  1874. |
  1875. p_move:
  1876. movew CMDREG1B(%a6),%d0
  1877. btstl #kfact_bit,%d0 |test for dynamic k-factor
  1878. beqs statick |if clear, k-factor is static
  1879. dynamick:
  1880. bfextu %d0{#25:#3},%d0 |isolate register for dynamic k-factor
  1881. lea p_regd,%a0
  1882. movel %a0@(%d0:l:4),%a0
  1883. jmp (%a0)
  1884. statick:
  1885. andiw #0x007f,%d0 |get k-factor
  1886. bfexts %d0{#25:#7},%d0 |sign extend d0 for bindec
  1887. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1888. bsrl bindec |perform the convert; data at a6
  1889. leal FP_SCR1(%a6),%a0 |load a0 with result address
  1890. bral p_write
  1891. p_movez:
  1892. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1893. clrw 2(%a0) |clear lower word of exp
  1894. clrl 4(%a0) |load second lword of ZERO
  1895. clrl 8(%a0) |load third lword of ZERO
  1896. bra p_write |go write results
  1897. p_movei:
  1898. fmovel #0,%FPSR |clear aiop
  1899. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1900. clrw 2(%a0) |clear lower word of exp
  1901. bra p_write |go write the result
  1902. p_moven:
  1903. leal ETEMP(%a6),%a0 |a0 will point to the packed decimal
  1904. clrw 2(%a0) |clear lower word of exp
  1905. bra p_write |go write the result
  1906. |
  1907. | Routines to read the dynamic k-factor from Dn.
  1908. |
  1909. p_dyd0:
  1910. movel USER_D0(%a6),%d0
  1911. bras statick
  1912. p_dyd1:
  1913. movel USER_D1(%a6),%d0
  1914. bras statick
  1915. p_dyd2:
  1916. movel %d2,%d0
  1917. bras statick
  1918. p_dyd3:
  1919. movel %d3,%d0
  1920. bras statick
  1921. p_dyd4:
  1922. movel %d4,%d0
  1923. bras statick
  1924. p_dyd5:
  1925. movel %d5,%d0
  1926. bras statick
  1927. p_dyd6:
  1928. movel %d6,%d0
  1929. bra statick
  1930. p_dyd7:
  1931. movel %d7,%d0
  1932. bra statick
  1933. |end