1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP 3M68000 Hi-Performance Microprocessor Division 4M68060 Software Package 5Production Release P1.00 -- October 10, 1994 6 7M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved. 8 9THE SOFTWARE is provided on an "AS IS" basis and without warranty. 10To the maximum extent permitted by applicable law, 11MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 12INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 13and any warranty against infringement with regard to the SOFTWARE 14(INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials. 15 16To the maximum extent permitted by applicable law, 17IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER 18(INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, 19BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) 20ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. 21Motorola assumes no responsibility for the maintenance and support of the SOFTWARE. 22 23You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE 24so long as this entire notice is retained without alteration in any modified and/or 25redistributed versions, and that such modified versions are clearly identified as such. 26No licenses are granted by implication, estoppel or otherwise under any patents 27or trademarks of Motorola, Inc. 28~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29# 30# freal.s: 31# This file is appended to the top of the 060FPSP package 32# and contains the entry points into the package. The user, in 33# effect, branches to one of the branch table entries located 34# after _060FPSP_TABLE. 35# Also, subroutine stubs exist in this file (_fpsp_done for 36# example) that are referenced by the FPSP package itself in order 37# to call a given routine. The stub routine actually performs the 38# callout. The FPSP code does a "bsr" to the stub routine. This 39# extra layer of hierarchy adds a slight performance penalty but 40# it makes the FPSP code easier to read and more mainatinable. 41# 42 43set _off_bsun, 0x00 44set _off_snan, 0x04 45set _off_operr, 0x08 46set _off_ovfl, 0x0c 47set _off_unfl, 0x10 48set _off_dz, 0x14 49set _off_inex, 0x18 50set _off_fline, 0x1c 51set _off_fpu_dis, 0x20 52set _off_trap, 0x24 53set _off_trace, 0x28 54set _off_access, 0x2c 55set _off_done, 0x30 56 57set _off_imr, 0x40 58set _off_dmr, 0x44 59set _off_dmw, 0x48 60set _off_irw, 0x4c 61set _off_irl, 0x50 62set _off_drb, 0x54 63set _off_drw, 0x58 64set _off_drl, 0x5c 65set _off_dwb, 0x60 66set _off_dww, 0x64 67set _off_dwl, 0x68 68 69_060FPSP_TABLE: 70 71############################################################### 72 73# Here's the table of ENTRY POINTS for those linking the package. 74 bra.l _fpsp_snan 75 short 0x0000 76 bra.l _fpsp_operr 77 short 0x0000 78 bra.l _fpsp_ovfl 79 short 0x0000 80 bra.l _fpsp_unfl 81 short 0x0000 82 bra.l _fpsp_dz 83 short 0x0000 84 bra.l _fpsp_inex 85 short 0x0000 86 bra.l _fpsp_fline 87 short 0x0000 88 bra.l _fpsp_unsupp 89 short 0x0000 90 bra.l _fpsp_effadd 91 short 0x0000 92 93 space 56 94 95############################################################### 96 global _fpsp_done 97_fpsp_done: 98 mov.l %d0,-(%sp) 99 mov.l (_060FPSP_TABLE-0x80+_off_done,%pc),%d0 100 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 101 mov.l 0x4(%sp),%d0 102 rtd &0x4 103 104 global _real_ovfl 105_real_ovfl: 106 mov.l %d0,-(%sp) 107 mov.l (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0 108 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 109 mov.l 0x4(%sp),%d0 110 rtd &0x4 111 112 global _real_unfl 113_real_unfl: 114 mov.l %d0,-(%sp) 115 mov.l (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0 116 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 117 mov.l 0x4(%sp),%d0 118 rtd &0x4 119 120 global _real_inex 121_real_inex: 122 mov.l %d0,-(%sp) 123 mov.l (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0 124 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 125 mov.l 0x4(%sp),%d0 126 rtd &0x4 127 128 global _real_bsun 129_real_bsun: 130 mov.l %d0,-(%sp) 131 mov.l (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0 132 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 133 mov.l 0x4(%sp),%d0 134 rtd &0x4 135 136 global _real_operr 137_real_operr: 138 mov.l %d0,-(%sp) 139 mov.l (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0 140 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 141 mov.l 0x4(%sp),%d0 142 rtd &0x4 143 144 global _real_snan 145_real_snan: 146 mov.l %d0,-(%sp) 147 mov.l (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0 148 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 149 mov.l 0x4(%sp),%d0 150 rtd &0x4 151 152 global _real_dz 153_real_dz: 154 mov.l %d0,-(%sp) 155 mov.l (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0 156 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 157 mov.l 0x4(%sp),%d0 158 rtd &0x4 159 160 global _real_fline 161_real_fline: 162 mov.l %d0,-(%sp) 163 mov.l (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0 164 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 165 mov.l 0x4(%sp),%d0 166 rtd &0x4 167 168 global _real_fpu_disabled 169_real_fpu_disabled: 170 mov.l %d0,-(%sp) 171 mov.l (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0 172 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 173 mov.l 0x4(%sp),%d0 174 rtd &0x4 175 176 global _real_trap 177_real_trap: 178 mov.l %d0,-(%sp) 179 mov.l (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0 180 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 181 mov.l 0x4(%sp),%d0 182 rtd &0x4 183 184 global _real_trace 185_real_trace: 186 mov.l %d0,-(%sp) 187 mov.l (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0 188 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 189 mov.l 0x4(%sp),%d0 190 rtd &0x4 191 192 global _real_access 193_real_access: 194 mov.l %d0,-(%sp) 195 mov.l (_060FPSP_TABLE-0x80+_off_access,%pc),%d0 196 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 197 mov.l 0x4(%sp),%d0 198 rtd &0x4 199 200####################################### 201 202 global _imem_read 203_imem_read: 204 mov.l %d0,-(%sp) 205 mov.l (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0 206 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 207 mov.l 0x4(%sp),%d0 208 rtd &0x4 209 210 global _dmem_read 211_dmem_read: 212 mov.l %d0,-(%sp) 213 mov.l (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0 214 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 215 mov.l 0x4(%sp),%d0 216 rtd &0x4 217 218 global _dmem_write 219_dmem_write: 220 mov.l %d0,-(%sp) 221 mov.l (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0 222 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 223 mov.l 0x4(%sp),%d0 224 rtd &0x4 225 226 global _imem_read_word 227_imem_read_word: 228 mov.l %d0,-(%sp) 229 mov.l (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0 230 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 231 mov.l 0x4(%sp),%d0 232 rtd &0x4 233 234 global _imem_read_long 235_imem_read_long: 236 mov.l %d0,-(%sp) 237 mov.l (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0 238 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 239 mov.l 0x4(%sp),%d0 240 rtd &0x4 241 242 global _dmem_read_byte 243_dmem_read_byte: 244 mov.l %d0,-(%sp) 245 mov.l (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0 246 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 247 mov.l 0x4(%sp),%d0 248 rtd &0x4 249 250 global _dmem_read_word 251_dmem_read_word: 252 mov.l %d0,-(%sp) 253 mov.l (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0 254 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 255 mov.l 0x4(%sp),%d0 256 rtd &0x4 257 258 global _dmem_read_long 259_dmem_read_long: 260 mov.l %d0,-(%sp) 261 mov.l (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0 262 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 263 mov.l 0x4(%sp),%d0 264 rtd &0x4 265 266 global _dmem_write_byte 267_dmem_write_byte: 268 mov.l %d0,-(%sp) 269 mov.l (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0 270 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 271 mov.l 0x4(%sp),%d0 272 rtd &0x4 273 274 global _dmem_write_word 275_dmem_write_word: 276 mov.l %d0,-(%sp) 277 mov.l (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0 278 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 279 mov.l 0x4(%sp),%d0 280 rtd &0x4 281 282 global _dmem_write_long 283_dmem_write_long: 284 mov.l %d0,-(%sp) 285 mov.l (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0 286 pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 287 mov.l 0x4(%sp),%d0 288 rtd &0x4 289 290# 291# This file contains a set of define statements for constants 292# in order to promote readability within the corecode itself. 293# 294 295set LOCAL_SIZE, 192 # stack frame size(bytes) 296set LV, -LOCAL_SIZE # stack offset 297 298set EXC_SR, 0x4 # stack status register 299set EXC_PC, 0x6 # stack pc 300set EXC_VOFF, 0xa # stacked vector offset 301set EXC_EA, 0xc # stacked <ea> 302 303set EXC_FP, 0x0 # frame pointer 304 305set EXC_AREGS, -68 # offset of all address regs 306set EXC_DREGS, -100 # offset of all data regs 307set EXC_FPREGS, -36 # offset of all fp regs 308 309set EXC_A7, EXC_AREGS+(7*4) # offset of saved a7 310set OLD_A7, EXC_AREGS+(6*4) # extra copy of saved a7 311set EXC_A6, EXC_AREGS+(6*4) # offset of saved a6 312set EXC_A5, EXC_AREGS+(5*4) 313set EXC_A4, EXC_AREGS+(4*4) 314set EXC_A3, EXC_AREGS+(3*4) 315set EXC_A2, EXC_AREGS+(2*4) 316set EXC_A1, EXC_AREGS+(1*4) 317set EXC_A0, EXC_AREGS+(0*4) 318set EXC_D7, EXC_DREGS+(7*4) 319set EXC_D6, EXC_DREGS+(6*4) 320set EXC_D5, EXC_DREGS+(5*4) 321set EXC_D4, EXC_DREGS+(4*4) 322set EXC_D3, EXC_DREGS+(3*4) 323set EXC_D2, EXC_DREGS+(2*4) 324set EXC_D1, EXC_DREGS+(1*4) 325set EXC_D0, EXC_DREGS+(0*4) 326 327set EXC_FP0, EXC_FPREGS+(0*12) # offset of saved fp0 328set EXC_FP1, EXC_FPREGS+(1*12) # offset of saved fp1 329set EXC_FP2, EXC_FPREGS+(2*12) # offset of saved fp2 (not used) 330 331set FP_SCR1, LV+80 # fp scratch 1 332set FP_SCR1_EX, FP_SCR1+0 333set FP_SCR1_SGN, FP_SCR1+2 334set FP_SCR1_HI, FP_SCR1+4 335set FP_SCR1_LO, FP_SCR1+8 336 337set FP_SCR0, LV+68 # fp scratch 0 338set FP_SCR0_EX, FP_SCR0+0 339set FP_SCR0_SGN, FP_SCR0+2 340set FP_SCR0_HI, FP_SCR0+4 341set FP_SCR0_LO, FP_SCR0+8 342 343set FP_DST, LV+56 # fp destination operand 344set FP_DST_EX, FP_DST+0 345set FP_DST_SGN, FP_DST+2 346set FP_DST_HI, FP_DST+4 347set FP_DST_LO, FP_DST+8 348 349set FP_SRC, LV+44 # fp source operand 350set FP_SRC_EX, FP_SRC+0 351set FP_SRC_SGN, FP_SRC+2 352set FP_SRC_HI, FP_SRC+4 353set FP_SRC_LO, FP_SRC+8 354 355set USER_FPIAR, LV+40 # FP instr address register 356 357set USER_FPSR, LV+36 # FP status register 358set FPSR_CC, USER_FPSR+0 # FPSR condition codes 359set FPSR_QBYTE, USER_FPSR+1 # FPSR qoutient byte 360set FPSR_EXCEPT, USER_FPSR+2 # FPSR exception status byte 361set FPSR_AEXCEPT, USER_FPSR+3 # FPSR accrued exception byte 362 363set USER_FPCR, LV+32 # FP control register 364set FPCR_ENABLE, USER_FPCR+2 # FPCR exception enable 365set FPCR_MODE, USER_FPCR+3 # FPCR rounding mode control 366 367set L_SCR3, LV+28 # integer scratch 3 368set L_SCR2, LV+24 # integer scratch 2 369set L_SCR1, LV+20 # integer scratch 1 370 371set STORE_FLG, LV+19 # flag: operand store (ie. not fcmp/ftst) 372 373set EXC_TEMP2, LV+24 # temporary space 374set EXC_TEMP, LV+16 # temporary space 375 376set DTAG, LV+15 # destination operand type 377set STAG, LV+14 # source operand type 378 379set SPCOND_FLG, LV+10 # flag: special case (see below) 380 381set EXC_CC, LV+8 # saved condition codes 382set EXC_EXTWPTR, LV+4 # saved current PC (active) 383set EXC_EXTWORD, LV+2 # saved extension word 384set EXC_CMDREG, LV+2 # saved extension word 385set EXC_OPWORD, LV+0 # saved operation word 386 387################################ 388 389# Helpful macros 390 391set FTEMP, 0 # offsets within an 392set FTEMP_EX, 0 # extended precision 393set FTEMP_SGN, 2 # value saved in memory. 394set FTEMP_HI, 4 395set FTEMP_LO, 8 396set FTEMP_GRS, 12 397 398set LOCAL, 0 # offsets within an 399set LOCAL_EX, 0 # extended precision 400set LOCAL_SGN, 2 # value saved in memory. 401set LOCAL_HI, 4 402set LOCAL_LO, 8 403set LOCAL_GRS, 12 404 405set DST, 0 # offsets within an 406set DST_EX, 0 # extended precision 407set DST_HI, 4 # value saved in memory. 408set DST_LO, 8 409 410set SRC, 0 # offsets within an 411set SRC_EX, 0 # extended precision 412set SRC_HI, 4 # value saved in memory. 413set SRC_LO, 8 414 415set SGL_LO, 0x3f81 # min sgl prec exponent 416set SGL_HI, 0x407e # max sgl prec exponent 417set DBL_LO, 0x3c01 # min dbl prec exponent 418set DBL_HI, 0x43fe # max dbl prec exponent 419set EXT_LO, 0x0 # min ext prec exponent 420set EXT_HI, 0x7ffe # max ext prec exponent 421 422set EXT_BIAS, 0x3fff # extended precision bias 423set SGL_BIAS, 0x007f # single precision bias 424set DBL_BIAS, 0x03ff # double precision bias 425 426set NORM, 0x00 # operand type for STAG/DTAG 427set ZERO, 0x01 # operand type for STAG/DTAG 428set INF, 0x02 # operand type for STAG/DTAG 429set QNAN, 0x03 # operand type for STAG/DTAG 430set DENORM, 0x04 # operand type for STAG/DTAG 431set SNAN, 0x05 # operand type for STAG/DTAG 432set UNNORM, 0x06 # operand type for STAG/DTAG 433 434################## 435# FPSR/FPCR bits # 436################## 437set neg_bit, 0x3 # negative result 438set z_bit, 0x2 # zero result 439set inf_bit, 0x1 # infinite result 440set nan_bit, 0x0 # NAN result 441 442set q_sn_bit, 0x7 # sign bit of quotient byte 443 444set bsun_bit, 7 # branch on unordered 445set snan_bit, 6 # signalling NAN 446set operr_bit, 5 # operand error 447set ovfl_bit, 4 # overflow 448set unfl_bit, 3 # underflow 449set dz_bit, 2 # divide by zero 450set inex2_bit, 1 # inexact result 2 451set inex1_bit, 0 # inexact result 1 452 453set aiop_bit, 7 # accrued inexact operation bit 454set aovfl_bit, 6 # accrued overflow bit 455set aunfl_bit, 5 # accrued underflow bit 456set adz_bit, 4 # accrued dz bit 457set ainex_bit, 3 # accrued inexact bit 458 459############################# 460# FPSR individual bit masks # 461############################# 462set neg_mask, 0x08000000 # negative bit mask (lw) 463set inf_mask, 0x02000000 # infinity bit mask (lw) 464set z_mask, 0x04000000 # zero bit mask (lw) 465set nan_mask, 0x01000000 # nan bit mask (lw) 466 467set neg_bmask, 0x08 # negative bit mask (byte) 468set inf_bmask, 0x02 # infinity bit mask (byte) 469set z_bmask, 0x04 # zero bit mask (byte) 470set nan_bmask, 0x01 # nan bit mask (byte) 471 472set bsun_mask, 0x00008000 # bsun exception mask 473set snan_mask, 0x00004000 # snan exception mask 474set operr_mask, 0x00002000 # operr exception mask 475set ovfl_mask, 0x00001000 # overflow exception mask 476set unfl_mask, 0x00000800 # underflow exception mask 477set dz_mask, 0x00000400 # dz exception mask 478set inex2_mask, 0x00000200 # inex2 exception mask 479set inex1_mask, 0x00000100 # inex1 exception mask 480 481set aiop_mask, 0x00000080 # accrued illegal operation 482set aovfl_mask, 0x00000040 # accrued overflow 483set aunfl_mask, 0x00000020 # accrued underflow 484set adz_mask, 0x00000010 # accrued divide by zero 485set ainex_mask, 0x00000008 # accrued inexact 486 487###################################### 488# FPSR combinations used in the FPSP # 489###################################### 490set dzinf_mask, inf_mask+dz_mask+adz_mask 491set opnan_mask, nan_mask+operr_mask+aiop_mask 492set nzi_mask, 0x01ffffff #clears N, Z, and I 493set unfinx_mask, unfl_mask+inex2_mask+aunfl_mask+ainex_mask 494set unf2inx_mask, unfl_mask+inex2_mask+ainex_mask 495set ovfinx_mask, ovfl_mask+inex2_mask+aovfl_mask+ainex_mask 496set inx1a_mask, inex1_mask+ainex_mask 497set inx2a_mask, inex2_mask+ainex_mask 498set snaniop_mask, nan_mask+snan_mask+aiop_mask 499set snaniop2_mask, snan_mask+aiop_mask 500set naniop_mask, nan_mask+aiop_mask 501set neginf_mask, neg_mask+inf_mask 502set infaiop_mask, inf_mask+aiop_mask 503set negz_mask, neg_mask+z_mask 504set opaop_mask, operr_mask+aiop_mask 505set unfl_inx_mask, unfl_mask+aunfl_mask+ainex_mask 506set ovfl_inx_mask, ovfl_mask+aovfl_mask+ainex_mask 507 508######### 509# misc. # 510######### 511set rnd_stky_bit, 29 # stky bit pos in longword 512 513set sign_bit, 0x7 # sign bit 514set signan_bit, 0x6 # signalling nan bit 515 516set sgl_thresh, 0x3f81 # minimum sgl exponent 517set dbl_thresh, 0x3c01 # minimum dbl exponent 518 519set x_mode, 0x0 # extended precision 520set s_mode, 0x4 # single precision 521set d_mode, 0x8 # double precision 522 523set rn_mode, 0x0 # round-to-nearest 524set rz_mode, 0x1 # round-to-zero 525set rm_mode, 0x2 # round-tp-minus-infinity 526set rp_mode, 0x3 # round-to-plus-infinity 527 528set mantissalen, 64 # length of mantissa in bits 529 530set BYTE, 1 # len(byte) == 1 byte 531set WORD, 2 # len(word) == 2 bytes 532set LONG, 4 # len(longword) == 2 bytes 533 534set BSUN_VEC, 0xc0 # bsun vector offset 535set INEX_VEC, 0xc4 # inexact vector offset 536set DZ_VEC, 0xc8 # dz vector offset 537set UNFL_VEC, 0xcc # unfl vector offset 538set OPERR_VEC, 0xd0 # operr vector offset 539set OVFL_VEC, 0xd4 # ovfl vector offset 540set SNAN_VEC, 0xd8 # snan vector offset 541 542########################### 543# SPecial CONDition FLaGs # 544########################### 545set ftrapcc_flg, 0x01 # flag bit: ftrapcc exception 546set fbsun_flg, 0x02 # flag bit: bsun exception 547set mia7_flg, 0x04 # flag bit: (a7)+ <ea> 548set mda7_flg, 0x08 # flag bit: -(a7) <ea> 549set fmovm_flg, 0x40 # flag bit: fmovm instruction 550set immed_flg, 0x80 # flag bit: &<data> <ea> 551 552set ftrapcc_bit, 0x0 553set fbsun_bit, 0x1 554set mia7_bit, 0x2 555set mda7_bit, 0x3 556set immed_bit, 0x7 557 558################################## 559# TRANSCENDENTAL "LAST-OP" FLAGS # 560################################## 561set FMUL_OP, 0x0 # fmul instr performed last 562set FDIV_OP, 0x1 # fdiv performed last 563set FADD_OP, 0x2 # fadd performed last 564set FMOV_OP, 0x3 # fmov performed last 565 566############# 567# CONSTANTS # 568############# 569T1: long 0x40C62D38,0xD3D64634 # 16381 LOG2 LEAD 570T2: long 0x3D6F90AE,0xB1E75CC7 # 16381 LOG2 TRAIL 571 572PI: long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000 573PIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 574 575TWOBYPI: 576 long 0x3FE45F30,0x6DC9C883 577 578######################################################################### 579# XDEF **************************************************************** # 580# _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception. # 581# # 582# This handler should be the first code executed upon taking the # 583# FP Overflow exception in an operating system. # 584# # 585# XREF **************************************************************** # 586# _imem_read_long() - read instruction longword # 587# fix_skewed_ops() - adjust src operand in fsave frame # 588# set_tag_x() - determine optype of src/dst operands # 589# store_fpreg() - store opclass 0 or 2 result to FP regfile # 590# unnorm_fix() - change UNNORM operands to NORM or ZERO # 591# load_fpn2() - load dst operand from FP regfile # 592# fout() - emulate an opclass 3 instruction # 593# tbl_unsupp - add of table of emulation routines for opclass 0,2 # 594# _fpsp_done() - "callout" for 060FPSP exit (all work done!) # 595# _real_ovfl() - "callout" for Overflow exception enabled code # 596# _real_inex() - "callout" for Inexact exception enabled code # 597# _real_trace() - "callout" for Trace exception code # 598# # 599# INPUT *************************************************************** # 600# - The system stack contains the FP Ovfl exception stack frame # 601# - The fsave frame contains the source operand # 602# # 603# OUTPUT ************************************************************** # 604# Overflow Exception enabled: # 605# - The system stack is unchanged # 606# - The fsave frame contains the adjusted src op for opclass 0,2 # 607# Overflow Exception disabled: # 608# - The system stack is unchanged # 609# - The "exception present" flag in the fsave frame is cleared # 610# # 611# ALGORITHM *********************************************************** # 612# On the 060, if an FP overflow is present as the result of any # 613# instruction, the 060 will take an overflow exception whether the # 614# exception is enabled or disabled in the FPCR. For the disabled case, # 615# This handler emulates the instruction to determine what the correct # 616# default result should be for the operation. This default result is # 617# then stored in either the FP regfile, data regfile, or memory. # 618# Finally, the handler exits through the "callout" _fpsp_done() # 619# denoting that no exceptional conditions exist within the machine. # 620# If the exception is enabled, then this handler must create the # 621# exceptional operand and plave it in the fsave state frame, and store # 622# the default result (only if the instruction is opclass 3). For # 623# exceptions enabled, this handler must exit through the "callout" # 624# _real_ovfl() so that the operating system enabled overflow handler # 625# can handle this case. # 626# Two other conditions exist. First, if overflow was disabled # 627# but the inexact exception was enabled, this handler must exit # 628# through the "callout" _real_inex() regardless of whether the result # 629# was inexact. # 630# Also, in the case of an opclass three instruction where # 631# overflow was disabled and the trace exception was enabled, this # 632# handler must exit through the "callout" _real_trace(). # 633# # 634######################################################################### 635 636 global _fpsp_ovfl 637_fpsp_ovfl: 638 639#$# sub.l &24,%sp # make room for src/dst 640 641 link.w %a6,&-LOCAL_SIZE # init stack frame 642 643 fsave FP_SRC(%a6) # grab the "busy" frame 644 645 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 646 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 647 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 648 649# the FPIAR holds the "current PC" of the faulting instruction 650 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 651 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 652 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 653 bsr.l _imem_read_long # fetch the instruction words 654 mov.l %d0,EXC_OPWORD(%a6) 655 656############################################################################## 657 658 btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out? 659 bne.w fovfl_out 660 661 662 lea FP_SRC(%a6),%a0 # pass: ptr to src op 663 bsr.l fix_skewed_ops # fix src op 664 665# since, I believe, only NORMs and DENORMs can come through here, 666# maybe we can avoid the subroutine call. 667 lea FP_SRC(%a6),%a0 # pass: ptr to src op 668 bsr.l set_tag_x # tag the operand type 669 mov.b %d0,STAG(%a6) # maybe NORM,DENORM 670 671# bit five of the fp extension word separates the monadic and dyadic operations 672# that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos 673# will never take this exception. 674 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 675 beq.b fovfl_extract # monadic 676 677 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 678 bsr.l load_fpn2 # load dst into FP_DST 679 680 lea FP_DST(%a6),%a0 # pass: ptr to dst op 681 bsr.l set_tag_x # tag the operand type 682 cmpi.b %d0,&UNNORM # is operand an UNNORM? 683 bne.b fovfl_op2_done # no 684 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 685fovfl_op2_done: 686 mov.b %d0,DTAG(%a6) # save dst optype tag 687 688fovfl_extract: 689 690#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 691#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 692#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 693#$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6) 694#$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6) 695#$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6) 696 697 clr.l %d0 698 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 699 700 mov.b 1+EXC_CMDREG(%a6),%d1 701 andi.w &0x007f,%d1 # extract extension 702 703 andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field 704 705 fmov.l &0x0,%fpcr # zero current control regs 706 fmov.l &0x0,%fpsr 707 708 lea FP_SRC(%a6),%a0 709 lea FP_DST(%a6),%a1 710 711# maybe we can make these entry points ONLY the OVFL entry points of each routine. 712 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 713 jsr (tbl_unsupp.l,%pc,%d1.l*1) 714 715# the operation has been emulated. the result is in fp0. 716# the EXOP, if an exception occurred, is in fp1. 717# we must save the default result regardless of whether 718# traps are enabled or disabled. 719 bfextu EXC_CMDREG(%a6){&6:&3},%d0 720 bsr.l store_fpreg 721 722# the exceptional possibilities we have left ourselves with are ONLY overflow 723# and inexact. and, the inexact is such that overflow occurred and was disabled 724# but inexact was enabled. 725 btst &ovfl_bit,FPCR_ENABLE(%a6) 726 bne.b fovfl_ovfl_on 727 728 btst &inex2_bit,FPCR_ENABLE(%a6) 729 bne.b fovfl_inex_on 730 731 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 732 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 733 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 734 735 unlk %a6 736#$# add.l &24,%sp 737 bra.l _fpsp_done 738 739# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP 740# in fp1. now, simply jump to _real_ovfl()! 741fovfl_ovfl_on: 742 fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack 743 744 mov.w &0xe005,2+FP_SRC(%a6) # save exc status 745 746 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 747 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 748 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 749 750 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 751 752 unlk %a6 753 754 bra.l _real_ovfl 755 756# overflow occurred but is disabled. meanwhile, inexact is enabled. Therefore, 757# we must jump to real_inex(). 758fovfl_inex_on: 759 760 fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack 761 762 mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4 763 mov.w &0xe001,2+FP_SRC(%a6) # save exc status 764 765 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 766 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 767 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 768 769 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 770 771 unlk %a6 772 773 bra.l _real_inex 774 775######################################################################## 776fovfl_out: 777 778 779#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 780#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 781#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 782 783# the src operand is definitely a NORM(!), so tag it as such 784 mov.b &NORM,STAG(%a6) # set src optype tag 785 786 clr.l %d0 787 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 788 789 and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field 790 791 fmov.l &0x0,%fpcr # zero current control regs 792 fmov.l &0x0,%fpsr 793 794 lea FP_SRC(%a6),%a0 # pass ptr to src operand 795 796 bsr.l fout 797 798 btst &ovfl_bit,FPCR_ENABLE(%a6) 799 bne.w fovfl_ovfl_on 800 801 btst &inex2_bit,FPCR_ENABLE(%a6) 802 bne.w fovfl_inex_on 803 804 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 805 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 806 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 807 808 unlk %a6 809#$# add.l &24,%sp 810 811 btst &0x7,(%sp) # is trace on? 812 beq.l _fpsp_done # no 813 814 fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR 815 mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 816 bra.l _real_trace 817 818######################################################################### 819# XDEF **************************************************************** # 820# _fpsp_unfl(): 060FPSP entry point for FP Underflow exception. # 821# # 822# This handler should be the first code executed upon taking the # 823# FP Underflow exception in an operating system. # 824# # 825# XREF **************************************************************** # 826# _imem_read_long() - read instruction longword # 827# fix_skewed_ops() - adjust src operand in fsave frame # 828# set_tag_x() - determine optype of src/dst operands # 829# store_fpreg() - store opclass 0 or 2 result to FP regfile # 830# unnorm_fix() - change UNNORM operands to NORM or ZERO # 831# load_fpn2() - load dst operand from FP regfile # 832# fout() - emulate an opclass 3 instruction # 833# tbl_unsupp - add of table of emulation routines for opclass 0,2 # 834# _fpsp_done() - "callout" for 060FPSP exit (all work done!) # 835# _real_ovfl() - "callout" for Overflow exception enabled code # 836# _real_inex() - "callout" for Inexact exception enabled code # 837# _real_trace() - "callout" for Trace exception code # 838# # 839# INPUT *************************************************************** # 840# - The system stack contains the FP Unfl exception stack frame # 841# - The fsave frame contains the source operand # 842# # 843# OUTPUT ************************************************************** # 844# Underflow Exception enabled: # 845# - The system stack is unchanged # 846# - The fsave frame contains the adjusted src op for opclass 0,2 # 847# Underflow Exception disabled: # 848# - The system stack is unchanged # 849# - The "exception present" flag in the fsave frame is cleared # 850# # 851# ALGORITHM *********************************************************** # 852# On the 060, if an FP underflow is present as the result of any # 853# instruction, the 060 will take an underflow exception whether the # 854# exception is enabled or disabled in the FPCR. For the disabled case, # 855# This handler emulates the instruction to determine what the correct # 856# default result should be for the operation. This default result is # 857# then stored in either the FP regfile, data regfile, or memory. # 858# Finally, the handler exits through the "callout" _fpsp_done() # 859# denoting that no exceptional conditions exist within the machine. # 860# If the exception is enabled, then this handler must create the # 861# exceptional operand and plave it in the fsave state frame, and store # 862# the default result (only if the instruction is opclass 3). For # 863# exceptions enabled, this handler must exit through the "callout" # 864# _real_unfl() so that the operating system enabled overflow handler # 865# can handle this case. # 866# Two other conditions exist. First, if underflow was disabled # 867# but the inexact exception was enabled and the result was inexact, # 868# this handler must exit through the "callout" _real_inex(). # 869# was inexact. # 870# Also, in the case of an opclass three instruction where # 871# underflow was disabled and the trace exception was enabled, this # 872# handler must exit through the "callout" _real_trace(). # 873# # 874######################################################################### 875 876 global _fpsp_unfl 877_fpsp_unfl: 878 879#$# sub.l &24,%sp # make room for src/dst 880 881 link.w %a6,&-LOCAL_SIZE # init stack frame 882 883 fsave FP_SRC(%a6) # grab the "busy" frame 884 885 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 886 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 887 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 888 889# the FPIAR holds the "current PC" of the faulting instruction 890 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 891 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 892 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 893 bsr.l _imem_read_long # fetch the instruction words 894 mov.l %d0,EXC_OPWORD(%a6) 895 896############################################################################## 897 898 btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out? 899 bne.w funfl_out 900 901 902 lea FP_SRC(%a6),%a0 # pass: ptr to src op 903 bsr.l fix_skewed_ops # fix src op 904 905 lea FP_SRC(%a6),%a0 # pass: ptr to src op 906 bsr.l set_tag_x # tag the operand type 907 mov.b %d0,STAG(%a6) # maybe NORM,DENORM 908 909# bit five of the fp ext word separates the monadic and dyadic operations 910# that can pass through fpsp_unfl(). remember that fcmp, and ftst 911# will never take this exception. 912 btst &0x5,1+EXC_CMDREG(%a6) # is op monadic or dyadic? 913 beq.b funfl_extract # monadic 914 915# now, what's left that's not dyadic is fsincos. we can distinguish it 916# from all dyadics by the '0110xxx pattern 917 btst &0x4,1+EXC_CMDREG(%a6) # is op an fsincos? 918 bne.b funfl_extract # yes 919 920 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 921 bsr.l load_fpn2 # load dst into FP_DST 922 923 lea FP_DST(%a6),%a0 # pass: ptr to dst op 924 bsr.l set_tag_x # tag the operand type 925 cmpi.b %d0,&UNNORM # is operand an UNNORM? 926 bne.b funfl_op2_done # no 927 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 928funfl_op2_done: 929 mov.b %d0,DTAG(%a6) # save dst optype tag 930 931funfl_extract: 932 933#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 934#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 935#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 936#$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6) 937#$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6) 938#$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6) 939 940 clr.l %d0 941 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 942 943 mov.b 1+EXC_CMDREG(%a6),%d1 944 andi.w &0x007f,%d1 # extract extension 945 946 andi.l &0x00ff01ff,USER_FPSR(%a6) 947 948 fmov.l &0x0,%fpcr # zero current control regs 949 fmov.l &0x0,%fpsr 950 951 lea FP_SRC(%a6),%a0 952 lea FP_DST(%a6),%a1 953 954# maybe we can make these entry points ONLY the OVFL entry points of each routine. 955 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 956 jsr (tbl_unsupp.l,%pc,%d1.l*1) 957 958 bfextu EXC_CMDREG(%a6){&6:&3},%d0 959 bsr.l store_fpreg 960 961# The `060 FPU multiplier hardware is such that if the result of a 962# multiply operation is the smallest possible normalized number 963# (0x00000000_80000000_00000000), then the machine will take an 964# underflow exception. Since this is incorrect, we need to check 965# if our emulation, after re-doing the operation, decided that 966# no underflow was called for. We do these checks only in 967# funfl_{unfl,inex}_on() because w/ both exceptions disabled, this 968# special case will simply exit gracefully with the correct result. 969 970# the exceptional possibilities we have left ourselves with are ONLY overflow 971# and inexact. and, the inexact is such that overflow occurred and was disabled 972# but inexact was enabled. 973 btst &unfl_bit,FPCR_ENABLE(%a6) 974 bne.b funfl_unfl_on 975 976funfl_chkinex: 977 btst &inex2_bit,FPCR_ENABLE(%a6) 978 bne.b funfl_inex_on 979 980funfl_exit: 981 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 982 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 983 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 984 985 unlk %a6 986#$# add.l &24,%sp 987 bra.l _fpsp_done 988 989# overflow is enabled AND overflow, of course, occurred. so, we have the EXOP 990# in fp1 (don't forget to save fp0). what to do now? 991# well, we simply have to get to go to _real_unfl()! 992funfl_unfl_on: 993 994# The `060 FPU multiplier hardware is such that if the result of a 995# multiply operation is the smallest possible normalized number 996# (0x00000000_80000000_00000000), then the machine will take an 997# underflow exception. Since this is incorrect, we check here to see 998# if our emulation, after re-doing the operation, decided that 999# no underflow was called for. 1000 btst &unfl_bit,FPSR_EXCEPT(%a6) 1001 beq.w funfl_chkinex 1002 1003funfl_unfl_on2: 1004 fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack 1005 1006 mov.w &0xe003,2+FP_SRC(%a6) # save exc status 1007 1008 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 1009 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1010 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1011 1012 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 1013 1014 unlk %a6 1015 1016 bra.l _real_unfl 1017 1018# underflow occurred but is disabled. meanwhile, inexact is enabled. Therefore, 1019# we must jump to real_inex(). 1020funfl_inex_on: 1021 1022# The `060 FPU multiplier hardware is such that if the result of a 1023# multiply operation is the smallest possible normalized number 1024# (0x00000000_80000000_00000000), then the machine will take an 1025# underflow exception. 1026# But, whether bogus or not, if inexact is enabled AND it occurred, 1027# then we have to branch to real_inex. 1028 1029 btst &inex2_bit,FPSR_EXCEPT(%a6) 1030 beq.w funfl_exit 1031 1032funfl_inex_on2: 1033 1034 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to stack 1035 1036 mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4 1037 mov.w &0xe001,2+FP_SRC(%a6) # save exc status 1038 1039 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 1040 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1041 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1042 1043 frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 1044 1045 unlk %a6 1046 1047 bra.l _real_inex 1048 1049####################################################################### 1050funfl_out: 1051 1052 1053#$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 1054#$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 1055#$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 1056 1057# the src operand is definitely a NORM(!), so tag it as such 1058 mov.b &NORM,STAG(%a6) # set src optype tag 1059 1060 clr.l %d0 1061 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 1062 1063 and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field 1064 1065 fmov.l &0x0,%fpcr # zero current control regs 1066 fmov.l &0x0,%fpsr 1067 1068 lea FP_SRC(%a6),%a0 # pass ptr to src operand 1069 1070 bsr.l fout 1071 1072 btst &unfl_bit,FPCR_ENABLE(%a6) 1073 bne.w funfl_unfl_on2 1074 1075 btst &inex2_bit,FPCR_ENABLE(%a6) 1076 bne.w funfl_inex_on2 1077 1078 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 1079 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1080 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1081 1082 unlk %a6 1083#$# add.l &24,%sp 1084 1085 btst &0x7,(%sp) # is trace on? 1086 beq.l _fpsp_done # no 1087 1088 fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR 1089 mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 1090 bra.l _real_trace 1091 1092######################################################################### 1093# XDEF **************************************************************** # 1094# _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented # 1095# Data Type" exception. # 1096# # 1097# This handler should be the first code executed upon taking the # 1098# FP Unimplemented Data Type exception in an operating system. # 1099# # 1100# XREF **************************************************************** # 1101# _imem_read_{word,long}() - read instruction word/longword # 1102# fix_skewed_ops() - adjust src operand in fsave frame # 1103# set_tag_x() - determine optype of src/dst operands # 1104# store_fpreg() - store opclass 0 or 2 result to FP regfile # 1105# unnorm_fix() - change UNNORM operands to NORM or ZERO # 1106# load_fpn2() - load dst operand from FP regfile # 1107# load_fpn1() - load src operand from FP regfile # 1108# fout() - emulate an opclass 3 instruction # 1109# tbl_unsupp - add of table of emulation routines for opclass 0,2 # 1110# _real_inex() - "callout" to operating system inexact handler # 1111# _fpsp_done() - "callout" for exit; work all done # 1112# _real_trace() - "callout" for Trace enabled exception # 1113# funimp_skew() - adjust fsave src ops to "incorrect" value # 1114# _real_snan() - "callout" for SNAN exception # 1115# _real_operr() - "callout" for OPERR exception # 1116# _real_ovfl() - "callout" for OVFL exception # 1117# _real_unfl() - "callout" for UNFL exception # 1118# get_packed() - fetch packed operand from memory # 1119# # 1120# INPUT *************************************************************** # 1121# - The system stack contains the "Unimp Data Type" stk frame # 1122# - The fsave frame contains the ssrc op (for UNNORM/DENORM) # 1123# # 1124# OUTPUT ************************************************************** # 1125# If Inexact exception (opclass 3): # 1126# - The system stack is changed to an Inexact exception stk frame # 1127# If SNAN exception (opclass 3): # 1128# - The system stack is changed to an SNAN exception stk frame # 1129# If OPERR exception (opclass 3): # 1130# - The system stack is changed to an OPERR exception stk frame # 1131# If OVFL exception (opclass 3): # 1132# - The system stack is changed to an OVFL exception stk frame # 1133# If UNFL exception (opclass 3): # 1134# - The system stack is changed to an UNFL exception stack frame # 1135# If Trace exception enabled: # 1136# - The system stack is changed to a Trace exception stack frame # 1137# Else: (normal case) # 1138# - Correct result has been stored as appropriate # 1139# # 1140# ALGORITHM *********************************************************** # 1141# Two main instruction types can enter here: (1) DENORM or UNNORM # 1142# unimplemented data types. These can be either opclass 0,2 or 3 # 1143# instructions, and (2) PACKED unimplemented data format instructions # 1144# also of opclasses 0,2, or 3. # 1145# For UNNORM/DENORM opclass 0 and 2, the handler fetches the src # 1146# operand from the fsave state frame and the dst operand (if dyadic) # 1147# from the FP register file. The instruction is then emulated by # 1148# choosing an emulation routine from a table of routines indexed by # 1149# instruction type. Once the instruction has been emulated and result # 1150# saved, then we check to see if any enabled exceptions resulted from # 1151# instruction emulation. If none, then we exit through the "callout" # 1152# _fpsp_done(). If there is an enabled FP exception, then we insert # 1153# this exception into the FPU in the fsave state frame and then exit # 1154# through _fpsp_done(). # 1155# PACKED opclass 0 and 2 is similar in how the instruction is # 1156# emulated and exceptions handled. The differences occur in how the # 1157# handler loads the packed op (by calling get_packed() routine) and # 1158# by the fact that a Trace exception could be pending for PACKED ops. # 1159# If a Trace exception is pending, then the current exception stack # 1160# frame is changed to a Trace exception stack frame and an exit is # 1161# made through _real_trace(). # 1162# For UNNORM/DENORM opclass 3, the actual move out to memory is # 1163# performed by calling the routine fout(). If no exception should occur # 1164# as the result of emulation, then an exit either occurs through # 1165# _fpsp_done() or through _real_trace() if a Trace exception is pending # 1166# (a Trace stack frame must be created here, too). If an FP exception # 1167# should occur, then we must create an exception stack frame of that # 1168# type and jump to either _real_snan(), _real_operr(), _real_inex(), # 1169# _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3 # 1170# emulation is performed in a similar manner. # 1171# # 1172######################################################################### 1173 1174# 1175# (1) DENORM and UNNORM (unimplemented) data types: 1176# 1177# post-instruction 1178# ***************** 1179# * EA * 1180# pre-instruction * * 1181# ***************** ***************** 1182# * 0x0 * 0x0dc * * 0x3 * 0x0dc * 1183# ***************** ***************** 1184# * Next * * Next * 1185# * PC * * PC * 1186# ***************** ***************** 1187# * SR * * SR * 1188# ***************** ***************** 1189# 1190# (2) PACKED format (unsupported) opclasses two and three: 1191# ***************** 1192# * EA * 1193# * * 1194# ***************** 1195# * 0x2 * 0x0dc * 1196# ***************** 1197# * Next * 1198# * PC * 1199# ***************** 1200# * SR * 1201# ***************** 1202# 1203 global _fpsp_unsupp 1204_fpsp_unsupp: 1205 1206 link.w %a6,&-LOCAL_SIZE # init stack frame 1207 1208 fsave FP_SRC(%a6) # save fp state 1209 1210 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 1211 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 1212 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 1213 1214 btst &0x5,EXC_SR(%a6) # user or supervisor mode? 1215 bne.b fu_s 1216fu_u: 1217 mov.l %usp,%a0 # fetch user stack pointer 1218 mov.l %a0,EXC_A7(%a6) # save on stack 1219 bra.b fu_cont 1220# if the exception is an opclass zero or two unimplemented data type 1221# exception, then the a7' calculated here is wrong since it doesn't 1222# stack an ea. however, we don't need an a7' for this case anyways. 1223fu_s: 1224 lea 0x4+EXC_EA(%a6),%a0 # load old a7' 1225 mov.l %a0,EXC_A7(%a6) # save on stack 1226 1227fu_cont: 1228 1229# the FPIAR holds the "current PC" of the faulting instruction 1230# the FPIAR should be set correctly for ALL exceptions passing through 1231# this point. 1232 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 1233 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 1234 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 1235 bsr.l _imem_read_long # fetch the instruction words 1236 mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD 1237 1238############################ 1239 1240 clr.b SPCOND_FLG(%a6) # clear special condition flag 1241 1242# Separate opclass three (fpn-to-mem) ops since they have a different 1243# stack frame and protocol. 1244 btst &0x5,EXC_CMDREG(%a6) # is it an fmove out? 1245 bne.w fu_out # yes 1246 1247# Separate packed opclass two instructions. 1248 bfextu EXC_CMDREG(%a6){&0:&6},%d0 1249 cmpi.b %d0,&0x13 1250 beq.w fu_in_pack 1251 1252 1253# I'm not sure at this point what FPSR bits are valid for this instruction. 1254# so, since the emulation routines re-create them anyways, zero exception field 1255 andi.l &0x00ff00ff,USER_FPSR(%a6) # zero exception field 1256 1257 fmov.l &0x0,%fpcr # zero current control regs 1258 fmov.l &0x0,%fpsr 1259 1260# Opclass two w/ memory-to-fpn operation will have an incorrect extended 1261# precision format if the src format was single or double and the 1262# source data type was an INF, NAN, DENORM, or UNNORM 1263 lea FP_SRC(%a6),%a0 # pass ptr to input 1264 bsr.l fix_skewed_ops 1265 1266# we don't know whether the src operand or the dst operand (or both) is the 1267# UNNORM or DENORM. call the function that tags the operand type. if the 1268# input is an UNNORM, then convert it to a NORM, DENORM, or ZERO. 1269 lea FP_SRC(%a6),%a0 # pass: ptr to src op 1270 bsr.l set_tag_x # tag the operand type 1271 cmpi.b %d0,&UNNORM # is operand an UNNORM? 1272 bne.b fu_op2 # no 1273 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 1274 1275fu_op2: 1276 mov.b %d0,STAG(%a6) # save src optype tag 1277 1278 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1279 1280# bit five of the fp extension word separates the monadic and dyadic operations 1281# at this point 1282 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 1283 beq.b fu_extract # monadic 1284 cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst? 1285 beq.b fu_extract # yes, so it's monadic, too 1286 1287 bsr.l load_fpn2 # load dst into FP_DST 1288 1289 lea FP_DST(%a6),%a0 # pass: ptr to dst op 1290 bsr.l set_tag_x # tag the operand type 1291 cmpi.b %d0,&UNNORM # is operand an UNNORM? 1292 bne.b fu_op2_done # no 1293 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 1294fu_op2_done: 1295 mov.b %d0,DTAG(%a6) # save dst optype tag 1296 1297fu_extract: 1298 clr.l %d0 1299 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 1300 1301 bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension 1302 1303 lea FP_SRC(%a6),%a0 1304 lea FP_DST(%a6),%a1 1305 1306 mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr 1307 jsr (tbl_unsupp.l,%pc,%d1.l*1) 1308 1309# 1310# Exceptions in order of precedence: 1311# BSUN : none 1312# SNAN : all dyadic ops 1313# OPERR : fsqrt(-NORM) 1314# OVFL : all except ftst,fcmp 1315# UNFL : all except ftst,fcmp 1316# DZ : fdiv 1317# INEX2 : all except ftst,fcmp 1318# INEX1 : none (packed doesn't go through here) 1319# 1320 1321# we determine the highest priority exception(if any) set by the 1322# emulation routine that has also been enabled by the user. 1323 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions set 1324 bne.b fu_in_ena # some are enabled 1325 1326fu_in_cont: 1327# fcmp and ftst do not store any result. 1328 mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension 1329 andi.b &0x38,%d0 # extract bits 3-5 1330 cmpi.b %d0,&0x38 # is instr fcmp or ftst? 1331 beq.b fu_in_exit # yes 1332 1333 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1334 bsr.l store_fpreg # store the result 1335 1336fu_in_exit: 1337 1338 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1339 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1340 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1341 1342 unlk %a6 1343 1344 bra.l _fpsp_done 1345 1346fu_in_ena: 1347 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled 1348 bfffo %d0{&24:&8},%d0 # find highest priority exception 1349 bne.b fu_in_exc # there is at least one set 1350 1351# 1352# No exceptions occurred that were also enabled. Now: 1353# 1354# if (OVFL && ovfl_disabled && inexact_enabled) { 1355# branch to _real_inex() (even if the result was exact!); 1356# } else { 1357# save the result in the proper fp reg (unless the op is fcmp or ftst); 1358# return; 1359# } 1360# 1361 btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? 1362 beq.b fu_in_cont # no 1363 1364fu_in_ovflchk: 1365 btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? 1366 beq.b fu_in_cont # no 1367 bra.w fu_in_exc_ovfl # go insert overflow frame 1368 1369# 1370# An exception occurred and that exception was enabled: 1371# 1372# shift enabled exception field into lo byte of d0; 1373# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) || 1374# ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) { 1375# /* 1376# * this is the case where we must call _real_inex() now or else 1377# * there will be no other way to pass it the exceptional operand 1378# */ 1379# call _real_inex(); 1380# } else { 1381# restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU; 1382# } 1383# 1384fu_in_exc: 1385 subi.l &24,%d0 # fix offset to be 0-8 1386 cmpi.b %d0,&0x6 # is exception INEX? (6) 1387 bne.b fu_in_exc_exit # no 1388 1389# the enabled exception was inexact 1390 btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur? 1391 bne.w fu_in_exc_unfl # yes 1392 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur? 1393 bne.w fu_in_exc_ovfl # yes 1394 1395# here, we insert the correct fsave status value into the fsave frame for the 1396# corresponding exception. the operand in the fsave frame should be the original 1397# src operand. 1398fu_in_exc_exit: 1399 mov.l %d0,-(%sp) # save d0 1400 bsr.l funimp_skew # skew sgl or dbl inputs 1401 mov.l (%sp)+,%d0 # restore d0 1402 1403 mov.w (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status 1404 1405 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1406 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1407 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1408 1409 frestore FP_SRC(%a6) # restore src op 1410 1411 unlk %a6 1412 1413 bra.l _fpsp_done 1414 1415tbl_except: 1416 short 0xe000,0xe006,0xe004,0xe005 1417 short 0xe003,0xe002,0xe001,0xe001 1418 1419fu_in_exc_unfl: 1420 mov.w &0x4,%d0 1421 bra.b fu_in_exc_exit 1422fu_in_exc_ovfl: 1423 mov.w &0x03,%d0 1424 bra.b fu_in_exc_exit 1425 1426# If the input operand to this operation was opclass two and a single 1427# or double precision denorm, inf, or nan, the operand needs to be 1428# "corrected" in order to have the proper equivalent extended precision 1429# number. 1430 global fix_skewed_ops 1431fix_skewed_ops: 1432 bfextu EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt 1433 cmpi.b %d0,&0x11 # is class = 2 & fmt = sgl? 1434 beq.b fso_sgl # yes 1435 cmpi.b %d0,&0x15 # is class = 2 & fmt = dbl? 1436 beq.b fso_dbl # yes 1437 rts # no 1438 1439fso_sgl: 1440 mov.w LOCAL_EX(%a0),%d0 # fetch src exponent 1441 andi.w &0x7fff,%d0 # strip sign 1442 cmpi.w %d0,&0x3f80 # is |exp| == $3f80? 1443 beq.b fso_sgl_dnrm_zero # yes 1444 cmpi.w %d0,&0x407f # no; is |exp| == $407f? 1445 beq.b fso_infnan # yes 1446 rts # no 1447 1448fso_sgl_dnrm_zero: 1449 andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit 1450 beq.b fso_zero # it's a skewed zero 1451fso_sgl_dnrm: 1452# here, we count on norm not to alter a0... 1453 bsr.l norm # normalize mantissa 1454 neg.w %d0 # -shft amt 1455 addi.w &0x3f81,%d0 # adjust new exponent 1456 andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent 1457 or.w %d0,LOCAL_EX(%a0) # insert new exponent 1458 rts 1459 1460fso_zero: 1461 andi.w &0x8000,LOCAL_EX(%a0) # clear bogus exponent 1462 rts 1463 1464fso_infnan: 1465 andi.b &0x7f,LOCAL_HI(%a0) # clear j-bit 1466 ori.w &0x7fff,LOCAL_EX(%a0) # make exponent = $7fff 1467 rts 1468 1469fso_dbl: 1470 mov.w LOCAL_EX(%a0),%d0 # fetch src exponent 1471 andi.w &0x7fff,%d0 # strip sign 1472 cmpi.w %d0,&0x3c00 # is |exp| == $3c00? 1473 beq.b fso_dbl_dnrm_zero # yes 1474 cmpi.w %d0,&0x43ff # no; is |exp| == $43ff? 1475 beq.b fso_infnan # yes 1476 rts # no 1477 1478fso_dbl_dnrm_zero: 1479 andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit 1480 bne.b fso_dbl_dnrm # it's a skewed denorm 1481 tst.l LOCAL_LO(%a0) # is it a zero? 1482 beq.b fso_zero # yes 1483fso_dbl_dnrm: 1484# here, we count on norm not to alter a0... 1485 bsr.l norm # normalize mantissa 1486 neg.w %d0 # -shft amt 1487 addi.w &0x3c01,%d0 # adjust new exponent 1488 andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent 1489 or.w %d0,LOCAL_EX(%a0) # insert new exponent 1490 rts 1491 1492################################################################# 1493 1494# fmove out took an unimplemented data type exception. 1495# the src operand is in FP_SRC. Call _fout() to write out the result and 1496# to determine which exceptions, if any, to take. 1497fu_out: 1498 1499# Separate packed move outs from the UNNORM and DENORM move outs. 1500 bfextu EXC_CMDREG(%a6){&3:&3},%d0 1501 cmpi.b %d0,&0x3 1502 beq.w fu_out_pack 1503 cmpi.b %d0,&0x7 1504 beq.w fu_out_pack 1505 1506 1507# I'm not sure at this point what FPSR bits are valid for this instruction. 1508# so, since the emulation routines re-create them anyways, zero exception field. 1509# fmove out doesn't affect ccodes. 1510 and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field 1511 1512 fmov.l &0x0,%fpcr # zero current control regs 1513 fmov.l &0x0,%fpsr 1514 1515# the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine 1516# call here. just figure out what it is... 1517 mov.w FP_SRC_EX(%a6),%d0 # get exponent 1518 andi.w &0x7fff,%d0 # strip sign 1519 beq.b fu_out_denorm # it's a DENORM 1520 1521 lea FP_SRC(%a6),%a0 1522 bsr.l unnorm_fix # yes; fix it 1523 1524 mov.b %d0,STAG(%a6) 1525 1526 bra.b fu_out_cont 1527fu_out_denorm: 1528 mov.b &DENORM,STAG(%a6) 1529fu_out_cont: 1530 1531 clr.l %d0 1532 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 1533 1534 lea FP_SRC(%a6),%a0 # pass ptr to src operand 1535 1536 mov.l (%a6),EXC_A6(%a6) # in case a6 changes 1537 bsr.l fout # call fmove out routine 1538 1539# Exceptions in order of precedence: 1540# BSUN : none 1541# SNAN : none 1542# OPERR : fmove.{b,w,l} out of large UNNORM 1543# OVFL : fmove.{s,d} 1544# UNFL : fmove.{s,d,x} 1545# DZ : none 1546# INEX2 : all 1547# INEX1 : none (packed doesn't travel through here) 1548 1549# determine the highest priority exception(if any) set by the 1550# emulation routine that has also been enabled by the user. 1551 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 1552 bne.w fu_out_ena # some are enabled 1553 1554fu_out_done: 1555 1556 mov.l EXC_A6(%a6),(%a6) # in case a6 changed 1557 1558# on extended precision opclass three instructions using pre-decrement or 1559# post-increment addressing mode, the address register is not updated. is the 1560# address register was the stack pointer used from user mode, then let's update 1561# it here. if it was used from supervisor mode, then we have to handle this 1562# as a special case. 1563 btst &0x5,EXC_SR(%a6) 1564 bne.b fu_out_done_s 1565 1566 mov.l EXC_A7(%a6),%a0 # restore a7 1567 mov.l %a0,%usp 1568 1569fu_out_done_cont: 1570 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1571 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1572 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1573 1574 unlk %a6 1575 1576 btst &0x7,(%sp) # is trace on? 1577 bne.b fu_out_trace # yes 1578 1579 bra.l _fpsp_done 1580 1581# is the ea mode pre-decrement of the stack pointer from supervisor mode? 1582# ("fmov.x fpm,-(a7)") if so, 1583fu_out_done_s: 1584 cmpi.b SPCOND_FLG(%a6),&mda7_flg 1585 bne.b fu_out_done_cont 1586 1587# the extended precision result is still in fp0. but, we need to save it 1588# somewhere on the stack until we can copy it to its final resting place. 1589# here, we're counting on the top of the stack to be the old place-holders 1590# for fp0/fp1 which have already been restored. that way, we can write 1591# over those destinations with the shifted stack frame. 1592 fmovm.x &0x80,FP_SRC(%a6) # put answer on stack 1593 1594 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1595 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1596 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1597 1598 mov.l (%a6),%a6 # restore frame pointer 1599 1600 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 1601 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 1602 1603# now, copy the result to the proper place on the stack 1604 mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) 1605 mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) 1606 mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) 1607 1608 add.l &LOCAL_SIZE-0x8,%sp 1609 1610 btst &0x7,(%sp) 1611 bne.b fu_out_trace 1612 1613 bra.l _fpsp_done 1614 1615fu_out_ena: 1616 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled 1617 bfffo %d0{&24:&8},%d0 # find highest priority exception 1618 bne.b fu_out_exc # there is at least one set 1619 1620# no exceptions were set. 1621# if a disabled overflow occurred and inexact was enabled but the result 1622# was exact, then a branch to _real_inex() is made. 1623 btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? 1624 beq.w fu_out_done # no 1625 1626fu_out_ovflchk: 1627 btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? 1628 beq.w fu_out_done # no 1629 bra.w fu_inex # yes 1630 1631# 1632# The fp move out that took the "Unimplemented Data Type" exception was 1633# being traced. Since the stack frames are similar, get the "current" PC 1634# from FPIAR and put it in the trace stack frame then jump to _real_trace(). 1635# 1636# UNSUPP FRAME TRACE FRAME 1637# ***************** ***************** 1638# * EA * * Current * 1639# * * * PC * 1640# ***************** ***************** 1641# * 0x3 * 0x0dc * * 0x2 * 0x024 * 1642# ***************** ***************** 1643# * Next * * Next * 1644# * PC * * PC * 1645# ***************** ***************** 1646# * SR * * SR * 1647# ***************** ***************** 1648# 1649fu_out_trace: 1650 mov.w &0x2024,0x6(%sp) 1651 fmov.l %fpiar,0x8(%sp) 1652 bra.l _real_trace 1653 1654# an exception occurred and that exception was enabled. 1655fu_out_exc: 1656 subi.l &24,%d0 # fix offset to be 0-8 1657 1658# we don't mess with the existing fsave frame. just re-insert it and 1659# jump to the "_real_{}()" handler... 1660 mov.w (tbl_fu_out.b,%pc,%d0.w*2),%d0 1661 jmp (tbl_fu_out.b,%pc,%d0.w*1) 1662 1663 swbeg &0x8 1664tbl_fu_out: 1665 short tbl_fu_out - tbl_fu_out # BSUN can't happen 1666 short tbl_fu_out - tbl_fu_out # SNAN can't happen 1667 short fu_operr - tbl_fu_out # OPERR 1668 short fu_ovfl - tbl_fu_out # OVFL 1669 short fu_unfl - tbl_fu_out # UNFL 1670 short tbl_fu_out - tbl_fu_out # DZ can't happen 1671 short fu_inex - tbl_fu_out # INEX2 1672 short tbl_fu_out - tbl_fu_out # INEX1 won't make it here 1673 1674# for snan,operr,ovfl,unfl, src op is still in FP_SRC so just 1675# frestore it. 1676fu_snan: 1677 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1678 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1679 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1680 1681 mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd8 1682 mov.w &0xe006,2+FP_SRC(%a6) 1683 1684 frestore FP_SRC(%a6) 1685 1686 unlk %a6 1687 1688 1689 bra.l _real_snan 1690 1691fu_operr: 1692 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1693 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1694 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1695 1696 mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0 1697 mov.w &0xe004,2+FP_SRC(%a6) 1698 1699 frestore FP_SRC(%a6) 1700 1701 unlk %a6 1702 1703 1704 bra.l _real_operr 1705 1706fu_ovfl: 1707 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack 1708 1709 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1710 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1711 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1712 1713 mov.w &0x30d4,EXC_VOFF(%a6) # vector offset = 0xd4 1714 mov.w &0xe005,2+FP_SRC(%a6) 1715 1716 frestore FP_SRC(%a6) # restore EXOP 1717 1718 unlk %a6 1719 1720 bra.l _real_ovfl 1721 1722# underflow can happen for extended precision. extended precision opclass 1723# three instruction exceptions don't update the stack pointer. so, if the 1724# exception occurred from user mode, then simply update a7 and exit normally. 1725# if the exception occurred from supervisor mode, check if 1726fu_unfl: 1727 mov.l EXC_A6(%a6),(%a6) # restore a6 1728 1729 btst &0x5,EXC_SR(%a6) 1730 bne.w fu_unfl_s 1731 1732 mov.l EXC_A7(%a6),%a0 # restore a7 whether we need 1733 mov.l %a0,%usp # to or not... 1734 1735fu_unfl_cont: 1736 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack 1737 1738 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1739 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1740 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1741 1742 mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc 1743 mov.w &0xe003,2+FP_SRC(%a6) 1744 1745 frestore FP_SRC(%a6) # restore EXOP 1746 1747 unlk %a6 1748 1749 bra.l _real_unfl 1750 1751fu_unfl_s: 1752 cmpi.b SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)? 1753 bne.b fu_unfl_cont 1754 1755# the extended precision result is still in fp0. but, we need to save it 1756# somewhere on the stack until we can copy it to its final resting place 1757# (where the exc frame is currently). make sure it's not at the top of the 1758# frame or it will get overwritten when the exc stack frame is shifted "down". 1759 fmovm.x &0x80,FP_SRC(%a6) # put answer on stack 1760 fmovm.x &0x40,FP_DST(%a6) # put EXOP on stack 1761 1762 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1763 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1764 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1765 1766 mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc 1767 mov.w &0xe003,2+FP_DST(%a6) 1768 1769 frestore FP_DST(%a6) # restore EXOP 1770 1771 mov.l (%a6),%a6 # restore frame pointer 1772 1773 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 1774 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 1775 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 1776 1777# now, copy the result to the proper place on the stack 1778 mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) 1779 mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) 1780 mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) 1781 1782 add.l &LOCAL_SIZE-0x8,%sp 1783 1784 bra.l _real_unfl 1785 1786# fmove in and out enter here. 1787fu_inex: 1788 fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack 1789 1790 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1791 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1792 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1793 1794 mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4 1795 mov.w &0xe001,2+FP_SRC(%a6) 1796 1797 frestore FP_SRC(%a6) # restore EXOP 1798 1799 unlk %a6 1800 1801 1802 bra.l _real_inex 1803 1804######################################################################### 1805######################################################################### 1806fu_in_pack: 1807 1808 1809# I'm not sure at this point what FPSR bits are valid for this instruction. 1810# so, since the emulation routines re-create them anyways, zero exception field 1811 andi.l &0x0ff00ff,USER_FPSR(%a6) # zero exception field 1812 1813 fmov.l &0x0,%fpcr # zero current control regs 1814 fmov.l &0x0,%fpsr 1815 1816 bsr.l get_packed # fetch packed src operand 1817 1818 lea FP_SRC(%a6),%a0 # pass ptr to src 1819 bsr.l set_tag_x # set src optype tag 1820 1821 mov.b %d0,STAG(%a6) # save src optype tag 1822 1823 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1824 1825# bit five of the fp extension word separates the monadic and dyadic operations 1826# at this point 1827 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 1828 beq.b fu_extract_p # monadic 1829 cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst? 1830 beq.b fu_extract_p # yes, so it's monadic, too 1831 1832 bsr.l load_fpn2 # load dst into FP_DST 1833 1834 lea FP_DST(%a6),%a0 # pass: ptr to dst op 1835 bsr.l set_tag_x # tag the operand type 1836 cmpi.b %d0,&UNNORM # is operand an UNNORM? 1837 bne.b fu_op2_done_p # no 1838 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 1839fu_op2_done_p: 1840 mov.b %d0,DTAG(%a6) # save dst optype tag 1841 1842fu_extract_p: 1843 clr.l %d0 1844 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 1845 1846 bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension 1847 1848 lea FP_SRC(%a6),%a0 1849 lea FP_DST(%a6),%a1 1850 1851 mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr 1852 jsr (tbl_unsupp.l,%pc,%d1.l*1) 1853 1854# 1855# Exceptions in order of precedence: 1856# BSUN : none 1857# SNAN : all dyadic ops 1858# OPERR : fsqrt(-NORM) 1859# OVFL : all except ftst,fcmp 1860# UNFL : all except ftst,fcmp 1861# DZ : fdiv 1862# INEX2 : all except ftst,fcmp 1863# INEX1 : all 1864# 1865 1866# we determine the highest priority exception(if any) set by the 1867# emulation routine that has also been enabled by the user. 1868 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 1869 bne.w fu_in_ena_p # some are enabled 1870 1871fu_in_cont_p: 1872# fcmp and ftst do not store any result. 1873 mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension 1874 andi.b &0x38,%d0 # extract bits 3-5 1875 cmpi.b %d0,&0x38 # is instr fcmp or ftst? 1876 beq.b fu_in_exit_p # yes 1877 1878 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1879 bsr.l store_fpreg # store the result 1880 1881fu_in_exit_p: 1882 1883 btst &0x5,EXC_SR(%a6) # user or supervisor? 1884 bne.w fu_in_exit_s_p # supervisor 1885 1886 mov.l EXC_A7(%a6),%a0 # update user a7 1887 mov.l %a0,%usp 1888 1889fu_in_exit_cont_p: 1890 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1891 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1892 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1893 1894 unlk %a6 # unravel stack frame 1895 1896 btst &0x7,(%sp) # is trace on? 1897 bne.w fu_trace_p # yes 1898 1899 bra.l _fpsp_done # exit to os 1900 1901# the exception occurred in supervisor mode. check to see if the 1902# addressing mode was (a7)+. if so, we'll need to shift the 1903# stack frame "up". 1904fu_in_exit_s_p: 1905 btst &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+ 1906 beq.b fu_in_exit_cont_p # no 1907 1908 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1909 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1910 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1911 1912 unlk %a6 # unravel stack frame 1913 1914# shift the stack frame "up". we don't really care about the <ea> field. 1915 mov.l 0x4(%sp),0x10(%sp) 1916 mov.l 0x0(%sp),0xc(%sp) 1917 add.l &0xc,%sp 1918 1919 btst &0x7,(%sp) # is trace on? 1920 bne.w fu_trace_p # yes 1921 1922 bra.l _fpsp_done # exit to os 1923 1924fu_in_ena_p: 1925 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled & set 1926 bfffo %d0{&24:&8},%d0 # find highest priority exception 1927 bne.b fu_in_exc_p # at least one was set 1928 1929# 1930# No exceptions occurred that were also enabled. Now: 1931# 1932# if (OVFL && ovfl_disabled && inexact_enabled) { 1933# branch to _real_inex() (even if the result was exact!); 1934# } else { 1935# save the result in the proper fp reg (unless the op is fcmp or ftst); 1936# return; 1937# } 1938# 1939 btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? 1940 beq.w fu_in_cont_p # no 1941 1942fu_in_ovflchk_p: 1943 btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? 1944 beq.w fu_in_cont_p # no 1945 bra.w fu_in_exc_ovfl_p # do _real_inex() now 1946 1947# 1948# An exception occurred and that exception was enabled: 1949# 1950# shift enabled exception field into lo byte of d0; 1951# if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) || 1952# ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) { 1953# /* 1954# * this is the case where we must call _real_inex() now or else 1955# * there will be no other way to pass it the exceptional operand 1956# */ 1957# call _real_inex(); 1958# } else { 1959# restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU; 1960# } 1961# 1962fu_in_exc_p: 1963 subi.l &24,%d0 # fix offset to be 0-8 1964 cmpi.b %d0,&0x6 # is exception INEX? (6 or 7) 1965 blt.b fu_in_exc_exit_p # no 1966 1967# the enabled exception was inexact 1968 btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur? 1969 bne.w fu_in_exc_unfl_p # yes 1970 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur? 1971 bne.w fu_in_exc_ovfl_p # yes 1972 1973# here, we insert the correct fsave status value into the fsave frame for the 1974# corresponding exception. the operand in the fsave frame should be the original 1975# src operand. 1976# as a reminder for future predicted pain and agony, we are passing in fsave the 1977# "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs. 1978# this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!! 1979fu_in_exc_exit_p: 1980 btst &0x5,EXC_SR(%a6) # user or supervisor? 1981 bne.w fu_in_exc_exit_s_p # supervisor 1982 1983 mov.l EXC_A7(%a6),%a0 # update user a7 1984 mov.l %a0,%usp 1985 1986fu_in_exc_exit_cont_p: 1987 mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6) 1988 1989 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1990 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1991 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1992 1993 frestore FP_SRC(%a6) # restore src op 1994 1995 unlk %a6 1996 1997 btst &0x7,(%sp) # is trace enabled? 1998 bne.w fu_trace_p # yes 1999 2000 bra.l _fpsp_done 2001 2002tbl_except_p: 2003 short 0xe000,0xe006,0xe004,0xe005 2004 short 0xe003,0xe002,0xe001,0xe001 2005 2006fu_in_exc_ovfl_p: 2007 mov.w &0x3,%d0 2008 bra.w fu_in_exc_exit_p 2009 2010fu_in_exc_unfl_p: 2011 mov.w &0x4,%d0 2012 bra.w fu_in_exc_exit_p 2013 2014fu_in_exc_exit_s_p: 2015 btst &mia7_bit,SPCOND_FLG(%a6) 2016 beq.b fu_in_exc_exit_cont_p 2017 2018 mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6) 2019 2020 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2021 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2022 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2023 2024 frestore FP_SRC(%a6) # restore src op 2025 2026 unlk %a6 # unravel stack frame 2027 2028# shift stack frame "up". who cares about <ea> field. 2029 mov.l 0x4(%sp),0x10(%sp) 2030 mov.l 0x0(%sp),0xc(%sp) 2031 add.l &0xc,%sp 2032 2033 btst &0x7,(%sp) # is trace on? 2034 bne.b fu_trace_p # yes 2035 2036 bra.l _fpsp_done # exit to os 2037 2038# 2039# The opclass two PACKED instruction that took an "Unimplemented Data Type" 2040# exception was being traced. Make the "current" PC the FPIAR and put it in the 2041# trace stack frame then jump to _real_trace(). 2042# 2043# UNSUPP FRAME TRACE FRAME 2044# ***************** ***************** 2045# * EA * * Current * 2046# * * * PC * 2047# ***************** ***************** 2048# * 0x2 * 0x0dc * * 0x2 * 0x024 * 2049# ***************** ***************** 2050# * Next * * Next * 2051# * PC * * PC * 2052# ***************** ***************** 2053# * SR * * SR * 2054# ***************** ***************** 2055fu_trace_p: 2056 mov.w &0x2024,0x6(%sp) 2057 fmov.l %fpiar,0x8(%sp) 2058 2059 bra.l _real_trace 2060 2061######################################################### 2062######################################################### 2063fu_out_pack: 2064 2065 2066# I'm not sure at this point what FPSR bits are valid for this instruction. 2067# so, since the emulation routines re-create them anyways, zero exception field. 2068# fmove out doesn't affect ccodes. 2069 and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field 2070 2071 fmov.l &0x0,%fpcr # zero current control regs 2072 fmov.l &0x0,%fpsr 2073 2074 bfextu EXC_CMDREG(%a6){&6:&3},%d0 2075 bsr.l load_fpn1 2076 2077# unlike other opclass 3, unimplemented data type exceptions, packed must be 2078# able to detect all operand types. 2079 lea FP_SRC(%a6),%a0 2080 bsr.l set_tag_x # tag the operand type 2081 cmpi.b %d0,&UNNORM # is operand an UNNORM? 2082 bne.b fu_op2_p # no 2083 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 2084 2085fu_op2_p: 2086 mov.b %d0,STAG(%a6) # save src optype tag 2087 2088 clr.l %d0 2089 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 2090 2091 lea FP_SRC(%a6),%a0 # pass ptr to src operand 2092 2093 mov.l (%a6),EXC_A6(%a6) # in case a6 changes 2094 bsr.l fout # call fmove out routine 2095 2096# Exceptions in order of precedence: 2097# BSUN : no 2098# SNAN : yes 2099# OPERR : if ((k_factor > +17) || (dec. exp exceeds 3 digits)) 2100# OVFL : no 2101# UNFL : no 2102# DZ : no 2103# INEX2 : yes 2104# INEX1 : no 2105 2106# determine the highest priority exception(if any) set by the 2107# emulation routine that has also been enabled by the user. 2108 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 2109 bne.w fu_out_ena_p # some are enabled 2110 2111fu_out_exit_p: 2112 mov.l EXC_A6(%a6),(%a6) # restore a6 2113 2114 btst &0x5,EXC_SR(%a6) # user or supervisor? 2115 bne.b fu_out_exit_s_p # supervisor 2116 2117 mov.l EXC_A7(%a6),%a0 # update user a7 2118 mov.l %a0,%usp 2119 2120fu_out_exit_cont_p: 2121 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2122 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2123 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2124 2125 unlk %a6 # unravel stack frame 2126 2127 btst &0x7,(%sp) # is trace on? 2128 bne.w fu_trace_p # yes 2129 2130 bra.l _fpsp_done # exit to os 2131 2132# the exception occurred in supervisor mode. check to see if the 2133# addressing mode was -(a7). if so, we'll need to shift the 2134# stack frame "down". 2135fu_out_exit_s_p: 2136 btst &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7) 2137 beq.b fu_out_exit_cont_p # no 2138 2139 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2140 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2141 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2142 2143 mov.l (%a6),%a6 # restore frame pointer 2144 2145 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2146 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2147 2148# now, copy the result to the proper place on the stack 2149 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) 2150 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) 2151 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) 2152 2153 add.l &LOCAL_SIZE-0x8,%sp 2154 2155 btst &0x7,(%sp) 2156 bne.w fu_trace_p 2157 2158 bra.l _fpsp_done 2159 2160fu_out_ena_p: 2161 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled 2162 bfffo %d0{&24:&8},%d0 # find highest priority exception 2163 beq.w fu_out_exit_p 2164 2165 mov.l EXC_A6(%a6),(%a6) # restore a6 2166 2167# an exception occurred and that exception was enabled. 2168# the only exception possible on packed move out are INEX, OPERR, and SNAN. 2169fu_out_exc_p: 2170 cmpi.b %d0,&0x1a 2171 bgt.w fu_inex_p2 2172 beq.w fu_operr_p 2173 2174fu_snan_p: 2175 btst &0x5,EXC_SR(%a6) 2176 bne.b fu_snan_s_p 2177 2178 mov.l EXC_A7(%a6),%a0 2179 mov.l %a0,%usp 2180 bra.w fu_snan 2181 2182fu_snan_s_p: 2183 cmpi.b SPCOND_FLG(%a6),&mda7_flg 2184 bne.w fu_snan 2185 2186# the instruction was "fmove.p fpn,-(a7)" from supervisor mode. 2187# the strategy is to move the exception frame "down" 12 bytes. then, we 2188# can store the default result where the exception frame was. 2189 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2190 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2191 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2192 2193 mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd0 2194 mov.w &0xe006,2+FP_SRC(%a6) # set fsave status 2195 2196 frestore FP_SRC(%a6) # restore src operand 2197 2198 mov.l (%a6),%a6 # restore frame pointer 2199 2200 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2201 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2202 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 2203 2204# now, we copy the default result to its proper location 2205 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) 2206 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) 2207 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) 2208 2209 add.l &LOCAL_SIZE-0x8,%sp 2210 2211 2212 bra.l _real_snan 2213 2214fu_operr_p: 2215 btst &0x5,EXC_SR(%a6) 2216 bne.w fu_operr_p_s 2217 2218 mov.l EXC_A7(%a6),%a0 2219 mov.l %a0,%usp 2220 bra.w fu_operr 2221 2222fu_operr_p_s: 2223 cmpi.b SPCOND_FLG(%a6),&mda7_flg 2224 bne.w fu_operr 2225 2226# the instruction was "fmove.p fpn,-(a7)" from supervisor mode. 2227# the strategy is to move the exception frame "down" 12 bytes. then, we 2228# can store the default result where the exception frame was. 2229 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2230 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2231 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2232 2233 mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0 2234 mov.w &0xe004,2+FP_SRC(%a6) # set fsave status 2235 2236 frestore FP_SRC(%a6) # restore src operand 2237 2238 mov.l (%a6),%a6 # restore frame pointer 2239 2240 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2241 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2242 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 2243 2244# now, we copy the default result to its proper location 2245 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) 2246 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) 2247 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) 2248 2249 add.l &LOCAL_SIZE-0x8,%sp 2250 2251 2252 bra.l _real_operr 2253 2254fu_inex_p2: 2255 btst &0x5,EXC_SR(%a6) 2256 bne.w fu_inex_s_p2 2257 2258 mov.l EXC_A7(%a6),%a0 2259 mov.l %a0,%usp 2260 bra.w fu_inex 2261 2262fu_inex_s_p2: 2263 cmpi.b SPCOND_FLG(%a6),&mda7_flg 2264 bne.w fu_inex 2265 2266# the instruction was "fmove.p fpn,-(a7)" from supervisor mode. 2267# the strategy is to move the exception frame "down" 12 bytes. then, we 2268# can store the default result where the exception frame was. 2269 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2270 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2271 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2272 2273 mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4 2274 mov.w &0xe001,2+FP_SRC(%a6) # set fsave status 2275 2276 frestore FP_SRC(%a6) # restore src operand 2277 2278 mov.l (%a6),%a6 # restore frame pointer 2279 2280 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2281 mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2282 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 2283 2284# now, we copy the default result to its proper location 2285 mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) 2286 mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) 2287 mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) 2288 2289 add.l &LOCAL_SIZE-0x8,%sp 2290 2291 2292 bra.l _real_inex 2293 2294######################################################################### 2295 2296# 2297# if we're stuffing a source operand back into an fsave frame then we 2298# have to make sure that for single or double source operands that the 2299# format stuffed is as weird as the hardware usually makes it. 2300# 2301 global funimp_skew 2302funimp_skew: 2303 bfextu EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier 2304 cmpi.b %d0,&0x1 # was src sgl? 2305 beq.b funimp_skew_sgl # yes 2306 cmpi.b %d0,&0x5 # was src dbl? 2307 beq.b funimp_skew_dbl # yes 2308 rts 2309 2310funimp_skew_sgl: 2311 mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent 2312 andi.w &0x7fff,%d0 # strip sign 2313 beq.b funimp_skew_sgl_not 2314 cmpi.w %d0,&0x3f80 2315 bgt.b funimp_skew_sgl_not 2316 neg.w %d0 # make exponent negative 2317 addi.w &0x3f81,%d0 # find amt to shift 2318 mov.l FP_SRC_HI(%a6),%d1 # fetch DENORM hi(man) 2319 lsr.l %d0,%d1 # shift it 2320 bset &31,%d1 # set j-bit 2321 mov.l %d1,FP_SRC_HI(%a6) # insert new hi(man) 2322 andi.w &0x8000,FP_SRC_EX(%a6) # clear old exponent 2323 ori.w &0x3f80,FP_SRC_EX(%a6) # insert new "skewed" exponent 2324funimp_skew_sgl_not: 2325 rts 2326 2327funimp_skew_dbl: 2328 mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent 2329 andi.w &0x7fff,%d0 # strip sign 2330 beq.b funimp_skew_dbl_not 2331 cmpi.w %d0,&0x3c00 2332 bgt.b funimp_skew_dbl_not 2333 2334 tst.b FP_SRC_EX(%a6) # make "internal format" 2335 smi.b 0x2+FP_SRC(%a6) 2336 mov.w %d0,FP_SRC_EX(%a6) # insert exponent with cleared sign 2337 clr.l %d0 # clear g,r,s 2338 lea FP_SRC(%a6),%a0 # pass ptr to src op 2339 mov.w &0x3c01,%d1 # pass denorm threshold 2340 bsr.l dnrm_lp # denorm it 2341 mov.w &0x3c00,%d0 # new exponent 2342 tst.b 0x2+FP_SRC(%a6) # is sign set? 2343 beq.b fss_dbl_denorm_done # no 2344 bset &15,%d0 # set sign 2345fss_dbl_denorm_done: 2346 bset &0x7,FP_SRC_HI(%a6) # set j-bit 2347 mov.w %d0,FP_SRC_EX(%a6) # insert new exponent 2348funimp_skew_dbl_not: 2349 rts 2350 2351######################################################################### 2352 global _mem_write2 2353_mem_write2: 2354 btst &0x5,EXC_SR(%a6) 2355 beq.l _dmem_write 2356 mov.l 0x0(%a0),FP_DST_EX(%a6) 2357 mov.l 0x4(%a0),FP_DST_HI(%a6) 2358 mov.l 0x8(%a0),FP_DST_LO(%a6) 2359 clr.l %d1 2360 rts 2361 2362######################################################################### 2363# XDEF **************************************************************** # 2364# _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented # 2365# effective address" exception. # 2366# # 2367# This handler should be the first code executed upon taking the # 2368# FP Unimplemented Effective Address exception in an operating # 2369# system. # 2370# # 2371# XREF **************************************************************** # 2372# _imem_read_long() - read instruction longword # 2373# fix_skewed_ops() - adjust src operand in fsave frame # 2374# set_tag_x() - determine optype of src/dst operands # 2375# store_fpreg() - store opclass 0 or 2 result to FP regfile # 2376# unnorm_fix() - change UNNORM operands to NORM or ZERO # 2377# load_fpn2() - load dst operand from FP regfile # 2378# tbl_unsupp - add of table of emulation routines for opclass 0,2 # 2379# decbin() - convert packed data to FP binary data # 2380# _real_fpu_disabled() - "callout" for "FPU disabled" exception # 2381# _real_access() - "callout" for access error exception # 2382# _mem_read() - read extended immediate operand from memory # 2383# _fpsp_done() - "callout" for exit; work all done # 2384# _real_trace() - "callout" for Trace enabled exception # 2385# fmovm_dynamic() - emulate dynamic fmovm instruction # 2386# fmovm_ctrl() - emulate fmovm control instruction # 2387# # 2388# INPUT *************************************************************** # 2389# - The system stack contains the "Unimplemented <ea>" stk frame # 2390# # 2391# OUTPUT ************************************************************** # 2392# If access error: # 2393# - The system stack is changed to an access error stack frame # 2394# If FPU disabled: # 2395# - The system stack is changed to an FPU disabled stack frame # 2396# If Trace exception enabled: # 2397# - The system stack is changed to a Trace exception stack frame # 2398# Else: (normal case) # 2399# - None (correct result has been stored as appropriate) # 2400# # 2401# ALGORITHM *********************************************************** # 2402# This exception handles 3 types of operations: # 2403# (1) FP Instructions using extended precision or packed immediate # 2404# addressing mode. # 2405# (2) The "fmovm.x" instruction w/ dynamic register specification. # 2406# (3) The "fmovm.l" instruction w/ 2 or 3 control registers. # 2407# # 2408# For immediate data operations, the data is read in w/ a # 2409# _mem_read() "callout", converted to FP binary (if packed), and used # 2410# as the source operand to the instruction specified by the instruction # 2411# word. If no FP exception should be reported ads a result of the # 2412# emulation, then the result is stored to the destination register and # 2413# the handler exits through _fpsp_done(). If an enabled exc has been # 2414# signalled as a result of emulation, then an fsave state frame # 2415# corresponding to the FP exception type must be entered into the 060 # 2416# FPU before exiting. In either the enabled or disabled cases, we # 2417# must also check if a Trace exception is pending, in which case, we # 2418# must create a Trace exception stack frame from the current exception # 2419# stack frame. If no Trace is pending, we simply exit through # 2420# _fpsp_done(). # 2421# For "fmovm.x", call the routine fmovm_dynamic() which will # 2422# decode and emulate the instruction. No FP exceptions can be pending # 2423# as a result of this operation emulation. A Trace exception can be # 2424# pending, though, which means the current stack frame must be changed # 2425# to a Trace stack frame and an exit made through _real_trace(). # 2426# For the case of "fmovm.x Dn,-(a7)", where the offending instruction # 2427# was executed from supervisor mode, this handler must store the FP # 2428# register file values to the system stack by itself since # 2429# fmovm_dynamic() can't handle this. A normal exit is made through # 2430# fpsp_done(). # 2431# For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. # 2432# Again, a Trace exception may be pending and an exit made through # 2433# _real_trace(). Else, a normal exit is made through _fpsp_done(). # 2434# # 2435# Before any of the above is attempted, it must be checked to # 2436# see if the FPU is disabled. Since the "Unimp <ea>" exception is taken # 2437# before the "FPU disabled" exception, but the "FPU disabled" exception # 2438# has higher priority, we check the disabled bit in the PCR. If set, # 2439# then we must create an 8 word "FPU disabled" exception stack frame # 2440# from the current 4 word exception stack frame. This includes # 2441# reproducing the effective address of the instruction to put on the # 2442# new stack frame. # 2443# # 2444# In the process of all emulation work, if a _mem_read() # 2445# "callout" returns a failing result indicating an access error, then # 2446# we must create an access error stack frame from the current stack # 2447# frame. This information includes a faulting address and a fault- # 2448# status-longword. These are created within this handler. # 2449# # 2450######################################################################### 2451 2452 global _fpsp_effadd 2453_fpsp_effadd: 2454 2455# This exception type takes priority over the "Line F Emulator" 2456# exception. Therefore, the FPU could be disabled when entering here. 2457# So, we must check to see if it's disabled and handle that case separately. 2458 mov.l %d0,-(%sp) # save d0 2459 movc %pcr,%d0 # load proc cr 2460 btst &0x1,%d0 # is FPU disabled? 2461 bne.w iea_disabled # yes 2462 mov.l (%sp)+,%d0 # restore d0 2463 2464 link %a6,&-LOCAL_SIZE # init stack frame 2465 2466 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 2467 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 2468 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 2469 2470# PC of instruction that took the exception is the PC in the frame 2471 mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) 2472 2473 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 2474 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 2475 bsr.l _imem_read_long # fetch the instruction words 2476 mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD 2477 2478######################################################################### 2479 2480 tst.w %d0 # is operation fmovem? 2481 bmi.w iea_fmovm # yes 2482 2483# 2484# here, we will have: 2485# fabs fdabs fsabs facos fmod 2486# fadd fdadd fsadd fasin frem 2487# fcmp fatan fscale 2488# fdiv fddiv fsdiv fatanh fsin 2489# fint fcos fsincos 2490# fintrz fcosh fsinh 2491# fmove fdmove fsmove fetox ftan 2492# fmul fdmul fsmul fetoxm1 ftanh 2493# fneg fdneg fsneg fgetexp ftentox 2494# fsgldiv fgetman ftwotox 2495# fsglmul flog10 2496# fsqrt flog2 2497# fsub fdsub fssub flogn 2498# ftst flognp1 2499# which can all use f<op>.{x,p} 2500# so, now it's immediate data extended precision AND PACKED FORMAT! 2501# 2502iea_op: 2503 andi.l &0x00ff00ff,USER_FPSR(%a6) 2504 2505 btst &0xa,%d0 # is src fmt x or p? 2506 bne.b iea_op_pack # packed 2507 2508 2509 mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data> 2510 lea FP_SRC(%a6),%a1 # pass: ptr to super addr 2511 mov.l &0xc,%d0 # pass: 12 bytes 2512 bsr.l _imem_read # read extended immediate 2513 2514 tst.l %d1 # did ifetch fail? 2515 bne.w iea_iacc # yes 2516 2517 bra.b iea_op_setsrc 2518 2519iea_op_pack: 2520 2521 mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data> 2522 lea FP_SRC(%a6),%a1 # pass: ptr to super dst 2523 mov.l &0xc,%d0 # pass: 12 bytes 2524 bsr.l _imem_read # read packed operand 2525 2526 tst.l %d1 # did ifetch fail? 2527 bne.w iea_iacc # yes 2528 2529# The packed operand is an INF or a NAN if the exponent field is all ones. 2530 bfextu FP_SRC(%a6){&1:&15},%d0 # get exp 2531 cmpi.w %d0,&0x7fff # INF or NAN? 2532 beq.b iea_op_setsrc # operand is an INF or NAN 2533 2534# The packed operand is a zero if the mantissa is all zero, else it's 2535# a normal packed op. 2536 mov.b 3+FP_SRC(%a6),%d0 # get byte 4 2537 andi.b &0x0f,%d0 # clear all but last nybble 2538 bne.b iea_op_gp_not_spec # not a zero 2539 tst.l FP_SRC_HI(%a6) # is lw 2 zero? 2540 bne.b iea_op_gp_not_spec # not a zero 2541 tst.l FP_SRC_LO(%a6) # is lw 3 zero? 2542 beq.b iea_op_setsrc # operand is a ZERO 2543iea_op_gp_not_spec: 2544 lea FP_SRC(%a6),%a0 # pass: ptr to packed op 2545 bsr.l decbin # convert to extended 2546 fmovm.x &0x80,FP_SRC(%a6) # make this the srcop 2547 2548iea_op_setsrc: 2549 addi.l &0xc,EXC_EXTWPTR(%a6) # update extension word pointer 2550 2551# FP_SRC now holds the src operand. 2552 lea FP_SRC(%a6),%a0 # pass: ptr to src op 2553 bsr.l set_tag_x # tag the operand type 2554 mov.b %d0,STAG(%a6) # could be ANYTHING!!! 2555 cmpi.b %d0,&UNNORM # is operand an UNNORM? 2556 bne.b iea_op_getdst # no 2557 bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO 2558 mov.b %d0,STAG(%a6) # set new optype tag 2559iea_op_getdst: 2560 clr.b STORE_FLG(%a6) # clear "store result" boolean 2561 2562 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 2563 beq.b iea_op_extract # monadic 2564 btst &0x4,1+EXC_CMDREG(%a6) # is operation fsincos,ftst,fcmp? 2565 bne.b iea_op_spec # yes 2566 2567iea_op_loaddst: 2568 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno 2569 bsr.l load_fpn2 # load dst operand 2570 2571 lea FP_DST(%a6),%a0 # pass: ptr to dst op 2572 bsr.l set_tag_x # tag the operand type 2573 mov.b %d0,DTAG(%a6) # could be ANYTHING!!! 2574 cmpi.b %d0,&UNNORM # is operand an UNNORM? 2575 bne.b iea_op_extract # no 2576 bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO 2577 mov.b %d0,DTAG(%a6) # set new optype tag 2578 bra.b iea_op_extract 2579 2580# the operation is fsincos, ftst, or fcmp. only fcmp is dyadic 2581iea_op_spec: 2582 btst &0x3,1+EXC_CMDREG(%a6) # is operation fsincos? 2583 beq.b iea_op_extract # yes 2584# now, we're left with ftst and fcmp. so, first let's tag them so that they don't 2585# store a result. then, only fcmp will branch back and pick up a dst operand. 2586 st STORE_FLG(%a6) # don't store a final result 2587 btst &0x1,1+EXC_CMDREG(%a6) # is operation fcmp? 2588 beq.b iea_op_loaddst # yes 2589 2590iea_op_extract: 2591 clr.l %d0 2592 mov.b FPCR_MODE(%a6),%d0 # pass: rnd mode,prec 2593 2594 mov.b 1+EXC_CMDREG(%a6),%d1 2595 andi.w &0x007f,%d1 # extract extension 2596 2597 fmov.l &0x0,%fpcr 2598 fmov.l &0x0,%fpsr 2599 2600 lea FP_SRC(%a6),%a0 2601 lea FP_DST(%a6),%a1 2602 2603 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 2604 jsr (tbl_unsupp.l,%pc,%d1.l*1) 2605 2606# 2607# Exceptions in order of precedence: 2608# BSUN : none 2609# SNAN : all operations 2610# OPERR : all reg-reg or mem-reg operations that can normally operr 2611# OVFL : same as OPERR 2612# UNFL : same as OPERR 2613# DZ : same as OPERR 2614# INEX2 : same as OPERR 2615# INEX1 : all packed immediate operations 2616# 2617 2618# we determine the highest priority exception(if any) set by the 2619# emulation routine that has also been enabled by the user. 2620 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 2621 bne.b iea_op_ena # some are enabled 2622 2623# now, we save the result, unless, of course, the operation was ftst or fcmp. 2624# these don't save results. 2625iea_op_save: 2626 tst.b STORE_FLG(%a6) # does this op store a result? 2627 bne.b iea_op_exit1 # exit with no frestore 2628 2629iea_op_store: 2630 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno 2631 bsr.l store_fpreg # store the result 2632 2633iea_op_exit1: 2634 mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC" 2635 mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame 2636 2637 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 2638 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2639 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2640 2641 unlk %a6 # unravel the frame 2642 2643 btst &0x7,(%sp) # is trace on? 2644 bne.w iea_op_trace # yes 2645 2646 bra.l _fpsp_done # exit to os 2647 2648iea_op_ena: 2649 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enable and set 2650 bfffo %d0{&24:&8},%d0 # find highest priority exception 2651 bne.b iea_op_exc # at least one was set 2652 2653# no exception occurred. now, did a disabled, exact overflow occur with inexact 2654# enabled? if so, then we have to stuff an overflow frame into the FPU. 2655 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? 2656 beq.b iea_op_save 2657 2658iea_op_ovfl: 2659 btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled? 2660 beq.b iea_op_store # no 2661 bra.b iea_op_exc_ovfl # yes 2662 2663# an enabled exception occurred. we have to insert the exception type back into 2664# the machine. 2665iea_op_exc: 2666 subi.l &24,%d0 # fix offset to be 0-8 2667 cmpi.b %d0,&0x6 # is exception INEX? 2668 bne.b iea_op_exc_force # no 2669 2670# the enabled exception was inexact. so, if it occurs with an overflow 2671# or underflow that was disabled, then we have to force an overflow or 2672# underflow frame. 2673 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? 2674 bne.b iea_op_exc_ovfl # yes 2675 btst &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur? 2676 bne.b iea_op_exc_unfl # yes 2677 2678iea_op_exc_force: 2679 mov.w (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) 2680 bra.b iea_op_exit2 # exit with frestore 2681 2682tbl_iea_except: 2683 short 0xe002, 0xe006, 0xe004, 0xe005 2684 short 0xe003, 0xe002, 0xe001, 0xe001 2685 2686iea_op_exc_ovfl: 2687 mov.w &0xe005,2+FP_SRC(%a6) 2688 bra.b iea_op_exit2 2689 2690iea_op_exc_unfl: 2691 mov.w &0xe003,2+FP_SRC(%a6) 2692 2693iea_op_exit2: 2694 mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC" 2695 mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame 2696 2697 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 2698 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2699 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2700 2701 frestore FP_SRC(%a6) # restore exceptional state 2702 2703 unlk %a6 # unravel the frame 2704 2705 btst &0x7,(%sp) # is trace on? 2706 bne.b iea_op_trace # yes 2707 2708 bra.l _fpsp_done # exit to os 2709 2710# 2711# The opclass two instruction that took an "Unimplemented Effective Address" 2712# exception was being traced. Make the "current" PC the FPIAR and put it in 2713# the trace stack frame then jump to _real_trace(). 2714# 2715# UNIMP EA FRAME TRACE FRAME 2716# ***************** ***************** 2717# * 0x0 * 0x0f0 * * Current * 2718# ***************** * PC * 2719# * Current * ***************** 2720# * PC * * 0x2 * 0x024 * 2721# ***************** ***************** 2722# * SR * * Next * 2723# ***************** * PC * 2724# ***************** 2725# * SR * 2726# ***************** 2727iea_op_trace: 2728 mov.l (%sp),-(%sp) # shift stack frame "down" 2729 mov.w 0x8(%sp),0x4(%sp) 2730 mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 2731 fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR 2732 2733 bra.l _real_trace 2734 2735######################################################################### 2736iea_fmovm: 2737 btst &14,%d0 # ctrl or data reg 2738 beq.w iea_fmovm_ctrl 2739 2740iea_fmovm_data: 2741 2742 btst &0x5,EXC_SR(%a6) # user or supervisor mode 2743 bne.b iea_fmovm_data_s 2744 2745iea_fmovm_data_u: 2746 mov.l %usp,%a0 2747 mov.l %a0,EXC_A7(%a6) # store current a7 2748 bsr.l fmovm_dynamic # do dynamic fmovm 2749 mov.l EXC_A7(%a6),%a0 # load possibly new a7 2750 mov.l %a0,%usp # update usp 2751 bra.w iea_fmovm_exit 2752 2753iea_fmovm_data_s: 2754 clr.b SPCOND_FLG(%a6) 2755 lea 0x2+EXC_VOFF(%a6),%a0 2756 mov.l %a0,EXC_A7(%a6) 2757 bsr.l fmovm_dynamic # do dynamic fmovm 2758 2759 cmpi.b SPCOND_FLG(%a6),&mda7_flg 2760 beq.w iea_fmovm_data_predec 2761 cmpi.b SPCOND_FLG(%a6),&mia7_flg 2762 bne.w iea_fmovm_exit 2763 2764# right now, d0 = the size. 2765# the data has been fetched from the supervisor stack, but we have not 2766# incremented the stack pointer by the appropriate number of bytes. 2767# do it here. 2768iea_fmovm_data_postinc: 2769 btst &0x7,EXC_SR(%a6) 2770 bne.b iea_fmovm_data_pi_trace 2771 2772 mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0) 2773 mov.l EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0) 2774 mov.w &0x00f0,(EXC_VOFF,%a6,%d0) 2775 2776 lea (EXC_SR,%a6,%d0),%a0 2777 mov.l %a0,EXC_SR(%a6) 2778 2779 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 2780 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2781 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2782 2783 unlk %a6 2784 mov.l (%sp)+,%sp 2785 bra.l _fpsp_done 2786 2787iea_fmovm_data_pi_trace: 2788 mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0) 2789 mov.l EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0) 2790 mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0) 2791 mov.l EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0) 2792 2793 lea (EXC_SR-0x4,%a6,%d0),%a0 2794 mov.l %a0,EXC_SR(%a6) 2795 2796 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 2797 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2798 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2799 2800 unlk %a6 2801 mov.l (%sp)+,%sp 2802 bra.l _real_trace 2803 2804# right now, d1 = size and d0 = the strg. 2805iea_fmovm_data_predec: 2806 mov.b %d1,EXC_VOFF(%a6) # store strg 2807 mov.b %d0,0x1+EXC_VOFF(%a6) # store size 2808 2809 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 2810 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2811 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2812 2813 mov.l (%a6),-(%sp) # make a copy of a6 2814 mov.l %d0,-(%sp) # save d0 2815 mov.l %d1,-(%sp) # save d1 2816 mov.l EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC 2817 2818 clr.l %d0 2819 mov.b 0x1+EXC_VOFF(%a6),%d0 # fetch size 2820 neg.l %d0 # get negative of size 2821 2822 btst &0x7,EXC_SR(%a6) # is trace enabled? 2823 beq.b iea_fmovm_data_p2 2824 2825 mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0) 2826 mov.l EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0) 2827 mov.l (%sp)+,(EXC_PC-0x4,%a6,%d0) 2828 mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0) 2829 2830 pea (%a6,%d0) # create final sp 2831 bra.b iea_fmovm_data_p3 2832 2833iea_fmovm_data_p2: 2834 mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0) 2835 mov.l (%sp)+,(EXC_PC,%a6,%d0) 2836 mov.w &0x00f0,(EXC_VOFF,%a6,%d0) 2837 2838 pea (0x4,%a6,%d0) # create final sp 2839 2840iea_fmovm_data_p3: 2841 clr.l %d1 2842 mov.b EXC_VOFF(%a6),%d1 # fetch strg 2843 2844 tst.b %d1 2845 bpl.b fm_1 2846 fmovm.x &0x80,(0x4+0x8,%a6,%d0) 2847 addi.l &0xc,%d0 2848fm_1: 2849 lsl.b &0x1,%d1 2850 bpl.b fm_2 2851 fmovm.x &0x40,(0x4+0x8,%a6,%d0) 2852 addi.l &0xc,%d0 2853fm_2: 2854 lsl.b &0x1,%d1 2855 bpl.b fm_3 2856 fmovm.x &0x20,(0x4+0x8,%a6,%d0) 2857 addi.l &0xc,%d0 2858fm_3: 2859 lsl.b &0x1,%d1 2860 bpl.b fm_4 2861 fmovm.x &0x10,(0x4+0x8,%a6,%d0) 2862 addi.l &0xc,%d0 2863fm_4: 2864 lsl.b &0x1,%d1 2865 bpl.b fm_5 2866 fmovm.x &0x08,(0x4+0x8,%a6,%d0) 2867 addi.l &0xc,%d0 2868fm_5: 2869 lsl.b &0x1,%d1 2870 bpl.b fm_6 2871 fmovm.x &0x04,(0x4+0x8,%a6,%d0) 2872 addi.l &0xc,%d0 2873fm_6: 2874 lsl.b &0x1,%d1 2875 bpl.b fm_7 2876 fmovm.x &0x02,(0x4+0x8,%a6,%d0) 2877 addi.l &0xc,%d0 2878fm_7: 2879 lsl.b &0x1,%d1 2880 bpl.b fm_end 2881 fmovm.x &0x01,(0x4+0x8,%a6,%d0) 2882fm_end: 2883 mov.l 0x4(%sp),%d1 2884 mov.l 0x8(%sp),%d0 2885 mov.l 0xc(%sp),%a6 2886 mov.l (%sp)+,%sp 2887 2888 btst &0x7,(%sp) # is trace enabled? 2889 beq.l _fpsp_done 2890 bra.l _real_trace 2891 2892######################################################################### 2893iea_fmovm_ctrl: 2894 2895 bsr.l fmovm_ctrl # load ctrl regs 2896 2897iea_fmovm_exit: 2898 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 2899 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2900 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2901 2902 btst &0x7,EXC_SR(%a6) # is trace on? 2903 bne.b iea_fmovm_trace # yes 2904 2905 mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC 2906 2907 unlk %a6 # unravel the frame 2908 2909 bra.l _fpsp_done # exit to os 2910 2911# 2912# The control reg instruction that took an "Unimplemented Effective Address" 2913# exception was being traced. The "Current PC" for the trace frame is the 2914# PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR. 2915# After fixing the stack frame, jump to _real_trace(). 2916# 2917# UNIMP EA FRAME TRACE FRAME 2918# ***************** ***************** 2919# * 0x0 * 0x0f0 * * Current * 2920# ***************** * PC * 2921# * Current * ***************** 2922# * PC * * 0x2 * 0x024 * 2923# ***************** ***************** 2924# * SR * * Next * 2925# ***************** * PC * 2926# ***************** 2927# * SR * 2928# ***************** 2929# this ain't a pretty solution, but it works: 2930# -restore a6 (not with unlk) 2931# -shift stack frame down over where old a6 used to be 2932# -add LOCAL_SIZE to stack pointer 2933iea_fmovm_trace: 2934 mov.l (%a6),%a6 # restore frame pointer 2935 mov.w EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp) 2936 mov.l EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp) 2937 mov.l EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp) 2938 mov.w &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024 2939 add.l &LOCAL_SIZE,%sp # clear stack frame 2940 2941 bra.l _real_trace 2942 2943######################################################################### 2944# The FPU is disabled and so we should really have taken the "Line 2945# F Emulator" exception. So, here we create an 8-word stack frame 2946# from our 4-word stack frame. This means we must calculate the length 2947# the faulting instruction to get the "next PC". This is trivial for 2948# immediate operands but requires some extra work for fmovm dynamic 2949# which can use most addressing modes. 2950iea_disabled: 2951 mov.l (%sp)+,%d0 # restore d0 2952 2953 link %a6,&-LOCAL_SIZE # init stack frame 2954 2955 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 2956 2957# PC of instruction that took the exception is the PC in the frame 2958 mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) 2959 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 2960 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 2961 bsr.l _imem_read_long # fetch the instruction words 2962 mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD 2963 2964 tst.w %d0 # is instr fmovm? 2965 bmi.b iea_dis_fmovm # yes 2966# instruction is using an extended precision immediate operand. Therefore, 2967# the total instruction length is 16 bytes. 2968iea_dis_immed: 2969 mov.l &0x10,%d0 # 16 bytes of instruction 2970 bra.b iea_dis_cont 2971iea_dis_fmovm: 2972 btst &0xe,%d0 # is instr fmovm ctrl 2973 bne.b iea_dis_fmovm_data # no 2974# the instruction is a fmovm.l with 2 or 3 registers. 2975 bfextu %d0{&19:&3},%d1 2976 mov.l &0xc,%d0 2977 cmpi.b %d1,&0x7 # move all regs? 2978 bne.b iea_dis_cont 2979 addq.l &0x4,%d0 2980 bra.b iea_dis_cont 2981# the instruction is an fmovm.x dynamic which can use many addressing 2982# modes and thus can have several different total instruction lengths. 2983# call fmovm_calc_ea which will go through the ea calc process and, 2984# as a by-product, will tell us how long the instruction is. 2985iea_dis_fmovm_data: 2986 clr.l %d0 2987 bsr.l fmovm_calc_ea 2988 mov.l EXC_EXTWPTR(%a6),%d0 2989 sub.l EXC_PC(%a6),%d0 2990iea_dis_cont: 2991 mov.w %d0,EXC_VOFF(%a6) # store stack shift value 2992 2993 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2994 2995 unlk %a6 2996 2997# here, we actually create the 8-word frame from the 4-word frame, 2998# with the "next PC" as additional info. 2999# the <ea> field is let as undefined. 3000 subq.l &0x8,%sp # make room for new stack 3001 mov.l %d0,-(%sp) # save d0 3002 mov.w 0xc(%sp),0x4(%sp) # move SR 3003 mov.l 0xe(%sp),0x6(%sp) # move Current PC 3004 clr.l %d0 3005 mov.w 0x12(%sp),%d0 3006 mov.l 0x6(%sp),0x10(%sp) # move Current PC 3007 add.l %d0,0x6(%sp) # make Next PC 3008 mov.w &0x402c,0xa(%sp) # insert offset,frame format 3009 mov.l (%sp)+,%d0 # restore d0 3010 3011 bra.l _real_fpu_disabled 3012 3013########## 3014 3015iea_iacc: 3016 movc %pcr,%d0 3017 btst &0x1,%d0 3018 bne.b iea_iacc_cont 3019 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3020 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack 3021iea_iacc_cont: 3022 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3023 3024 unlk %a6 3025 3026 subq.w &0x8,%sp # make stack frame bigger 3027 mov.l 0x8(%sp),(%sp) # store SR,hi(PC) 3028 mov.w 0xc(%sp),0x4(%sp) # store lo(PC) 3029 mov.w &0x4008,0x6(%sp) # store voff 3030 mov.l 0x2(%sp),0x8(%sp) # store ea 3031 mov.l &0x09428001,0xc(%sp) # store fslw 3032 3033iea_acc_done: 3034 btst &0x5,(%sp) # user or supervisor mode? 3035 beq.b iea_acc_done2 # user 3036 bset &0x2,0xd(%sp) # set supervisor TM bit 3037 3038iea_acc_done2: 3039 bra.l _real_access 3040 3041iea_dacc: 3042 lea -LOCAL_SIZE(%a6),%sp 3043 3044 movc %pcr,%d1 3045 btst &0x1,%d1 3046 bne.b iea_dacc_cont 3047 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack 3048 fmovm.l LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs 3049iea_dacc_cont: 3050 mov.l (%a6),%a6 3051 3052 mov.l 0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp) 3053 mov.w 0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp) 3054 mov.w &0x4008,-0x8+0xa+LOCAL_SIZE(%sp) 3055 mov.l %a0,-0x8+0xc+LOCAL_SIZE(%sp) 3056 mov.w %d0,-0x8+0x10+LOCAL_SIZE(%sp) 3057 mov.w &0x0001,-0x8+0x12+LOCAL_SIZE(%sp) 3058 3059 movm.l LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1 3060 add.w &LOCAL_SIZE-0x4,%sp 3061 3062 bra.b iea_acc_done 3063 3064######################################################################### 3065# XDEF **************************************************************** # 3066# _fpsp_operr(): 060FPSP entry point for FP Operr exception. # 3067# # 3068# This handler should be the first code executed upon taking the # 3069# FP Operand Error exception in an operating system. # 3070# # 3071# XREF **************************************************************** # 3072# _imem_read_long() - read instruction longword # 3073# fix_skewed_ops() - adjust src operand in fsave frame # 3074# _real_operr() - "callout" to operating system operr handler # 3075# _dmem_write_{byte,word,long}() - store data to mem (opclass 3) # 3076# store_dreg_{b,w,l}() - store data to data regfile (opclass 3) # 3077# facc_out_{b,w,l}() - store to memory took access error (opcl 3) # 3078# # 3079# INPUT *************************************************************** # 3080# - The system stack contains the FP Operr exception frame # 3081# - The fsave frame contains the source operand # 3082# # 3083# OUTPUT ************************************************************** # 3084# No access error: # 3085# - The system stack is unchanged # 3086# - The fsave frame contains the adjusted src op for opclass 0,2 # 3087# # 3088# ALGORITHM *********************************************************** # 3089# In a system where the FP Operr exception is enabled, the goal # 3090# is to get to the handler specified at _real_operr(). But, on the 060, # 3091# for opclass zero and two instruction taking this exception, the # 3092# input operand in the fsave frame may be incorrect for some cases # 3093# and needs to be corrected. This handler calls fix_skewed_ops() to # 3094# do just this and then exits through _real_operr(). # 3095# For opclass 3 instructions, the 060 doesn't store the default # 3096# operr result out to memory or data register file as it should. # 3097# This code must emulate the move out before finally exiting through # 3098# _real_inex(). The move out, if to memory, is performed using # 3099# _mem_write() "callout" routines that may return a failing result. # 3100# In this special case, the handler must exit through facc_out() # 3101# which creates an access error stack frame from the current operr # 3102# stack frame. # 3103# # 3104######################################################################### 3105 3106 global _fpsp_operr 3107_fpsp_operr: 3108 3109 link.w %a6,&-LOCAL_SIZE # init stack frame 3110 3111 fsave FP_SRC(%a6) # grab the "busy" frame 3112 3113 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3114 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3115 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3116 3117# the FPIAR holds the "current PC" of the faulting instruction 3118 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3119 3120 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3121 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3122 bsr.l _imem_read_long # fetch the instruction words 3123 mov.l %d0,EXC_OPWORD(%a6) 3124 3125############################################################################## 3126 3127 btst &13,%d0 # is instr an fmove out? 3128 bne.b foperr_out # fmove out 3129 3130 3131# here, we simply see if the operand in the fsave frame needs to be "unskewed". 3132# this would be the case for opclass two operations with a source infinity or 3133# denorm operand in the sgl or dbl format. NANs also become skewed, but can't 3134# cause an operr so we don't need to check for them here. 3135 lea FP_SRC(%a6),%a0 # pass: ptr to src op 3136 bsr.l fix_skewed_ops # fix src op 3137 3138foperr_exit: 3139 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3140 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3141 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3142 3143 frestore FP_SRC(%a6) 3144 3145 unlk %a6 3146 bra.l _real_operr 3147 3148######################################################################## 3149 3150# 3151# the hardware does not save the default result to memory on enabled 3152# operand error exceptions. we do this here before passing control to 3153# the user operand error handler. 3154# 3155# byte, word, and long destination format operations can pass 3156# through here. we simply need to test the sign of the src 3157# operand and save the appropriate minimum or maximum integer value 3158# to the effective address as pointed to by the stacked effective address. 3159# 3160# although packed opclass three operations can take operand error 3161# exceptions, they won't pass through here since they are caught 3162# first by the unsupported data format exception handler. that handler 3163# sends them directly to _real_operr() if necessary. 3164# 3165foperr_out: 3166 3167 mov.w FP_SRC_EX(%a6),%d1 # fetch exponent 3168 andi.w &0x7fff,%d1 3169 cmpi.w %d1,&0x7fff 3170 bne.b foperr_out_not_qnan 3171# the operand is either an infinity or a QNAN. 3172 tst.l FP_SRC_LO(%a6) 3173 bne.b foperr_out_qnan 3174 mov.l FP_SRC_HI(%a6),%d1 3175 andi.l &0x7fffffff,%d1 3176 beq.b foperr_out_not_qnan 3177foperr_out_qnan: 3178 mov.l FP_SRC_HI(%a6),L_SCR1(%a6) 3179 bra.b foperr_out_jmp 3180 3181foperr_out_not_qnan: 3182 mov.l &0x7fffffff,%d1 3183 tst.b FP_SRC_EX(%a6) 3184 bpl.b foperr_out_not_qnan2 3185 addq.l &0x1,%d1 3186foperr_out_not_qnan2: 3187 mov.l %d1,L_SCR1(%a6) 3188 3189foperr_out_jmp: 3190 bfextu %d0{&19:&3},%d0 # extract dst format field 3191 mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg 3192 mov.w (tbl_operr.b,%pc,%d0.w*2),%a0 3193 jmp (tbl_operr.b,%pc,%a0) 3194 3195tbl_operr: 3196 short foperr_out_l - tbl_operr # long word integer 3197 short tbl_operr - tbl_operr # sgl prec shouldn't happen 3198 short tbl_operr - tbl_operr # ext prec shouldn't happen 3199 short foperr_exit - tbl_operr # packed won't enter here 3200 short foperr_out_w - tbl_operr # word integer 3201 short tbl_operr - tbl_operr # dbl prec shouldn't happen 3202 short foperr_out_b - tbl_operr # byte integer 3203 short tbl_operr - tbl_operr # packed won't enter here 3204 3205foperr_out_b: 3206 mov.b L_SCR1(%a6),%d0 # load positive default result 3207 cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3208 ble.b foperr_out_b_save_dn # yes 3209 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3210 bsr.l _dmem_write_byte # write the default result 3211 3212 tst.l %d1 # did dstore fail? 3213 bne.l facc_out_b # yes 3214 3215 bra.w foperr_exit 3216foperr_out_b_save_dn: 3217 andi.w &0x0007,%d1 3218 bsr.l store_dreg_b # store result to regfile 3219 bra.w foperr_exit 3220 3221foperr_out_w: 3222 mov.w L_SCR1(%a6),%d0 # load positive default result 3223 cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3224 ble.b foperr_out_w_save_dn # yes 3225 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3226 bsr.l _dmem_write_word # write the default result 3227 3228 tst.l %d1 # did dstore fail? 3229 bne.l facc_out_w # yes 3230 3231 bra.w foperr_exit 3232foperr_out_w_save_dn: 3233 andi.w &0x0007,%d1 3234 bsr.l store_dreg_w # store result to regfile 3235 bra.w foperr_exit 3236 3237foperr_out_l: 3238 mov.l L_SCR1(%a6),%d0 # load positive default result 3239 cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3240 ble.b foperr_out_l_save_dn # yes 3241 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3242 bsr.l _dmem_write_long # write the default result 3243 3244 tst.l %d1 # did dstore fail? 3245 bne.l facc_out_l # yes 3246 3247 bra.w foperr_exit 3248foperr_out_l_save_dn: 3249 andi.w &0x0007,%d1 3250 bsr.l store_dreg_l # store result to regfile 3251 bra.w foperr_exit 3252 3253######################################################################### 3254# XDEF **************************************************************** # 3255# _fpsp_snan(): 060FPSP entry point for FP SNAN exception. # 3256# # 3257# This handler should be the first code executed upon taking the # 3258# FP Signalling NAN exception in an operating system. # 3259# # 3260# XREF **************************************************************** # 3261# _imem_read_long() - read instruction longword # 3262# fix_skewed_ops() - adjust src operand in fsave frame # 3263# _real_snan() - "callout" to operating system SNAN handler # 3264# _dmem_write_{byte,word,long}() - store data to mem (opclass 3) # 3265# store_dreg_{b,w,l}() - store data to data regfile (opclass 3) # 3266# facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3) # 3267# _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea> # 3268# # 3269# INPUT *************************************************************** # 3270# - The system stack contains the FP SNAN exception frame # 3271# - The fsave frame contains the source operand # 3272# # 3273# OUTPUT ************************************************************** # 3274# No access error: # 3275# - The system stack is unchanged # 3276# - The fsave frame contains the adjusted src op for opclass 0,2 # 3277# # 3278# ALGORITHM *********************************************************** # 3279# In a system where the FP SNAN exception is enabled, the goal # 3280# is to get to the handler specified at _real_snan(). But, on the 060, # 3281# for opclass zero and two instructions taking this exception, the # 3282# input operand in the fsave frame may be incorrect for some cases # 3283# and needs to be corrected. This handler calls fix_skewed_ops() to # 3284# do just this and then exits through _real_snan(). # 3285# For opclass 3 instructions, the 060 doesn't store the default # 3286# SNAN result out to memory or data register file as it should. # 3287# This code must emulate the move out before finally exiting through # 3288# _real_snan(). The move out, if to memory, is performed using # 3289# _mem_write() "callout" routines that may return a failing result. # 3290# In this special case, the handler must exit through facc_out() # 3291# which creates an access error stack frame from the current SNAN # 3292# stack frame. # 3293# For the case of an extended precision opclass 3 instruction, # 3294# if the effective addressing mode was -() or ()+, then the address # 3295# register must get updated by calling _calc_ea_fout(). If the <ea> # 3296# was -(a7) from supervisor mode, then the exception frame currently # 3297# on the system stack must be carefully moved "down" to make room # 3298# for the operand being moved. # 3299# # 3300######################################################################### 3301 3302 global _fpsp_snan 3303_fpsp_snan: 3304 3305 link.w %a6,&-LOCAL_SIZE # init stack frame 3306 3307 fsave FP_SRC(%a6) # grab the "busy" frame 3308 3309 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3310 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3311 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3312 3313# the FPIAR holds the "current PC" of the faulting instruction 3314 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3315 3316 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3317 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3318 bsr.l _imem_read_long # fetch the instruction words 3319 mov.l %d0,EXC_OPWORD(%a6) 3320 3321############################################################################## 3322 3323 btst &13,%d0 # is instr an fmove out? 3324 bne.w fsnan_out # fmove out 3325 3326 3327# here, we simply see if the operand in the fsave frame needs to be "unskewed". 3328# this would be the case for opclass two operations with a source infinity or 3329# denorm operand in the sgl or dbl format. NANs also become skewed and must be 3330# fixed here. 3331 lea FP_SRC(%a6),%a0 # pass: ptr to src op 3332 bsr.l fix_skewed_ops # fix src op 3333 3334fsnan_exit: 3335 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3336 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3337 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3338 3339 frestore FP_SRC(%a6) 3340 3341 unlk %a6 3342 bra.l _real_snan 3343 3344######################################################################## 3345 3346# 3347# the hardware does not save the default result to memory on enabled 3348# snan exceptions. we do this here before passing control to 3349# the user snan handler. 3350# 3351# byte, word, long, and packed destination format operations can pass 3352# through here. since packed format operations already were handled by 3353# fpsp_unsupp(), then we need to do nothing else for them here. 3354# for byte, word, and long, we simply need to test the sign of the src 3355# operand and save the appropriate minimum or maximum integer value 3356# to the effective address as pointed to by the stacked effective address. 3357# 3358fsnan_out: 3359 3360 bfextu %d0{&19:&3},%d0 # extract dst format field 3361 mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg 3362 mov.w (tbl_snan.b,%pc,%d0.w*2),%a0 3363 jmp (tbl_snan.b,%pc,%a0) 3364 3365tbl_snan: 3366 short fsnan_out_l - tbl_snan # long word integer 3367 short fsnan_out_s - tbl_snan # sgl prec shouldn't happen 3368 short fsnan_out_x - tbl_snan # ext prec shouldn't happen 3369 short tbl_snan - tbl_snan # packed needs no help 3370 short fsnan_out_w - tbl_snan # word integer 3371 short fsnan_out_d - tbl_snan # dbl prec shouldn't happen 3372 short fsnan_out_b - tbl_snan # byte integer 3373 short tbl_snan - tbl_snan # packed needs no help 3374 3375fsnan_out_b: 3376 mov.b FP_SRC_HI(%a6),%d0 # load upper byte of SNAN 3377 bset &6,%d0 # set SNAN bit 3378 cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3379 ble.b fsnan_out_b_dn # yes 3380 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3381 bsr.l _dmem_write_byte # write the default result 3382 3383 tst.l %d1 # did dstore fail? 3384 bne.l facc_out_b # yes 3385 3386 bra.w fsnan_exit 3387fsnan_out_b_dn: 3388 andi.w &0x0007,%d1 3389 bsr.l store_dreg_b # store result to regfile 3390 bra.w fsnan_exit 3391 3392fsnan_out_w: 3393 mov.w FP_SRC_HI(%a6),%d0 # load upper word of SNAN 3394 bset &14,%d0 # set SNAN bit 3395 cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3396 ble.b fsnan_out_w_dn # yes 3397 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3398 bsr.l _dmem_write_word # write the default result 3399 3400 tst.l %d1 # did dstore fail? 3401 bne.l facc_out_w # yes 3402 3403 bra.w fsnan_exit 3404fsnan_out_w_dn: 3405 andi.w &0x0007,%d1 3406 bsr.l store_dreg_w # store result to regfile 3407 bra.w fsnan_exit 3408 3409fsnan_out_l: 3410 mov.l FP_SRC_HI(%a6),%d0 # load upper longword of SNAN 3411 bset &30,%d0 # set SNAN bit 3412 cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3413 ble.b fsnan_out_l_dn # yes 3414 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3415 bsr.l _dmem_write_long # write the default result 3416 3417 tst.l %d1 # did dstore fail? 3418 bne.l facc_out_l # yes 3419 3420 bra.w fsnan_exit 3421fsnan_out_l_dn: 3422 andi.w &0x0007,%d1 3423 bsr.l store_dreg_l # store result to regfile 3424 bra.w fsnan_exit 3425 3426fsnan_out_s: 3427 cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3428 ble.b fsnan_out_d_dn # yes 3429 mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign 3430 andi.l &0x80000000,%d0 # keep sign 3431 ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit 3432 mov.l FP_SRC_HI(%a6),%d1 # load mantissa 3433 lsr.l &0x8,%d1 # shift mantissa for sgl 3434 or.l %d1,%d0 # create sgl SNAN 3435 mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3436 bsr.l _dmem_write_long # write the default result 3437 3438 tst.l %d1 # did dstore fail? 3439 bne.l facc_out_l # yes 3440 3441 bra.w fsnan_exit 3442fsnan_out_d_dn: 3443 mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign 3444 andi.l &0x80000000,%d0 # keep sign 3445 ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit 3446 mov.l %d1,-(%sp) 3447 mov.l FP_SRC_HI(%a6),%d1 # load mantissa 3448 lsr.l &0x8,%d1 # shift mantissa for sgl 3449 or.l %d1,%d0 # create sgl SNAN 3450 mov.l (%sp)+,%d1 3451 andi.w &0x0007,%d1 3452 bsr.l store_dreg_l # store result to regfile 3453 bra.w fsnan_exit 3454 3455fsnan_out_d: 3456 mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign 3457 andi.l &0x80000000,%d0 # keep sign 3458 ori.l &0x7ff80000,%d0 # insert new exponent,SNAN bit 3459 mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa 3460 mov.l %d0,FP_SCR0_EX(%a6) # store to temp space 3461 mov.l &11,%d0 # load shift amt 3462 lsr.l %d0,%d1 3463 or.l %d1,FP_SCR0_EX(%a6) # create dbl hi 3464 mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa 3465 andi.l &0x000007ff,%d1 3466 ror.l %d0,%d1 3467 mov.l %d1,FP_SCR0_HI(%a6) # store to temp space 3468 mov.l FP_SRC_LO(%a6),%d1 # load lo mantissa 3469 lsr.l %d0,%d1 3470 or.l %d1,FP_SCR0_HI(%a6) # create dbl lo 3471 lea FP_SCR0(%a6),%a0 # pass: ptr to operand 3472 mov.l EXC_EA(%a6),%a1 # pass: dst addr 3473 movq.l &0x8,%d0 # pass: size of 8 bytes 3474 bsr.l _dmem_write # write the default result 3475 3476 tst.l %d1 # did dstore fail? 3477 bne.l facc_out_d # yes 3478 3479 bra.w fsnan_exit 3480 3481# for extended precision, if the addressing mode is pre-decrement or 3482# post-increment, then the address register did not get updated. 3483# in addition, for pre-decrement, the stacked <ea> is incorrect. 3484fsnan_out_x: 3485 clr.b SPCOND_FLG(%a6) # clear special case flag 3486 3487 mov.w FP_SRC_EX(%a6),FP_SCR0_EX(%a6) 3488 clr.w 2+FP_SCR0(%a6) 3489 mov.l FP_SRC_HI(%a6),%d0 3490 bset &30,%d0 3491 mov.l %d0,FP_SCR0_HI(%a6) 3492 mov.l FP_SRC_LO(%a6),FP_SCR0_LO(%a6) 3493 3494 btst &0x5,EXC_SR(%a6) # supervisor mode exception? 3495 bne.b fsnan_out_x_s # yes 3496 3497 mov.l %usp,%a0 # fetch user stack pointer 3498 mov.l %a0,EXC_A7(%a6) # save on stack for calc_ea() 3499 mov.l (%a6),EXC_A6(%a6) 3500 3501 bsr.l _calc_ea_fout # find the correct ea,update An 3502 mov.l %a0,%a1 3503 mov.l %a0,EXC_EA(%a6) # stack correct <ea> 3504 3505 mov.l EXC_A7(%a6),%a0 3506 mov.l %a0,%usp # restore user stack pointer 3507 mov.l EXC_A6(%a6),(%a6) 3508 3509fsnan_out_x_save: 3510 lea FP_SCR0(%a6),%a0 # pass: ptr to operand 3511 movq.l &0xc,%d0 # pass: size of extended 3512 bsr.l _dmem_write # write the default result 3513 3514 tst.l %d1 # did dstore fail? 3515 bne.l facc_out_x # yes 3516 3517 bra.w fsnan_exit 3518 3519fsnan_out_x_s: 3520 mov.l (%a6),EXC_A6(%a6) 3521 3522 bsr.l _calc_ea_fout # find the correct ea,update An 3523 mov.l %a0,%a1 3524 mov.l %a0,EXC_EA(%a6) # stack correct <ea> 3525 3526 mov.l EXC_A6(%a6),(%a6) 3527 3528 cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)? 3529 bne.b fsnan_out_x_save # no 3530 3531# the operation was "fmove.x SNAN,-(a7)" from supervisor mode. 3532 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3533 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3534 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3535 3536 frestore FP_SRC(%a6) 3537 3538 mov.l EXC_A6(%a6),%a6 # restore frame pointer 3539 3540 mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 3541 mov.l LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp) 3542 mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 3543 3544 mov.l LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp) 3545 mov.l LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp) 3546 mov.l LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp) 3547 3548 add.l &LOCAL_SIZE-0x8,%sp 3549 3550 bra.l _real_snan 3551 3552######################################################################### 3553# XDEF **************************************************************** # 3554# _fpsp_inex(): 060FPSP entry point for FP Inexact exception. # 3555# # 3556# This handler should be the first code executed upon taking the # 3557# FP Inexact exception in an operating system. # 3558# # 3559# XREF **************************************************************** # 3560# _imem_read_long() - read instruction longword # 3561# fix_skewed_ops() - adjust src operand in fsave frame # 3562# set_tag_x() - determine optype of src/dst operands # 3563# store_fpreg() - store opclass 0 or 2 result to FP regfile # 3564# unnorm_fix() - change UNNORM operands to NORM or ZERO # 3565# load_fpn2() - load dst operand from FP regfile # 3566# smovcr() - emulate an "fmovcr" instruction # 3567# fout() - emulate an opclass 3 instruction # 3568# tbl_unsupp - add of table of emulation routines for opclass 0,2 # 3569# _real_inex() - "callout" to operating system inexact handler # 3570# # 3571# INPUT *************************************************************** # 3572# - The system stack contains the FP Inexact exception frame # 3573# - The fsave frame contains the source operand # 3574# # 3575# OUTPUT ************************************************************** # 3576# - The system stack is unchanged # 3577# - The fsave frame contains the adjusted src op for opclass 0,2 # 3578# # 3579# ALGORITHM *********************************************************** # 3580# In a system where the FP Inexact exception is enabled, the goal # 3581# is to get to the handler specified at _real_inex(). But, on the 060, # 3582# for opclass zero and two instruction taking this exception, the # 3583# hardware doesn't store the correct result to the destination FP # 3584# register as did the '040 and '881/2. This handler must emulate the # 3585# instruction in order to get this value and then store it to the # 3586# correct register before calling _real_inex(). # 3587# For opclass 3 instructions, the 060 doesn't store the default # 3588# inexact result out to memory or data register file as it should. # 3589# This code must emulate the move out by calling fout() before finally # 3590# exiting through _real_inex(). # 3591# # 3592######################################################################### 3593 3594 global _fpsp_inex 3595_fpsp_inex: 3596 3597 link.w %a6,&-LOCAL_SIZE # init stack frame 3598 3599 fsave FP_SRC(%a6) # grab the "busy" frame 3600 3601 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3602 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3603 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3604 3605# the FPIAR holds the "current PC" of the faulting instruction 3606 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3607 3608 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3609 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3610 bsr.l _imem_read_long # fetch the instruction words 3611 mov.l %d0,EXC_OPWORD(%a6) 3612 3613############################################################################## 3614 3615 btst &13,%d0 # is instr an fmove out? 3616 bne.w finex_out # fmove out 3617 3618 3619# the hardware, for "fabs" and "fneg" w/ a long source format, puts the 3620# longword integer directly into the upper longword of the mantissa along 3621# w/ an exponent value of 0x401e. we convert this to extended precision here. 3622 bfextu %d0{&19:&3},%d0 # fetch instr size 3623 bne.b finex_cont # instr size is not long 3624 cmpi.w FP_SRC_EX(%a6),&0x401e # is exponent 0x401e? 3625 bne.b finex_cont # no 3626 fmov.l &0x0,%fpcr 3627 fmov.l FP_SRC_HI(%a6),%fp0 # load integer src 3628 fmov.x %fp0,FP_SRC(%a6) # store integer as extended precision 3629 mov.w &0xe001,0x2+FP_SRC(%a6) 3630 3631finex_cont: 3632 lea FP_SRC(%a6),%a0 # pass: ptr to src op 3633 bsr.l fix_skewed_ops # fix src op 3634 3635# Here, we zero the ccode and exception byte field since we're going to 3636# emulate the whole instruction. Notice, though, that we don't kill the 3637# INEX1 bit. This is because a packed op has long since been converted 3638# to extended before arriving here. Therefore, we need to retain the 3639# INEX1 bit from when the operand was first converted. 3640 andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field 3641 3642 fmov.l &0x0,%fpcr # zero current control regs 3643 fmov.l &0x0,%fpsr 3644 3645 bfextu EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg 3646 cmpi.b %d1,&0x17 # is op an fmovecr? 3647 beq.w finex_fmovcr # yes 3648 3649 lea FP_SRC(%a6),%a0 # pass: ptr to src op 3650 bsr.l set_tag_x # tag the operand type 3651 mov.b %d0,STAG(%a6) # maybe NORM,DENORM 3652 3653# bits four and five of the fp extension word separate the monadic and dyadic 3654# operations that can pass through fpsp_inex(). remember that fcmp and ftst 3655# will never take this exception, but fsincos will. 3656 btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 3657 beq.b finex_extract # monadic 3658 3659 btst &0x4,1+EXC_CMDREG(%a6) # is operation an fsincos? 3660 bne.b finex_extract # yes 3661 3662 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 3663 bsr.l load_fpn2 # load dst into FP_DST 3664 3665 lea FP_DST(%a6),%a0 # pass: ptr to dst op 3666 bsr.l set_tag_x # tag the operand type 3667 cmpi.b %d0,&UNNORM # is operand an UNNORM? 3668 bne.b finex_op2_done # no 3669 bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 3670finex_op2_done: 3671 mov.b %d0,DTAG(%a6) # save dst optype tag 3672 3673finex_extract: 3674 clr.l %d0 3675 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 3676 3677 mov.b 1+EXC_CMDREG(%a6),%d1 3678 andi.w &0x007f,%d1 # extract extension 3679 3680 lea FP_SRC(%a6),%a0 3681 lea FP_DST(%a6),%a1 3682 3683 mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 3684 jsr (tbl_unsupp.l,%pc,%d1.l*1) 3685 3686# the operation has been emulated. the result is in fp0. 3687finex_save: 3688 bfextu EXC_CMDREG(%a6){&6:&3},%d0 3689 bsr.l store_fpreg 3690 3691finex_exit: 3692 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3693 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3694 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3695 3696 frestore FP_SRC(%a6) 3697 3698 unlk %a6 3699 bra.l _real_inex 3700 3701finex_fmovcr: 3702 clr.l %d0 3703 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode 3704 mov.b 1+EXC_CMDREG(%a6),%d1 3705 andi.l &0x0000007f,%d1 # pass rom offset 3706 bsr.l smovcr 3707 bra.b finex_save 3708 3709######################################################################## 3710 3711# 3712# the hardware does not save the default result to memory on enabled 3713# inexact exceptions. we do this here before passing control to 3714# the user inexact handler. 3715# 3716# byte, word, and long destination format operations can pass 3717# through here. so can double and single precision. 3718# although packed opclass three operations can take inexact 3719# exceptions, they won't pass through here since they are caught 3720# first by the unsupported data format exception handler. that handler 3721# sends them directly to _real_inex() if necessary. 3722# 3723finex_out: 3724 3725 mov.b &NORM,STAG(%a6) # src is a NORM 3726 3727 clr.l %d0 3728 mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode 3729 3730 andi.l &0xffff00ff,USER_FPSR(%a6) # zero exception field 3731 3732 lea FP_SRC(%a6),%a0 # pass ptr to src operand 3733 3734 bsr.l fout # store the default result 3735 3736 bra.b finex_exit 3737 3738######################################################################### 3739# XDEF **************************************************************** # 3740# _fpsp_dz(): 060FPSP entry point for FP DZ exception. # 3741# # 3742# This handler should be the first code executed upon taking # 3743# the FP DZ exception in an operating system. # 3744# # 3745# XREF **************************************************************** # 3746# _imem_read_long() - read instruction longword from memory # 3747# fix_skewed_ops() - adjust fsave operand # 3748# _real_dz() - "callout" exit point from FP DZ handler # 3749# # 3750# INPUT *************************************************************** # 3751# - The system stack contains the FP DZ exception stack. # 3752# - The fsave frame contains the source operand. # 3753# # 3754# OUTPUT ************************************************************** # 3755# - The system stack contains the FP DZ exception stack. # 3756# - The fsave frame contains the adjusted source operand. # 3757# # 3758# ALGORITHM *********************************************************** # 3759# In a system where the DZ exception is enabled, the goal is to # 3760# get to the handler specified at _real_dz(). But, on the 060, when the # 3761# exception is taken, the input operand in the fsave state frame may # 3762# be incorrect for some cases and need to be adjusted. So, this package # 3763# adjusts the operand using fix_skewed_ops() and then branches to # 3764# _real_dz(). # 3765# # 3766######################################################################### 3767 3768 global _fpsp_dz 3769_fpsp_dz: 3770 3771 link.w %a6,&-LOCAL_SIZE # init stack frame 3772 3773 fsave FP_SRC(%a6) # grab the "busy" frame 3774 3775 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3776 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3777 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3778 3779# the FPIAR holds the "current PC" of the faulting instruction 3780 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3781 3782 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3783 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3784 bsr.l _imem_read_long # fetch the instruction words 3785 mov.l %d0,EXC_OPWORD(%a6) 3786 3787############################################################################## 3788 3789 3790# here, we simply see if the operand in the fsave frame needs to be "unskewed". 3791# this would be the case for opclass two operations with a source zero 3792# in the sgl or dbl format. 3793 lea FP_SRC(%a6),%a0 # pass: ptr to src op 3794 bsr.l fix_skewed_ops # fix src op 3795 3796fdz_exit: 3797 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3798 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3799 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3800 3801 frestore FP_SRC(%a6) 3802 3803 unlk %a6 3804 bra.l _real_dz 3805 3806######################################################################### 3807# XDEF **************************************************************** # 3808# _fpsp_fline(): 060FPSP entry point for "Line F emulator" exc. # 3809# # 3810# This handler should be the first code executed upon taking the # 3811# "Line F Emulator" exception in an operating system. # 3812# # 3813# XREF **************************************************************** # 3814# _fpsp_unimp() - handle "FP Unimplemented" exceptions # 3815# _real_fpu_disabled() - handle "FPU disabled" exceptions # 3816# _real_fline() - handle "FLINE" exceptions # 3817# _imem_read_long() - read instruction longword # 3818# # 3819# INPUT *************************************************************** # 3820# - The system stack contains a "Line F Emulator" exception # 3821# stack frame. # 3822# # 3823# OUTPUT ************************************************************** # 3824# - The system stack is unchanged # 3825# # 3826# ALGORITHM *********************************************************** # 3827# When a "Line F Emulator" exception occurs, there are 3 possible # 3828# exception types, denoted by the exception stack frame format number: # 3829# (1) FPU unimplemented instruction (6 word stack frame) # 3830# (2) FPU disabled (8 word stack frame) # 3831# (3) Line F (4 word stack frame) # 3832# # 3833# This module determines which and forks the flow off to the # 3834# appropriate "callout" (for "disabled" and "Line F") or to the # 3835# correct emulation code (for "FPU unimplemented"). # 3836# This code also must check for "fmovecr" instructions w/ a # 3837# non-zero <ea> field. These may get flagged as "Line F" but should # 3838# really be flagged as "FPU Unimplemented". (This is a "feature" on # 3839# the '060. # 3840# # 3841######################################################################### 3842 3843 global _fpsp_fline 3844_fpsp_fline: 3845 3846# check to see if this exception is a "FP Unimplemented Instruction" 3847# exception. if so, branch directly to that handler's entry point. 3848 cmpi.w 0x6(%sp),&0x202c 3849 beq.l _fpsp_unimp 3850 3851# check to see if the FPU is disabled. if so, jump to the OS entry 3852# point for that condition. 3853 cmpi.w 0x6(%sp),&0x402c 3854 beq.l _real_fpu_disabled 3855 3856# the exception was an "F-Line Illegal" exception. we check to see 3857# if the F-Line instruction is an "fmovecr" w/ a non-zero <ea>. if 3858# so, convert the F-Line exception stack frame to an FP Unimplemented 3859# Instruction exception stack frame else branch to the OS entry 3860# point for the F-Line exception handler. 3861 link.w %a6,&-LOCAL_SIZE # init stack frame 3862 3863 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3864 3865 mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) 3866 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3867 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3868 bsr.l _imem_read_long # fetch instruction words 3869 3870 bfextu %d0{&0:&10},%d1 # is it an fmovecr? 3871 cmpi.w %d1,&0x03c8 3872 bne.b fline_fline # no 3873 3874 bfextu %d0{&16:&6},%d1 # is it an fmovecr? 3875 cmpi.b %d1,&0x17 3876 bne.b fline_fline # no 3877 3878# it's an fmovecr w/ a non-zero <ea> that has entered through 3879# the F-Line Illegal exception. 3880# so, we need to convert the F-Line exception stack frame into an 3881# FP Unimplemented Instruction stack frame and jump to that entry 3882# point. 3883# 3884# but, if the FPU is disabled, then we need to jump to the FPU disabled 3885# entry point. 3886 movc %pcr,%d0 3887 btst &0x1,%d0 3888 beq.b fline_fmovcr 3889 3890 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3891 3892 unlk %a6 3893 3894 sub.l &0x8,%sp # make room for "Next PC", <ea> 3895 mov.w 0x8(%sp),(%sp) 3896 mov.l 0xa(%sp),0x2(%sp) # move "Current PC" 3897 mov.w &0x402c,0x6(%sp) 3898 mov.l 0x2(%sp),0xc(%sp) 3899 addq.l &0x4,0x2(%sp) # set "Next PC" 3900 3901 bra.l _real_fpu_disabled 3902 3903fline_fmovcr: 3904 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3905 3906 unlk %a6 3907 3908 fmov.l 0x2(%sp),%fpiar # set current PC 3909 addq.l &0x4,0x2(%sp) # set Next PC 3910 3911 mov.l (%sp),-(%sp) 3912 mov.l 0x8(%sp),0x4(%sp) 3913 mov.b &0x20,0x6(%sp) 3914 3915 bra.l _fpsp_unimp 3916 3917fline_fline: 3918 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3919 3920 unlk %a6 3921 3922 bra.l _real_fline 3923 3924######################################################################### 3925# XDEF **************************************************************** # 3926# _fpsp_unimp(): 060FPSP entry point for FP "Unimplemented # 3927# Instruction" exception. # 3928# # 3929# This handler should be the first code executed upon taking the # 3930# FP Unimplemented Instruction exception in an operating system. # 3931# # 3932# XREF **************************************************************** # 3933# _imem_read_{word,long}() - read instruction word/longword # 3934# load_fop() - load src/dst ops from memory and/or FP regfile # 3935# store_fpreg() - store opclass 0 or 2 result to FP regfile # 3936# tbl_trans - addr of table of emulation routines for trnscndls # 3937# _real_access() - "callout" for access error exception # 3938# _fpsp_done() - "callout" for exit; work all done # 3939# _real_trace() - "callout" for Trace enabled exception # 3940# smovcr() - emulate "fmovecr" instruction # 3941# funimp_skew() - adjust fsave src ops to "incorrect" value # 3942# _ftrapcc() - emulate an "ftrapcc" instruction # 3943# _fdbcc() - emulate an "fdbcc" instruction # 3944# _fscc() - emulate an "fscc" instruction # 3945# _real_trap() - "callout" for Trap exception # 3946# _real_bsun() - "callout" for enabled Bsun exception # 3947# # 3948# INPUT *************************************************************** # 3949# - The system stack contains the "Unimplemented Instr" stk frame # 3950# # 3951# OUTPUT ************************************************************** # 3952# If access error: # 3953# - The system stack is changed to an access error stack frame # 3954# If Trace exception enabled: # 3955# - The system stack is changed to a Trace exception stack frame # 3956# Else: (normal case) # 3957# - Correct result has been stored as appropriate # 3958# # 3959# ALGORITHM *********************************************************** # 3960# There are two main cases of instructions that may enter here to # 3961# be emulated: (1) the FPgen instructions, most of which were also # 3962# unimplemented on the 040, and (2) "ftrapcc", "fscc", and "fdbcc". # 3963# For the first set, this handler calls the routine load_fop() # 3964# to load the source and destination (for dyadic) operands to be used # 3965# for instruction emulation. The correct emulation routine is then # 3966# chosen by decoding the instruction type and indexing into an # 3967# emulation subroutine index table. After emulation returns, this # 3968# handler checks to see if an exception should occur as a result of the # 3969# FP instruction emulation. If so, then an FP exception of the correct # 3970# type is inserted into the FPU state frame using the "frestore" # 3971# instruction before exiting through _fpsp_done(). In either the # 3972# exceptional or non-exceptional cases, we must check to see if the # 3973# Trace exception is enabled. If so, then we must create a Trace # 3974# exception frame from the current exception frame and exit through # 3975# _real_trace(). # 3976# For "fdbcc", "ftrapcc", and "fscc", the emulation subroutines # 3977# _fdbcc(), _ftrapcc(), and _fscc() respectively are used. All three # 3978# may flag that a BSUN exception should be taken. If so, then the # 3979# current exception stack frame is converted into a BSUN exception # 3980# stack frame and an exit is made through _real_bsun(). If the # 3981# instruction was "ftrapcc" and a Trap exception should result, a Trap # 3982# exception stack frame is created from the current frame and an exit # 3983# is made through _real_trap(). If a Trace exception is pending, then # 3984# a Trace exception frame is created from the current frame and a jump # 3985# is made to _real_trace(). Finally, if none of these conditions exist, # 3986# then the handler exits though the callout _fpsp_done(). # 3987# # 3988# In any of the above scenarios, if a _mem_read() or _mem_write() # 3989# "callout" returns a failing value, then an access error stack frame # 3990# is created from the current stack frame and an exit is made through # 3991# _real_access(). # 3992# # 3993######################################################################### 3994 3995# 3996# FP UNIMPLEMENTED INSTRUCTION STACK FRAME: 3997# 3998# ***************** 3999# * * => <ea> of fp unimp instr. 4000# - EA - 4001# * * 4002# ***************** 4003# * 0x2 * 0x02c * => frame format and vector offset(vector #11) 4004# ***************** 4005# * * 4006# - Next PC - => PC of instr to execute after exc handling 4007# * * 4008# ***************** 4009# * SR * => SR at the time the exception was taken 4010# ***************** 4011# 4012# Note: the !NULL bit does not get set in the fsave frame when the 4013# machine encounters an fp unimp exception. Therefore, it must be set 4014# before leaving this handler. 4015# 4016 global _fpsp_unimp 4017_fpsp_unimp: 4018 4019 link.w %a6,&-LOCAL_SIZE # init stack frame 4020 4021 movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 4022 fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 4023 fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 4024 4025 btst &0x5,EXC_SR(%a6) # user mode exception? 4026 bne.b funimp_s # no; supervisor mode 4027 4028# save the value of the user stack pointer onto the stack frame 4029funimp_u: 4030 mov.l %usp,%a0 # fetch user stack pointer 4031 mov.l %a0,EXC_A7(%a6) # store in stack frame 4032 bra.b funimp_cont 4033 4034# store the value of the supervisor stack pointer BEFORE the exc occurred. 4035# old_sp is address just above stacked effective address. 4036funimp_s: 4037 lea 4+EXC_EA(%a6),%a0 # load old a7' 4038 mov.l %a0,EXC_A7(%a6) # store a7' 4039 mov.l %a0,OLD_A7(%a6) # make a copy 4040 4041funimp_cont: 4042 4043# the FPIAR holds the "current PC" of the faulting instruction. 4044 mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 4045 4046 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4047 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 4048 bsr.l _imem_read_long # fetch the instruction words 4049 mov.l %d0,EXC_OPWORD(%a6) 4050 4051############################################################################ 4052 4053 fmov.l &0x0,%fpcr # clear FPCR 4054 fmov.l &0x0,%fpsr # clear FPSR 4055 4056 clr.b SPCOND_FLG(%a6) # clear "special case" flag 4057 4058# Divide the fp instructions into 8 types based on the TYPE field in 4059# bits 6-8 of the opword(classes 6,7 are undefined). 4060# (for the '060, only two types can take this exception) 4061# bftst %d0{&7:&3} # test TYPE 4062 btst &22,%d0 # type 0 or 1 ? 4063 bne.w funimp_misc # type 1 4064 4065######################################### 4066# TYPE == 0: General instructions # 4067######################################### 4068funimp_gen: 4069 4070 clr.b STORE_FLG(%a6) # clear "store result" flag 4071 4072# clear the ccode byte and exception status byte 4073 andi.l &0x00ff00ff,USER_FPSR(%a6) 4074 4075 bfextu %d0{&16:&6},%d1 # extract upper 6 of cmdreg 4076 cmpi.b %d1,&0x17 # is op an fmovecr? 4077 beq.w funimp_fmovcr # yes 4078 4079funimp_gen_op: 4080 bsr.l _load_fop # load 4081 4082 clr.l %d0 4083 mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode 4084 4085 mov.b 1+EXC_CMDREG(%a6),%d1 4086 andi.w &0x003f,%d1 # extract extension bits 4087 lsl.w &0x3,%d1 # shift right 3 bits 4088 or.b STAG(%a6),%d1 # insert src optag bits 4089 4090 lea FP_DST(%a6),%a1 # pass dst ptr in a1 4091 lea FP_SRC(%a6),%a0 # pass src ptr in a0 4092 4093 mov.w (tbl_trans.w,%pc,%d1.w*2),%d1 4094 jsr (tbl_trans.w,%pc,%d1.w*1) # emulate 4095 4096funimp_fsave: 4097 mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 4098 bne.w funimp_ena # some are enabled 4099 4100funimp_store: 4101 bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch Dn 4102 bsr.l store_fpreg # store result to fp regfile 4103 4104funimp_gen_exit: 4105 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 4106 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 4107 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 4108 4109funimp_gen_exit_cmp: 4110 cmpi.b SPCOND_FLG(%a6),&mia7_flg # was the ea mode (sp)+ ? 4111 beq.b funimp_gen_exit_a7 # yes 4112 4113 cmpi.b SPCOND_FLG(%a6),&mda7_flg # was the ea mode -(sp) ? 4114 beq.b funimp_gen_exit_a7 # yes 4115 4116funimp_gen_exit_cont: 4117 unlk %a6 4118 4119funimp_gen_exit_cont2: 4120 btst &0x7,(%sp) # is trace on? 4121 beq.l _fpsp_done # no 4122 4123# this catches a problem with the case where an exception will be re-inserted 4124# into the machine. the frestore has already been executed...so, the fmov.l 4125# alone of the control register would trigger an unwanted exception. 4126# until I feel like fixing this, we'll sidestep the exception. 4127 fsave -(%sp) 4128 fmov.l %fpiar,0x14(%sp) # "Current PC" is in FPIAR 4129 frestore (%sp)+ 4130 mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x24 4131 bra.l _real_trace 4132 4133funimp_gen_exit_a7: 4134 btst &0x5,EXC_SR(%a6) # supervisor or user mode? 4135 bne.b funimp_gen_exit_a7_s # supervisor 4136 4137 mov.l %a0,-(%sp) 4138 mov.l EXC_A7(%a6),%a0 4139 mov.l %a0,%usp 4140 mov.l (%sp)+,%a0 4141 bra.b funimp_gen_exit_cont 4142 4143# if the instruction was executed from supervisor mode and the addressing 4144# mode was (a7)+, then the stack frame for the rte must be shifted "up" 4145# "n" bytes where "n" is the size of the src operand type. 4146# f<op>.{b,w,l,s,d,x,p} 4147funimp_gen_exit_a7_s: 4148 mov.l %d0,-(%sp) # save d0 4149 mov.l EXC_A7(%a6),%d0 # load new a7' 4150 sub.l OLD_A7(%a6),%d0 # subtract old a7' 4151 mov.l 0x2+EXC_PC(%a6),(0x2+EXC_PC,%a6,%d0) # shift stack frame 4152 mov.l EXC_SR(%a6),(EXC_SR,%a6,%d0) # shift stack frame 4153 mov.w %d0,EXC_SR(%a6) # store incr number 4154 mov.l (%sp)+,%d0 # restore d0 4155 4156 unlk %a6 4157 4158 add.w (%sp),%sp # stack frame shifted 4159 bra.b funimp_gen_exit_cont2 4160 4161###################### 4162# fmovecr.x #ccc,fpn # 4163###################### 4164funimp_fmovcr: 4165 clr.l %d0 4166 mov.b FPCR_MODE(%a6),%d0 4167 mov.b 1+EXC_CMDREG(%a6),%d1 4168 andi.l &0x0000007f,%d1 # pass rom offset in d1 4169 bsr.l smovcr 4170 bra.w funimp_fsave 4171 4172######################################################################### 4173 4174# 4175# the user has enabled some exceptions. we figure not to see this too 4176# often so that's why it gets lower priority. 4177# 4178funimp_ena: 4179 4180# was an exception set that was also enabled? 4181 and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled and set 4182 bfffo %d0{&24:&8},%d0 # find highest priority exception 4183 bne.b funimp_exc # at least one was set 4184 4185# no exception that was enabled was set BUT if we got an exact overflow 4186# and overflow wasn't enabled but inexact was (yech!) then this is 4187# an inexact exception; otherwise, return to normal non-exception flow. 4188 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? 4189 beq.w funimp_store # no; return to normal flow 4190 4191# the overflow w/ exact result happened but was inexact set in the FPCR? 4192funimp_ovfl: 4193 btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled? 4194 beq.w funimp_store # no; return to normal flow 4195 bra.b funimp_exc_ovfl # yes 4196 4197# some exception happened that was actually enabled. 4198# we'll insert this new exception into the FPU and then return. 4199funimp_exc: 4200 subi.l &24,%d0 # fix offset to be 0-8 4201 cmpi.b %d0,&0x6 # is exception INEX? 4202 bne.b funimp_exc_force # no 4203 4204# the enabled exception was inexact. so, if it occurs with an overflow 4205# or underflow that was disabled, then we have to force an overflow or 4206# underflow frame. the eventual overflow or underflow handler will see that 4207# it's actually an inexact and act appropriately. this is the only easy 4208# way to have the EXOP available for the enabled inexact handler when 4209# a disabled overflow or underflow has also happened. 4210 btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? 4211 bne.b funimp_exc_ovfl # yes 4212 btst &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur? 4213 bne.b funimp_exc_unfl # yes 4214 4215# force the fsave exception status bits to signal an exception of the 4216# appropriate type. don't forget to "skew" the source operand in case we 4217# "unskewed" the one the hardware initially gave us. 4218funimp_exc_force: 4219 mov.l %d0,-(%sp) # save d0 4220 bsr.l funimp_skew # check for special case 4221 mov.l (%sp)+,%d0 # restore d0 4222 mov.w (tbl_funimp_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) 4223 bra.b funimp_gen_exit2 # exit with frestore 4224 4225tbl_funimp_except: 4226 short 0xe002, 0xe006, 0xe004, 0xe005 4227 short 0xe003, 0xe002, 0xe001, 0xe001 4228 4229# insert an overflow frame 4230funimp_exc_ovfl: 4231 bsr.l funimp_skew # check for special case 4232 mov.w &0xe005,2+FP_SRC(%a6) 4233 bra.b funimp_gen_exit2 4234 4235# insert an underflow frame 4236funimp_exc_unfl: 4237 bsr.l funimp_skew # check for special case 4238 mov.w &0xe003,2+FP_SRC(%a6) 4239 4240# this is the general exit point for an enabled exception that will be 4241# restored into the machine for the instruction just emulated. 4242funimp_gen_exit2: 4243 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 4244 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 4245 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 4246 4247 frestore FP_SRC(%a6) # insert exceptional status 4248 4249 bra.w funimp_gen_exit_cmp 4250 4251############################################################################ 4252 4253# 4254# TYPE == 1: FDB<cc>, FS<cc>, FTRAP<cc> 4255# 4256# These instructions were implemented on the '881/2 and '040 in hardware but 4257# are emulated in software on the '060. 4258# 4259funimp_misc: 4260 bfextu %d0{&10:&3},%d1 # extract mode field 4261 cmpi.b %d1,&0x1 # is it an fdb<cc>? 4262 beq.w funimp_fdbcc # yes 4263 cmpi.b %d1,&0x7 # is it an fs<cc>? 4264 bne.w funimp_fscc # yes 4265 bfextu %d0{&13:&3},%d1 4266 cmpi.b %d1,&0x2 # is it an fs<cc>? 4267 blt.w funimp_fscc # yes 4268 4269######################### 4270# ftrap<cc> # 4271# ftrap<cc>.w #<data> # 4272# ftrap<cc>.l #<data> # 4273######################### 4274funimp_ftrapcc: 4275 4276 bsr.l _ftrapcc # FTRAP<cc>() 4277 4278 cmpi.b SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring? 4279 beq.w funimp_bsun # yes 4280 4281 cmpi.b SPCOND_FLG(%a6),&ftrapcc_flg # should a trap occur? 4282 bne.w funimp_done # no 4283 4284# FP UNIMP FRAME TRAP FRAME 4285# ***************** ***************** 4286# ** <EA> ** ** Current PC ** 4287# ***************** ***************** 4288# * 0x2 * 0x02c * * 0x2 * 0x01c * 4289# ***************** ***************** 4290# ** Next PC ** ** Next PC ** 4291# ***************** ***************** 4292# * SR * * SR * 4293# ***************** ***************** 4294# (6 words) (6 words) 4295# 4296# the ftrapcc instruction should take a trap. so, here we must create a 4297# trap stack frame from an unimplemented fp instruction stack frame and 4298# jump to the user supplied entry point for the trap exception 4299funimp_ftrapcc_tp: 4300 mov.l USER_FPIAR(%a6),EXC_EA(%a6) # Address = Current PC 4301 mov.w &0x201c,EXC_VOFF(%a6) # Vector Offset = 0x01c 4302 4303 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 4304 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 4305 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 4306 4307 unlk %a6 4308 bra.l _real_trap 4309 4310######################### 4311# fdb<cc> Dn,<label> # 4312######################### 4313funimp_fdbcc: 4314 4315 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4316 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4317 bsr.l _imem_read_word # read displacement 4318 4319 tst.l %d1 # did ifetch fail? 4320 bne.w funimp_iacc # yes 4321 4322 ext.l %d0 # sign extend displacement 4323 4324 bsr.l _fdbcc # FDB<cc>() 4325 4326 cmpi.b SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring? 4327 beq.w funimp_bsun 4328 4329 bra.w funimp_done # branch to finish 4330 4331################# 4332# fs<cc>.b <ea> # 4333################# 4334funimp_fscc: 4335 4336 bsr.l _fscc # FS<cc>() 4337 4338# I am assuming here that an "fs<cc>.b -(An)" or "fs<cc>.b (An)+" instruction 4339# does not need to update "An" before taking a bsun exception. 4340 cmpi.b SPCOND_FLG(%a6),&fbsun_flg # is enabled bsun occurring? 4341 beq.w funimp_bsun 4342 4343 btst &0x5,EXC_SR(%a6) # yes; is it a user mode exception? 4344 bne.b funimp_fscc_s # no 4345 4346funimp_fscc_u: 4347 mov.l EXC_A7(%a6),%a0 # yes; set new USP 4348 mov.l %a0,%usp 4349 bra.w funimp_done # branch to finish 4350 4351# remember, I'm assuming that post-increment is bogus...(it IS!!!) 4352# so, the least significant WORD of the stacked effective address got 4353# overwritten by the "fs<cc> -(An)". We must shift the stack frame "down" 4354# so that the rte will work correctly without destroying the result. 4355# even though the operation size is byte, the stack ptr is decr by 2. 4356# 4357# remember, also, this instruction may be traced. 4358funimp_fscc_s: 4359 cmpi.b SPCOND_FLG(%a6),&mda7_flg # was a7 modified? 4360 bne.w funimp_done # no 4361 4362 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 4363 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 4364 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 4365 4366 unlk %a6 4367 4368 btst &0x7,(%sp) # is trace enabled? 4369 bne.b funimp_fscc_s_trace # yes 4370 4371 subq.l &0x2,%sp 4372 mov.l 0x2(%sp),(%sp) # shift SR,hi(PC) "down" 4373 mov.l 0x6(%sp),0x4(%sp) # shift lo(PC),voff "down" 4374 bra.l _fpsp_done 4375 4376funimp_fscc_s_trace: 4377 subq.l &0x2,%sp 4378 mov.l 0x2(%sp),(%sp) # shift SR,hi(PC) "down" 4379 mov.w 0x6(%sp),0x4(%sp) # shift lo(PC) 4380 mov.w &0x2024,0x6(%sp) # fmt/voff = $2024 4381 fmov.l %fpiar,0x8(%sp) # insert "current PC" 4382 4383 bra.l _real_trace 4384 4385# 4386# The ftrap<cc>, fs<cc>, or fdb<cc> is to take an enabled bsun. we must convert 4387# the fp unimplemented instruction exception stack frame into a bsun stack frame, 4388# restore a bsun exception into the machine, and branch to the user 4389# supplied bsun hook. 4390# 4391# FP UNIMP FRAME BSUN FRAME 4392# ***************** ***************** 4393# ** <EA> ** * 0x0 * 0x0c0 * 4394# ***************** ***************** 4395# * 0x2 * 0x02c * ** Current PC ** 4396# ***************** ***************** 4397# ** Next PC ** * SR * 4398# ***************** ***************** 4399# * SR * (4 words) 4400# ***************** 4401# (6 words) 4402# 4403funimp_bsun: 4404 mov.w &0x00c0,2+EXC_EA(%a6) # Fmt = 0x0; Vector Offset = 0x0c0 4405 mov.l USER_FPIAR(%a6),EXC_VOFF(%a6) # PC = Current PC 4406 mov.w EXC_SR(%a6),2+EXC_PC(%a6) # shift SR "up" 4407 4408 mov.w &0xe000,2+FP_SRC(%a6) # bsun exception enabled 4409 4410 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 4411 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 4412 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 4413 4414 frestore FP_SRC(%a6) # restore bsun exception 4415 4416 unlk %a6 4417 4418 addq.l &0x4,%sp # erase sludge 4419 4420 bra.l _real_bsun # branch to user bsun hook 4421 4422# 4423# all ftrapcc/fscc/fdbcc processing has been completed. unwind the stack frame 4424# and return. 4425# 4426# as usual, we have to check for trace mode being on here. since instructions 4427# modifying the supervisor stack frame don't pass through here, this is a 4428# relatively easy task. 4429# 4430funimp_done: 4431 fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 4432 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 4433 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 4434 4435 unlk %a6 4436 4437 btst &0x7,(%sp) # is trace enabled? 4438 bne.b funimp_trace # yes 4439 4440 bra.l _fpsp_done 4441 4442# FP UNIMP FRAME TRACE FRAME 4443# ***************** ***************** 4444# ** <EA> ** ** Current PC ** 4445# ***************** ***************** 4446# * 0x2 * 0x02c * * 0x2 * 0x024 * 4447# ***************** ***************** 4448# ** Next PC ** ** Next PC ** 4449# ***************** ***************** 4450# * SR * * SR * 4451# ***************** ***************** 4452# (6 words) (6 words) 4453# 4454# the fscc instruction should take a trace trap. so, here we must create a 4455# trace stack frame from an unimplemented fp instruction stack frame and 4456# jump to the user supplied entry point for the trace exception 4457funimp_trace: 4458 fmov.l %fpiar,0x8(%sp) # current PC is in fpiar 4459 mov.b &0x24,0x7(%sp) # vector offset = 0x024 4460 4461 bra.l _real_trace 4462 4463################################################################ 4464 4465 global tbl_trans 4466 swbeg &0x1c0 4467tbl_trans: 4468 short tbl_trans - tbl_trans # $00-0 fmovecr all 4469 short tbl_trans - tbl_trans # $00-1 fmovecr all 4470 short tbl_trans - tbl_trans # $00-2 fmovecr all 4471 short tbl_trans - tbl_trans # $00-3 fmovecr all 4472 short tbl_trans - tbl_trans # $00-4 fmovecr all 4473 short tbl_trans - tbl_trans # $00-5 fmovecr all 4474 short tbl_trans - tbl_trans # $00-6 fmovecr all 4475 short tbl_trans - tbl_trans # $00-7 fmovecr all 4476 4477 short tbl_trans - tbl_trans # $01-0 fint norm 4478 short tbl_trans - tbl_trans # $01-1 fint zero 4479 short tbl_trans - tbl_trans # $01-2 fint inf 4480 short tbl_trans - tbl_trans # $01-3 fint qnan 4481 short tbl_trans - tbl_trans # $01-5 fint denorm 4482 short tbl_trans - tbl_trans # $01-4 fint snan 4483 short tbl_trans - tbl_trans # $01-6 fint unnorm 4484 short tbl_trans - tbl_trans # $01-7 ERROR 4485 4486 short ssinh - tbl_trans # $02-0 fsinh norm 4487 short src_zero - tbl_trans # $02-1 fsinh zero 4488 short src_inf - tbl_trans # $02-2 fsinh inf 4489 short src_qnan - tbl_trans # $02-3 fsinh qnan 4490 short ssinhd - tbl_trans # $02-5 fsinh denorm 4491 short src_snan - tbl_trans # $02-4 fsinh snan 4492 short tbl_trans - tbl_trans # $02-6 fsinh unnorm 4493 short tbl_trans - tbl_trans # $02-7 ERROR 4494 4495 short tbl_trans - tbl_trans # $03-0 fintrz norm 4496 short tbl_trans - tbl_trans # $03-1 fintrz zero 4497 short tbl_trans - tbl_trans # $03-2 fintrz inf 4498 short tbl_trans - tbl_trans # $03-3 fintrz qnan 4499 short tbl_trans - tbl_trans # $03-5 fintrz denorm 4500 short tbl_trans - tbl_trans # $03-4 fintrz snan 4501 short tbl_trans - tbl_trans # $03-6 fintrz unnorm 4502 short tbl_trans - tbl_trans # $03-7 ERROR 4503 4504 short tbl_trans - tbl_trans # $04-0 fsqrt norm 4505 short tbl_trans - tbl_trans # $04-1 fsqrt zero 4506 short tbl_trans - tbl_trans # $04-2 fsqrt inf 4507 short tbl_trans - tbl_trans # $04-3 fsqrt qnan 4508 short tbl_trans - tbl_trans # $04-5 fsqrt denorm 4509 short tbl_trans - tbl_trans # $04-4 fsqrt snan 4510 short tbl_trans - tbl_trans # $04-6 fsqrt unnorm 4511 short tbl_trans - tbl_trans # $04-7 ERROR 4512 4513 short tbl_trans - tbl_trans # $05-0 ERROR 4514 short tbl_trans - tbl_trans # $05-1 ERROR 4515 short tbl_trans - tbl_trans # $05-2 ERROR 4516 short tbl_trans - tbl_trans # $05-3 ERROR 4517 short tbl_trans - tbl_trans # $05-4 ERROR 4518 short tbl_trans - tbl_trans # $05-5 ERROR 4519 short tbl_trans - tbl_trans # $05-6 ERROR 4520 short tbl_trans - tbl_trans # $05-7 ERROR 4521 4522 short slognp1 - tbl_trans # $06-0 flognp1 norm 4523 short src_zero - tbl_trans # $06-1 flognp1 zero 4524 short sopr_inf - tbl_trans # $06-2 flognp1 inf 4525 short src_qnan - tbl_trans # $06-3 flognp1 qnan 4526 short slognp1d - tbl_trans # $06-5 flognp1 denorm 4527 short src_snan - tbl_trans # $06-4 flognp1 snan 4528 short tbl_trans - tbl_trans # $06-6 flognp1 unnorm 4529 short tbl_trans - tbl_trans # $06-7 ERROR 4530 4531 short tbl_trans - tbl_trans # $07-0 ERROR 4532 short tbl_trans - tbl_trans # $07-1 ERROR 4533 short tbl_trans - tbl_trans # $07-2 ERROR 4534 short tbl_trans - tbl_trans # $07-3 ERROR 4535 short tbl_trans - tbl_trans # $07-4 ERROR 4536 short tbl_trans - tbl_trans # $07-5 ERROR 4537 short tbl_trans - tbl_trans # $07-6 ERROR 4538 short tbl_trans - tbl_trans # $07-7 ERROR 4539 4540 short setoxm1 - tbl_trans # $08-0 fetoxm1 norm 4541 short src_zero - tbl_trans # $08-1 fetoxm1 zero 4542 short setoxm1i - tbl_trans # $08-2 fetoxm1 inf 4543 short src_qnan - tbl_trans # $08-3 fetoxm1 qnan 4544 short setoxm1d - tbl_trans # $08-5 fetoxm1 denorm 4545 short src_snan - tbl_trans # $08-4 fetoxm1 snan 4546 short tbl_trans - tbl_trans # $08-6 fetoxm1 unnorm 4547 short tbl_trans - tbl_trans # $08-7 ERROR 4548 4549 short stanh - tbl_trans # $09-0 ftanh norm 4550 short src_zero - tbl_trans # $09-1 ftanh zero 4551 short src_one - tbl_trans # $09-2 ftanh inf 4552 short src_qnan - tbl_trans # $09-3 ftanh qnan 4553 short stanhd - tbl_trans # $09-5 ftanh denorm 4554 short src_snan - tbl_trans # $09-4 ftanh snan 4555 short tbl_trans - tbl_trans # $09-6 ftanh unnorm 4556 short tbl_trans - tbl_trans # $09-7 ERROR 4557 4558 short satan - tbl_trans # $0a-0 fatan norm 4559 short src_zero - tbl_trans # $0a-1 fatan zero 4560 short spi_2 - tbl_trans # $0a-2 fatan inf 4561 short src_qnan - tbl_trans # $0a-3 fatan qnan 4562 short satand - tbl_trans # $0a-5 fatan denorm 4563 short src_snan - tbl_trans # $0a-4 fatan snan 4564 short tbl_trans - tbl_trans # $0a-6 fatan unnorm 4565 short tbl_trans - tbl_trans # $0a-7 ERROR 4566 4567 short tbl_trans - tbl_trans # $0b-0 ERROR 4568 short tbl_trans - tbl_trans # $0b-1 ERROR 4569 short tbl_trans - tbl_trans # $0b-2 ERROR 4570 short tbl_trans - tbl_trans # $0b-3 ERROR 4571 short tbl_trans - tbl_trans # $0b-4 ERROR 4572 short tbl_trans - tbl_trans # $0b-5 ERROR 4573 short tbl_trans - tbl_trans # $0b-6 ERROR 4574 short tbl_trans - tbl_trans # $0b-7 ERROR 4575 4576 short sasin - tbl_trans # $0c-0 fasin norm 4577 short src_zero - tbl_trans # $0c-1 fasin zero 4578 short t_operr - tbl_trans # $0c-2 fasin inf 4579 short src_qnan - tbl_trans # $0c-3 fasin qnan 4580 short sasind - tbl_trans # $0c-5 fasin denorm 4581 short src_snan - tbl_trans # $0c-4 fasin snan 4582 short tbl_trans - tbl_trans # $0c-6 fasin unnorm 4583 short tbl_trans - tbl_trans # $0c-7 ERROR 4584 4585 short satanh - tbl_trans # $0d-0 fatanh norm 4586 short src_zero - tbl_trans # $0d-1 fatanh zero 4587 short t_operr - tbl_trans # $0d-2 fatanh inf 4588 short src_qnan - tbl_trans # $0d-3 fatanh qnan 4589 short satanhd - tbl_trans # $0d-5 fatanh denorm 4590 short src_snan - tbl_trans # $0d-4 fatanh snan 4591 short tbl_trans - tbl_trans # $0d-6 fatanh unnorm 4592 short tbl_trans - tbl_trans # $0d-7 ERROR 4593 4594 short ssin - tbl_trans # $0e-0 fsin norm 4595 short src_zero - tbl_trans # $0e-1 fsin zero 4596 short t_operr - tbl_trans # $0e-2 fsin inf 4597 short src_qnan - tbl_trans # $0e-3 fsin qnan 4598 short ssind - tbl_trans # $0e-5 fsin denorm 4599 short src_snan - tbl_trans # $0e-4 fsin snan 4600 short tbl_trans - tbl_trans # $0e-6 fsin unnorm 4601 short tbl_trans - tbl_trans # $0e-7 ERROR 4602 4603 short stan - tbl_trans # $0f-0 ftan norm 4604 short src_zero - tbl_trans # $0f-1 ftan zero 4605 short t_operr - tbl_trans # $0f-2 ftan inf 4606 short src_qnan - tbl_trans # $0f-3 ftan qnan 4607 short stand - tbl_trans # $0f-5 ftan denorm 4608 short src_snan - tbl_trans # $0f-4 ftan snan 4609 short tbl_trans - tbl_trans # $0f-6 ftan unnorm 4610 short tbl_trans - tbl_trans # $0f-7 ERROR 4611 4612 short setox - tbl_trans # $10-0 fetox norm 4613 short ld_pone - tbl_trans # $10-1 fetox zero 4614 short szr_inf - tbl_trans # $10-2 fetox inf 4615 short src_qnan - tbl_trans # $10-3 fetox qnan 4616 short setoxd - tbl_trans # $10-5 fetox denorm 4617 short src_snan - tbl_trans # $10-4 fetox snan 4618 short tbl_trans - tbl_trans # $10-6 fetox unnorm 4619 short tbl_trans - tbl_trans # $10-7 ERROR 4620 4621 short stwotox - tbl_trans # $11-0 ftwotox norm 4622 short ld_pone - tbl_trans # $11-1 ftwotox zero 4623 short szr_inf - tbl_trans # $11-2 ftwotox inf 4624 short src_qnan - tbl_trans # $11-3 ftwotox qnan 4625 short stwotoxd - tbl_trans # $11-5 ftwotox denorm 4626 short src_snan - tbl_trans # $11-4 ftwotox snan 4627 short tbl_trans - tbl_trans # $11-6 ftwotox unnorm 4628 short tbl_trans - tbl_trans # $11-7 ERROR 4629 4630 short stentox - tbl_trans # $12-0 ftentox norm 4631 short ld_pone - tbl_trans # $12-1 ftentox zero 4632 short szr_inf - tbl_trans # $12-2 ftentox inf 4633 short src_qnan - tbl_trans # $12-3 ftentox qnan 4634 short stentoxd - tbl_trans # $12-5 ftentox denorm 4635 short src_snan - tbl_trans # $12-4 ftentox snan 4636 short tbl_trans - tbl_trans # $12-6 ftentox unnorm 4637 short tbl_trans - tbl_trans # $12-7 ERROR 4638 4639 short tbl_trans - tbl_trans # $13-0 ERROR 4640 short tbl_trans - tbl_trans # $13-1 ERROR 4641 short tbl_trans - tbl_trans # $13-2 ERROR 4642 short tbl_trans - tbl_trans # $13-3 ERROR 4643 short tbl_trans - tbl_trans # $13-4 ERROR 4644 short tbl_trans - tbl_trans # $13-5 ERROR 4645 short tbl_trans - tbl_trans # $13-6 ERROR 4646 short tbl_trans - tbl_trans # $13-7 ERROR 4647 4648 short slogn - tbl_trans # $14-0 flogn norm 4649 short t_dz2 - tbl_trans # $14-1 flogn zero 4650 short sopr_inf - tbl_trans # $14-2 flogn inf 4651 short src_qnan - tbl_trans # $14-3 flogn qnan 4652 short slognd - tbl_trans # $14-5 flogn denorm 4653 short src_snan - tbl_trans # $14-4 flogn snan 4654 short tbl_trans - tbl_trans # $14-6 flogn unnorm 4655 short tbl_trans - tbl_trans # $14-7 ERROR 4656 4657 short slog10 - tbl_trans # $15-0 flog10 norm 4658 short t_dz2 - tbl_trans # $15-1 flog10 zero 4659 short sopr_inf - tbl_trans # $15-2 flog10 inf 4660 short src_qnan - tbl_trans # $15-3 flog10 qnan 4661 short slog10d - tbl_trans # $15-5 flog10 denorm 4662 short src_snan - tbl_trans # $15-4 flog10 snan 4663 short tbl_trans - tbl_trans # $15-6 flog10 unnorm 4664 short tbl_trans - tbl_trans # $15-7 ERROR 4665 4666 short slog2 - tbl_trans # $16-0 flog2 norm 4667 short t_dz2 - tbl_trans # $16-1 flog2 zero 4668 short sopr_inf - tbl_trans # $16-2 flog2 inf 4669 short src_qnan - tbl_trans # $16-3 flog2 qnan 4670 short slog2d - tbl_trans # $16-5 flog2 denorm 4671 short src_snan - tbl_trans # $16-4 flog2 snan 4672 short tbl_trans - tbl_trans # $16-6 flog2 unnorm 4673 short tbl_trans - tbl_trans # $16-7 ERROR 4674 4675 short tbl_trans - tbl_trans # $17-0 ERROR 4676 short tbl_trans - tbl_trans # $17-1 ERROR 4677 short tbl_trans - tbl_trans # $17-2 ERROR 4678 short tbl_trans - tbl_trans # $17-3 ERROR 4679 short tbl_trans - tbl_trans # $17-4 ERROR 4680 short tbl_trans - tbl_trans # $17-5 ERROR 4681 short tbl_trans - tbl_trans # $17-6 ERROR 4682 short tbl_trans - tbl_trans # $17-7 ERROR 4683 4684 short tbl_trans - tbl_trans # $18-0 fabs norm 4685 short tbl_trans - tbl_trans # $18-1 fabs zero 4686 short tbl_trans - tbl_trans # $18-2 fabs inf 4687 short tbl_trans - tbl_trans # $18-3 fabs qnan 4688 short tbl_trans - tbl_trans # $18-5 fabs denorm 4689 short tbl_trans - tbl_trans # $18-4 fabs snan 4690 short tbl_trans - tbl_trans # $18-6 fabs unnorm 4691 short tbl_trans - tbl_trans # $18-7 ERROR 4692 4693 short scosh - tbl_trans # $19-0 fcosh norm 4694 short ld_pone - tbl_trans # $19-1 fcosh zero 4695 short ld_pinf - tbl_trans # $19-2 fcosh inf 4696 short src_qnan - tbl_trans # $19-3 fcosh qnan 4697 short scoshd - tbl_trans # $19-5 fcosh denorm 4698 short src_snan - tbl_trans # $19-4 fcosh snan 4699 short tbl_trans - tbl_trans # $19-6 fcosh unnorm 4700 short tbl_trans - tbl_trans # $19-7 ERROR 4701 4702 short tbl_trans - tbl_trans # $1a-0 fneg norm 4703 short tbl_trans - tbl_trans # $1a-1 fneg zero 4704 short tbl_trans - tbl_trans # $1a-2 fneg inf 4705 short tbl_trans - tbl_trans # $1a-3 fneg qnan 4706 short tbl_trans - tbl_trans # $1a-5 fneg denorm 4707 short tbl_trans - tbl_trans # $1a-4 fneg snan 4708 short tbl_trans - tbl_trans # $1a-6 fneg unnorm 4709 short tbl_trans - tbl_trans # $1a-7 ERROR 4710 4711 short tbl_trans - tbl_trans # $1b-0 ERROR 4712 short tbl_trans - tbl_trans # $1b-1 ERROR 4713 short tbl_trans - tbl_trans # $1b-2 ERROR 4714 short tbl_trans - tbl_trans # $1b-3 ERROR 4715 short tbl_trans - tbl_trans # $1b-4 ERROR 4716 short tbl_trans - tbl_trans # $1b-5 ERROR 4717 short tbl_trans - tbl_trans # $1b-6 ERROR 4718 short tbl_trans - tbl_trans # $1b-7 ERROR 4719 4720 short sacos - tbl_trans # $1c-0 facos norm 4721 short ld_ppi2 - tbl_trans # $1c-1 facos zero 4722 short t_operr - tbl_trans # $1c-2 facos inf 4723 short src_qnan - tbl_trans # $1c-3 facos qnan 4724 short sacosd - tbl_trans # $1c-5 facos denorm 4725 short src_snan - tbl_trans # $1c-4 facos snan 4726 short tbl_trans - tbl_trans # $1c-6 facos unnorm 4727 short tbl_trans - tbl_trans # $1c-7 ERROR 4728 4729 short scos - tbl_trans # $1d-0 fcos norm 4730 short ld_pone - tbl_trans # $1d-1 fcos zero 4731 short t_operr - tbl_trans # $1d-2 fcos inf 4732 short src_qnan - tbl_trans # $1d-3 fcos qnan 4733 short scosd - tbl_trans # $1d-5 fcos denorm 4734 short src_snan - tbl_trans # $1d-4 fcos snan 4735 short tbl_trans - tbl_trans # $1d-6 fcos unnorm 4736 short tbl_trans - tbl_trans # $1d-7 ERROR 4737 4738 short sgetexp - tbl_trans # $1e-0 fgetexp norm 4739 short src_zero - tbl_trans # $1e-1 fgetexp zero 4740 short t_operr - tbl_trans # $1e-2 fgetexp inf 4741 short src_qnan - tbl_trans # $1e-3 fgetexp qnan 4742 short sgetexpd - tbl_trans # $1e-5 fgetexp denorm 4743 short src_snan - tbl_trans # $1e-4 fgetexp snan 4744 short tbl_trans - tbl_trans # $1e-6 fgetexp unnorm 4745 short tbl_trans - tbl_trans # $1e-7 ERROR 4746 4747 short sgetman - tbl_trans # $1f-0 fgetman norm 4748 short src_zero - tbl_trans # $1f-1 fgetman zero 4749 short t_operr - tbl_trans # $1f-2 fgetman inf 4750 short src_qnan - tbl_trans # $1f-3 fgetman qnan 4751 short sgetmand - tbl_trans # $1f-5 fgetman denorm 4752 short src_snan - tbl_trans # $1f-4 fgetman snan 4753 short tbl_trans - tbl_trans # $1f-6 fgetman unnorm 4754 short tbl_trans - tbl_trans # $1f-7 ERROR 4755 4756 short tbl_trans - tbl_trans # $20-0 fdiv norm 4757 short tbl_trans - tbl_trans # $20-1 fdiv zero 4758 short tbl_trans - tbl_trans # $20-2 fdiv inf 4759 short tbl_trans - tbl_trans # $20-3 fdiv qnan 4760 short tbl_trans - tbl_trans # $20-5 fdiv denorm 4761 short tbl_trans - tbl_trans # $20-4 fdiv snan 4762 short tbl_trans - tbl_trans # $20-6 fdiv unnorm 4763 short tbl_trans - tbl_trans # $20-7 ERROR 4764 4765 short smod_snorm - tbl_trans # $21-0 fmod norm 4766 short smod_szero - tbl_trans # $21-1 fmod zero 4767 short smod_sinf - tbl_trans # $21-2 fmod inf 4768 short sop_sqnan - tbl_trans # $21-3 fmod qnan 4769 short smod_sdnrm - tbl_trans # $21-5 fmod denorm 4770 short sop_ssnan - tbl_trans # $21-4 fmod snan 4771 short tbl_trans - tbl_trans # $21-6 fmod unnorm 4772 short tbl_trans - tbl_trans # $21-7 ERROR 4773 4774 short tbl_trans - tbl_trans # $22-0 fadd norm 4775 short tbl_trans - tbl_trans # $22-1 fadd zero 4776 short tbl_trans - tbl_trans # $22-2 fadd inf 4777 short tbl_trans - tbl_trans # $22-3 fadd qnan 4778 short tbl_trans - tbl_trans # $22-5 fadd denorm 4779 short tbl_trans - tbl_trans # $22-4 fadd snan 4780 short tbl_trans - tbl_trans # $22-6 fadd unnorm 4781 short tbl_trans - tbl_trans # $22-7 ERROR 4782 4783 short tbl_trans - tbl_trans # $23-0 fmul norm 4784 short tbl_trans - tbl_trans # $23-1 fmul zero 4785 short tbl_trans - tbl_trans # $23-2 fmul inf 4786 short tbl_trans - tbl_trans # $23-3 fmul qnan 4787 short tbl_trans - tbl_trans # $23-5 fmul denorm 4788 short tbl_trans - tbl_trans # $23-4 fmul snan 4789 short tbl_trans - tbl_trans # $23-6 fmul unnorm 4790 short tbl_trans - tbl_trans # $23-7 ERROR 4791 4792 short tbl_trans - tbl_trans # $24-0 fsgldiv norm 4793 short tbl_trans - tbl_trans # $24-1 fsgldiv zero 4794 short tbl_trans - tbl_trans # $24-2 fsgldiv inf 4795 short tbl_trans - tbl_trans # $24-3 fsgldiv qnan 4796 short tbl_trans - tbl_trans # $24-5 fsgldiv denorm 4797 short tbl_trans - tbl_trans # $24-4 fsgldiv snan 4798 short tbl_trans - tbl_trans # $24-6 fsgldiv unnorm 4799 short tbl_trans - tbl_trans # $24-7 ERROR 4800 4801 short srem_snorm - tbl_trans # $25-0 frem norm 4802 short srem_szero - tbl_trans # $25-1 frem zero 4803 short srem_sinf - tbl_trans # $25-2 frem inf 4804 short sop_sqnan - tbl_trans # $25-3 frem qnan 4805 short srem_sdnrm - tbl_trans # $25-5 frem denorm 4806 short sop_ssnan - tbl_trans # $25-4 frem snan 4807 short tbl_trans - tbl_trans # $25-6 frem unnorm 4808 short tbl_trans - tbl_trans # $25-7 ERROR 4809 4810 short sscale_snorm - tbl_trans # $26-0 fscale norm 4811 short sscale_szero - tbl_trans # $26-1 fscale zero 4812 short sscale_sinf - tbl_trans # $26-2 fscale inf 4813 short sop_sqnan - tbl_trans # $26-3 fscale qnan 4814 short sscale_sdnrm - tbl_trans # $26-5 fscale denorm 4815 short sop_ssnan - tbl_trans # $26-4 fscale snan 4816 short tbl_trans - tbl_trans # $26-6 fscale unnorm 4817 short tbl_trans - tbl_trans # $26-7 ERROR 4818 4819 short tbl_trans - tbl_trans # $27-0 fsglmul norm 4820 short tbl_trans - tbl_trans # $27-1 fsglmul zero 4821 short tbl_trans - tbl_trans # $27-2 fsglmul inf 4822 short tbl_trans - tbl_trans # $27-3 fsglmul qnan 4823 short tbl_trans - tbl_trans # $27-5 fsglmul denorm 4824 short tbl_trans - tbl_trans # $27-4 fsglmul snan 4825 short tbl_trans - tbl_trans # $27-6 fsglmul unnorm 4826 short tbl_trans - tbl_trans # $27-7 ERROR 4827 4828 short tbl_trans - tbl_trans # $28-0 fsub norm 4829 short tbl_trans - tbl_trans # $28-1 fsub zero 4830 short tbl_trans - tbl_trans # $28-2 fsub inf 4831 short tbl_trans - tbl_trans # $28-3 fsub qnan 4832 short tbl_trans - tbl_trans # $28-5 fsub denorm 4833 short tbl_trans - tbl_trans # $28-4 fsub snan 4834 short tbl_trans - tbl_trans # $28-6 fsub unnorm 4835 short tbl_trans - tbl_trans # $28-7 ERROR 4836 4837 short tbl_trans - tbl_trans # $29-0 ERROR 4838 short tbl_trans - tbl_trans # $29-1 ERROR 4839 short tbl_trans - tbl_trans # $29-2 ERROR 4840 short tbl_trans - tbl_trans # $29-3 ERROR 4841 short tbl_trans - tbl_trans # $29-4 ERROR 4842 short tbl_trans - tbl_trans # $29-5 ERROR 4843 short tbl_trans - tbl_trans # $29-6 ERROR 4844 short tbl_trans - tbl_trans # $29-7 ERROR 4845 4846 short tbl_trans - tbl_trans # $2a-0 ERROR 4847 short tbl_trans - tbl_trans # $2a-1 ERROR 4848 short tbl_trans - tbl_trans # $2a-2 ERROR 4849 short tbl_trans - tbl_trans # $2a-3 ERROR 4850 short tbl_trans - tbl_trans # $2a-4 ERROR 4851 short tbl_trans - tbl_trans # $2a-5 ERROR 4852 short tbl_trans - tbl_trans # $2a-6 ERROR 4853 short tbl_trans - tbl_trans # $2a-7 ERROR 4854 4855 short tbl_trans - tbl_trans # $2b-0 ERROR 4856 short tbl_trans - tbl_trans # $2b-1 ERROR 4857 short tbl_trans - tbl_trans # $2b-2 ERROR 4858 short tbl_trans - tbl_trans # $2b-3 ERROR 4859 short tbl_trans - tbl_trans # $2b-4 ERROR 4860 short tbl_trans - tbl_trans # $2b-5 ERROR 4861 short tbl_trans - tbl_trans # $2b-6 ERROR 4862 short tbl_trans - tbl_trans # $2b-7 ERROR 4863 4864 short tbl_trans - tbl_trans # $2c-0 ERROR 4865 short tbl_trans - tbl_trans # $2c-1 ERROR 4866 short tbl_trans - tbl_trans # $2c-2 ERROR 4867 short tbl_trans - tbl_trans # $2c-3 ERROR 4868 short tbl_trans - tbl_trans # $2c-4 ERROR 4869 short tbl_trans - tbl_trans # $2c-5 ERROR 4870 short tbl_trans - tbl_trans # $2c-6 ERROR 4871 short tbl_trans - tbl_trans # $2c-7 ERROR 4872 4873 short tbl_trans - tbl_trans # $2d-0 ERROR 4874 short tbl_trans - tbl_trans # $2d-1 ERROR 4875 short tbl_trans - tbl_trans # $2d-2 ERROR 4876 short tbl_trans - tbl_trans # $2d-3 ERROR 4877 short tbl_trans - tbl_trans # $2d-4 ERROR 4878 short tbl_trans - tbl_trans # $2d-5 ERROR 4879 short tbl_trans - tbl_trans # $2d-6 ERROR 4880 short tbl_trans - tbl_trans # $2d-7 ERROR 4881 4882 short tbl_trans - tbl_trans # $2e-0 ERROR 4883 short tbl_trans - tbl_trans # $2e-1 ERROR 4884 short tbl_trans - tbl_trans # $2e-2 ERROR 4885 short tbl_trans - tbl_trans # $2e-3 ERROR 4886 short tbl_trans - tbl_trans # $2e-4 ERROR 4887 short tbl_trans - tbl_trans # $2e-5 ERROR 4888 short tbl_trans - tbl_trans # $2e-6 ERROR 4889 short tbl_trans - tbl_trans # $2e-7 ERROR 4890 4891 short tbl_trans - tbl_trans # $2f-0 ERROR 4892 short tbl_trans - tbl_trans # $2f-1 ERROR 4893 short tbl_trans - tbl_trans # $2f-2 ERROR 4894 short tbl_trans - tbl_trans # $2f-3 ERROR 4895 short tbl_trans - tbl_trans # $2f-4 ERROR 4896 short tbl_trans - tbl_trans # $2f-5 ERROR 4897 short tbl_trans - tbl_trans # $2f-6 ERROR 4898 short tbl_trans - tbl_trans # $2f-7 ERROR 4899 4900 short ssincos - tbl_trans # $30-0 fsincos norm 4901 short ssincosz - tbl_trans # $30-1 fsincos zero 4902 short ssincosi - tbl_trans # $30-2 fsincos inf 4903 short ssincosqnan - tbl_trans # $30-3 fsincos qnan 4904 short ssincosd - tbl_trans # $30-5 fsincos denorm 4905 short ssincossnan - tbl_trans # $30-4 fsincos snan 4906 short tbl_trans - tbl_trans # $30-6 fsincos unnorm 4907 short tbl_trans - tbl_trans # $30-7 ERROR 4908 4909 short ssincos - tbl_trans # $31-0 fsincos norm 4910 short ssincosz - tbl_trans # $31-1 fsincos zero 4911 short ssincosi - tbl_trans # $31-2 fsincos inf 4912 short ssincosqnan - tbl_trans # $31-3 fsincos qnan 4913 short ssincosd - tbl_trans # $31-5 fsincos denorm 4914 short ssincossnan - tbl_trans # $31-4 fsincos snan 4915 short tbl_trans - tbl_trans # $31-6 fsincos unnorm 4916 short tbl_trans - tbl_trans # $31-7 ERROR 4917 4918 short ssincos - tbl_trans # $32-0 fsincos norm 4919 short ssincosz - tbl_trans # $32-1 fsincos zero 4920 short ssincosi - tbl_trans # $32-2 fsincos inf 4921 short ssincosqnan - tbl_trans # $32-3 fsincos qnan 4922 short ssincosd - tbl_trans # $32-5 fsincos denorm 4923 short ssincossnan - tbl_trans # $32-4 fsincos snan 4924 short tbl_trans - tbl_trans # $32-6 fsincos unnorm 4925 short tbl_trans - tbl_trans # $32-7 ERROR 4926 4927 short ssincos - tbl_trans # $33-0 fsincos norm 4928 short ssincosz - tbl_trans # $33-1 fsincos zero 4929 short ssincosi - tbl_trans # $33-2 fsincos inf 4930 short ssincosqnan - tbl_trans # $33-3 fsincos qnan 4931 short ssincosd - tbl_trans # $33-5 fsincos denorm 4932 short ssincossnan - tbl_trans # $33-4 fsincos snan 4933 short tbl_trans - tbl_trans # $33-6 fsincos unnorm 4934 short tbl_trans - tbl_trans # $33-7 ERROR 4935 4936 short ssincos - tbl_trans # $34-0 fsincos norm 4937 short ssincosz - tbl_trans # $34-1 fsincos zero 4938 short ssincosi - tbl_trans # $34-2 fsincos inf 4939 short ssincosqnan - tbl_trans # $34-3 fsincos qnan 4940 short ssincosd - tbl_trans # $34-5 fsincos denorm 4941 short ssincossnan - tbl_trans # $34-4 fsincos snan 4942 short tbl_trans - tbl_trans # $34-6 fsincos unnorm 4943 short tbl_trans - tbl_trans # $34-7 ERROR 4944 4945 short ssincos - tbl_trans # $35-0 fsincos norm 4946 short ssincosz - tbl_trans # $35-1 fsincos zero 4947 short ssincosi - tbl_trans # $35-2 fsincos inf 4948 short ssincosqnan - tbl_trans # $35-3 fsincos qnan 4949 short ssincosd - tbl_trans # $35-5 fsincos denorm 4950 short ssincossnan - tbl_trans # $35-4 fsincos snan 4951 short tbl_trans - tbl_trans # $35-6 fsincos unnorm 4952 short tbl_trans - tbl_trans # $35-7 ERROR 4953 4954 short ssincos - tbl_trans # $36-0 fsincos norm 4955 short ssincosz - tbl_trans # $36-1 fsincos zero 4956 short ssincosi - tbl_trans # $36-2 fsincos inf 4957 short ssincosqnan - tbl_trans # $36-3 fsincos qnan 4958 short ssincosd - tbl_trans # $36-5 fsincos denorm 4959 short ssincossnan - tbl_trans # $36-4 fsincos snan 4960 short tbl_trans - tbl_trans # $36-6 fsincos unnorm 4961 short tbl_trans - tbl_trans # $36-7 ERROR 4962 4963 short ssincos - tbl_trans # $37-0 fsincos norm 4964 short ssincosz - tbl_trans # $37-1 fsincos zero 4965 short ssincosi - tbl_trans # $37-2 fsincos inf 4966 short ssincosqnan - tbl_trans # $37-3 fsincos qnan 4967 short ssincosd - tbl_trans # $37-5 fsincos denorm 4968 short ssincossnan - tbl_trans # $37-4 fsincos snan 4969 short tbl_trans - tbl_trans # $37-6 fsincos unnorm 4970 short tbl_trans - tbl_trans # $37-7 ERROR 4971 4972########## 4973 4974# the instruction fetch access for the displacement word for the 4975# fdbcc emulation failed. here, we create an access error frame 4976# from the current frame and branch to _real_access(). 4977funimp_iacc: 4978 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 4979 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 4980 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 4981 4982 mov.l USER_FPIAR(%a6),EXC_PC(%a6) # store current PC 4983 4984 unlk %a6 4985 4986 mov.l (%sp),-(%sp) # store SR,hi(PC) 4987 mov.w 0x8(%sp),0x4(%sp) # store lo(PC) 4988 mov.w &0x4008,0x6(%sp) # store voff 4989 mov.l 0x2(%sp),0x8(%sp) # store EA 4990 mov.l &0x09428001,0xc(%sp) # store FSLW 4991 4992 btst &0x5,(%sp) # user or supervisor mode? 4993 beq.b funimp_iacc_end # user 4994 bset &0x2,0xd(%sp) # set supervisor TM bit 4995 4996funimp_iacc_end: 4997 bra.l _real_access 4998 4999######################################################################### 5000# ssin(): computes the sine of a normalized input # 5001# ssind(): computes the sine of a denormalized input # 5002# scos(): computes the cosine of a normalized input # 5003# scosd(): computes the cosine of a denormalized input # 5004# ssincos(): computes the sine and cosine of a normalized input # 5005# ssincosd(): computes the sine and cosine of a denormalized input # 5006# # 5007# INPUT *************************************************************** # 5008# a0 = pointer to extended precision input # 5009# d0 = round precision,mode # 5010# # 5011# OUTPUT ************************************************************** # 5012# fp0 = sin(X) or cos(X) # 5013# # 5014# For ssincos(X): # 5015# fp0 = sin(X) # 5016# fp1 = cos(X) # 5017# # 5018# ACCURACY and MONOTONICITY ******************************************* # 5019# The returned result is within 1 ulp in 64 significant bit, i.e. # 5020# within 0.5001 ulp to 53 bits if the result is subsequently # 5021# rounded to double precision. The result is provably monotonic # 5022# in double precision. # 5023# # 5024# ALGORITHM *********************************************************** # 5025# # 5026# SIN and COS: # 5027# 1. If SIN is invoked, set AdjN := 0; otherwise, set AdjN := 1. # 5028# # 5029# 2. If |X| >= 15Pi or |X| < 2**(-40), go to 7. # 5030# # 5031# 3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let # 5032# k = N mod 4, so in particular, k = 0,1,2,or 3. # 5033# Overwrite k by k := k + AdjN. # 5034# # 5035# 4. If k is even, go to 6. # 5036# # 5037# 5. (k is odd) Set j := (k-1)/2, sgn := (-1)**j. # 5038# Return sgn*cos(r) where cos(r) is approximated by an # 5039# even polynomial in r, 1 + r*r*(B1+s*(B2+ ... + s*B8)), # 5040# s = r*r. # 5041# Exit. # 5042# # 5043# 6. (k is even) Set j := k/2, sgn := (-1)**j. Return sgn*sin(r) # 5044# where sin(r) is approximated by an odd polynomial in r # 5045# r + r*s*(A1+s*(A2+ ... + s*A7)), s = r*r. # 5046# Exit. # 5047# # 5048# 7. If |X| > 1, go to 9. # 5049# # 5050# 8. (|X|<2**(-40)) If SIN is invoked, return X; # 5051# otherwise return 1. # 5052# # 5053# 9. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, # 5054# go back to 3. # 5055# # 5056# SINCOS: # 5057# 1. If |X| >= 15Pi or |X| < 2**(-40), go to 6. # 5058# # 5059# 2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let # 5060# k = N mod 4, so in particular, k = 0,1,2,or 3. # 5061# # 5062# 3. If k is even, go to 5. # 5063# # 5064# 4. (k is odd) Set j1 := (k-1)/2, j2 := j1 (EOR) (k mod 2), ie. # 5065# j1 exclusive or with the l.s.b. of k. # 5066# sgn1 := (-1)**j1, sgn2 := (-1)**j2. # 5067# SIN(X) = sgn1 * cos(r) and COS(X) = sgn2*sin(r) where # 5068# sin(r) and cos(r) are computed as odd and even # 5069# polynomials in r, respectively. Exit # 5070# # 5071# 5. (k is even) Set j1 := k/2, sgn1 := (-1)**j1. # 5072# SIN(X) = sgn1 * sin(r) and COS(X) = sgn1*cos(r) where # 5073# sin(r) and cos(r) are computed as odd and even # 5074# polynomials in r, respectively. Exit # 5075# # 5076# 6. If |X| > 1, go to 8. # 5077# # 5078# 7. (|X|<2**(-40)) SIN(X) = X and COS(X) = 1. Exit. # 5079# # 5080# 8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, # 5081# go back to 2. # 5082# # 5083######################################################################### 5084 5085SINA7: long 0xBD6AAA77,0xCCC994F5 5086SINA6: long 0x3DE61209,0x7AAE8DA1 5087SINA5: long 0xBE5AE645,0x2A118AE4 5088SINA4: long 0x3EC71DE3,0xA5341531 5089SINA3: long 0xBF2A01A0,0x1A018B59,0x00000000,0x00000000 5090SINA2: long 0x3FF80000,0x88888888,0x888859AF,0x00000000 5091SINA1: long 0xBFFC0000,0xAAAAAAAA,0xAAAAAA99,0x00000000 5092 5093COSB8: long 0x3D2AC4D0,0xD6011EE3 5094COSB7: long 0xBDA9396F,0x9F45AC19 5095COSB6: long 0x3E21EED9,0x0612C972 5096COSB5: long 0xBE927E4F,0xB79D9FCF 5097COSB4: long 0x3EFA01A0,0x1A01D423,0x00000000,0x00000000 5098COSB3: long 0xBFF50000,0xB60B60B6,0x0B61D438,0x00000000 5099COSB2: long 0x3FFA0000,0xAAAAAAAA,0xAAAAAB5E 5100COSB1: long 0xBF000000 5101 5102 set INARG,FP_SCR0 5103 5104 set X,FP_SCR0 5105# set XDCARE,X+2 5106 set XFRAC,X+4 5107 5108 set RPRIME,FP_SCR0 5109 set SPRIME,FP_SCR1 5110 5111 set POSNEG1,L_SCR1 5112 set TWOTO63,L_SCR1 5113 5114 set ENDFLAG,L_SCR2 5115 set INT,L_SCR2 5116 5117 set ADJN,L_SCR3 5118 5119############################################ 5120 global ssin 5121ssin: 5122 mov.l &0,ADJN(%a6) # yes; SET ADJN TO 0 5123 bra.b SINBGN 5124 5125############################################ 5126 global scos 5127scos: 5128 mov.l &1,ADJN(%a6) # yes; SET ADJN TO 1 5129 5130############################################ 5131SINBGN: 5132#--SAVE FPCR, FP1. CHECK IF |X| IS TOO SMALL OR LARGE 5133 5134 fmov.x (%a0),%fp0 # LOAD INPUT 5135 fmov.x %fp0,X(%a6) # save input at X 5136 5137# "COMPACTIFY" X 5138 mov.l (%a0),%d1 # put exp in hi word 5139 mov.w 4(%a0),%d1 # fetch hi(man) 5140 and.l &0x7FFFFFFF,%d1 # strip sign 5141 5142 cmpi.l %d1,&0x3FD78000 # is |X| >= 2**(-40)? 5143 bge.b SOK1 # no 5144 bra.w SINSM # yes; input is very small 5145 5146SOK1: 5147 cmp.l %d1,&0x4004BC7E # is |X| < 15 PI? 5148 blt.b SINMAIN # no 5149 bra.w SREDUCEX # yes; input is very large 5150 5151#--THIS IS THE USUAL CASE, |X| <= 15 PI. 5152#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. 5153SINMAIN: 5154 fmov.x %fp0,%fp1 5155 fmul.d TWOBYPI(%pc),%fp1 # X*2/PI 5156 5157 lea PITBL+0x200(%pc),%a1 # TABLE OF N*PI/2, N = -32,...,32 5158 5159 fmov.l %fp1,INT(%a6) # CONVERT TO INTEGER 5160 5161 mov.l INT(%a6),%d1 # make a copy of N 5162 asl.l &4,%d1 # N *= 16 5163 add.l %d1,%a1 # tbl_addr = a1 + (N*16) 5164 5165# A1 IS THE ADDRESS OF N*PIBY2 5166# ...WHICH IS IN TWO PIECES Y1 & Y2 5167 fsub.x (%a1)+,%fp0 # X-Y1 5168 fsub.s (%a1),%fp0 # fp0 = R = (X-Y1)-Y2 5169 5170SINCONT: 5171#--continuation from REDUCEX 5172 5173#--GET N+ADJN AND SEE IF SIN(R) OR COS(R) IS NEEDED 5174 mov.l INT(%a6),%d1 5175 add.l ADJN(%a6),%d1 # SEE IF D0 IS ODD OR EVEN 5176 ror.l &1,%d1 # D0 WAS ODD IFF D0 IS NEGATIVE 5177 cmp.l %d1,&0 5178 blt.w COSPOLY 5179 5180#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J. 5181#--THEN WE RETURN SGN*SIN(R). SGN*SIN(R) IS COMPUTED BY 5182#--R' + R'*S*(A1 + S(A2 + S(A3 + S(A4 + ... + SA7)))), WHERE 5183#--R' = SGN*R, S=R*R. THIS CAN BE REWRITTEN AS 5184#--R' + R'*S*( [A1+T(A3+T(A5+TA7))] + [S(A2+T(A4+TA6))]) 5185#--WHERE T=S*S. 5186#--NOTE THAT A3 THROUGH A7 ARE STORED IN DOUBLE PRECISION 5187#--WHILE A1 AND A2 ARE IN DOUBLE-EXTENDED FORMAT. 5188SINPOLY: 5189 fmovm.x &0x0c,-(%sp) # save fp2/fp3 5190 5191 fmov.x %fp0,X(%a6) # X IS R 5192 fmul.x %fp0,%fp0 # FP0 IS S 5193 5194 fmov.d SINA7(%pc),%fp3 5195 fmov.d SINA6(%pc),%fp2 5196 5197 fmov.x %fp0,%fp1 5198 fmul.x %fp1,%fp1 # FP1 IS T 5199 5200 ror.l &1,%d1 5201 and.l &0x80000000,%d1 5202# ...LEAST SIG. BIT OF D0 IN SIGN POSITION 5203 eor.l %d1,X(%a6) # X IS NOW R'= SGN*R 5204 5205 fmul.x %fp1,%fp3 # TA7 5206 fmul.x %fp1,%fp2 # TA6 5207 5208 fadd.d SINA5(%pc),%fp3 # A5+TA7 5209 fadd.d SINA4(%pc),%fp2 # A4+TA6 5210 5211 fmul.x %fp1,%fp3 # T(A5+TA7) 5212 fmul.x %fp1,%fp2 # T(A4+TA6) 5213 5214 fadd.d SINA3(%pc),%fp3 # A3+T(A5+TA7) 5215 fadd.x SINA2(%pc),%fp2 # A2+T(A4+TA6) 5216 5217 fmul.x %fp3,%fp1 # T(A3+T(A5+TA7)) 5218 5219 fmul.x %fp0,%fp2 # S(A2+T(A4+TA6)) 5220 fadd.x SINA1(%pc),%fp1 # A1+T(A3+T(A5+TA7)) 5221 fmul.x X(%a6),%fp0 # R'*S 5222 5223 fadd.x %fp2,%fp1 # [A1+T(A3+T(A5+TA7))]+[S(A2+T(A4+TA6))] 5224 5225 fmul.x %fp1,%fp0 # SIN(R')-R' 5226 5227 fmovm.x (%sp)+,&0x30 # restore fp2/fp3 5228 5229 fmov.l %d0,%fpcr # restore users round mode,prec 5230 fadd.x X(%a6),%fp0 # last inst - possible exception set 5231 bra t_inx2 5232 5233#--LET J BE THE LEAST SIG. BIT OF D0, LET SGN := (-1)**J. 5234#--THEN WE RETURN SGN*COS(R). SGN*COS(R) IS COMPUTED BY 5235#--SGN + S'*(B1 + S(B2 + S(B3 + S(B4 + ... + SB8)))), WHERE 5236#--S=R*R AND S'=SGN*S. THIS CAN BE REWRITTEN AS 5237#--SGN + S'*([B1+T(B3+T(B5+TB7))] + [S(B2+T(B4+T(B6+TB8)))]) 5238#--WHERE T=S*S. 5239#--NOTE THAT B4 THROUGH B8 ARE STORED IN DOUBLE PRECISION 5240#--WHILE B2 AND B3 ARE IN DOUBLE-EXTENDED FORMAT, B1 IS -1/2 5241#--AND IS THEREFORE STORED AS SINGLE PRECISION. 5242COSPOLY: 5243 fmovm.x &0x0c,-(%sp) # save fp2/fp3 5244 5245 fmul.x %fp0,%fp0 # FP0 IS S 5246 5247 fmov.d COSB8(%pc),%fp2 5248 fmov.d COSB7(%pc),%fp3 5249 5250 fmov.x %fp0,%fp1 5251 fmul.x %fp1,%fp1 # FP1 IS T 5252 5253 fmov.x %fp0,X(%a6) # X IS S 5254 ror.l &1,%d1 5255 and.l &0x80000000,%d1 5256# ...LEAST SIG. BIT OF D0 IN SIGN POSITION 5257 5258 fmul.x %fp1,%fp2 # TB8 5259 5260 eor.l %d1,X(%a6) # X IS NOW S'= SGN*S 5261 and.l &0x80000000,%d1 5262 5263 fmul.x %fp1,%fp3 # TB7 5264 5265 or.l &0x3F800000,%d1 # D0 IS SGN IN SINGLE 5266 mov.l %d1,POSNEG1(%a6) 5267 5268 fadd.d COSB6(%pc),%fp2 # B6+TB8 5269 fadd.d COSB5(%pc),%fp3 # B5+TB7 5270 5271 fmul.x %fp1,%fp2 # T(B6+TB8) 5272 fmul.x %fp1,%fp3 # T(B5+TB7) 5273 5274 fadd.d COSB4(%pc),%fp2 # B4+T(B6+TB8) 5275 fadd.x COSB3(%pc),%fp3 # B3+T(B5+TB7) 5276 5277 fmul.x %fp1,%fp2 # T(B4+T(B6+TB8)) 5278 fmul.x %fp3,%fp1 # T(B3+T(B5+TB7)) 5279 5280 fadd.x COSB2(%pc),%fp2 # B2+T(B4+T(B6+TB8)) 5281 fadd.s COSB1(%pc),%fp1 # B1+T(B3+T(B5+TB7)) 5282 5283 fmul.x %fp2,%fp0 # S(B2+T(B4+T(B6+TB8))) 5284 5285 fadd.x %fp1,%fp0 5286 5287 fmul.x X(%a6),%fp0 5288 5289 fmovm.x (%sp)+,&0x30 # restore fp2/fp3 5290 5291 fmov.l %d0,%fpcr # restore users round mode,prec 5292 fadd.s POSNEG1(%a6),%fp0 # last inst - possible exception set 5293 bra t_inx2 5294 5295############################################## 5296 5297# SINe: Big OR Small? 5298#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION. 5299#--IF |X| < 2**(-40), RETURN X OR 1. 5300SINBORS: 5301 cmp.l %d1,&0x3FFF8000 5302 bgt.l SREDUCEX 5303 5304SINSM: 5305 mov.l ADJN(%a6),%d1 5306 cmp.l %d1,&0 5307 bgt.b COSTINY 5308 5309# here, the operation may underflow iff the precision is sgl or dbl. 5310# extended denorms are handled through another entry point. 5311SINTINY: 5312# mov.w &0x0000,XDCARE(%a6) # JUST IN CASE 5313 5314 fmov.l %d0,%fpcr # restore users round mode,prec 5315 mov.b &FMOV_OP,%d1 # last inst is MOVE 5316 fmov.x X(%a6),%fp0 # last inst - possible exception set 5317 bra t_catch 5318 5319COSTINY: 5320 fmov.s &0x3F800000,%fp0 # fp0 = 1.0 5321 fmov.l %d0,%fpcr # restore users round mode,prec 5322 fadd.s &0x80800000,%fp0 # last inst - possible exception set 5323 bra t_pinx2 5324 5325################################################ 5326 global ssind 5327#--SIN(X) = X FOR DENORMALIZED X 5328ssind: 5329 bra t_extdnrm 5330 5331############################################ 5332 global scosd 5333#--COS(X) = 1 FOR DENORMALIZED X 5334scosd: 5335 fmov.s &0x3F800000,%fp0 # fp0 = 1.0 5336 bra t_pinx2 5337 5338################################################## 5339 5340 global ssincos 5341ssincos: 5342#--SET ADJN TO 4 5343 mov.l &4,ADJN(%a6) 5344 5345 fmov.x (%a0),%fp0 # LOAD INPUT 5346 fmov.x %fp0,X(%a6) 5347 5348 mov.l (%a0),%d1 5349 mov.w 4(%a0),%d1 5350 and.l &0x7FFFFFFF,%d1 # COMPACTIFY X 5351 5352 cmp.l %d1,&0x3FD78000 # |X| >= 2**(-40)? 5353 bge.b SCOK1 5354 bra.w SCSM 5355 5356SCOK1: 5357 cmp.l %d1,&0x4004BC7E # |X| < 15 PI? 5358 blt.b SCMAIN 5359 bra.w SREDUCEX 5360 5361 5362#--THIS IS THE USUAL CASE, |X| <= 15 PI. 5363#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. 5364SCMAIN: 5365 fmov.x %fp0,%fp1 5366 5367 fmul.d TWOBYPI(%pc),%fp1 # X*2/PI 5368 5369 lea PITBL+0x200(%pc),%a1 # TABLE OF N*PI/2, N = -32,...,32 5370 5371 fmov.l %fp1,INT(%a6) # CONVERT TO INTEGER 5372 5373 mov.l INT(%a6),%d1 5374 asl.l &4,%d1 5375 add.l %d1,%a1 # ADDRESS OF N*PIBY2, IN Y1, Y2 5376 5377 fsub.x (%a1)+,%fp0 # X-Y1 5378 fsub.s (%a1),%fp0 # FP0 IS R = (X-Y1)-Y2 5379 5380SCCONT: 5381#--continuation point from REDUCEX 5382 5383 mov.l INT(%a6),%d1 5384 ror.l &1,%d1 5385 cmp.l %d1,&0 # D0 < 0 IFF N IS ODD 5386 bge.w NEVEN 5387 5388SNODD: 5389#--REGISTERS SAVED SO FAR: D0, A0, FP2. 5390 fmovm.x &0x04,-(%sp) # save fp2 5391 5392 fmov.x %fp0,RPRIME(%a6) 5393 fmul.x %fp0,%fp0 # FP0 IS S = R*R 5394 fmov.d SINA7(%pc),%fp1 # A7 5395 fmov.d COSB8(%pc),%fp2 # B8 5396 fmul.x %fp0,%fp1 # SA7 5397 fmul.x %fp0,%fp2 # SB8 5398 5399 mov.l %d2,-(%sp) 5400 mov.l %d1,%d2 5401 ror.l &1,%d2 5402 and.l &0x80000000,%d2 5403 eor.l %d1,%d2 5404 and.l &0x80000000,%d2 5405 5406 fadd.d SINA6(%pc),%fp1 # A6+SA7 5407 fadd.d COSB7(%pc),%fp2 # B7+SB8 5408 5409 fmul.x %fp0,%fp1 # S(A6+SA7) 5410 eor.l %d2,RPRIME(%a6) 5411 mov.l (%sp)+,%d2 5412 fmul.x %fp0,%fp2 # S(B7+SB8) 5413 ror.l &1,%d1 5414 and.l &0x80000000,%d1 5415 mov.l &0x3F800000,POSNEG1(%a6) 5416 eor.l %d1,POSNEG1(%a6) 5417 5418 fadd.d SINA5(%pc),%fp1 # A5+S(A6+SA7) 5419 fadd.d COSB6(%pc),%fp2 # B6+S(B7+SB8) 5420 5421 fmul.x %fp0,%fp1 # S(A5+S(A6+SA7)) 5422 fmul.x %fp0,%fp2 # S(B6+S(B7+SB8)) 5423 fmov.x %fp0,SPRIME(%a6) 5424 5425 fadd.d SINA4(%pc),%fp1 # A4+S(A5+S(A6+SA7)) 5426 eor.l %d1,SPRIME(%a6) 5427 fadd.d COSB5(%pc),%fp2 # B5+S(B6+S(B7+SB8)) 5428 5429 fmul.x %fp0,%fp1 # S(A4+...) 5430 fmul.x %fp0,%fp2 # S(B5+...) 5431 5432 fadd.d SINA3(%pc),%fp1 # A3+S(A4+...) 5433 fadd.d COSB4(%pc),%fp2 # B4+S(B5+...) 5434 5435 fmul.x %fp0,%fp1 # S(A3+...) 5436 fmul.x %fp0,%fp2 # S(B4+...) 5437 5438 fadd.x SINA2(%pc),%fp1 # A2+S(A3+...) 5439 fadd.x COSB3(%pc),%fp2 # B3+S(B4+...) 5440 5441 fmul.x %fp0,%fp1 # S(A2+...) 5442 fmul.x %fp0,%fp2 # S(B3+...) 5443 5444 fadd.x SINA1(%pc),%fp1 # A1+S(A2+...) 5445 fadd.x COSB2(%pc),%fp2 # B2+S(B3+...) 5446 5447 fmul.x %fp0,%fp1 # S(A1+...) 5448 fmul.x %fp2,%fp0 # S(B2+...) 5449 5450 fmul.x RPRIME(%a6),%fp1 # R'S(A1+...) 5451 fadd.s COSB1(%pc),%fp0 # B1+S(B2...) 5452 fmul.x SPRIME(%a6),%fp0 # S'(B1+S(B2+...)) 5453 5454 fmovm.x (%sp)+,&0x20 # restore fp2 5455 5456 fmov.l %d0,%fpcr 5457 fadd.x RPRIME(%a6),%fp1 # COS(X) 5458 bsr sto_cos # store cosine result 5459 fadd.s POSNEG1(%a6),%fp0 # SIN(X) 5460 bra t_inx2 5461 5462NEVEN: 5463#--REGISTERS SAVED SO FAR: FP2. 5464 fmovm.x &0x04,-(%sp) # save fp2 5465 5466 fmov.x %fp0,RPRIME(%a6) 5467 fmul.x %fp0,%fp0 # FP0 IS S = R*R 5468 5469 fmov.d COSB8(%pc),%fp1 # B8 5470 fmov.d SINA7(%pc),%fp2 # A7 5471 5472 fmul.x %fp0,%fp1 # SB8 5473 fmov.x %fp0,SPRIME(%a6) 5474 fmul.x %fp0,%fp2 # SA7 5475 5476 ror.l &1,%d1 5477 and.l &0x80000000,%d1 5478 5479 fadd.d COSB7(%pc),%fp1 # B7+SB8 5480 fadd.d SINA6(%pc),%fp2 # A6+SA7 5481 5482 eor.l %d1,RPRIME(%a6) 5483 eor.l %d1,SPRIME(%a6) 5484 5485 fmul.x %fp0,%fp1 # S(B7+SB8) 5486 5487 or.l &0x3F800000,%d1 5488 mov.l %d1,POSNEG1(%a6) 5489 5490 fmul.x %fp0,%fp2 # S(A6+SA7) 5491 5492 fadd.d COSB6(%pc),%fp1 # B6+S(B7+SB8) 5493 fadd.d SINA5(%pc),%fp2 # A5+S(A6+SA7) 5494 5495 fmul.x %fp0,%fp1 # S(B6+S(B7+SB8)) 5496 fmul.x %fp0,%fp2 # S(A5+S(A6+SA7)) 5497 5498 fadd.d COSB5(%pc),%fp1 # B5+S(B6+S(B7+SB8)) 5499 fadd.d SINA4(%pc),%fp2 # A4+S(A5+S(A6+SA7)) 5500 5501 fmul.x %fp0,%fp1 # S(B5+...) 5502 fmul.x %fp0,%fp2 # S(A4+...) 5503 5504 fadd.d COSB4(%pc),%fp1 # B4+S(B5+...) 5505 fadd.d SINA3(%pc),%fp2 # A3+S(A4+...) 5506 5507 fmul.x %fp0,%fp1 # S(B4+...) 5508 fmul.x %fp0,%fp2 # S(A3+...) 5509 5510 fadd.x COSB3(%pc),%fp1 # B3+S(B4+...) 5511 fadd.x SINA2(%pc),%fp2 # A2+S(A3+...) 5512 5513 fmul.x %fp0,%fp1 # S(B3+...) 5514 fmul.x %fp0,%fp2 # S(A2+...) 5515 5516 fadd.x COSB2(%pc),%fp1 # B2+S(B3+...) 5517 fadd.x SINA1(%pc),%fp2 # A1+S(A2+...) 5518 5519 fmul.x %fp0,%fp1 # S(B2+...) 5520 fmul.x %fp2,%fp0 # s(a1+...) 5521 5522 5523 fadd.s COSB1(%pc),%fp1 # B1+S(B2...) 5524 fmul.x RPRIME(%a6),%fp0 # R'S(A1+...) 5525 fmul.x SPRIME(%a6),%fp1 # S'(B1+S(B2+...)) 5526 5527 fmovm.x (%sp)+,&0x20 # restore fp2 5528 5529 fmov.l %d0,%fpcr 5530 fadd.s POSNEG1(%a6),%fp1 # COS(X) 5531 bsr sto_cos # store cosine result 5532 fadd.x RPRIME(%a6),%fp0 # SIN(X) 5533 bra t_inx2 5534 5535################################################ 5536 5537SCBORS: 5538 cmp.l %d1,&0x3FFF8000 5539 bgt.w SREDUCEX 5540 5541################################################ 5542 5543SCSM: 5544# mov.w &0x0000,XDCARE(%a6) 5545 fmov.s &0x3F800000,%fp1 5546 5547 fmov.l %d0,%fpcr 5548 fsub.s &0x00800000,%fp1 5549 bsr sto_cos # store cosine result 5550 fmov.l %fpcr,%d0 # d0 must have fpcr,too 5551 mov.b &FMOV_OP,%d1 # last inst is MOVE 5552 fmov.x X(%a6),%fp0 5553 bra t_catch 5554 5555############################################## 5556 5557 global ssincosd 5558#--SIN AND COS OF X FOR DENORMALIZED X 5559ssincosd: 5560 mov.l %d0,-(%sp) # save d0 5561 fmov.s &0x3F800000,%fp1 5562 bsr sto_cos # store cosine result 5563 mov.l (%sp)+,%d0 # restore d0 5564 bra t_extdnrm 5565 5566############################################ 5567 5568#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW. 5569#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING 5570#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE. 5571SREDUCEX: 5572 fmovm.x &0x3c,-(%sp) # save {fp2-fp5} 5573 mov.l %d2,-(%sp) # save d2 5574 fmov.s &0x00000000,%fp1 # fp1 = 0 5575 5576#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that 5577#--there is a danger of unwanted overflow in first LOOP iteration. In this 5578#--case, reduce argument by one remainder step to make subsequent reduction 5579#--safe. 5580 cmp.l %d1,&0x7ffeffff # is arg dangerously large? 5581 bne.b SLOOP # no 5582 5583# yes; create 2**16383*PI/2 5584 mov.w &0x7ffe,FP_SCR0_EX(%a6) 5585 mov.l &0xc90fdaa2,FP_SCR0_HI(%a6) 5586 clr.l FP_SCR0_LO(%a6) 5587 5588# create low half of 2**16383*PI/2 at FP_SCR1 5589 mov.w &0x7fdc,FP_SCR1_EX(%a6) 5590 mov.l &0x85a308d3,FP_SCR1_HI(%a6) 5591 clr.l FP_SCR1_LO(%a6) 5592 5593 ftest.x %fp0 # test sign of argument 5594 fblt.w sred_neg 5595 5596 or.b &0x80,FP_SCR0_EX(%a6) # positive arg 5597 or.b &0x80,FP_SCR1_EX(%a6) 5598sred_neg: 5599 fadd.x FP_SCR0(%a6),%fp0 # high part of reduction is exact 5600 fmov.x %fp0,%fp1 # save high result in fp1 5601 fadd.x FP_SCR1(%a6),%fp0 # low part of reduction 5602 fsub.x %fp0,%fp1 # determine low component of result 5603 fadd.x FP_SCR1(%a6),%fp1 # fp0/fp1 are reduced argument. 5604 5605#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. 5606#--integer quotient will be stored in N 5607#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) 5608SLOOP: 5609 fmov.x %fp0,INARG(%a6) # +-2**K * F, 1 <= F < 2 5610 mov.w INARG(%a6),%d1 5611 mov.l %d1,%a1 # save a copy of D0 5612 and.l &0x00007FFF,%d1 5613 sub.l &0x00003FFF,%d1 # d0 = K 5614 cmp.l %d1,&28 5615 ble.b SLASTLOOP 5616SCONTLOOP: 5617 sub.l &27,%d1 # d0 = L := K-27 5618 mov.b &0,ENDFLAG(%a6) 5619 bra.b SWORK 5620SLASTLOOP: 5621 clr.l %d1 # d0 = L := 0 5622 mov.b &1,ENDFLAG(%a6) 5623 5624SWORK: 5625#--FIND THE REMAINDER OF (R,r) W.R.T. 2**L * (PI/2). L IS SO CHOSEN 5626#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29. 5627 5628#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63), 5629#--2**L * (PIby2_1), 2**L * (PIby2_2) 5630 5631 mov.l &0x00003FFE,%d2 # BIASED EXP OF 2/PI 5632 sub.l %d1,%d2 # BIASED EXP OF 2**(-L)*(2/PI) 5633 5634 mov.l &0xA2F9836E,FP_SCR0_HI(%a6) 5635 mov.l &0x4E44152A,FP_SCR0_LO(%a6) 5636 mov.w %d2,FP_SCR0_EX(%a6) # FP_SCR0 = 2**(-L)*(2/PI) 5637 5638 fmov.x %fp0,%fp2 5639 fmul.x FP_SCR0(%a6),%fp2 # fp2 = X * 2**(-L)*(2/PI) 5640 5641#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN 5642#--FLOATING POINT FORMAT, THE TWO FMOVE'S FMOVE.L FP <--> N 5643#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT 5644#--(SIGN(INARG)*2**63 + FP2) - SIGN(INARG)*2**63 WILL GIVE 5645#--US THE DESIRED VALUE IN FLOATING POINT. 5646 mov.l %a1,%d2 5647 swap %d2 5648 and.l &0x80000000,%d2 5649 or.l &0x5F000000,%d2 # d2 = SIGN(INARG)*2**63 IN SGL 5650 mov.l %d2,TWOTO63(%a6) 5651 fadd.s TWOTO63(%a6),%fp2 # THE FRACTIONAL PART OF FP1 IS ROUNDED 5652 fsub.s TWOTO63(%a6),%fp2 # fp2 = N 5653# fint.x %fp2 5654 5655#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2 5656 mov.l %d1,%d2 # d2 = L 5657 5658 add.l &0x00003FFF,%d2 # BIASED EXP OF 2**L * (PI/2) 5659 mov.w %d2,FP_SCR0_EX(%a6) 5660 mov.l &0xC90FDAA2,FP_SCR0_HI(%a6) 5661 clr.l FP_SCR0_LO(%a6) # FP_SCR0 = 2**(L) * Piby2_1 5662 5663 add.l &0x00003FDD,%d1 5664 mov.w %d1,FP_SCR1_EX(%a6) 5665 mov.l &0x85A308D3,FP_SCR1_HI(%a6) 5666 clr.l FP_SCR1_LO(%a6) # FP_SCR1 = 2**(L) * Piby2_2 5667 5668 mov.b ENDFLAG(%a6),%d1 5669 5670#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and 5671#--P2 = 2**(L) * Piby2_2 5672 fmov.x %fp2,%fp4 # fp4 = N 5673 fmul.x FP_SCR0(%a6),%fp4 # fp4 = W = N*P1 5674 fmov.x %fp2,%fp5 # fp5 = N 5675 fmul.x FP_SCR1(%a6),%fp5 # fp5 = w = N*P2 5676 fmov.x %fp4,%fp3 # fp3 = W = N*P1 5677 5678#--we want P+p = W+w but |p| <= half ulp of P 5679#--Then, we need to compute A := R-P and a := r-p 5680 fadd.x %fp5,%fp3 # fp3 = P 5681 fsub.x %fp3,%fp4 # fp4 = W-P 5682 5683 fsub.x %fp3,%fp0 # fp0 = A := R - P 5684 fadd.x %fp5,%fp4 # fp4 = p = (W-P)+w 5685 5686 fmov.x %fp0,%fp3 # fp3 = A 5687 fsub.x %fp4,%fp1 # fp1 = a := r - p 5688 5689#--Now we need to normalize (A,a) to "new (R,r)" where R+r = A+a but 5690#--|r| <= half ulp of R. 5691 fadd.x %fp1,%fp0 # fp0 = R := A+a 5692#--No need to calculate r if this is the last loop 5693 cmp.b %d1,&0 5694 bgt.w SRESTORE 5695 5696#--Need to calculate r 5697 fsub.x %fp0,%fp3 # fp3 = A-R 5698 fadd.x %fp3,%fp1 # fp1 = r := (A-R)+a 5699 bra.w SLOOP 5700 5701SRESTORE: 5702 fmov.l %fp2,INT(%a6) 5703 mov.l (%sp)+,%d2 # restore d2 5704 fmovm.x (%sp)+,&0x3c # restore {fp2-fp5} 5705 5706 mov.l ADJN(%a6),%d1 5707 cmp.l %d1,&4 5708 5709 blt.w SINCONT 5710 bra.w SCCONT 5711 5712######################################################################### 5713# stan(): computes the tangent of a normalized input # 5714# stand(): computes the tangent of a denormalized input # 5715# # 5716# INPUT *************************************************************** # 5717# a0 = pointer to extended precision input # 5718# d0 = round precision,mode # 5719# # 5720# OUTPUT ************************************************************** # 5721# fp0 = tan(X) # 5722# # 5723# ACCURACY and MONOTONICITY ******************************************* # 5724# The returned result is within 3 ulp in 64 significant bit, i.e. # 5725# within 0.5001 ulp to 53 bits if the result is subsequently # 5726# rounded to double precision. The result is provably monotonic # 5727# in double precision. # 5728# # 5729# ALGORITHM *********************************************************** # 5730# # 5731# 1. If |X| >= 15Pi or |X| < 2**(-40), go to 6. # 5732# # 5733# 2. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let # 5734# k = N mod 2, so in particular, k = 0 or 1. # 5735# # 5736# 3. If k is odd, go to 5. # 5737# # 5738# 4. (k is even) Tan(X) = tan(r) and tan(r) is approximated by a # 5739# rational function U/V where # 5740# U = r + r*s*(P1 + s*(P2 + s*P3)), and # 5741# V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r. # 5742# Exit. # 5743# # 5744# 4. (k is odd) Tan(X) = -cot(r). Since tan(r) is approximated by # 5745# a rational function U/V where # 5746# U = r + r*s*(P1 + s*(P2 + s*P3)), and # 5747# V = 1 + s*(Q1 + s*(Q2 + s*(Q3 + s*Q4))), s = r*r, # 5748# -Cot(r) = -V/U. Exit. # 5749# # 5750# 6. If |X| > 1, go to 8. # 5751# # 5752# 7. (|X|<2**(-40)) Tan(X) = X. Exit. # 5753# # 5754# 8. Overwrite X by X := X rem 2Pi. Now that |X| <= Pi, go back # 5755# to 2. # 5756# # 5757######################################################################### 5758 5759TANQ4: 5760 long 0x3EA0B759,0xF50F8688 5761TANP3: 5762 long 0xBEF2BAA5,0xA8924F04 5763 5764TANQ3: 5765 long 0xBF346F59,0xB39BA65F,0x00000000,0x00000000 5766 5767TANP2: 5768 long 0x3FF60000,0xE073D3FC,0x199C4A00,0x00000000 5769 5770TANQ2: 5771 long 0x3FF90000,0xD23CD684,0x15D95FA1,0x00000000 5772 5773TANP1: 5774 long 0xBFFC0000,0x8895A6C5,0xFB423BCA,0x00000000 5775 5776TANQ1: 5777 long 0xBFFD0000,0xEEF57E0D,0xA84BC8CE,0x00000000 5778 5779INVTWOPI: 5780 long 0x3FFC0000,0xA2F9836E,0x4E44152A,0x00000000 5781 5782TWOPI1: 5783 long 0x40010000,0xC90FDAA2,0x00000000,0x00000000 5784TWOPI2: 5785 long 0x3FDF0000,0x85A308D4,0x00000000,0x00000000 5786 5787#--N*PI/2, -32 <= N <= 32, IN A LEADING TERM IN EXT. AND TRAILING 5788#--TERM IN SGL. NOTE THAT PI IS 64-BIT LONG, THUS N*PI/2 IS AT 5789#--MOST 69 BITS LONG. 5790# global PITBL 5791PITBL: 5792 long 0xC0040000,0xC90FDAA2,0x2168C235,0x21800000 5793 long 0xC0040000,0xC2C75BCD,0x105D7C23,0xA0D00000 5794 long 0xC0040000,0xBC7EDCF7,0xFF523611,0xA1E80000 5795 long 0xC0040000,0xB6365E22,0xEE46F000,0x21480000 5796 long 0xC0040000,0xAFEDDF4D,0xDD3BA9EE,0xA1200000 5797 long 0xC0040000,0xA9A56078,0xCC3063DD,0x21FC0000 5798 long 0xC0040000,0xA35CE1A3,0xBB251DCB,0x21100000 5799 long 0xC0040000,0x9D1462CE,0xAA19D7B9,0xA1580000 5800 long 0xC0040000,0x96CBE3F9,0x990E91A8,0x21E00000 5801 long 0xC0040000,0x90836524,0x88034B96,0x20B00000 5802 long 0xC0040000,0x8A3AE64F,0x76F80584,0xA1880000 5803 long 0xC0040000,0x83F2677A,0x65ECBF73,0x21C40000 5804 long 0xC0030000,0xFB53D14A,0xA9C2F2C2,0x20000000 5805 long 0xC0030000,0xEEC2D3A0,0x87AC669F,0x21380000 5806 long 0xC0030000,0xE231D5F6,0x6595DA7B,0xA1300000 5807 long 0xC0030000,0xD5A0D84C,0x437F4E58,0x9FC00000 5808 long 0xC0030000,0xC90FDAA2,0x2168C235,0x21000000 5809 long 0xC0030000,0xBC7EDCF7,0xFF523611,0xA1680000 5810 long 0xC0030000,0xAFEDDF4D,0xDD3BA9EE,0xA0A00000 5811 long 0xC0030000,0xA35CE1A3,0xBB251DCB,0x20900000 5812 long 0xC0030000,0x96CBE3F9,0x990E91A8,0x21600000 5813 long 0xC0030000,0x8A3AE64F,0x76F80584,0xA1080000 5814 long 0xC0020000,0xFB53D14A,0xA9C2F2C2,0x1F800000 5815 long 0xC0020000,0xE231D5F6,0x6595DA7B,0xA0B00000 5816 long 0xC0020000,0xC90FDAA2,0x2168C235,0x20800000 5817 long 0xC0020000,0xAFEDDF4D,0xDD3BA9EE,0xA0200000 5818 long 0xC0020000,0x96CBE3F9,0x990E91A8,0x20E00000 5819 long 0xC0010000,0xFB53D14A,0xA9C2F2C2,0x1F000000 5820 long 0xC0010000,0xC90FDAA2,0x2168C235,0x20000000 5821 long 0xC0010000,0x96CBE3F9,0x990E91A8,0x20600000 5822 long 0xC0000000,0xC90FDAA2,0x2168C235,0x1F800000 5823 long 0xBFFF0000,0xC90FDAA2,0x2168C235,0x1F000000 5824 long 0x00000000,0x00000000,0x00000000,0x00000000 5825 long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x9F000000 5826 long 0x40000000,0xC90FDAA2,0x2168C235,0x9F800000 5827 long 0x40010000,0x96CBE3F9,0x990E91A8,0xA0600000 5828 long 0x40010000,0xC90FDAA2,0x2168C235,0xA0000000 5829 long 0x40010000,0xFB53D14A,0xA9C2F2C2,0x9F000000 5830 long 0x40020000,0x96CBE3F9,0x990E91A8,0xA0E00000 5831 long 0x40020000,0xAFEDDF4D,0xDD3BA9EE,0x20200000 5832 long 0x40020000,0xC90FDAA2,0x2168C235,0xA0800000 5833 long 0x40020000,0xE231D5F6,0x6595DA7B,0x20B00000 5834 long 0x40020000,0xFB53D14A,0xA9C2F2C2,0x9F800000 5835 long 0x40030000,0x8A3AE64F,0x76F80584,0x21080000 5836 long 0x40030000,0x96CBE3F9,0x990E91A8,0xA1600000 5837 long 0x40030000,0xA35CE1A3,0xBB251DCB,0xA0900000 5838 long 0x40030000,0xAFEDDF4D,0xDD3BA9EE,0x20A00000 5839 long 0x40030000,0xBC7EDCF7,0xFF523611,0x21680000 5840 long 0x40030000,0xC90FDAA2,0x2168C235,0xA1000000 5841 long 0x40030000,0xD5A0D84C,0x437F4E58,0x1FC00000 5842 long 0x40030000,0xE231D5F6,0x6595DA7B,0x21300000 5843 long 0x40030000,0xEEC2D3A0,0x87AC669F,0xA1380000 5844 long 0x40030000,0xFB53D14A,0xA9C2F2C2,0xA0000000 5845 long 0x40040000,0x83F2677A,0x65ECBF73,0xA1C40000 5846 long 0x40040000,0x8A3AE64F,0x76F80584,0x21880000 5847 long 0x40040000,0x90836524,0x88034B96,0xA0B00000 5848 long 0x40040000,0x96CBE3F9,0x990E91A8,0xA1E00000 5849 long 0x40040000,0x9D1462CE,0xAA19D7B9,0x21580000 5850 long 0x40040000,0xA35CE1A3,0xBB251DCB,0xA1100000 5851 long 0x40040000,0xA9A56078,0xCC3063DD,0xA1FC0000 5852 long 0x40040000,0xAFEDDF4D,0xDD3BA9EE,0x21200000 5853 long 0x40040000,0xB6365E22,0xEE46F000,0xA1480000 5854 long 0x40040000,0xBC7EDCF7,0xFF523611,0x21E80000 5855 long 0x40040000,0xC2C75BCD,0x105D7C23,0x20D00000 5856 long 0x40040000,0xC90FDAA2,0x2168C235,0xA1800000 5857 5858 set INARG,FP_SCR0 5859 5860 set TWOTO63,L_SCR1 5861 set INT,L_SCR1 5862 set ENDFLAG,L_SCR2 5863 5864 global stan 5865stan: 5866 fmov.x (%a0),%fp0 # LOAD INPUT 5867 5868 mov.l (%a0),%d1 5869 mov.w 4(%a0),%d1 5870 and.l &0x7FFFFFFF,%d1 5871 5872 cmp.l %d1,&0x3FD78000 # |X| >= 2**(-40)? 5873 bge.b TANOK1 5874 bra.w TANSM 5875TANOK1: 5876 cmp.l %d1,&0x4004BC7E # |X| < 15 PI? 5877 blt.b TANMAIN 5878 bra.w REDUCEX 5879 5880TANMAIN: 5881#--THIS IS THE USUAL CASE, |X| <= 15 PI. 5882#--THE ARGUMENT REDUCTION IS DONE BY TABLE LOOK UP. 5883 fmov.x %fp0,%fp1 5884 fmul.d TWOBYPI(%pc),%fp1 # X*2/PI 5885 5886 lea.l PITBL+0x200(%pc),%a1 # TABLE OF N*PI/2, N = -32,...,32 5887 5888 fmov.l %fp1,%d1 # CONVERT TO INTEGER 5889 5890 asl.l &4,%d1 5891 add.l %d1,%a1 # ADDRESS N*PIBY2 IN Y1, Y2 5892 5893 fsub.x (%a1)+,%fp0 # X-Y1 5894 5895 fsub.s (%a1),%fp0 # FP0 IS R = (X-Y1)-Y2 5896 5897 ror.l &5,%d1 5898 and.l &0x80000000,%d1 # D0 WAS ODD IFF D0 < 0 5899 5900TANCONT: 5901 fmovm.x &0x0c,-(%sp) # save fp2,fp3 5902 5903 cmp.l %d1,&0 5904 blt.w NODD 5905 5906 fmov.x %fp0,%fp1 5907 fmul.x %fp1,%fp1 # S = R*R 5908 5909 fmov.d TANQ4(%pc),%fp3 5910 fmov.d TANP3(%pc),%fp2 5911 5912 fmul.x %fp1,%fp3 # SQ4 5913 fmul.x %fp1,%fp2 # SP3 5914 5915 fadd.d TANQ3(%pc),%fp3 # Q3+SQ4 5916 fadd.x TANP2(%pc),%fp2 # P2+SP3 5917 5918 fmul.x %fp1,%fp3 # S(Q3+SQ4) 5919 fmul.x %fp1,%fp2 # S(P2+SP3) 5920 5921 fadd.x TANQ2(%pc),%fp3 # Q2+S(Q3+SQ4) 5922 fadd.x TANP1(%pc),%fp2 # P1+S(P2+SP3) 5923 5924 fmul.x %fp1,%fp3 # S(Q2+S(Q3+SQ4)) 5925 fmul.x %fp1,%fp2 # S(P1+S(P2+SP3)) 5926 5927 fadd.x TANQ1(%pc),%fp3 # Q1+S(Q2+S(Q3+SQ4)) 5928 fmul.x %fp0,%fp2 # RS(P1+S(P2+SP3)) 5929 5930 fmul.x %fp3,%fp1 # S(Q1+S(Q2+S(Q3+SQ4))) 5931 5932 fadd.x %fp2,%fp0 # R+RS(P1+S(P2+SP3)) 5933 5934 fadd.s &0x3F800000,%fp1 # 1+S(Q1+...) 5935 5936 fmovm.x (%sp)+,&0x30 # restore fp2,fp3 5937 5938 fmov.l %d0,%fpcr # restore users round mode,prec 5939 fdiv.x %fp1,%fp0 # last inst - possible exception set 5940 bra t_inx2 5941 5942NODD: 5943 fmov.x %fp0,%fp1 5944 fmul.x %fp0,%fp0 # S = R*R 5945 5946 fmov.d TANQ4(%pc),%fp3 5947 fmov.d TANP3(%pc),%fp2 5948 5949 fmul.x %fp0,%fp3 # SQ4 5950 fmul.x %fp0,%fp2 # SP3 5951 5952 fadd.d TANQ3(%pc),%fp3 # Q3+SQ4 5953 fadd.x TANP2(%pc),%fp2 # P2+SP3 5954 5955 fmul.x %fp0,%fp3 # S(Q3+SQ4) 5956 fmul.x %fp0,%fp2 # S(P2+SP3) 5957 5958 fadd.x TANQ2(%pc),%fp3 # Q2+S(Q3+SQ4) 5959 fadd.x TANP1(%pc),%fp2 # P1+S(P2+SP3) 5960 5961 fmul.x %fp0,%fp3 # S(Q2+S(Q3+SQ4)) 5962 fmul.x %fp0,%fp2 # S(P1+S(P2+SP3)) 5963 5964 fadd.x TANQ1(%pc),%fp3 # Q1+S(Q2+S(Q3+SQ4)) 5965 fmul.x %fp1,%fp2 # RS(P1+S(P2+SP3)) 5966 5967 fmul.x %fp3,%fp0 # S(Q1+S(Q2+S(Q3+SQ4))) 5968 5969 fadd.x %fp2,%fp1 # R+RS(P1+S(P2+SP3)) 5970 fadd.s &0x3F800000,%fp0 # 1+S(Q1+...) 5971 5972 fmovm.x (%sp)+,&0x30 # restore fp2,fp3 5973 5974 fmov.x %fp1,-(%sp) 5975 eor.l &0x80000000,(%sp) 5976 5977 fmov.l %d0,%fpcr # restore users round mode,prec 5978 fdiv.x (%sp)+,%fp0 # last inst - possible exception set 5979 bra t_inx2 5980 5981TANBORS: 5982#--IF |X| > 15PI, WE USE THE GENERAL ARGUMENT REDUCTION. 5983#--IF |X| < 2**(-40), RETURN X OR 1. 5984 cmp.l %d1,&0x3FFF8000 5985 bgt.b REDUCEX 5986 5987TANSM: 5988 fmov.x %fp0,-(%sp) 5989 fmov.l %d0,%fpcr # restore users round mode,prec 5990 mov.b &FMOV_OP,%d1 # last inst is MOVE 5991 fmov.x (%sp)+,%fp0 # last inst - posibble exception set 5992 bra t_catch 5993 5994 global stand 5995#--TAN(X) = X FOR DENORMALIZED X 5996stand: 5997 bra t_extdnrm 5998 5999#--WHEN REDUCEX IS USED, THE CODE WILL INEVITABLY BE SLOW. 6000#--THIS REDUCTION METHOD, HOWEVER, IS MUCH FASTER THAN USING 6001#--THE REMAINDER INSTRUCTION WHICH IS NOW IN SOFTWARE. 6002REDUCEX: 6003 fmovm.x &0x3c,-(%sp) # save {fp2-fp5} 6004 mov.l %d2,-(%sp) # save d2 6005 fmov.s &0x00000000,%fp1 # fp1 = 0 6006 6007#--If compact form of abs(arg) in d0=$7ffeffff, argument is so large that 6008#--there is a danger of unwanted overflow in first LOOP iteration. In this 6009#--case, reduce argument by one remainder step to make subsequent reduction 6010#--safe. 6011 cmp.l %d1,&0x7ffeffff # is arg dangerously large? 6012 bne.b LOOP # no 6013 6014# yes; create 2**16383*PI/2 6015 mov.w &0x7ffe,FP_SCR0_EX(%a6) 6016 mov.l &0xc90fdaa2,FP_SCR0_HI(%a6) 6017 clr.l FP_SCR0_LO(%a6) 6018 6019# create low half of 2**16383*PI/2 at FP_SCR1 6020 mov.w &0x7fdc,FP_SCR1_EX(%a6) 6021 mov.l &0x85a308d3,FP_SCR1_HI(%a6) 6022 clr.l FP_SCR1_LO(%a6) 6023 6024 ftest.x %fp0 # test sign of argument 6025 fblt.w red_neg 6026 6027 or.b &0x80,FP_SCR0_EX(%a6) # positive arg 6028 or.b &0x80,FP_SCR1_EX(%a6) 6029red_neg: 6030 fadd.x FP_SCR0(%a6),%fp0 # high part of reduction is exact 6031 fmov.x %fp0,%fp1 # save high result in fp1 6032 fadd.x FP_SCR1(%a6),%fp0 # low part of reduction 6033 fsub.x %fp0,%fp1 # determine low component of result 6034 fadd.x FP_SCR1(%a6),%fp1 # fp0/fp1 are reduced argument. 6035 6036#--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. 6037#--integer quotient will be stored in N 6038#--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) 6039LOOP: 6040 fmov.x %fp0,INARG(%a6) # +-2**K * F, 1 <= F < 2 6041 mov.w INARG(%a6),%d1 6042 mov.l %d1,%a1 # save a copy of D0 6043 and.l &0x00007FFF,%d1 6044 sub.l &0x00003FFF,%d1 # d0 = K 6045 cmp.l %d1,&28 6046 ble.b LASTLOOP 6047CONTLOOP: 6048 sub.l &27,%d1 # d0 = L := K-27 6049 mov.b &0,ENDFLAG(%a6) 6050 bra.b WORK 6051LASTLOOP: 6052 clr.l %d1 # d0 = L := 0 6053 mov.b &1,ENDFLAG(%a6) 6054 6055WORK: 6056#--FIND THE REMAINDER OF (R,r) W.R.T. 2**L * (PI/2). L IS SO CHOSEN 6057#--THAT INT( X * (2/PI) / 2**(L) ) < 2**29. 6058 6059#--CREATE 2**(-L) * (2/PI), SIGN(INARG)*2**(63), 6060#--2**L * (PIby2_1), 2**L * (PIby2_2) 6061 6062 mov.l &0x00003FFE,%d2 # BIASED EXP OF 2/PI 6063 sub.l %d1,%d2 # BIASED EXP OF 2**(-L)*(2/PI) 6064 6065 mov.l &0xA2F9836E,FP_SCR0_HI(%a6) 6066 mov.l &0x4E44152A,FP_SCR0_LO(%a6) 6067 mov.w %d2,FP_SCR0_EX(%a6) # FP_SCR0 = 2**(-L)*(2/PI) 6068 6069 fmov.x %fp0,%fp2 6070 fmul.x FP_SCR0(%a6),%fp2 # fp2 = X * 2**(-L)*(2/PI) 6071 6072#--WE MUST NOW FIND INT(FP2). SINCE WE NEED THIS VALUE IN 6073#--FLOATING POINT FORMAT, THE TWO FMOVE'S FMOVE.L FP <--> N 6074#--WILL BE TOO INEFFICIENT. THE WAY AROUND IT IS THAT 6075#--(SIGN(INARG)*2**63 + FP2) - SIGN(INARG)*2**63 WILL GIVE 6076#--US THE DESIRED VALUE IN FLOATING POINT. 6077 mov.l %a1,%d2 6078 swap %d2 6079 and.l &0x80000000,%d2 6080 or.l &0x5F000000,%d2 # d2 = SIGN(INARG)*2**63 IN SGL 6081 mov.l %d2,TWOTO63(%a6) 6082 fadd.s TWOTO63(%a6),%fp2 # THE FRACTIONAL PART OF FP1 IS ROUNDED 6083 fsub.s TWOTO63(%a6),%fp2 # fp2 = N 6084# fintrz.x %fp2,%fp2 6085 6086#--CREATING 2**(L)*Piby2_1 and 2**(L)*Piby2_2 6087 mov.l %d1,%d2 # d2 = L 6088 6089 add.l &0x00003FFF,%d2 # BIASED EXP OF 2**L * (PI/2) 6090 mov.w %d2,FP_SCR0_EX(%a6) 6091 mov.l &0xC90FDAA2,FP_SCR0_HI(%a6) 6092 clr.l FP_SCR0_LO(%a6) # FP_SCR0 = 2**(L) * Piby2_1 6093 6094 add.l &0x00003FDD,%d1 6095 mov.w %d1,FP_SCR1_EX(%a6) 6096 mov.l &0x85A308D3,FP_SCR1_HI(%a6) 6097 clr.l FP_SCR1_LO(%a6) # FP_SCR1 = 2**(L) * Piby2_2 6098 6099 mov.b ENDFLAG(%a6),%d1 6100 6101#--We are now ready to perform (R+r) - N*P1 - N*P2, P1 = 2**(L) * Piby2_1 and 6102#--P2 = 2**(L) * Piby2_2 6103 fmov.x %fp2,%fp4 # fp4 = N 6104 fmul.x FP_SCR0(%a6),%fp4 # fp4 = W = N*P1 6105 fmov.x %fp2,%fp5 # fp5 = N 6106 fmul.x FP_SCR1(%a6),%fp5 # fp5 = w = N*P2 6107 fmov.x %fp4,%fp3 # fp3 = W = N*P1 6108 6109#--we want P+p = W+w but |p| <= half ulp of P 6110#--Then, we need to compute A := R-P and a := r-p 6111 fadd.x %fp5,%fp3 # fp3 = P 6112 fsub.x %fp3,%fp4 # fp4 = W-P 6113 6114 fsub.x %fp3,%fp0 # fp0 = A := R - P 6115 fadd.x %fp5,%fp4 # fp4 = p = (W-P)+w 6116 6117 fmov.x %fp0,%fp3 # fp3 = A 6118 fsub.x %fp4,%fp1 # fp1 = a := r - p 6119 6120#--Now we need to normalize (A,a) to "new (R,r)" where R+r = A+a but 6121#--|r| <= half ulp of R. 6122 fadd.x %fp1,%fp0 # fp0 = R := A+a 6123#--No need to calculate r if this is the last loop 6124 cmp.b %d1,&0 6125 bgt.w RESTORE 6126 6127#--Need to calculate r 6128 fsub.x %fp0,%fp3 # fp3 = A-R 6129 fadd.x %fp3,%fp1 # fp1 = r := (A-R)+a 6130 bra.w LOOP 6131 6132RESTORE: 6133 fmov.l %fp2,INT(%a6) 6134 mov.l (%sp)+,%d2 # restore d2 6135 fmovm.x (%sp)+,&0x3c # restore {fp2-fp5} 6136 6137 mov.l INT(%a6),%d1 6138 ror.l &1,%d1 6139 6140 bra.w TANCONT 6141 6142######################################################################### 6143# satan(): computes the arctangent of a normalized number # 6144# satand(): computes the arctangent of a denormalized number # 6145# # 6146# INPUT *************************************************************** # 6147# a0 = pointer to extended precision input # 6148# d0 = round precision,mode # 6149# # 6150# OUTPUT ************************************************************** # 6151# fp0 = arctan(X) # 6152# # 6153# ACCURACY and MONOTONICITY ******************************************* # 6154# The returned result is within 2 ulps in 64 significant bit, # 6155# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 6156# rounded to double precision. The result is provably monotonic # 6157# in double precision. # 6158# # 6159# ALGORITHM *********************************************************** # 6160# Step 1. If |X| >= 16 or |X| < 1/16, go to Step 5. # 6161# # 6162# Step 2. Let X = sgn * 2**k * 1.xxxxxxxx...x. # 6163# Note that k = -4, -3,..., or 3. # 6164# Define F = sgn * 2**k * 1.xxxx1, i.e. the first 5 # 6165# significant bits of X with a bit-1 attached at the 6-th # 6166# bit position. Define u to be u = (X-F) / (1 + X*F). # 6167# # 6168# Step 3. Approximate arctan(u) by a polynomial poly. # 6169# # 6170# Step 4. Return arctan(F) + poly, arctan(F) is fetched from a # 6171# table of values calculated beforehand. Exit. # 6172# # 6173# Step 5. If |X| >= 16, go to Step 7. # 6174# # 6175# Step 6. Approximate arctan(X) by an odd polynomial in X. Exit. # 6176# # 6177# Step 7. Define X' = -1/X. Approximate arctan(X') by an odd # 6178# polynomial in X'. # 6179# Arctan(X) = sign(X)*Pi/2 + arctan(X'). Exit. # 6180# # 6181######################################################################### 6182 6183ATANA3: long 0xBFF6687E,0x314987D8 6184ATANA2: long 0x4002AC69,0x34A26DB3 6185ATANA1: long 0xBFC2476F,0x4E1DA28E 6186 6187ATANB6: long 0x3FB34444,0x7F876989 6188ATANB5: long 0xBFB744EE,0x7FAF45DB 6189ATANB4: long 0x3FBC71C6,0x46940220 6190ATANB3: long 0xBFC24924,0x921872F9 6191ATANB2: long 0x3FC99999,0x99998FA9 6192ATANB1: long 0xBFD55555,0x55555555 6193 6194ATANC5: long 0xBFB70BF3,0x98539E6A 6195ATANC4: long 0x3FBC7187,0x962D1D7D 6196ATANC3: long 0xBFC24924,0x827107B8 6197ATANC2: long 0x3FC99999,0x9996263E 6198ATANC1: long 0xBFD55555,0x55555536 6199 6200PPIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 6201NPIBY2: long 0xBFFF0000,0xC90FDAA2,0x2168C235,0x00000000 6202 6203PTINY: long 0x00010000,0x80000000,0x00000000,0x00000000 6204NTINY: long 0x80010000,0x80000000,0x00000000,0x00000000 6205 6206ATANTBL: 6207 long 0x3FFB0000,0x83D152C5,0x060B7A51,0x00000000 6208 long 0x3FFB0000,0x8BC85445,0x65498B8B,0x00000000 6209 long 0x3FFB0000,0x93BE4060,0x17626B0D,0x00000000 6210 long 0x3FFB0000,0x9BB3078D,0x35AEC202,0x00000000 6211 long 0x3FFB0000,0xA3A69A52,0x5DDCE7DE,0x00000000 6212 long 0x3FFB0000,0xAB98E943,0x62765619,0x00000000 6213 long 0x3FFB0000,0xB389E502,0xF9C59862,0x00000000 6214 long 0x3FFB0000,0xBB797E43,0x6B09E6FB,0x00000000 6215 long 0x3FFB0000,0xC367A5C7,0x39E5F446,0x00000000 6216 long 0x3FFB0000,0xCB544C61,0xCFF7D5C6,0x00000000 6217 long 0x3FFB0000,0xD33F62F8,0x2488533E,0x00000000 6218 long 0x3FFB0000,0xDB28DA81,0x62404C77,0x00000000 6219 long 0x3FFB0000,0xE310A407,0x8AD34F18,0x00000000 6220 long 0x3FFB0000,0xEAF6B0A8,0x188EE1EB,0x00000000 6221 long 0x3FFB0000,0xF2DAF194,0x9DBE79D5,0x00000000 6222 long 0x3FFB0000,0xFABD5813,0x61D47E3E,0x00000000 6223 long 0x3FFC0000,0x8346AC21,0x0959ECC4,0x00000000 6224 long 0x3FFC0000,0x8B232A08,0x304282D8,0x00000000 6225 long 0x3FFC0000,0x92FB70B8,0xD29AE2F9,0x00000000 6226 long 0x3FFC0000,0x9ACF476F,0x5CCD1CB4,0x00000000 6227 long 0x3FFC0000,0xA29E7630,0x4954F23F,0x00000000 6228 long 0x3FFC0000,0xAA68C5D0,0x8AB85230,0x00000000 6229 long 0x3FFC0000,0xB22DFFFD,0x9D539F83,0x00000000 6230 long 0x3FFC0000,0xB9EDEF45,0x3E900EA5,0x00000000 6231 long 0x3FFC0000,0xC1A85F1C,0xC75E3EA5,0x00000000 6232 long 0x3FFC0000,0xC95D1BE8,0x28138DE6,0x00000000 6233 long 0x3FFC0000,0xD10BF300,0x840D2DE4,0x00000000 6234 long 0x3FFC0000,0xD8B4B2BA,0x6BC05E7A,0x00000000 6235 long 0x3FFC0000,0xE0572A6B,0xB42335F6,0x00000000 6236 long 0x3FFC0000,0xE7F32A70,0xEA9CAA8F,0x00000000 6237 long 0x3FFC0000,0xEF888432,0x64ECEFAA,0x00000000 6238 long 0x3FFC0000,0xF7170A28,0xECC06666,0x00000000 6239 long 0x3FFD0000,0x812FD288,0x332DAD32,0x00000000 6240 long 0x3FFD0000,0x88A8D1B1,0x218E4D64,0x00000000 6241 long 0x3FFD0000,0x9012AB3F,0x23E4AEE8,0x00000000 6242 long 0x3FFD0000,0x976CC3D4,0x11E7F1B9,0x00000000 6243 long 0x3FFD0000,0x9EB68949,0x3889A227,0x00000000 6244 long 0x3FFD0000,0xA5EF72C3,0x4487361B,0x00000000 6245 long 0x3FFD0000,0xAD1700BA,0xF07A7227,0x00000000 6246 long 0x3FFD0000,0xB42CBCFA,0xFD37EFB7,0x00000000 6247 long 0x3FFD0000,0xBB303A94,0x0BA80F89,0x00000000 6248 long 0x3FFD0000,0xC22115C6,0xFCAEBBAF,0x00000000 6249 long 0x3FFD0000,0xC8FEF3E6,0x86331221,0x00000000 6250 long 0x3FFD0000,0xCFC98330,0xB4000C70,0x00000000 6251 long 0x3FFD0000,0xD6807AA1,0x102C5BF9,0x00000000 6252 long 0x3FFD0000,0xDD2399BC,0x31252AA3,0x00000000 6253 long 0x3FFD0000,0xE3B2A855,0x6B8FC517,0x00000000 6254 long 0x3FFD0000,0xEA2D764F,0x64315989,0x00000000 6255 long 0x3FFD0000,0xF3BF5BF8,0xBAD1A21D,0x00000000 6256 long 0x3FFE0000,0x801CE39E,0x0D205C9A,0x00000000 6257 long 0x3FFE0000,0x8630A2DA,0xDA1ED066,0x00000000 6258 long 0x3FFE0000,0x8C1AD445,0xF3E09B8C,0x00000000 6259 long 0x3FFE0000,0x91DB8F16,0x64F350E2,0x00000000 6260 long 0x3FFE0000,0x97731420,0x365E538C,0x00000000 6261 long 0x3FFE0000,0x9CE1C8E6,0xA0B8CDBA,0x00000000 6262 long 0x3FFE0000,0xA22832DB,0xCADAAE09,0x00000000 6263 long 0x3FFE0000,0xA746F2DD,0xB7602294,0x00000000 6264 long 0x3FFE0000,0xAC3EC0FB,0x997DD6A2,0x00000000 6265 long 0x3FFE0000,0xB110688A,0xEBDC6F6A,0x00000000 6266 long 0x3FFE0000,0xB5BCC490,0x59ECC4B0,0x00000000 6267 long 0x3FFE0000,0xBA44BC7D,0xD470782F,0x00000000 6268 long 0x3FFE0000,0xBEA94144,0xFD049AAC,0x00000000 6269 long 0x3FFE0000,0xC2EB4ABB,0x661628B6,0x00000000 6270 long 0x3FFE0000,0xC70BD54C,0xE602EE14,0x00000000 6271 long 0x3FFE0000,0xCD000549,0xADEC7159,0x00000000 6272 long 0x3FFE0000,0xD48457D2,0xD8EA4EA3,0x00000000 6273 long 0x3FFE0000,0xDB948DA7,0x12DECE3B,0x00000000 6274 long 0x3FFE0000,0xE23855F9,0x69E8096A,0x00000000 6275 long 0x3FFE0000,0xE8771129,0xC4353259,0x00000000 6276 long 0x3FFE0000,0xEE57C16E,0x0D379C0D,0x00000000 6277 long 0x3FFE0000,0xF3E10211,0xA87C3779,0x00000000 6278 long 0x3FFE0000,0xF919039D,0x758B8D41,0x00000000 6279 long 0x3FFE0000,0xFE058B8F,0x64935FB3,0x00000000 6280 long 0x3FFF0000,0x8155FB49,0x7B685D04,0x00000000 6281 long 0x3FFF0000,0x83889E35,0x49D108E1,0x00000000 6282 long 0x3FFF0000,0x859CFA76,0x511D724B,0x00000000 6283 long 0x3FFF0000,0x87952ECF,0xFF8131E7,0x00000000 6284 long 0x3FFF0000,0x89732FD1,0x9557641B,0x00000000 6285 long 0x3FFF0000,0x8B38CAD1,0x01932A35,0x00000000 6286 long 0x3FFF0000,0x8CE7A8D8,0x301EE6B5,0x00000000 6287 long 0x3FFF0000,0x8F46A39E,0x2EAE5281,0x00000000 6288 long 0x3FFF0000,0x922DA7D7,0x91888487,0x00000000 6289 long 0x3FFF0000,0x94D19FCB,0xDEDF5241,0x00000000 6290 long 0x3FFF0000,0x973AB944,0x19D2A08B,0x00000000 6291 long 0x3FFF0000,0x996FF00E,0x08E10B96,0x00000000 6292 long 0x3FFF0000,0x9B773F95,0x12321DA7,0x00000000 6293 long 0x3FFF0000,0x9D55CC32,0x0F935624,0x00000000 6294 long 0x3FFF0000,0x9F100575,0x006CC571,0x00000000 6295 long 0x3FFF0000,0xA0A9C290,0xD97CC06C,0x00000000 6296 long 0x3FFF0000,0xA22659EB,0xEBC0630A,0x00000000 6297 long 0x3FFF0000,0xA388B4AF,0xF6EF0EC9,0x00000000 6298 long 0x3FFF0000,0xA4D35F10,0x61D292C4,0x00000000 6299 long 0x3FFF0000,0xA60895DC,0xFBE3187E,0x00000000 6300 long 0x3FFF0000,0xA72A51DC,0x7367BEAC,0x00000000 6301 long 0x3FFF0000,0xA83A5153,0x0956168F,0x00000000 6302 long 0x3FFF0000,0xA93A2007,0x7539546E,0x00000000 6303 long 0x3FFF0000,0xAA9E7245,0x023B2605,0x00000000 6304 long 0x3FFF0000,0xAC4C84BA,0x6FE4D58F,0x00000000 6305 long 0x3FFF0000,0xADCE4A4A,0x606B9712,0x00000000 6306 long 0x3FFF0000,0xAF2A2DCD,0x8D263C9C,0x00000000 6307 long 0x3FFF0000,0xB0656F81,0xF22265C7,0x00000000 6308 long 0x3FFF0000,0xB1846515,0x0F71496A,0x00000000 6309 long 0x3FFF0000,0xB28AAA15,0x6F9ADA35,0x00000000 6310 long 0x3FFF0000,0xB37B44FF,0x3766B895,0x00000000 6311 long 0x3FFF0000,0xB458C3DC,0xE9630433,0x00000000 6312 long 0x3FFF0000,0xB525529D,0x562246BD,0x00000000 6313 long 0x3FFF0000,0xB5E2CCA9,0x5F9D88CC,0x00000000 6314 long 0x3FFF0000,0xB692CADA,0x7ACA1ADA,0x00000000 6315 long 0x3FFF0000,0xB736AEA7,0xA6925838,0x00000000 6316 long 0x3FFF0000,0xB7CFAB28,0x7E9F7B36,0x00000000 6317 long 0x3FFF0000,0xB85ECC66,0xCB219835,0x00000000 6318 long 0x3FFF0000,0xB8E4FD5A,0x20A593DA,0x00000000 6319 long 0x3FFF0000,0xB99F41F6,0x4AFF9BB5,0x00000000 6320 long 0x3FFF0000,0xBA7F1E17,0x842BBE7B,0x00000000 6321 long 0x3FFF0000,0xBB471285,0x7637E17D,0x00000000 6322 long 0x3FFF0000,0xBBFABE8A,0x4788DF6F,0x00000000 6323 long 0x3FFF0000,0xBC9D0FAD,0x2B689D79,0x00000000 6324 long 0x3FFF0000,0xBD306A39,0x471ECD86,0x00000000 6325 long 0x3FFF0000,0xBDB6C731,0x856AF18A,0x00000000 6326 long 0x3FFF0000,0xBE31CAC5,0x02E80D70,0x00000000 6327 long 0x3FFF0000,0xBEA2D55C,0xE33194E2,0x00000000 6328 long 0x3FFF0000,0xBF0B10B7,0xC03128F0,0x00000000 6329 long 0x3FFF0000,0xBF6B7A18,0xDACB778D,0x00000000 6330 long 0x3FFF0000,0xBFC4EA46,0x63FA18F6,0x00000000 6331 long 0x3FFF0000,0xC0181BDE,0x8B89A454,0x00000000 6332 long 0x3FFF0000,0xC065B066,0xCFBF6439,0x00000000 6333 long 0x3FFF0000,0xC0AE345F,0x56340AE6,0x00000000 6334 long 0x3FFF0000,0xC0F22291,0x9CB9E6A7,0x00000000 6335 6336 set X,FP_SCR0 6337 set XDCARE,X+2 6338 set XFRAC,X+4 6339 set XFRACLO,X+8 6340 6341 set ATANF,FP_SCR1 6342 set ATANFHI,ATANF+4 6343 set ATANFLO,ATANF+8 6344 6345 global satan 6346#--ENTRY POINT FOR ATAN(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S 6347satan: 6348 fmov.x (%a0),%fp0 # LOAD INPUT 6349 6350 mov.l (%a0),%d1 6351 mov.w 4(%a0),%d1 6352 fmov.x %fp0,X(%a6) 6353 and.l &0x7FFFFFFF,%d1 6354 6355 cmp.l %d1,&0x3FFB8000 # |X| >= 1/16? 6356 bge.b ATANOK1 6357 bra.w ATANSM 6358 6359ATANOK1: 6360 cmp.l %d1,&0x4002FFFF # |X| < 16 ? 6361 ble.b ATANMAIN 6362 bra.w ATANBIG 6363 6364#--THE MOST LIKELY CASE, |X| IN [1/16, 16). WE USE TABLE TECHNIQUE 6365#--THE IDEA IS ATAN(X) = ATAN(F) + ATAN( [X-F] / [1+XF] ). 6366#--SO IF F IS CHOSEN TO BE CLOSE TO X AND ATAN(F) IS STORED IN 6367#--A TABLE, ALL WE NEED IS TO APPROXIMATE ATAN(U) WHERE 6368#--U = (X-F)/(1+XF) IS SMALL (REMEMBER F IS CLOSE TO X). IT IS 6369#--TRUE THAT A DIVIDE IS NOW NEEDED, BUT THE APPROXIMATION FOR 6370#--ATAN(U) IS A VERY SHORT POLYNOMIAL AND THE INDEXING TO 6371#--FETCH F AND SAVING OF REGISTERS CAN BE ALL HIDED UNDER THE 6372#--DIVIDE. IN THE END THIS METHOD IS MUCH FASTER THAN A TRADITIONAL 6373#--ONE. NOTE ALSO THAT THE TRADITIONAL SCHEME THAT APPROXIMATE 6374#--ATAN(X) DIRECTLY WILL NEED TO USE A RATIONAL APPROXIMATION 6375#--(DIVISION NEEDED) ANYWAY BECAUSE A POLYNOMIAL APPROXIMATION 6376#--WILL INVOLVE A VERY LONG POLYNOMIAL. 6377 6378#--NOW WE SEE X AS +-2^K * 1.BBBBBBB....B <- 1. + 63 BITS 6379#--WE CHOSE F TO BE +-2^K * 1.BBBB1 6380#--THAT IS IT MATCHES THE EXPONENT AND FIRST 5 BITS OF X, THE 6381#--SIXTH BITS IS SET TO BE 1. SINCE K = -4, -3, ..., 3, THERE 6382#--ARE ONLY 8 TIMES 16 = 2^7 = 128 |F|'S. SINCE ATAN(-|F|) IS 6383#-- -ATAN(|F|), WE NEED TO STORE ONLY ATAN(|F|). 6384 6385ATANMAIN: 6386 6387 and.l &0xF8000000,XFRAC(%a6) # FIRST 5 BITS 6388 or.l &0x04000000,XFRAC(%a6) # SET 6-TH BIT TO 1 6389 mov.l &0x00000000,XFRACLO(%a6) # LOCATION OF X IS NOW F 6390 6391 fmov.x %fp0,%fp1 # FP1 IS X 6392 fmul.x X(%a6),%fp1 # FP1 IS X*F, NOTE THAT X*F > 0 6393 fsub.x X(%a6),%fp0 # FP0 IS X-F 6394 fadd.s &0x3F800000,%fp1 # FP1 IS 1 + X*F 6395 fdiv.x %fp1,%fp0 # FP0 IS U = (X-F)/(1+X*F) 6396 6397#--WHILE THE DIVISION IS TAKING ITS TIME, WE FETCH ATAN(|F|) 6398#--CREATE ATAN(F) AND STORE IT IN ATANF, AND 6399#--SAVE REGISTERS FP2. 6400 6401 mov.l %d2,-(%sp) # SAVE d2 TEMPORARILY 6402 mov.l %d1,%d2 # THE EXP AND 16 BITS OF X 6403 and.l &0x00007800,%d1 # 4 VARYING BITS OF F'S FRACTION 6404 and.l &0x7FFF0000,%d2 # EXPONENT OF F 6405 sub.l &0x3FFB0000,%d2 # K+4 6406 asr.l &1,%d2 6407 add.l %d2,%d1 # THE 7 BITS IDENTIFYING F 6408 asr.l &7,%d1 # INDEX INTO TBL OF ATAN(|F|) 6409 lea ATANTBL(%pc),%a1 6410 add.l %d1,%a1 # ADDRESS OF ATAN(|F|) 6411 mov.l (%a1)+,ATANF(%a6) 6412 mov.l (%a1)+,ATANFHI(%a6) 6413 mov.l (%a1)+,ATANFLO(%a6) # ATANF IS NOW ATAN(|F|) 6414 mov.l X(%a6),%d1 # LOAD SIGN AND EXPO. AGAIN 6415 and.l &0x80000000,%d1 # SIGN(F) 6416 or.l %d1,ATANF(%a6) # ATANF IS NOW SIGN(F)*ATAN(|F|) 6417 mov.l (%sp)+,%d2 # RESTORE d2 6418 6419#--THAT'S ALL I HAVE TO DO FOR NOW, 6420#--BUT ALAS, THE DIVIDE IS STILL CRANKING! 6421 6422#--U IN FP0, WE ARE NOW READY TO COMPUTE ATAN(U) AS 6423#--U + A1*U*V*(A2 + V*(A3 + V)), V = U*U 6424#--THE POLYNOMIAL MAY LOOK STRANGE, BUT IS NEVERTHELESS CORRECT. 6425#--THE NATURAL FORM IS U + U*V*(A1 + V*(A2 + V*A3)) 6426#--WHAT WE HAVE HERE IS MERELY A1 = A3, A2 = A1/A3, A3 = A2/A3. 6427#--THE REASON FOR THIS REARRANGEMENT IS TO MAKE THE INDEPENDENT 6428#--PARTS A1*U*V AND (A2 + ... STUFF) MORE LOAD-BALANCED 6429 6430 fmovm.x &0x04,-(%sp) # save fp2 6431 6432 fmov.x %fp0,%fp1 6433 fmul.x %fp1,%fp1 6434 fmov.d ATANA3(%pc),%fp2 6435 fadd.x %fp1,%fp2 # A3+V 6436 fmul.x %fp1,%fp2 # V*(A3+V) 6437 fmul.x %fp0,%fp1 # U*V 6438 fadd.d ATANA2(%pc),%fp2 # A2+V*(A3+V) 6439 fmul.d ATANA1(%pc),%fp1 # A1*U*V 6440 fmul.x %fp2,%fp1 # A1*U*V*(A2+V*(A3+V)) 6441 fadd.x %fp1,%fp0 # ATAN(U), FP1 RELEASED 6442 6443 fmovm.x (%sp)+,&0x20 # restore fp2 6444 6445 fmov.l %d0,%fpcr # restore users rnd mode,prec 6446 fadd.x ATANF(%a6),%fp0 # ATAN(X) 6447 bra t_inx2 6448 6449ATANBORS: 6450#--|X| IS IN d0 IN COMPACT FORM. FP1, d0 SAVED. 6451#--FP0 IS X AND |X| <= 1/16 OR |X| >= 16. 6452 cmp.l %d1,&0x3FFF8000 6453 bgt.w ATANBIG # I.E. |X| >= 16 6454 6455ATANSM: 6456#--|X| <= 1/16 6457#--IF |X| < 2^(-40), RETURN X AS ANSWER. OTHERWISE, APPROXIMATE 6458#--ATAN(X) BY X + X*Y*(B1+Y*(B2+Y*(B3+Y*(B4+Y*(B5+Y*B6))))) 6459#--WHICH IS X + X*Y*( [B1+Z*(B3+Z*B5)] + [Y*(B2+Z*(B4+Z*B6)] ) 6460#--WHERE Y = X*X, AND Z = Y*Y. 6461 6462 cmp.l %d1,&0x3FD78000 6463 blt.w ATANTINY 6464 6465#--COMPUTE POLYNOMIAL 6466 fmovm.x &0x0c,-(%sp) # save fp2/fp3 6467 6468 fmul.x %fp0,%fp0 # FPO IS Y = X*X 6469 6470 fmov.x %fp0,%fp1 6471 fmul.x %fp1,%fp1 # FP1 IS Z = Y*Y 6472 6473 fmov.d ATANB6(%pc),%fp2 6474 fmov.d ATANB5(%pc),%fp3 6475 6476 fmul.x %fp1,%fp2 # Z*B6 6477 fmul.x %fp1,%fp3 # Z*B5 6478 6479 fadd.d ATANB4(%pc),%fp2 # B4+Z*B6 6480 fadd.d ATANB3(%pc),%fp3 # B3+Z*B5 6481 6482 fmul.x %fp1,%fp2 # Z*(B4+Z*B6) 6483 fmul.x %fp3,%fp1 # Z*(B3+Z*B5) 6484 6485 fadd.d ATANB2(%pc),%fp2 # B2+Z*(B4+Z*B6) 6486 fadd.d ATANB1(%pc),%fp1 # B1+Z*(B3+Z*B5) 6487 6488 fmul.x %fp0,%fp2 # Y*(B2+Z*(B4+Z*B6)) 6489 fmul.x X(%a6),%fp0 # X*Y 6490 6491 fadd.x %fp2,%fp1 # [B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))] 6492 6493 fmul.x %fp1,%fp0 # X*Y*([B1+Z*(B3+Z*B5)]+[Y*(B2+Z*(B4+Z*B6))]) 6494 6495 fmovm.x (%sp)+,&0x30 # restore fp2/fp3 6496 6497 fmov.l %d0,%fpcr # restore users rnd mode,prec 6498 fadd.x X(%a6),%fp0 6499 bra t_inx2 6500 6501ATANTINY: 6502#--|X| < 2^(-40), ATAN(X) = X 6503 6504 fmov.l %d0,%fpcr # restore users rnd mode,prec 6505 mov.b &FMOV_OP,%d1 # last inst is MOVE 6506 fmov.x X(%a6),%fp0 # last inst - possible exception set 6507 6508 bra t_catch 6509 6510ATANBIG: 6511#--IF |X| > 2^(100), RETURN SIGN(X)*(PI/2 - TINY). OTHERWISE, 6512#--RETURN SIGN(X)*PI/2 + ATAN(-1/X). 6513 cmp.l %d1,&0x40638000 6514 bgt.w ATANHUGE 6515 6516#--APPROXIMATE ATAN(-1/X) BY 6517#--X'+X'*Y*(C1+Y*(C2+Y*(C3+Y*(C4+Y*C5)))), X' = -1/X, Y = X'*X' 6518#--THIS CAN BE RE-WRITTEN AS 6519#--X'+X'*Y*( [C1+Z*(C3+Z*C5)] + [Y*(C2+Z*C4)] ), Z = Y*Y. 6520 6521 fmovm.x &0x0c,-(%sp) # save fp2/fp3 6522 6523 fmov.s &0xBF800000,%fp1 # LOAD -1 6524 fdiv.x %fp0,%fp1 # FP1 IS -1/X 6525 6526#--DIVIDE IS STILL CRANKING 6527 6528 fmov.x %fp1,%fp0 # FP0 IS X' 6529 fmul.x %fp0,%fp0 # FP0 IS Y = X'*X' 6530 fmov.x %fp1,X(%a6) # X IS REALLY X' 6531 6532 fmov.x %fp0,%fp1 6533 fmul.x %fp1,%fp1 # FP1 IS Z = Y*Y 6534 6535 fmov.d ATANC5(%pc),%fp3 6536 fmov.d ATANC4(%pc),%fp2 6537 6538 fmul.x %fp1,%fp3 # Z*C5 6539 fmul.x %fp1,%fp2 # Z*B4 6540 6541 fadd.d ATANC3(%pc),%fp3 # C3+Z*C5 6542 fadd.d ATANC2(%pc),%fp2 # C2+Z*C4 6543 6544 fmul.x %fp3,%fp1 # Z*(C3+Z*C5), FP3 RELEASED 6545 fmul.x %fp0,%fp2 # Y*(C2+Z*C4) 6546 6547 fadd.d ATANC1(%pc),%fp1 # C1+Z*(C3+Z*C5) 6548 fmul.x X(%a6),%fp0 # X'*Y 6549 6550 fadd.x %fp2,%fp1 # [Y*(C2+Z*C4)]+[C1+Z*(C3+Z*C5)] 6551 6552 fmul.x %fp1,%fp0 # X'*Y*([B1+Z*(B3+Z*B5)] 6553# ... +[Y*(B2+Z*(B4+Z*B6))]) 6554 fadd.x X(%a6),%fp0 6555 6556 fmovm.x (%sp)+,&0x30 # restore fp2/fp3 6557 6558 fmov.l %d0,%fpcr # restore users rnd mode,prec 6559 tst.b (%a0) 6560 bpl.b pos_big 6561 6562neg_big: 6563 fadd.x NPIBY2(%pc),%fp0 6564 bra t_minx2 6565 6566pos_big: 6567 fadd.x PPIBY2(%pc),%fp0 6568 bra t_pinx2 6569 6570ATANHUGE: 6571#--RETURN SIGN(X)*(PIBY2 - TINY) = SIGN(X)*PIBY2 - SIGN(X)*TINY 6572 tst.b (%a0) 6573 bpl.b pos_huge 6574 6575neg_huge: 6576 fmov.x NPIBY2(%pc),%fp0 6577 fmov.l %d0,%fpcr 6578 fadd.x PTINY(%pc),%fp0 6579 bra t_minx2 6580 6581pos_huge: 6582 fmov.x PPIBY2(%pc),%fp0 6583 fmov.l %d0,%fpcr 6584 fadd.x NTINY(%pc),%fp0 6585 bra t_pinx2 6586 6587 global satand 6588#--ENTRY POINT FOR ATAN(X) FOR DENORMALIZED ARGUMENT 6589satand: 6590 bra t_extdnrm 6591 6592######################################################################### 6593# sasin(): computes the inverse sine of a normalized input # 6594# sasind(): computes the inverse sine of a denormalized input # 6595# # 6596# INPUT *************************************************************** # 6597# a0 = pointer to extended precision input # 6598# d0 = round precision,mode # 6599# # 6600# OUTPUT ************************************************************** # 6601# fp0 = arcsin(X) # 6602# # 6603# ACCURACY and MONOTONICITY ******************************************* # 6604# The returned result is within 3 ulps in 64 significant bit, # 6605# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 6606# rounded to double precision. The result is provably monotonic # 6607# in double precision. # 6608# # 6609# ALGORITHM *********************************************************** # 6610# # 6611# ASIN # 6612# 1. If |X| >= 1, go to 3. # 6613# # 6614# 2. (|X| < 1) Calculate asin(X) by # 6615# z := sqrt( [1-X][1+X] ) # 6616# asin(X) = atan( x / z ). # 6617# Exit. # 6618# # 6619# 3. If |X| > 1, go to 5. # 6620# # 6621# 4. (|X| = 1) sgn := sign(X), return asin(X) := sgn * Pi/2. Exit.# 6622# # 6623# 5. (|X| > 1) Generate an invalid operation by 0 * infinity. # 6624# Exit. # 6625# # 6626######################################################################### 6627 6628 global sasin 6629sasin: 6630 fmov.x (%a0),%fp0 # LOAD INPUT 6631 6632 mov.l (%a0),%d1 6633 mov.w 4(%a0),%d1 6634 and.l &0x7FFFFFFF,%d1 6635 cmp.l %d1,&0x3FFF8000 6636 bge.b ASINBIG 6637 6638# This catch is added here for the '060 QSP. Originally, the call to 6639# satan() would handle this case by causing the exception which would 6640# not be caught until gen_except(). Now, with the exceptions being 6641# detected inside of satan(), the exception would have been handled there 6642# instead of inside sasin() as expected. 6643 cmp.l %d1,&0x3FD78000 6644 blt.w ASINTINY 6645 6646#--THIS IS THE USUAL CASE, |X| < 1 6647#--ASIN(X) = ATAN( X / SQRT( (1-X)(1+X) ) ) 6648 6649ASINMAIN: 6650 fmov.s &0x3F800000,%fp1 6651 fsub.x %fp0,%fp1 # 1-X 6652 fmovm.x &0x4,-(%sp) # {fp2} 6653 fmov.s &0x3F800000,%fp2 6654 fadd.x %fp0,%fp2 # 1+X 6655 fmul.x %fp2,%fp1 # (1+X)(1-X) 6656 fmovm.x (%sp)+,&0x20 # {fp2} 6657 fsqrt.x %fp1 # SQRT([1-X][1+X]) 6658 fdiv.x %fp1,%fp0 # X/SQRT([1-X][1+X]) 6659 fmovm.x &0x01,-(%sp) # save X/SQRT(...) 6660 lea (%sp),%a0 # pass ptr to X/SQRT(...) 6661 bsr satan 6662 add.l &0xc,%sp # clear X/SQRT(...) from stack 6663 bra t_inx2 6664 6665ASINBIG: 6666 fabs.x %fp0 # |X| 6667 fcmp.s %fp0,&0x3F800000 6668 fbgt t_operr # cause an operr exception 6669 6670#--|X| = 1, ASIN(X) = +- PI/2. 6671ASINONE: 6672 fmov.x PIBY2(%pc),%fp0 6673 mov.l (%a0),%d1 6674 and.l &0x80000000,%d1 # SIGN BIT OF X 6675 or.l &0x3F800000,%d1 # +-1 IN SGL FORMAT 6676 mov.l %d1,-(%sp) # push SIGN(X) IN SGL-FMT 6677 fmov.l %d0,%fpcr 6678 fmul.s (%sp)+,%fp0 6679 bra t_inx2 6680 6681#--|X| < 2^(-40), ATAN(X) = X 6682ASINTINY: 6683 fmov.l %d0,%fpcr # restore users rnd mode,prec 6684 mov.b &FMOV_OP,%d1 # last inst is MOVE 6685 fmov.x (%a0),%fp0 # last inst - possible exception 6686 bra t_catch 6687 6688 global sasind 6689#--ASIN(X) = X FOR DENORMALIZED X 6690sasind: 6691 bra t_extdnrm 6692 6693######################################################################### 6694# sacos(): computes the inverse cosine of a normalized input # 6695# sacosd(): computes the inverse cosine of a denormalized input # 6696# # 6697# INPUT *************************************************************** # 6698# a0 = pointer to extended precision input # 6699# d0 = round precision,mode # 6700# # 6701# OUTPUT ************************************************************** # 6702# fp0 = arccos(X) # 6703# # 6704# ACCURACY and MONOTONICITY ******************************************* # 6705# The returned result is within 3 ulps in 64 significant bit, # 6706# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 6707# rounded to double precision. The result is provably monotonic # 6708# in double precision. # 6709# # 6710# ALGORITHM *********************************************************** # 6711# # 6712# ACOS # 6713# 1. If |X| >= 1, go to 3. # 6714# # 6715# 2. (|X| < 1) Calculate acos(X) by # 6716# z := (1-X) / (1+X) # 6717# acos(X) = 2 * atan( sqrt(z) ). # 6718# Exit. # 6719# # 6720# 3. If |X| > 1, go to 5. # 6721# # 6722# 4. (|X| = 1) If X > 0, return 0. Otherwise, return Pi. Exit. # 6723# # 6724# 5. (|X| > 1) Generate an invalid operation by 0 * infinity. # 6725# Exit. # 6726# # 6727######################################################################### 6728 6729 global sacos 6730sacos: 6731 fmov.x (%a0),%fp0 # LOAD INPUT 6732 6733 mov.l (%a0),%d1 # pack exp w/ upper 16 fraction 6734 mov.w 4(%a0),%d1 6735 and.l &0x7FFFFFFF,%d1 6736 cmp.l %d1,&0x3FFF8000 6737 bge.b ACOSBIG 6738 6739#--THIS IS THE USUAL CASE, |X| < 1 6740#--ACOS(X) = 2 * ATAN( SQRT( (1-X)/(1+X) ) ) 6741 6742ACOSMAIN: 6743 fmov.s &0x3F800000,%fp1 6744 fadd.x %fp0,%fp1 # 1+X 6745 fneg.x %fp0 # -X 6746 fadd.s &0x3F800000,%fp0 # 1-X 6747 fdiv.x %fp1,%fp0 # (1-X)/(1+X) 6748 fsqrt.x %fp0 # SQRT((1-X)/(1+X)) 6749 mov.l %d0,-(%sp) # save original users fpcr 6750 clr.l %d0 6751 fmovm.x &0x01,-(%sp) # save SQRT(...) to stack 6752 lea (%sp),%a0 # pass ptr to sqrt 6753 bsr satan # ATAN(SQRT([1-X]/[1+X])) 6754 add.l &0xc,%sp # clear SQRT(...) from stack 6755 6756 fmov.l (%sp)+,%fpcr # restore users round prec,mode 6757 fadd.x %fp0,%fp0 # 2 * ATAN( STUFF ) 6758 bra t_pinx2 6759 6760ACOSBIG: 6761 fabs.x %fp0 6762 fcmp.s %fp0,&0x3F800000 6763 fbgt t_operr # cause an operr exception 6764 6765#--|X| = 1, ACOS(X) = 0 OR PI 6766 tst.b (%a0) # is X positive or negative? 6767 bpl.b ACOSP1 6768 6769#--X = -1 6770#Returns PI and inexact exception 6771ACOSM1: 6772 fmov.x PI(%pc),%fp0 # load PI 6773 fmov.l %d0,%fpcr # load round mode,prec 6774 fadd.s &0x00800000,%fp0 # add a small value 6775 bra t_pinx2 6776 6777ACOSP1: 6778 bra ld_pzero # answer is positive zero 6779 6780 global sacosd 6781#--ACOS(X) = PI/2 FOR DENORMALIZED X 6782sacosd: 6783 fmov.l %d0,%fpcr # load user's rnd mode/prec 6784 fmov.x PIBY2(%pc),%fp0 6785 bra t_pinx2 6786 6787######################################################################### 6788# setox(): computes the exponential for a normalized input # 6789# setoxd(): computes the exponential for a denormalized input # 6790# setoxm1(): computes the exponential minus 1 for a normalized input # 6791# setoxm1d(): computes the exponential minus 1 for a denormalized input # 6792# # 6793# INPUT *************************************************************** # 6794# a0 = pointer to extended precision input # 6795# d0 = round precision,mode # 6796# # 6797# OUTPUT ************************************************************** # 6798# fp0 = exp(X) or exp(X)-1 # 6799# # 6800# ACCURACY and MONOTONICITY ******************************************* # 6801# The returned result is within 0.85 ulps in 64 significant bit, # 6802# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 6803# rounded to double precision. The result is provably monotonic # 6804# in double precision. # 6805# # 6806# ALGORITHM and IMPLEMENTATION **************************************** # 6807# # 6808# setoxd # 6809# ------ # 6810# Step 1. Set ans := 1.0 # 6811# # 6812# Step 2. Return ans := ans + sign(X)*2^(-126). Exit. # 6813# Notes: This will always generate one exception -- inexact. # 6814# # 6815# # 6816# setox # 6817# ----- # 6818# # 6819# Step 1. Filter out extreme cases of input argument. # 6820# 1.1 If |X| >= 2^(-65), go to Step 1.3. # 6821# 1.2 Go to Step 7. # 6822# 1.3 If |X| < 16380 log(2), go to Step 2. # 6823# 1.4 Go to Step 8. # 6824# Notes: The usual case should take the branches 1.1 -> 1.3 -> 2.# 6825# To avoid the use of floating-point comparisons, a # 6826# compact representation of |X| is used. This format is a # 6827# 32-bit integer, the upper (more significant) 16 bits # 6828# are the sign and biased exponent field of |X|; the # 6829# lower 16 bits are the 16 most significant fraction # 6830# (including the explicit bit) bits of |X|. Consequently, # 6831# the comparisons in Steps 1.1 and 1.3 can be performed # 6832# by integer comparison. Note also that the constant # 6833# 16380 log(2) used in Step 1.3 is also in the compact # 6834# form. Thus taking the branch to Step 2 guarantees # 6835# |X| < 16380 log(2). There is no harm to have a small # 6836# number of cases where |X| is less than, but close to, # 6837# 16380 log(2) and the branch to Step 9 is taken. # 6838# # 6839# Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). # 6840# 2.1 Set AdjFlag := 0 (indicates the branch 1.3 -> 2 # 6841# was taken) # 6842# 2.2 N := round-to-nearest-integer( X * 64/log2 ). # 6843# 2.3 Calculate J = N mod 64; so J = 0,1,2,..., # 6844# or 63. # 6845# 2.4 Calculate M = (N - J)/64; so N = 64M + J. # 6846# 2.5 Calculate the address of the stored value of # 6847# 2^(J/64). # 6848# 2.6 Create the value Scale = 2^M. # 6849# Notes: The calculation in 2.2 is really performed by # 6850# Z := X * constant # 6851# N := round-to-nearest-integer(Z) # 6852# where # 6853# constant := single-precision( 64/log 2 ). # 6854# # 6855# Using a single-precision constant avoids memory # 6856# access. Another effect of using a single-precision # 6857# "constant" is that the calculated value Z is # 6858# # 6859# Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24). # 6860# # 6861# This error has to be considered later in Steps 3 and 4. # 6862# # 6863# Step 3. Calculate X - N*log2/64. # 6864# 3.1 R := X + N*L1, # 6865# where L1 := single-precision(-log2/64). # 6866# 3.2 R := R + N*L2, # 6867# L2 := extended-precision(-log2/64 - L1).# 6868# Notes: a) The way L1 and L2 are chosen ensures L1+L2 # 6869# approximate the value -log2/64 to 88 bits of accuracy. # 6870# b) N*L1 is exact because N is no longer than 22 bits # 6871# and L1 is no longer than 24 bits. # 6872# c) The calculation X+N*L1 is also exact due to # 6873# cancellation. Thus, R is practically X+N(L1+L2) to full # 6874# 64 bits. # 6875# d) It is important to estimate how large can |R| be # 6876# after Step 3.2. # 6877# # 6878# N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24) # 6879# X*64/log2 (1+eps) = N + f, |f| <= 0.5 # 6880# X*64/log2 - N = f - eps*X 64/log2 # 6881# X - N*log2/64 = f*log2/64 - eps*X # 6882# # 6883# # 6884# Now |X| <= 16446 log2, thus # 6885# # 6886# |X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64 # 6887# <= 0.57 log2/64. # 6888# This bound will be used in Step 4. # 6889# # 6890# Step 4. Approximate exp(R)-1 by a polynomial # 6891# p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) # 6892# Notes: a) In order to reduce memory access, the coefficients # 6893# are made as "short" as possible: A1 (which is 1/2), A4 # 6894# and A5 are single precision; A2 and A3 are double # 6895# precision. # 6896# b) Even with the restrictions above, # 6897# |p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062. # 6898# Note that 0.0062 is slightly bigger than 0.57 log2/64. # 6899# c) To fully utilize the pipeline, p is separated into # 6900# two independent pieces of roughly equal complexities # 6901# p = [ R + R*S*(A2 + S*A4) ] + # 6902# [ S*(A1 + S*(A3 + S*A5)) ] # 6903# where S = R*R. # 6904# # 6905# Step 5. Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by # 6906# ans := T + ( T*p + t) # 6907# where T and t are the stored values for 2^(J/64). # 6908# Notes: 2^(J/64) is stored as T and t where T+t approximates # 6909# 2^(J/64) to roughly 85 bits; T is in extended precision # 6910# and t is in single precision. Note also that T is # 6911# rounded to 62 bits so that the last two bits of T are # 6912# zero. The reason for such a special form is that T-1, # 6913# T-2, and T-8 will all be exact --- a property that will # 6914# give much more accurate computation of the function # 6915# EXPM1. # 6916# # 6917# Step 6. Reconstruction of exp(X) # 6918# exp(X) = 2^M * 2^(J/64) * exp(R). # 6919# 6.1 If AdjFlag = 0, go to 6.3 # 6920# 6.2 ans := ans * AdjScale # 6921# 6.3 Restore the user FPCR # 6922# 6.4 Return ans := ans * Scale. Exit. # 6923# Notes: If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R, # 6924# |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will # 6925# neither overflow nor underflow. If AdjFlag = 1, that # 6926# means that # 6927# X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380. # 6928# Hence, exp(X) may overflow or underflow or neither. # 6929# When that is the case, AdjScale = 2^(M1) where M1 is # 6930# approximately M. Thus 6.2 will never cause # 6931# over/underflow. Possible exception in 6.4 is overflow # 6932# or underflow. The inexact exception is not generated in # 6933# 6.4. Although one can argue that the inexact flag # 6934# should always be raised, to simulate that exception # 6935# cost to much than the flag is worth in practical uses. # 6936# # 6937# Step 7. Return 1 + X. # 6938# 7.1 ans := X # 6939# 7.2 Restore user FPCR. # 6940# 7.3 Return ans := 1 + ans. Exit # 6941# Notes: For non-zero X, the inexact exception will always be # 6942# raised by 7.3. That is the only exception raised by 7.3.# 6943# Note also that we use the FMOVEM instruction to move X # 6944# in Step 7.1 to avoid unnecessary trapping. (Although # 6945# the FMOVEM may not seem relevant since X is normalized, # 6946# the precaution will be useful in the library version of # 6947# this code where the separate entry for denormalized # 6948# inputs will be done away with.) # 6949# # 6950# Step 8. Handle exp(X) where |X| >= 16380log2. # 6951# 8.1 If |X| > 16480 log2, go to Step 9. # 6952# (mimic 2.2 - 2.6) # 6953# 8.2 N := round-to-integer( X * 64/log2 ) # 6954# 8.3 Calculate J = N mod 64, J = 0,1,...,63 # 6955# 8.4 K := (N-J)/64, M1 := truncate(K/2), M = K-M1, # 6956# AdjFlag := 1. # 6957# 8.5 Calculate the address of the stored value # 6958# 2^(J/64). # 6959# 8.6 Create the values Scale = 2^M, AdjScale = 2^M1. # 6960# 8.7 Go to Step 3. # 6961# Notes: Refer to notes for 2.2 - 2.6. # 6962# # 6963# Step 9. Handle exp(X), |X| > 16480 log2. # 6964# 9.1 If X < 0, go to 9.3 # 6965# 9.2 ans := Huge, go to 9.4 # 6966# 9.3 ans := Tiny. # 6967# 9.4 Restore user FPCR. # 6968# 9.5 Return ans := ans * ans. Exit. # 6969# Notes: Exp(X) will surely overflow or underflow, depending on # 6970# X's sign. "Huge" and "Tiny" are respectively large/tiny # 6971# extended-precision numbers whose square over/underflow # 6972# with an inexact result. Thus, 9.5 always raises the # 6973# inexact together with either overflow or underflow. # 6974# # 6975# setoxm1d # 6976# -------- # 6977# # 6978# Step 1. Set ans := 0 # 6979# # 6980# Step 2. Return ans := X + ans. Exit. # 6981# Notes: This will return X with the appropriate rounding # 6982# precision prescribed by the user FPCR. # 6983# # 6984# setoxm1 # 6985# ------- # 6986# # 6987# Step 1. Check |X| # 6988# 1.1 If |X| >= 1/4, go to Step 1.3. # 6989# 1.2 Go to Step 7. # 6990# 1.3 If |X| < 70 log(2), go to Step 2. # 6991# 1.4 Go to Step 10. # 6992# Notes: The usual case should take the branches 1.1 -> 1.3 -> 2.# 6993# However, it is conceivable |X| can be small very often # 6994# because EXPM1 is intended to evaluate exp(X)-1 # 6995# accurately when |X| is small. For further details on # 6996# the comparisons, see the notes on Step 1 of setox. # 6997# # 6998# Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). # 6999# 2.1 N := round-to-nearest-integer( X * 64/log2 ). # 7000# 2.2 Calculate J = N mod 64; so J = 0,1,2,..., # 7001# or 63. # 7002# 2.3 Calculate M = (N - J)/64; so N = 64M + J. # 7003# 2.4 Calculate the address of the stored value of # 7004# 2^(J/64). # 7005# 2.5 Create the values Sc = 2^M and # 7006# OnebySc := -2^(-M). # 7007# Notes: See the notes on Step 2 of setox. # 7008# # 7009# Step 3. Calculate X - N*log2/64. # 7010# 3.1 R := X + N*L1, # 7011# where L1 := single-precision(-log2/64). # 7012# 3.2 R := R + N*L2, # 7013# L2 := extended-precision(-log2/64 - L1).# 7014# Notes: Applying the analysis of Step 3 of setox in this case # 7015# shows that |R| <= 0.0055 (note that |X| <= 70 log2 in # 7016# this case). # 7017# # 7018# Step 4. Approximate exp(R)-1 by a polynomial # 7019# p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6))))) # 7020# Notes: a) In order to reduce memory access, the coefficients # 7021# are made as "short" as possible: A1 (which is 1/2), A5 # 7022# and A6 are single precision; A2, A3 and A4 are double # 7023# precision. # 7024# b) Even with the restriction above, # 7025# |p - (exp(R)-1)| < |R| * 2^(-72.7) # 7026# for all |R| <= 0.0055. # 7027# c) To fully utilize the pipeline, p is separated into # 7028# two independent pieces of roughly equal complexity # 7029# p = [ R*S*(A2 + S*(A4 + S*A6)) ] + # 7030# [ R + S*(A1 + S*(A3 + S*A5)) ] # 7031# where S = R*R. # 7032# # 7033# Step 5. Compute 2^(J/64)*p by # 7034# p := T*p # 7035# where T and t are the stored values for 2^(J/64). # 7036# Notes: 2^(J/64) is stored as T and t where T+t approximates # 7037# 2^(J/64) to roughly 85 bits; T is in extended precision # 7038# and t is in single precision. Note also that T is # 7039# rounded to 62 bits so that the last two bits of T are # 7040# zero. The reason for such a special form is that T-1, # 7041# T-2, and T-8 will all be exact --- a property that will # 7042# be exploited in Step 6 below. The total relative error # 7043# in p is no bigger than 2^(-67.7) compared to the final # 7044# result. # 7045# # 7046# Step 6. Reconstruction of exp(X)-1 # 7047# exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ). # 7048# 6.1 If M <= 63, go to Step 6.3. # 7049# 6.2 ans := T + (p + (t + OnebySc)). Go to 6.6 # 7050# 6.3 If M >= -3, go to 6.5. # 7051# 6.4 ans := (T + (p + t)) + OnebySc. Go to 6.6 # 7052# 6.5 ans := (T + OnebySc) + (p + t). # 7053# 6.6 Restore user FPCR. # 7054# 6.7 Return ans := Sc * ans. Exit. # 7055# Notes: The various arrangements of the expressions give # 7056# accurate evaluations. # 7057# # 7058# Step 7. exp(X)-1 for |X| < 1/4. # 7059# 7.1 If |X| >= 2^(-65), go to Step 9. # 7060# 7.2 Go to Step 8. # 7061# # 7062# Step 8. Calculate exp(X)-1, |X| < 2^(-65). # 7063# 8.1 If |X| < 2^(-16312), goto 8.3 # 7064# 8.2 Restore FPCR; return ans := X - 2^(-16382). # 7065# Exit. # 7066# 8.3 X := X * 2^(140). # 7067# 8.4 Restore FPCR; ans := ans - 2^(-16382). # 7068# Return ans := ans*2^(140). Exit # 7069# Notes: The idea is to return "X - tiny" under the user # 7070# precision and rounding modes. To avoid unnecessary # 7071# inefficiency, we stay away from denormalized numbers # 7072# the best we can. For |X| >= 2^(-16312), the # 7073# straightforward 8.2 generates the inexact exception as # 7074# the case warrants. # 7075# # 7076# Step 9. Calculate exp(X)-1, |X| < 1/4, by a polynomial # 7077# p = X + X*X*(B1 + X*(B2 + ... + X*B12)) # 7078# Notes: a) In order to reduce memory access, the coefficients # 7079# are made as "short" as possible: B1 (which is 1/2), B9 # 7080# to B12 are single precision; B3 to B8 are double # 7081# precision; and B2 is double extended. # 7082# b) Even with the restriction above, # 7083# |p - (exp(X)-1)| < |X| 2^(-70.6) # 7084# for all |X| <= 0.251. # 7085# Note that 0.251 is slightly bigger than 1/4. # 7086# c) To fully preserve accuracy, the polynomial is # 7087# computed as # 7088# X + ( S*B1 + Q ) where S = X*X and # 7089# Q = X*S*(B2 + X*(B3 + ... + X*B12)) # 7090# d) To fully utilize the pipeline, Q is separated into # 7091# two independent pieces of roughly equal complexity # 7092# Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] + # 7093# [ S*S*(B3 + S*(B5 + ... + S*B11)) ] # 7094# # 7095# Step 10. Calculate exp(X)-1 for |X| >= 70 log 2. # 7096# 10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all # 7097# practical purposes. Therefore, go to Step 1 of setox. # 7098# 10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical # 7099# purposes. # 7100# ans := -1 # 7101# Restore user FPCR # 7102# Return ans := ans + 2^(-126). Exit. # 7103# Notes: 10.2 will always create an inexact and return -1 + tiny # 7104# in the user rounding precision and mode. # 7105# # 7106######################################################################### 7107 7108L2: long 0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000 7109 7110EEXPA3: long 0x3FA55555,0x55554CC1 7111EEXPA2: long 0x3FC55555,0x55554A54 7112 7113EM1A4: long 0x3F811111,0x11174385 7114EM1A3: long 0x3FA55555,0x55554F5A 7115 7116EM1A2: long 0x3FC55555,0x55555555,0x00000000,0x00000000 7117 7118EM1B8: long 0x3EC71DE3,0xA5774682 7119EM1B7: long 0x3EFA01A0,0x19D7CB68 7120 7121EM1B6: long 0x3F2A01A0,0x1A019DF3 7122EM1B5: long 0x3F56C16C,0x16C170E2 7123 7124EM1B4: long 0x3F811111,0x11111111 7125EM1B3: long 0x3FA55555,0x55555555 7126 7127EM1B2: long 0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB 7128 long 0x00000000 7129 7130TWO140: long 0x48B00000,0x00000000 7131TWON140: 7132 long 0x37300000,0x00000000 7133 7134EEXPTBL: 7135 long 0x3FFF0000,0x80000000,0x00000000,0x00000000 7136 long 0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B 7137 long 0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9 7138 long 0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369 7139 long 0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C 7140 long 0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F 7141 long 0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729 7142 long 0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF 7143 long 0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF 7144 long 0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA 7145 long 0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051 7146 long 0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029 7147 long 0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494 7148 long 0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0 7149 long 0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D 7150 long 0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537 7151 long 0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD 7152 long 0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087 7153 long 0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818 7154 long 0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D 7155 long 0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890 7156 long 0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C 7157 long 0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05 7158 long 0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126 7159 long 0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140 7160 long 0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA 7161 long 0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A 7162 long 0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC 7163 long 0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC 7164 long 0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610 7165 long 0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90 7166 long 0x3FFF0000,0xB311C412,0xA9112488,0x201F678A 7167 long 0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13 7168 long 0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30 7169 long 0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC 7170 long 0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6 7171 long 0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70 7172 long 0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518 7173 long 0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41 7174 long 0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B 7175 long 0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568 7176 long 0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E 7177 long 0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03 7178 long 0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D 7179 long 0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4 7180 long 0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C 7181 long 0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9 7182 long 0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21 7183 long 0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F 7184 long 0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F 7185 long 0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207 7186 long 0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175 7187 long 0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B 7188 long 0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5 7189 long 0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A 7190 long 0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22 7191 long 0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945 7192 long 0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B 7193 long 0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3 7194 long 0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05 7195 long 0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19 7196 long 0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5 7197 long 0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22 7198 long 0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A 7199 7200 set ADJFLAG,L_SCR2 7201 set SCALE,FP_SCR0 7202 set ADJSCALE,FP_SCR1 7203 set SC,FP_SCR0 7204 set ONEBYSC,FP_SCR1 7205 7206 global setox 7207setox: 7208#--entry point for EXP(X), here X is finite, non-zero, and not NaN's 7209 7210#--Step 1. 7211 mov.l (%a0),%d1 # load part of input X 7212 and.l &0x7FFF0000,%d1 # biased expo. of X 7213 cmp.l %d1,&0x3FBE0000 # 2^(-65) 7214 bge.b EXPC1 # normal case 7215 bra EXPSM 7216 7217EXPC1: 7218#--The case |X| >= 2^(-65) 7219 mov.w 4(%a0),%d1 # expo. and partial sig. of |X| 7220 cmp.l %d1,&0x400CB167 # 16380 log2 trunc. 16 bits 7221 blt.b EXPMAIN # normal case 7222 bra EEXPBIG 7223 7224EXPMAIN: 7225#--Step 2. 7226#--This is the normal branch: 2^(-65) <= |X| < 16380 log2. 7227 fmov.x (%a0),%fp0 # load input from (a0) 7228 7229 fmov.x %fp0,%fp1 7230 fmul.s &0x42B8AA3B,%fp0 # 64/log2 * X 7231 fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} 7232 mov.l &0,ADJFLAG(%a6) 7233 fmov.l %fp0,%d1 # N = int( X * 64/log2 ) 7234 lea EEXPTBL(%pc),%a1 7235 fmov.l %d1,%fp0 # convert to floating-format 7236 7237 mov.l %d1,L_SCR1(%a6) # save N temporarily 7238 and.l &0x3F,%d1 # D0 is J = N mod 64 7239 lsl.l &4,%d1 7240 add.l %d1,%a1 # address of 2^(J/64) 7241 mov.l L_SCR1(%a6),%d1 7242 asr.l &6,%d1 # D0 is M 7243 add.w &0x3FFF,%d1 # biased expo. of 2^(M) 7244 mov.w L2(%pc),L_SCR1(%a6) # prefetch L2, no need in CB 7245 7246EXPCONT1: 7247#--Step 3. 7248#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, 7249#--a0 points to 2^(J/64), D0 is biased expo. of 2^(M) 7250 fmov.x %fp0,%fp2 7251 fmul.s &0xBC317218,%fp0 # N * L1, L1 = lead(-log2/64) 7252 fmul.x L2(%pc),%fp2 # N * L2, L1+L2 = -log2/64 7253 fadd.x %fp1,%fp0 # X + N*L1 7254 fadd.x %fp2,%fp0 # fp0 is R, reduced arg. 7255 7256#--Step 4. 7257#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL 7258#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) 7259#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R 7260#--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))] 7261 7262 fmov.x %fp0,%fp1 7263 fmul.x %fp1,%fp1 # fp1 IS S = R*R 7264 7265 fmov.s &0x3AB60B70,%fp2 # fp2 IS A5 7266 7267 fmul.x %fp1,%fp2 # fp2 IS S*A5 7268 fmov.x %fp1,%fp3 7269 fmul.s &0x3C088895,%fp3 # fp3 IS S*A4 7270 7271 fadd.d EEXPA3(%pc),%fp2 # fp2 IS A3+S*A5 7272 fadd.d EEXPA2(%pc),%fp3 # fp3 IS A2+S*A4 7273 7274 fmul.x %fp1,%fp2 # fp2 IS S*(A3+S*A5) 7275 mov.w %d1,SCALE(%a6) # SCALE is 2^(M) in extended 7276 mov.l &0x80000000,SCALE+4(%a6) 7277 clr.l SCALE+8(%a6) 7278 7279 fmul.x %fp1,%fp3 # fp3 IS S*(A2+S*A4) 7280 7281 fadd.s &0x3F000000,%fp2 # fp2 IS A1+S*(A3+S*A5) 7282 fmul.x %fp0,%fp3 # fp3 IS R*S*(A2+S*A4) 7283 7284 fmul.x %fp1,%fp2 # fp2 IS S*(A1+S*(A3+S*A5)) 7285 fadd.x %fp3,%fp0 # fp0 IS R+R*S*(A2+S*A4), 7286 7287 fmov.x (%a1)+,%fp1 # fp1 is lead. pt. of 2^(J/64) 7288 fadd.x %fp2,%fp0 # fp0 is EXP(R) - 1 7289 7290#--Step 5 7291#--final reconstruction process 7292#--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) ) 7293 7294 fmul.x %fp1,%fp0 # 2^(J/64)*(Exp(R)-1) 7295 fmovm.x (%sp)+,&0x30 # fp2 restored {%fp2/%fp3} 7296 fadd.s (%a1),%fp0 # accurate 2^(J/64) 7297 7298 fadd.x %fp1,%fp0 # 2^(J/64) + 2^(J/64)*... 7299 mov.l ADJFLAG(%a6),%d1 7300 7301#--Step 6 7302 tst.l %d1 7303 beq.b NORMAL 7304ADJUST: 7305 fmul.x ADJSCALE(%a6),%fp0 7306NORMAL: 7307 fmov.l %d0,%fpcr # restore user FPCR 7308 mov.b &FMUL_OP,%d1 # last inst is MUL 7309 fmul.x SCALE(%a6),%fp0 # multiply 2^(M) 7310 bra t_catch 7311 7312EXPSM: 7313#--Step 7 7314 fmovm.x (%a0),&0x80 # load X 7315 fmov.l %d0,%fpcr 7316 fadd.s &0x3F800000,%fp0 # 1+X in user mode 7317 bra t_pinx2 7318 7319EEXPBIG: 7320#--Step 8 7321 cmp.l %d1,&0x400CB27C # 16480 log2 7322 bgt.b EXP2BIG 7323#--Steps 8.2 -- 8.6 7324 fmov.x (%a0),%fp0 # load input from (a0) 7325 7326 fmov.x %fp0,%fp1 7327 fmul.s &0x42B8AA3B,%fp0 # 64/log2 * X 7328 fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} 7329 mov.l &1,ADJFLAG(%a6) 7330 fmov.l %fp0,%d1 # N = int( X * 64/log2 ) 7331 lea EEXPTBL(%pc),%a1 7332 fmov.l %d1,%fp0 # convert to floating-format 7333 mov.l %d1,L_SCR1(%a6) # save N temporarily 7334 and.l &0x3F,%d1 # D0 is J = N mod 64 7335 lsl.l &4,%d1 7336 add.l %d1,%a1 # address of 2^(J/64) 7337 mov.l L_SCR1(%a6),%d1 7338 asr.l &6,%d1 # D0 is K 7339 mov.l %d1,L_SCR1(%a6) # save K temporarily 7340 asr.l &1,%d1 # D0 is M1 7341 sub.l %d1,L_SCR1(%a6) # a1 is M 7342 add.w &0x3FFF,%d1 # biased expo. of 2^(M1) 7343 mov.w %d1,ADJSCALE(%a6) # ADJSCALE := 2^(M1) 7344 mov.l &0x80000000,ADJSCALE+4(%a6) 7345 clr.l ADJSCALE+8(%a6) 7346 mov.l L_SCR1(%a6),%d1 # D0 is M 7347 add.w &0x3FFF,%d1 # biased expo. of 2^(M) 7348 bra.w EXPCONT1 # go back to Step 3 7349 7350EXP2BIG: 7351#--Step 9 7352 tst.b (%a0) # is X positive or negative? 7353 bmi t_unfl2 7354 bra t_ovfl2 7355 7356 global setoxd 7357setoxd: 7358#--entry point for EXP(X), X is denormalized 7359 mov.l (%a0),-(%sp) 7360 andi.l &0x80000000,(%sp) 7361 ori.l &0x00800000,(%sp) # sign(X)*2^(-126) 7362 7363 fmov.s &0x3F800000,%fp0 7364 7365 fmov.l %d0,%fpcr 7366 fadd.s (%sp)+,%fp0 7367 bra t_pinx2 7368 7369 global setoxm1 7370setoxm1: 7371#--entry point for EXPM1(X), here X is finite, non-zero, non-NaN 7372 7373#--Step 1. 7374#--Step 1.1 7375 mov.l (%a0),%d1 # load part of input X 7376 and.l &0x7FFF0000,%d1 # biased expo. of X 7377 cmp.l %d1,&0x3FFD0000 # 1/4 7378 bge.b EM1CON1 # |X| >= 1/4 7379 bra EM1SM 7380 7381EM1CON1: 7382#--Step 1.3 7383#--The case |X| >= 1/4 7384 mov.w 4(%a0),%d1 # expo. and partial sig. of |X| 7385 cmp.l %d1,&0x4004C215 # 70log2 rounded up to 16 bits 7386 ble.b EM1MAIN # 1/4 <= |X| <= 70log2 7387 bra EM1BIG 7388 7389EM1MAIN: 7390#--Step 2. 7391#--This is the case: 1/4 <= |X| <= 70 log2. 7392 fmov.x (%a0),%fp0 # load input from (a0) 7393 7394 fmov.x %fp0,%fp1 7395 fmul.s &0x42B8AA3B,%fp0 # 64/log2 * X 7396 fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} 7397 fmov.l %fp0,%d1 # N = int( X * 64/log2 ) 7398 lea EEXPTBL(%pc),%a1 7399 fmov.l %d1,%fp0 # convert to floating-format 7400 7401 mov.l %d1,L_SCR1(%a6) # save N temporarily 7402 and.l &0x3F,%d1 # D0 is J = N mod 64 7403 lsl.l &4,%d1 7404 add.l %d1,%a1 # address of 2^(J/64) 7405 mov.l L_SCR1(%a6),%d1 7406 asr.l &6,%d1 # D0 is M 7407 mov.l %d1,L_SCR1(%a6) # save a copy of M 7408 7409#--Step 3. 7410#--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, 7411#--a0 points to 2^(J/64), D0 and a1 both contain M 7412 fmov.x %fp0,%fp2 7413 fmul.s &0xBC317218,%fp0 # N * L1, L1 = lead(-log2/64) 7414 fmul.x L2(%pc),%fp2 # N * L2, L1+L2 = -log2/64 7415 fadd.x %fp1,%fp0 # X + N*L1 7416 fadd.x %fp2,%fp0 # fp0 is R, reduced arg. 7417 add.w &0x3FFF,%d1 # D0 is biased expo. of 2^M 7418 7419#--Step 4. 7420#--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL 7421#-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6))))) 7422#--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R 7423#--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))] 7424 7425 fmov.x %fp0,%fp1 7426 fmul.x %fp1,%fp1 # fp1 IS S = R*R 7427 7428 fmov.s &0x3950097B,%fp2 # fp2 IS a6 7429 7430 fmul.x %fp1,%fp2 # fp2 IS S*A6 7431 fmov.x %fp1,%fp3 7432 fmul.s &0x3AB60B6A,%fp3 # fp3 IS S*A5 7433 7434 fadd.d EM1A4(%pc),%fp2 # fp2 IS A4+S*A6 7435 fadd.d EM1A3(%pc),%fp3 # fp3 IS A3+S*A5 7436 mov.w %d1,SC(%a6) # SC is 2^(M) in extended 7437 mov.l &0x80000000,SC+4(%a6) 7438 clr.l SC+8(%a6) 7439 7440 fmul.x %fp1,%fp2 # fp2 IS S*(A4+S*A6) 7441 mov.l L_SCR1(%a6),%d1 # D0 is M 7442 neg.w %d1 # D0 is -M 7443 fmul.x %fp1,%fp3 # fp3 IS S*(A3+S*A5) 7444 add.w &0x3FFF,%d1 # biased expo. of 2^(-M) 7445 fadd.d EM1A2(%pc),%fp2 # fp2 IS A2+S*(A4+S*A6) 7446 fadd.s &0x3F000000,%fp3 # fp3 IS A1+S*(A3+S*A5) 7447 7448 fmul.x %fp1,%fp2 # fp2 IS S*(A2+S*(A4+S*A6)) 7449 or.w &0x8000,%d1 # signed/expo. of -2^(-M) 7450 mov.w %d1,ONEBYSC(%a6) # OnebySc is -2^(-M) 7451 mov.l &0x80000000,ONEBYSC+4(%a6) 7452 clr.l ONEBYSC+8(%a6) 7453 fmul.x %fp3,%fp1 # fp1 IS S*(A1+S*(A3+S*A5)) 7454 7455 fmul.x %fp0,%fp2 # fp2 IS R*S*(A2+S*(A4+S*A6)) 7456 fadd.x %fp1,%fp0 # fp0 IS R+S*(A1+S*(A3+S*A5)) 7457 7458 fadd.x %fp2,%fp0 # fp0 IS EXP(R)-1 7459 7460 fmovm.x (%sp)+,&0x30 # fp2 restored {%fp2/%fp3} 7461 7462#--Step 5 7463#--Compute 2^(J/64)*p 7464 7465 fmul.x (%a1),%fp0 # 2^(J/64)*(Exp(R)-1) 7466 7467#--Step 6 7468#--Step 6.1 7469 mov.l L_SCR1(%a6),%d1 # retrieve M 7470 cmp.l %d1,&63 7471 ble.b MLE63 7472#--Step 6.2 M >= 64 7473 fmov.s 12(%a1),%fp1 # fp1 is t 7474 fadd.x ONEBYSC(%a6),%fp1 # fp1 is t+OnebySc 7475 fadd.x %fp1,%fp0 # p+(t+OnebySc), fp1 released 7476 fadd.x (%a1),%fp0 # T+(p+(t+OnebySc)) 7477 bra EM1SCALE 7478MLE63: 7479#--Step 6.3 M <= 63 7480 cmp.l %d1,&-3 7481 bge.b MGEN3 7482MLTN3: 7483#--Step 6.4 M <= -4 7484 fadd.s 12(%a1),%fp0 # p+t 7485 fadd.x (%a1),%fp0 # T+(p+t) 7486 fadd.x ONEBYSC(%a6),%fp0 # OnebySc + (T+(p+t)) 7487 bra EM1SCALE 7488MGEN3: 7489#--Step 6.5 -3 <= M <= 63 7490 fmov.x (%a1)+,%fp1 # fp1 is T 7491 fadd.s (%a1),%fp0 # fp0 is p+t 7492 fadd.x ONEBYSC(%a6),%fp1 # fp1 is T+OnebySc 7493 fadd.x %fp1,%fp0 # (T+OnebySc)+(p+t) 7494 7495EM1SCALE: 7496#--Step 6.6 7497 fmov.l %d0,%fpcr 7498 fmul.x SC(%a6),%fp0 7499 bra t_inx2 7500 7501EM1SM: 7502#--Step 7 |X| < 1/4. 7503 cmp.l %d1,&0x3FBE0000 # 2^(-65) 7504 bge.b EM1POLY 7505 7506EM1TINY: 7507#--Step 8 |X| < 2^(-65) 7508 cmp.l %d1,&0x00330000 # 2^(-16312) 7509 blt.b EM12TINY 7510#--Step 8.2 7511 mov.l &0x80010000,SC(%a6) # SC is -2^(-16382) 7512 mov.l &0x80000000,SC+4(%a6) 7513 clr.l SC+8(%a6) 7514 fmov.x (%a0),%fp0 7515 fmov.l %d0,%fpcr 7516 mov.b &FADD_OP,%d1 # last inst is ADD 7517 fadd.x SC(%a6),%fp0 7518 bra t_catch 7519 7520EM12TINY: 7521#--Step 8.3 7522 fmov.x (%a0),%fp0 7523 fmul.d TWO140(%pc),%fp0 7524 mov.l &0x80010000,SC(%a6) 7525 mov.l &0x80000000,SC+4(%a6) 7526 clr.l SC+8(%a6) 7527 fadd.x SC(%a6),%fp0 7528 fmov.l %d0,%fpcr 7529 mov.b &FMUL_OP,%d1 # last inst is MUL 7530 fmul.d TWON140(%pc),%fp0 7531 bra t_catch 7532 7533EM1POLY: 7534#--Step 9 exp(X)-1 by a simple polynomial 7535 fmov.x (%a0),%fp0 # fp0 is X 7536 fmul.x %fp0,%fp0 # fp0 is S := X*X 7537 fmovm.x &0xc,-(%sp) # save fp2 {%fp2/%fp3} 7538 fmov.s &0x2F30CAA8,%fp1 # fp1 is B12 7539 fmul.x %fp0,%fp1 # fp1 is S*B12 7540 fmov.s &0x310F8290,%fp2 # fp2 is B11 7541 fadd.s &0x32D73220,%fp1 # fp1 is B10+S*B12 7542 7543 fmul.x %fp0,%fp2 # fp2 is S*B11 7544 fmul.x %fp0,%fp1 # fp1 is S*(B10 + ... 7545 7546 fadd.s &0x3493F281,%fp2 # fp2 is B9+S*... 7547 fadd.d EM1B8(%pc),%fp1 # fp1 is B8+S*... 7548 7549 fmul.x %fp0,%fp2 # fp2 is S*(B9+... 7550 fmul.x %fp0,%fp1 # fp1 is S*(B8+... 7551 7552 fadd.d EM1B7(%pc),%fp2 # fp2 is B7+S*... 7553 fadd.d EM1B6(%pc),%fp1 # fp1 is B6+S*... 7554 7555 fmul.x %fp0,%fp2 # fp2 is S*(B7+... 7556 fmul.x %fp0,%fp1 # fp1 is S*(B6+... 7557 7558 fadd.d EM1B5(%pc),%fp2 # fp2 is B5+S*... 7559 fadd.d EM1B4(%pc),%fp1 # fp1 is B4+S*... 7560 7561 fmul.x %fp0,%fp2 # fp2 is S*(B5+... 7562 fmul.x %fp0,%fp1 # fp1 is S*(B4+... 7563 7564 fadd.d EM1B3(%pc),%fp2 # fp2 is B3+S*... 7565 fadd.x EM1B2(%pc),%fp1 # fp1 is B2+S*... 7566 7567 fmul.x %fp0,%fp2 # fp2 is S*(B3+... 7568 fmul.x %fp0,%fp1 # fp1 is S*(B2+... 7569 7570 fmul.x %fp0,%fp2 # fp2 is S*S*(B3+...) 7571 fmul.x (%a0),%fp1 # fp1 is X*S*(B2... 7572 7573 fmul.s &0x3F000000,%fp0 # fp0 is S*B1 7574 fadd.x %fp2,%fp1 # fp1 is Q 7575 7576 fmovm.x (%sp)+,&0x30 # fp2 restored {%fp2/%fp3} 7577 7578 fadd.x %fp1,%fp0 # fp0 is S*B1+Q 7579 7580 fmov.l %d0,%fpcr 7581 fadd.x (%a0),%fp0 7582 bra t_inx2 7583 7584EM1BIG: 7585#--Step 10 |X| > 70 log2 7586 mov.l (%a0),%d1 7587 cmp.l %d1,&0 7588 bgt.w EXPC1 7589#--Step 10.2 7590 fmov.s &0xBF800000,%fp0 # fp0 is -1 7591 fmov.l %d0,%fpcr 7592 fadd.s &0x00800000,%fp0 # -1 + 2^(-126) 7593 bra t_minx2 7594 7595 global setoxm1d 7596setoxm1d: 7597#--entry point for EXPM1(X), here X is denormalized 7598#--Step 0. 7599 bra t_extdnrm 7600 7601######################################################################### 7602# sgetexp(): returns the exponent portion of the input argument. # 7603# The exponent bias is removed and the exponent value is # 7604# returned as an extended precision number in fp0. # 7605# sgetexpd(): handles denormalized numbers. # 7606# # 7607# sgetman(): extracts the mantissa of the input argument. The # 7608# mantissa is converted to an extended precision number w/ # 7609# an exponent of $3fff and is returned in fp0. The range of # 7610# the result is [1.0 - 2.0). # 7611# sgetmand(): handles denormalized numbers. # 7612# # 7613# INPUT *************************************************************** # 7614# a0 = pointer to extended precision input # 7615# # 7616# OUTPUT ************************************************************** # 7617# fp0 = exponent(X) or mantissa(X) # 7618# # 7619######################################################################### 7620 7621 global sgetexp 7622sgetexp: 7623 mov.w SRC_EX(%a0),%d0 # get the exponent 7624 bclr &0xf,%d0 # clear the sign bit 7625 subi.w &0x3fff,%d0 # subtract off the bias 7626 fmov.w %d0,%fp0 # return exp in fp0 7627 blt.b sgetexpn # it's negative 7628 rts 7629 7630sgetexpn: 7631 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 7632 rts 7633 7634 global sgetexpd 7635sgetexpd: 7636 bsr.l norm # normalize 7637 neg.w %d0 # new exp = -(shft amt) 7638 subi.w &0x3fff,%d0 # subtract off the bias 7639 fmov.w %d0,%fp0 # return exp in fp0 7640 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 7641 rts 7642 7643 global sgetman 7644sgetman: 7645 mov.w SRC_EX(%a0),%d0 # get the exp 7646 ori.w &0x7fff,%d0 # clear old exp 7647 bclr &0xe,%d0 # make it the new exp +-3fff 7648 7649# here, we build the result in a tmp location so as not to disturb the input 7650 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy to tmp loc 7651 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy to tmp loc 7652 mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent 7653 fmov.x FP_SCR0(%a6),%fp0 # put new value back in fp0 7654 bmi.b sgetmann # it's negative 7655 rts 7656 7657sgetmann: 7658 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 7659 rts 7660 7661# 7662# For denormalized numbers, shift the mantissa until the j-bit = 1, 7663# then load the exponent with +/1 $3fff. 7664# 7665 global sgetmand 7666sgetmand: 7667 bsr.l norm # normalize exponent 7668 bra.b sgetman 7669 7670######################################################################### 7671# scosh(): computes the hyperbolic cosine of a normalized input # 7672# scoshd(): computes the hyperbolic cosine of a denormalized input # 7673# # 7674# INPUT *************************************************************** # 7675# a0 = pointer to extended precision input # 7676# d0 = round precision,mode # 7677# # 7678# OUTPUT ************************************************************** # 7679# fp0 = cosh(X) # 7680# # 7681# ACCURACY and MONOTONICITY ******************************************* # 7682# The returned result is within 3 ulps in 64 significant bit, # 7683# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 7684# rounded to double precision. The result is provably monotonic # 7685# in double precision. # 7686# # 7687# ALGORITHM *********************************************************** # 7688# # 7689# COSH # 7690# 1. If |X| > 16380 log2, go to 3. # 7691# # 7692# 2. (|X| <= 16380 log2) Cosh(X) is obtained by the formulae # 7693# y = |X|, z = exp(Y), and # 7694# cosh(X) = (1/2)*( z + 1/z ). # 7695# Exit. # 7696# # 7697# 3. (|X| > 16380 log2). If |X| > 16480 log2, go to 5. # 7698# # 7699# 4. (16380 log2 < |X| <= 16480 log2) # 7700# cosh(X) = sign(X) * exp(|X|)/2. # 7701# However, invoking exp(|X|) may cause premature # 7702# overflow. Thus, we calculate sinh(X) as follows: # 7703# Y := |X| # 7704# Fact := 2**(16380) # 7705# Y' := Y - 16381 log2 # 7706# cosh(X) := Fact * exp(Y'). # 7707# Exit. # 7708# # 7709# 5. (|X| > 16480 log2) sinh(X) must overflow. Return # 7710# Huge*Huge to generate overflow and an infinity with # 7711# the appropriate sign. Huge is the largest finite number # 7712# in extended format. Exit. # 7713# # 7714######################################################################### 7715 7716TWO16380: 7717 long 0x7FFB0000,0x80000000,0x00000000,0x00000000 7718 7719 global scosh 7720scosh: 7721 fmov.x (%a0),%fp0 # LOAD INPUT 7722 7723 mov.l (%a0),%d1 7724 mov.w 4(%a0),%d1 7725 and.l &0x7FFFFFFF,%d1 7726 cmp.l %d1,&0x400CB167 7727 bgt.b COSHBIG 7728 7729#--THIS IS THE USUAL CASE, |X| < 16380 LOG2 7730#--COSH(X) = (1/2) * ( EXP(X) + 1/EXP(X) ) 7731 7732 fabs.x %fp0 # |X| 7733 7734 mov.l %d0,-(%sp) 7735 clr.l %d0 7736 fmovm.x &0x01,-(%sp) # save |X| to stack 7737 lea (%sp),%a0 # pass ptr to |X| 7738 bsr setox # FP0 IS EXP(|X|) 7739 add.l &0xc,%sp # erase |X| from stack 7740 fmul.s &0x3F000000,%fp0 # (1/2)EXP(|X|) 7741 mov.l (%sp)+,%d0 7742 7743 fmov.s &0x3E800000,%fp1 # (1/4) 7744 fdiv.x %fp0,%fp1 # 1/(2 EXP(|X|)) 7745 7746 fmov.l %d0,%fpcr 7747 mov.b &FADD_OP,%d1 # last inst is ADD 7748 fadd.x %fp1,%fp0 7749 bra t_catch 7750 7751COSHBIG: 7752 cmp.l %d1,&0x400CB2B3 7753 bgt.b COSHHUGE 7754 7755 fabs.x %fp0 7756 fsub.d T1(%pc),%fp0 # (|X|-16381LOG2_LEAD) 7757 fsub.d T2(%pc),%fp0 # |X| - 16381 LOG2, ACCURATE 7758 7759 mov.l %d0,-(%sp) 7760 clr.l %d0 7761 fmovm.x &0x01,-(%sp) # save fp0 to stack 7762 lea (%sp),%a0 # pass ptr to fp0 7763 bsr setox 7764 add.l &0xc,%sp # clear fp0 from stack 7765 mov.l (%sp)+,%d0 7766 7767 fmov.l %d0,%fpcr 7768 mov.b &FMUL_OP,%d1 # last inst is MUL 7769 fmul.x TWO16380(%pc),%fp0 7770 bra t_catch 7771 7772COSHHUGE: 7773 bra t_ovfl2 7774 7775 global scoshd 7776#--COSH(X) = 1 FOR DENORMALIZED X 7777scoshd: 7778 fmov.s &0x3F800000,%fp0 7779 7780 fmov.l %d0,%fpcr 7781 fadd.s &0x00800000,%fp0 7782 bra t_pinx2 7783 7784######################################################################### 7785# ssinh(): computes the hyperbolic sine of a normalized input # 7786# ssinhd(): computes the hyperbolic sine of a denormalized input # 7787# # 7788# INPUT *************************************************************** # 7789# a0 = pointer to extended precision input # 7790# d0 = round precision,mode # 7791# # 7792# OUTPUT ************************************************************** # 7793# fp0 = sinh(X) # 7794# # 7795# ACCURACY and MONOTONICITY ******************************************* # 7796# The returned result is within 3 ulps in 64 significant bit, # 7797# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 7798# rounded to double precision. The result is provably monotonic # 7799# in double precision. # 7800# # 7801# ALGORITHM *********************************************************** # 7802# # 7803# SINH # 7804# 1. If |X| > 16380 log2, go to 3. # 7805# # 7806# 2. (|X| <= 16380 log2) Sinh(X) is obtained by the formula # 7807# y = |X|, sgn = sign(X), and z = expm1(Y), # 7808# sinh(X) = sgn*(1/2)*( z + z/(1+z) ). # 7809# Exit. # 7810# # 7811# 3. If |X| > 16480 log2, go to 5. # 7812# # 7813# 4. (16380 log2 < |X| <= 16480 log2) # 7814# sinh(X) = sign(X) * exp(|X|)/2. # 7815# However, invoking exp(|X|) may cause premature overflow. # 7816# Thus, we calculate sinh(X) as follows: # 7817# Y := |X| # 7818# sgn := sign(X) # 7819# sgnFact := sgn * 2**(16380) # 7820# Y' := Y - 16381 log2 # 7821# sinh(X) := sgnFact * exp(Y'). # 7822# Exit. # 7823# # 7824# 5. (|X| > 16480 log2) sinh(X) must overflow. Return # 7825# sign(X)*Huge*Huge to generate overflow and an infinity with # 7826# the appropriate sign. Huge is the largest finite number in # 7827# extended format. Exit. # 7828# # 7829######################################################################### 7830 7831 global ssinh 7832ssinh: 7833 fmov.x (%a0),%fp0 # LOAD INPUT 7834 7835 mov.l (%a0),%d1 7836 mov.w 4(%a0),%d1 7837 mov.l %d1,%a1 # save (compacted) operand 7838 and.l &0x7FFFFFFF,%d1 7839 cmp.l %d1,&0x400CB167 7840 bgt.b SINHBIG 7841 7842#--THIS IS THE USUAL CASE, |X| < 16380 LOG2 7843#--Y = |X|, Z = EXPM1(Y), SINH(X) = SIGN(X)*(1/2)*( Z + Z/(1+Z) ) 7844 7845 fabs.x %fp0 # Y = |X| 7846 7847 movm.l &0x8040,-(%sp) # {a1/d0} 7848 fmovm.x &0x01,-(%sp) # save Y on stack 7849 lea (%sp),%a0 # pass ptr to Y 7850 clr.l %d0 7851 bsr setoxm1 # FP0 IS Z = EXPM1(Y) 7852 add.l &0xc,%sp # clear Y from stack 7853 fmov.l &0,%fpcr 7854 movm.l (%sp)+,&0x0201 # {a1/d0} 7855 7856 fmov.x %fp0,%fp1 7857 fadd.s &0x3F800000,%fp1 # 1+Z 7858 fmov.x %fp0,-(%sp) 7859 fdiv.x %fp1,%fp0 # Z/(1+Z) 7860 mov.l %a1,%d1 7861 and.l &0x80000000,%d1 7862 or.l &0x3F000000,%d1 7863 fadd.x (%sp)+,%fp0 7864 mov.l %d1,-(%sp) 7865 7866 fmov.l %d0,%fpcr 7867 mov.b &FMUL_OP,%d1 # last inst is MUL 7868 fmul.s (%sp)+,%fp0 # last fp inst - possible exceptions set 7869 bra t_catch 7870 7871SINHBIG: 7872 cmp.l %d1,&0x400CB2B3 7873 bgt t_ovfl 7874 fabs.x %fp0 7875 fsub.d T1(%pc),%fp0 # (|X|-16381LOG2_LEAD) 7876 mov.l &0,-(%sp) 7877 mov.l &0x80000000,-(%sp) 7878 mov.l %a1,%d1 7879 and.l &0x80000000,%d1 7880 or.l &0x7FFB0000,%d1 7881 mov.l %d1,-(%sp) # EXTENDED FMT 7882 fsub.d T2(%pc),%fp0 # |X| - 16381 LOG2, ACCURATE 7883 7884 mov.l %d0,-(%sp) 7885 clr.l %d0 7886 fmovm.x &0x01,-(%sp) # save fp0 on stack 7887 lea (%sp),%a0 # pass ptr to fp0 7888 bsr setox 7889 add.l &0xc,%sp # clear fp0 from stack 7890 7891 mov.l (%sp)+,%d0 7892 fmov.l %d0,%fpcr 7893 mov.b &FMUL_OP,%d1 # last inst is MUL 7894 fmul.x (%sp)+,%fp0 # possible exception 7895 bra t_catch 7896 7897 global ssinhd 7898#--SINH(X) = X FOR DENORMALIZED X 7899ssinhd: 7900 bra t_extdnrm 7901 7902######################################################################### 7903# stanh(): computes the hyperbolic tangent of a normalized input # 7904# stanhd(): computes the hyperbolic tangent of a denormalized input # 7905# # 7906# INPUT *************************************************************** # 7907# a0 = pointer to extended precision input # 7908# d0 = round precision,mode # 7909# # 7910# OUTPUT ************************************************************** # 7911# fp0 = tanh(X) # 7912# # 7913# ACCURACY and MONOTONICITY ******************************************* # 7914# The returned result is within 3 ulps in 64 significant bit, # 7915# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 7916# rounded to double precision. The result is provably monotonic # 7917# in double precision. # 7918# # 7919# ALGORITHM *********************************************************** # 7920# # 7921# TANH # 7922# 1. If |X| >= (5/2) log2 or |X| <= 2**(-40), go to 3. # 7923# # 7924# 2. (2**(-40) < |X| < (5/2) log2) Calculate tanh(X) by # 7925# sgn := sign(X), y := 2|X|, z := expm1(Y), and # 7926# tanh(X) = sgn*( z/(2+z) ). # 7927# Exit. # 7928# # 7929# 3. (|X| <= 2**(-40) or |X| >= (5/2) log2). If |X| < 1, # 7930# go to 7. # 7931# # 7932# 4. (|X| >= (5/2) log2) If |X| >= 50 log2, go to 6. # 7933# # 7934# 5. ((5/2) log2 <= |X| < 50 log2) Calculate tanh(X) by # 7935# sgn := sign(X), y := 2|X|, z := exp(Y), # 7936# tanh(X) = sgn - [ sgn*2/(1+z) ]. # 7937# Exit. # 7938# # 7939# 6. (|X| >= 50 log2) Tanh(X) = +-1 (round to nearest). Thus, we # 7940# calculate Tanh(X) by # 7941# sgn := sign(X), Tiny := 2**(-126), # 7942# tanh(X) := sgn - sgn*Tiny. # 7943# Exit. # 7944# # 7945# 7. (|X| < 2**(-40)). Tanh(X) = X. Exit. # 7946# # 7947######################################################################### 7948 7949 set X,FP_SCR0 7950 set XFRAC,X+4 7951 7952 set SGN,L_SCR3 7953 7954 set V,FP_SCR0 7955 7956 global stanh 7957stanh: 7958 fmov.x (%a0),%fp0 # LOAD INPUT 7959 7960 fmov.x %fp0,X(%a6) 7961 mov.l (%a0),%d1 7962 mov.w 4(%a0),%d1 7963 mov.l %d1,X(%a6) 7964 and.l &0x7FFFFFFF,%d1 7965 cmp.l %d1, &0x3fd78000 # is |X| < 2^(-40)? 7966 blt.w TANHBORS # yes 7967 cmp.l %d1, &0x3fffddce # is |X| > (5/2)LOG2? 7968 bgt.w TANHBORS # yes 7969 7970#--THIS IS THE USUAL CASE 7971#--Y = 2|X|, Z = EXPM1(Y), TANH(X) = SIGN(X) * Z / (Z+2). 7972 7973 mov.l X(%a6),%d1 7974 mov.l %d1,SGN(%a6) 7975 and.l &0x7FFF0000,%d1 7976 add.l &0x00010000,%d1 # EXPONENT OF 2|X| 7977 mov.l %d1,X(%a6) 7978 and.l &0x80000000,SGN(%a6) 7979 fmov.x X(%a6),%fp0 # FP0 IS Y = 2|X| 7980 7981 mov.l %d0,-(%sp) 7982 clr.l %d0 7983 fmovm.x &0x1,-(%sp) # save Y on stack 7984 lea (%sp),%a0 # pass ptr to Y 7985 bsr setoxm1 # FP0 IS Z = EXPM1(Y) 7986 add.l &0xc,%sp # clear Y from stack 7987 mov.l (%sp)+,%d0 7988 7989 fmov.x %fp0,%fp1 7990 fadd.s &0x40000000,%fp1 # Z+2 7991 mov.l SGN(%a6),%d1 7992 fmov.x %fp1,V(%a6) 7993 eor.l %d1,V(%a6) 7994 7995 fmov.l %d0,%fpcr # restore users round prec,mode 7996 fdiv.x V(%a6),%fp0 7997 bra t_inx2 7998 7999TANHBORS: 8000 cmp.l %d1,&0x3FFF8000 8001 blt.w TANHSM 8002 8003 cmp.l %d1,&0x40048AA1 8004 bgt.w TANHHUGE 8005 8006#-- (5/2) LOG2 < |X| < 50 LOG2, 8007#--TANH(X) = 1 - (2/[EXP(2X)+1]). LET Y = 2|X|, SGN = SIGN(X), 8008#--TANH(X) = SGN - SGN*2/[EXP(Y)+1]. 8009 8010 mov.l X(%a6),%d1 8011 mov.l %d1,SGN(%a6) 8012 and.l &0x7FFF0000,%d1 8013 add.l &0x00010000,%d1 # EXPO OF 2|X| 8014 mov.l %d1,X(%a6) # Y = 2|X| 8015 and.l &0x80000000,SGN(%a6) 8016 mov.l SGN(%a6),%d1 8017 fmov.x X(%a6),%fp0 # Y = 2|X| 8018 8019 mov.l %d0,-(%sp) 8020 clr.l %d0 8021 fmovm.x &0x01,-(%sp) # save Y on stack 8022 lea (%sp),%a0 # pass ptr to Y 8023 bsr setox # FP0 IS EXP(Y) 8024 add.l &0xc,%sp # clear Y from stack 8025 mov.l (%sp)+,%d0 8026 mov.l SGN(%a6),%d1 8027 fadd.s &0x3F800000,%fp0 # EXP(Y)+1 8028 8029 eor.l &0xC0000000,%d1 # -SIGN(X)*2 8030 fmov.s %d1,%fp1 # -SIGN(X)*2 IN SGL FMT 8031 fdiv.x %fp0,%fp1 # -SIGN(X)2 / [EXP(Y)+1 ] 8032 8033 mov.l SGN(%a6),%d1 8034 or.l &0x3F800000,%d1 # SGN 8035 fmov.s %d1,%fp0 # SGN IN SGL FMT 8036 8037 fmov.l %d0,%fpcr # restore users round prec,mode 8038 mov.b &FADD_OP,%d1 # last inst is ADD 8039 fadd.x %fp1,%fp0 8040 bra t_inx2 8041 8042TANHSM: 8043 fmov.l %d0,%fpcr # restore users round prec,mode 8044 mov.b &FMOV_OP,%d1 # last inst is MOVE 8045 fmov.x X(%a6),%fp0 # last inst - possible exception set 8046 bra t_catch 8047 8048#---RETURN SGN(X) - SGN(X)EPS 8049TANHHUGE: 8050 mov.l X(%a6),%d1 8051 and.l &0x80000000,%d1 8052 or.l &0x3F800000,%d1 8053 fmov.s %d1,%fp0 8054 and.l &0x80000000,%d1 8055 eor.l &0x80800000,%d1 # -SIGN(X)*EPS 8056 8057 fmov.l %d0,%fpcr # restore users round prec,mode 8058 fadd.s %d1,%fp0 8059 bra t_inx2 8060 8061 global stanhd 8062#--TANH(X) = X FOR DENORMALIZED X 8063stanhd: 8064 bra t_extdnrm 8065 8066######################################################################### 8067# slogn(): computes the natural logarithm of a normalized input # 8068# slognd(): computes the natural logarithm of a denormalized input # 8069# slognp1(): computes the log(1+X) of a normalized input # 8070# slognp1d(): computes the log(1+X) of a denormalized input # 8071# # 8072# INPUT *************************************************************** # 8073# a0 = pointer to extended precision input # 8074# d0 = round precision,mode # 8075# # 8076# OUTPUT ************************************************************** # 8077# fp0 = log(X) or log(1+X) # 8078# # 8079# ACCURACY and MONOTONICITY ******************************************* # 8080# The returned result is within 2 ulps in 64 significant bit, # 8081# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 8082# rounded to double precision. The result is provably monotonic # 8083# in double precision. # 8084# # 8085# ALGORITHM *********************************************************** # 8086# LOGN: # 8087# Step 1. If |X-1| < 1/16, approximate log(X) by an odd # 8088# polynomial in u, where u = 2(X-1)/(X+1). Otherwise, # 8089# move on to Step 2. # 8090# # 8091# Step 2. X = 2**k * Y where 1 <= Y < 2. Define F to be the first # 8092# seven significant bits of Y plus 2**(-7), i.e. # 8093# F = 1.xxxxxx1 in base 2 where the six "x" match those # 8094# of Y. Note that |Y-F| <= 2**(-7). # 8095# # 8096# Step 3. Define u = (Y-F)/F. Approximate log(1+u) by a # 8097# polynomial in u, log(1+u) = poly. # 8098# # 8099# Step 4. Reconstruct # 8100# log(X) = log( 2**k * Y ) = k*log(2) + log(F) + log(1+u) # 8101# by k*log(2) + (log(F) + poly). The values of log(F) are # 8102# calculated beforehand and stored in the program. # 8103# # 8104# lognp1: # 8105# Step 1: If |X| < 1/16, approximate log(1+X) by an odd # 8106# polynomial in u where u = 2X/(2+X). Otherwise, move on # 8107# to Step 2. # 8108# # 8109# Step 2: Let 1+X = 2**k * Y, where 1 <= Y < 2. Define F as done # 8110# in Step 2 of the algorithm for LOGN and compute # 8111# log(1+X) as k*log(2) + log(F) + poly where poly # 8112# approximates log(1+u), u = (Y-F)/F. # 8113# # 8114# Implementation Notes: # 8115# Note 1. There are 64 different possible values for F, thus 64 # 8116# log(F)'s need to be tabulated. Moreover, the values of # 8117# 1/F are also tabulated so that the division in (Y-F)/F # 8118# can be performed by a multiplication. # 8119# # 8120# Note 2. In Step 2 of lognp1, in order to preserved accuracy, # 8121# the value Y-F has to be calculated carefully when # 8122# 1/2 <= X < 3/2. # 8123# # 8124# Note 3. To fully exploit the pipeline, polynomials are usually # 8125# separated into two parts evaluated independently before # 8126# being added up. # 8127# # 8128######################################################################### 8129LOGOF2: 8130 long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000 8131 8132one: 8133 long 0x3F800000 8134zero: 8135 long 0x00000000 8136infty: 8137 long 0x7F800000 8138negone: 8139 long 0xBF800000 8140 8141LOGA6: 8142 long 0x3FC2499A,0xB5E4040B 8143LOGA5: 8144 long 0xBFC555B5,0x848CB7DB 8145 8146LOGA4: 8147 long 0x3FC99999,0x987D8730 8148LOGA3: 8149 long 0xBFCFFFFF,0xFF6F7E97 8150 8151LOGA2: 8152 long 0x3FD55555,0x555555A4 8153LOGA1: 8154 long 0xBFE00000,0x00000008 8155 8156LOGB5: 8157 long 0x3F175496,0xADD7DAD6 8158LOGB4: 8159 long 0x3F3C71C2,0xFE80C7E0 8160 8161LOGB3: 8162 long 0x3F624924,0x928BCCFF 8163LOGB2: 8164 long 0x3F899999,0x999995EC 8165 8166LOGB1: 8167 long 0x3FB55555,0x55555555 8168TWO: 8169 long 0x40000000,0x00000000 8170 8171LTHOLD: 8172 long 0x3f990000,0x80000000,0x00000000,0x00000000 8173 8174LOGTBL: 8175 long 0x3FFE0000,0xFE03F80F,0xE03F80FE,0x00000000 8176 long 0x3FF70000,0xFF015358,0x833C47E2,0x00000000 8177 long 0x3FFE0000,0xFA232CF2,0x52138AC0,0x00000000 8178 long 0x3FF90000,0xBDC8D83E,0xAD88D549,0x00000000 8179 long 0x3FFE0000,0xF6603D98,0x0F6603DA,0x00000000 8180 long 0x3FFA0000,0x9CF43DCF,0xF5EAFD48,0x00000000 8181 long 0x3FFE0000,0xF2B9D648,0x0F2B9D65,0x00000000 8182 long 0x3FFA0000,0xDA16EB88,0xCB8DF614,0x00000000 8183 long 0x3FFE0000,0xEF2EB71F,0xC4345238,0x00000000 8184 long 0x3FFB0000,0x8B29B775,0x1BD70743,0x00000000 8185 long 0x3FFE0000,0xEBBDB2A5,0xC1619C8C,0x00000000 8186 long 0x3FFB0000,0xA8D839F8,0x30C1FB49,0x00000000 8187 long 0x3FFE0000,0xE865AC7B,0x7603A197,0x00000000 8188 long 0x3FFB0000,0xC61A2EB1,0x8CD907AD,0x00000000 8189 long 0x3FFE0000,0xE525982A,0xF70C880E,0x00000000 8190 long 0x3FFB0000,0xE2F2A47A,0xDE3A18AF,0x00000000 8191 long 0x3FFE0000,0xE1FC780E,0x1FC780E2,0x00000000 8192 long 0x3FFB0000,0xFF64898E,0xDF55D551,0x00000000 8193 long 0x3FFE0000,0xDEE95C4C,0xA037BA57,0x00000000 8194 long 0x3FFC0000,0x8DB956A9,0x7B3D0148,0x00000000 8195 long 0x3FFE0000,0xDBEB61EE,0xD19C5958,0x00000000 8196 long 0x3FFC0000,0x9B8FE100,0xF47BA1DE,0x00000000 8197 long 0x3FFE0000,0xD901B203,0x6406C80E,0x00000000 8198 long 0x3FFC0000,0xA9372F1D,0x0DA1BD17,0x00000000 8199 long 0x3FFE0000,0xD62B80D6,0x2B80D62C,0x00000000 8200 long 0x3FFC0000,0xB6B07F38,0xCE90E46B,0x00000000 8201 long 0x3FFE0000,0xD3680D36,0x80D3680D,0x00000000 8202 long 0x3FFC0000,0xC3FD0329,0x06488481,0x00000000 8203 long 0x3FFE0000,0xD0B69FCB,0xD2580D0B,0x00000000 8204 long 0x3FFC0000,0xD11DE0FF,0x15AB18CA,0x00000000 8205 long 0x3FFE0000,0xCE168A77,0x25080CE1,0x00000000 8206 long 0x3FFC0000,0xDE1433A1,0x6C66B150,0x00000000 8207 long 0x3FFE0000,0xCB8727C0,0x65C393E0,0x00000000 8208 long 0x3FFC0000,0xEAE10B5A,0x7DDC8ADD,0x00000000 8209 long 0x3FFE0000,0xC907DA4E,0x871146AD,0x00000000 8210 long 0x3FFC0000,0xF7856E5E,0xE2C9B291,0x00000000 8211 long 0x3FFE0000,0xC6980C69,0x80C6980C,0x00000000 8212 long 0x3FFD0000,0x82012CA5,0xA68206D7,0x00000000 8213 long 0x3FFE0000,0xC4372F85,0x5D824CA6,0x00000000 8214 long 0x3FFD0000,0x882C5FCD,0x7256A8C5,0x00000000 8215 long 0x3FFE0000,0xC1E4BBD5,0x95F6E947,0x00000000 8216 long 0x3FFD0000,0x8E44C60B,0x4CCFD7DE,0x00000000 8217 long 0x3FFE0000,0xBFA02FE8,0x0BFA02FF,0x00000000 8218 long 0x3FFD0000,0x944AD09E,0xF4351AF6,0x00000000 8219 long 0x3FFE0000,0xBD691047,0x07661AA3,0x00000000 8220 long 0x3FFD0000,0x9A3EECD4,0xC3EAA6B2,0x00000000 8221 long 0x3FFE0000,0xBB3EE721,0xA54D880C,0x00000000 8222 long 0x3FFD0000,0xA0218434,0x353F1DE8,0x00000000 8223 long 0x3FFE0000,0xB92143FA,0x36F5E02E,0x00000000 8224 long 0x3FFD0000,0xA5F2FCAB,0xBBC506DA,0x00000000 8225 long 0x3FFE0000,0xB70FBB5A,0x19BE3659,0x00000000 8226 long 0x3FFD0000,0xABB3B8BA,0x2AD362A5,0x00000000 8227 long 0x3FFE0000,0xB509E68A,0x9B94821F,0x00000000 8228 long 0x3FFD0000,0xB1641795,0xCE3CA97B,0x00000000 8229 long 0x3FFE0000,0xB30F6352,0x8917C80B,0x00000000 8230 long 0x3FFD0000,0xB7047551,0x5D0F1C61,0x00000000 8231 long 0x3FFE0000,0xB11FD3B8,0x0B11FD3C,0x00000000 8232 long 0x3FFD0000,0xBC952AFE,0xEA3D13E1,0x00000000 8233 long 0x3FFE0000,0xAF3ADDC6,0x80AF3ADE,0x00000000 8234 long 0x3FFD0000,0xC2168ED0,0xF458BA4A,0x00000000 8235 long 0x3FFE0000,0xAD602B58,0x0AD602B6,0x00000000 8236 long 0x3FFD0000,0xC788F439,0xB3163BF1,0x00000000 8237 long 0x3FFE0000,0xAB8F69E2,0x8359CD11,0x00000000 8238 long 0x3FFD0000,0xCCECAC08,0xBF04565D,0x00000000 8239 long 0x3FFE0000,0xA9C84A47,0xA07F5638,0x00000000 8240 long 0x3FFD0000,0xD2420487,0x2DD85160,0x00000000 8241 long 0x3FFE0000,0xA80A80A8,0x0A80A80B,0x00000000 8242 long 0x3FFD0000,0xD7894992,0x3BC3588A,0x00000000 8243 long 0x3FFE0000,0xA655C439,0x2D7B73A8,0x00000000 8244 long 0x3FFD0000,0xDCC2C4B4,0x9887DACC,0x00000000 8245 long 0x3FFE0000,0xA4A9CF1D,0x96833751,0x00000000 8246 long 0x3FFD0000,0xE1EEBD3E,0x6D6A6B9E,0x00000000 8247 long 0x3FFE0000,0xA3065E3F,0xAE7CD0E0,0x00000000 8248 long 0x3FFD0000,0xE70D785C,0x2F9F5BDC,0x00000000 8249 long 0x3FFE0000,0xA16B312E,0xA8FC377D,0x00000000 8250 long 0x3FFD0000,0xEC1F392C,0x5179F283,0x00000000 8251 long 0x3FFE0000,0x9FD809FD,0x809FD80A,0x00000000 8252 long 0x3FFD0000,0xF12440D3,0xE36130E6,0x00000000 8253 long 0x3FFE0000,0x9E4CAD23,0xDD5F3A20,0x00000000 8254 long 0x3FFD0000,0xF61CCE92,0x346600BB,0x00000000 8255 long 0x3FFE0000,0x9CC8E160,0xC3FB19B9,0x00000000 8256 long 0x3FFD0000,0xFB091FD3,0x8145630A,0x00000000 8257 long 0x3FFE0000,0x9B4C6F9E,0xF03A3CAA,0x00000000 8258 long 0x3FFD0000,0xFFE97042,0xBFA4C2AD,0x00000000 8259 long 0x3FFE0000,0x99D722DA,0xBDE58F06,0x00000000 8260 long 0x3FFE0000,0x825EFCED,0x49369330,0x00000000 8261 long 0x3FFE0000,0x9868C809,0x868C8098,0x00000000 8262 long 0x3FFE0000,0x84C37A7A,0xB9A905C9,0x00000000 8263 long 0x3FFE0000,0x97012E02,0x5C04B809,0x00000000 8264 long 0x3FFE0000,0x87224C2E,0x8E645FB7,0x00000000 8265 long 0x3FFE0000,0x95A02568,0x095A0257,0x00000000 8266 long 0x3FFE0000,0x897B8CAC,0x9F7DE298,0x00000000 8267 long 0x3FFE0000,0x94458094,0x45809446,0x00000000 8268 long 0x3FFE0000,0x8BCF55DE,0xC4CD05FE,0x00000000 8269 long 0x3FFE0000,0x92F11384,0x0497889C,0x00000000 8270 long 0x3FFE0000,0x8E1DC0FB,0x89E125E5,0x00000000 8271 long 0x3FFE0000,0x91A2B3C4,0xD5E6F809,0x00000000 8272 long 0x3FFE0000,0x9066E68C,0x955B6C9B,0x00000000 8273 long 0x3FFE0000,0x905A3863,0x3E06C43B,0x00000000 8274 long 0x3FFE0000,0x92AADE74,0xC7BE59E0,0x00000000 8275 long 0x3FFE0000,0x8F1779D9,0xFDC3A219,0x00000000 8276 long 0x3FFE0000,0x94E9BFF6,0x15845643,0x00000000 8277 long 0x3FFE0000,0x8DDA5202,0x37694809,0x00000000 8278 long 0x3FFE0000,0x9723A1B7,0x20134203,0x00000000 8279 long 0x3FFE0000,0x8CA29C04,0x6514E023,0x00000000 8280 long 0x3FFE0000,0x995899C8,0x90EB8990,0x00000000 8281 long 0x3FFE0000,0x8B70344A,0x139BC75A,0x00000000 8282 long 0x3FFE0000,0x9B88BDAA,0x3A3DAE2F,0x00000000 8283 long 0x3FFE0000,0x8A42F870,0x5669DB46,0x00000000 8284 long 0x3FFE0000,0x9DB4224F,0xFFE1157C,0x00000000 8285 long 0x3FFE0000,0x891AC73A,0xE9819B50,0x00000000 8286 long 0x3FFE0000,0x9FDADC26,0x8B7A12DA,0x00000000 8287 long 0x3FFE0000,0x87F78087,0xF78087F8,0x00000000 8288 long 0x3FFE0000,0xA1FCFF17,0xCE733BD4,0x00000000 8289 long 0x3FFE0000,0x86D90544,0x7A34ACC6,0x00000000 8290 long 0x3FFE0000,0xA41A9E8F,0x5446FB9F,0x00000000 8291 long 0x3FFE0000,0x85BF3761,0x2CEE3C9B,0x00000000 8292 long 0x3FFE0000,0xA633CD7E,0x6771CD8B,0x00000000 8293 long 0x3FFE0000,0x84A9F9C8,0x084A9F9D,0x00000000 8294 long 0x3FFE0000,0xA8489E60,0x0B435A5E,0x00000000 8295 long 0x3FFE0000,0x83993052,0x3FBE3368,0x00000000 8296 long 0x3FFE0000,0xAA59233C,0xCCA4BD49,0x00000000 8297 long 0x3FFE0000,0x828CBFBE,0xB9A020A3,0x00000000 8298 long 0x3FFE0000,0xAC656DAE,0x6BCC4985,0x00000000 8299 long 0x3FFE0000,0x81848DA8,0xFAF0D277,0x00000000 8300 long 0x3FFE0000,0xAE6D8EE3,0x60BB2468,0x00000000 8301 long 0x3FFE0000,0x80808080,0x80808081,0x00000000 8302 long 0x3FFE0000,0xB07197A2,0x3C46C654,0x00000000 8303 8304 set ADJK,L_SCR1 8305 8306 set X,FP_SCR0 8307 set XDCARE,X+2 8308 set XFRAC,X+4 8309 8310 set F,FP_SCR1 8311 set FFRAC,F+4 8312 8313 set KLOG2,FP_SCR0 8314 8315 set SAVEU,FP_SCR0 8316 8317 global slogn 8318#--ENTRY POINT FOR LOG(X) FOR X FINITE, NON-ZERO, NOT NAN'S 8319slogn: 8320 fmov.x (%a0),%fp0 # LOAD INPUT 8321 mov.l &0x00000000,ADJK(%a6) 8322 8323LOGBGN: 8324#--FPCR SAVED AND CLEARED, INPUT IS 2^(ADJK)*FP0, FP0 CONTAINS 8325#--A FINITE, NON-ZERO, NORMALIZED NUMBER. 8326 8327 mov.l (%a0),%d1 8328 mov.w 4(%a0),%d1 8329 8330 mov.l (%a0),X(%a6) 8331 mov.l 4(%a0),X+4(%a6) 8332 mov.l 8(%a0),X+8(%a6) 8333 8334 cmp.l %d1,&0 # CHECK IF X IS NEGATIVE 8335 blt.w LOGNEG # LOG OF NEGATIVE ARGUMENT IS INVALID 8336# X IS POSITIVE, CHECK IF X IS NEAR 1 8337 cmp.l %d1,&0x3ffef07d # IS X < 15/16? 8338 blt.b LOGMAIN # YES 8339 cmp.l %d1,&0x3fff8841 # IS X > 17/16? 8340 ble.w LOGNEAR1 # NO 8341 8342LOGMAIN: 8343#--THIS SHOULD BE THE USUAL CASE, X NOT VERY CLOSE TO 1 8344 8345#--X = 2^(K) * Y, 1 <= Y < 2. THUS, Y = 1.XXXXXXXX....XX IN BINARY. 8346#--WE DEFINE F = 1.XXXXXX1, I.E. FIRST 7 BITS OF Y AND ATTACH A 1. 8347#--THE IDEA IS THAT LOG(X) = K*LOG2 + LOG(Y) 8348#-- = K*LOG2 + LOG(F) + LOG(1 + (Y-F)/F). 8349#--NOTE THAT U = (Y-F)/F IS VERY SMALL AND THUS APPROXIMATING 8350#--LOG(1+U) CAN BE VERY EFFICIENT. 8351#--ALSO NOTE THAT THE VALUE 1/F IS STORED IN A TABLE SO THAT NO 8352#--DIVISION IS NEEDED TO CALCULATE (Y-F)/F. 8353 8354#--GET K, Y, F, AND ADDRESS OF 1/F. 8355 asr.l &8,%d1 8356 asr.l &8,%d1 # SHIFTED 16 BITS, BIASED EXPO. OF X 8357 sub.l &0x3FFF,%d1 # THIS IS K 8358 add.l ADJK(%a6),%d1 # ADJUST K, ORIGINAL INPUT MAY BE DENORM. 8359 lea LOGTBL(%pc),%a0 # BASE ADDRESS OF 1/F AND LOG(F) 8360 fmov.l %d1,%fp1 # CONVERT K TO FLOATING-POINT FORMAT 8361 8362#--WHILE THE CONVERSION IS GOING ON, WE GET F AND ADDRESS OF 1/F 8363 mov.l &0x3FFF0000,X(%a6) # X IS NOW Y, I.E. 2^(-K)*X 8364 mov.l XFRAC(%a6),FFRAC(%a6) 8365 and.l &0xFE000000,FFRAC(%a6) # FIRST 7 BITS OF Y 8366 or.l &0x01000000,FFRAC(%a6) # GET F: ATTACH A 1 AT THE EIGHTH BIT 8367 mov.l FFRAC(%a6),%d1 # READY TO GET ADDRESS OF 1/F 8368 and.l &0x7E000000,%d1 8369 asr.l &8,%d1 8370 asr.l &8,%d1 8371 asr.l &4,%d1 # SHIFTED 20, D0 IS THE DISPLACEMENT 8372 add.l %d1,%a0 # A0 IS THE ADDRESS FOR 1/F 8373 8374 fmov.x X(%a6),%fp0 8375 mov.l &0x3fff0000,F(%a6) 8376 clr.l F+8(%a6) 8377 fsub.x F(%a6),%fp0 # Y-F 8378 fmovm.x &0xc,-(%sp) # SAVE FP2-3 WHILE FP0 IS NOT READY 8379#--SUMMARY: FP0 IS Y-F, A0 IS ADDRESS OF 1/F, FP1 IS K 8380#--REGISTERS SAVED: FPCR, FP1, FP2 8381 8382LP1CONT1: 8383#--AN RE-ENTRY POINT FOR LOGNP1 8384 fmul.x (%a0),%fp0 # FP0 IS U = (Y-F)/F 8385 fmul.x LOGOF2(%pc),%fp1 # GET K*LOG2 WHILE FP0 IS NOT READY 8386 fmov.x %fp0,%fp2 8387 fmul.x %fp2,%fp2 # FP2 IS V=U*U 8388 fmov.x %fp1,KLOG2(%a6) # PUT K*LOG2 IN MEMEORY, FREE FP1 8389 8390#--LOG(1+U) IS APPROXIMATED BY 8391#--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS 8392#--[U + V*(A1+V*(A3+V*A5))] + [U*V*(A2+V*(A4+V*A6))] 8393 8394 fmov.x %fp2,%fp3 8395 fmov.x %fp2,%fp1 8396 8397 fmul.d LOGA6(%pc),%fp1 # V*A6 8398 fmul.d LOGA5(%pc),%fp2 # V*A5 8399 8400 fadd.d LOGA4(%pc),%fp1 # A4+V*A6 8401 fadd.d LOGA3(%pc),%fp2 # A3+V*A5 8402 8403 fmul.x %fp3,%fp1 # V*(A4+V*A6) 8404 fmul.x %fp3,%fp2 # V*(A3+V*A5) 8405 8406 fadd.d LOGA2(%pc),%fp1 # A2+V*(A4+V*A6) 8407 fadd.d LOGA1(%pc),%fp2 # A1+V*(A3+V*A5) 8408 8409 fmul.x %fp3,%fp1 # V*(A2+V*(A4+V*A6)) 8410 add.l &16,%a0 # ADDRESS OF LOG(F) 8411 fmul.x %fp3,%fp2 # V*(A1+V*(A3+V*A5)) 8412 8413 fmul.x %fp0,%fp1 # U*V*(A2+V*(A4+V*A6)) 8414 fadd.x %fp2,%fp0 # U+V*(A1+V*(A3+V*A5)) 8415 8416 fadd.x (%a0),%fp1 # LOG(F)+U*V*(A2+V*(A4+V*A6)) 8417 fmovm.x (%sp)+,&0x30 # RESTORE FP2-3 8418 fadd.x %fp1,%fp0 # FP0 IS LOG(F) + LOG(1+U) 8419 8420 fmov.l %d0,%fpcr 8421 fadd.x KLOG2(%a6),%fp0 # FINAL ADD 8422 bra t_inx2 8423 8424 8425LOGNEAR1: 8426 8427# if the input is exactly equal to one, then exit through ld_pzero. 8428# if these 2 lines weren't here, the correct answer would be returned 8429# but the INEX2 bit would be set. 8430 fcmp.b %fp0,&0x1 # is it equal to one? 8431 fbeq.l ld_pzero # yes 8432 8433#--REGISTERS SAVED: FPCR, FP1. FP0 CONTAINS THE INPUT. 8434 fmov.x %fp0,%fp1 8435 fsub.s one(%pc),%fp1 # FP1 IS X-1 8436 fadd.s one(%pc),%fp0 # FP0 IS X+1 8437 fadd.x %fp1,%fp1 # FP1 IS 2(X-1) 8438#--LOG(X) = LOG(1+U/2)-LOG(1-U/2) WHICH IS AN ODD POLYNOMIAL 8439#--IN U, U = 2(X-1)/(X+1) = FP1/FP0 8440 8441LP1CONT2: 8442#--THIS IS AN RE-ENTRY POINT FOR LOGNP1 8443 fdiv.x %fp0,%fp1 # FP1 IS U 8444 fmovm.x &0xc,-(%sp) # SAVE FP2-3 8445#--REGISTERS SAVED ARE NOW FPCR,FP1,FP2,FP3 8446#--LET V=U*U, W=V*V, CALCULATE 8447#--U + U*V*(B1 + V*(B2 + V*(B3 + V*(B4 + V*B5)))) BY 8448#--U + U*V*( [B1 + W*(B3 + W*B5)] + [V*(B2 + W*B4)] ) 8449 fmov.x %fp1,%fp0 8450 fmul.x %fp0,%fp0 # FP0 IS V 8451 fmov.x %fp1,SAVEU(%a6) # STORE U IN MEMORY, FREE FP1 8452 fmov.x %fp0,%fp1 8453 fmul.x %fp1,%fp1 # FP1 IS W 8454 8455 fmov.d LOGB5(%pc),%fp3 8456 fmov.d LOGB4(%pc),%fp2 8457 8458 fmul.x %fp1,%fp3 # W*B5 8459 fmul.x %fp1,%fp2 # W*B4 8460 8461 fadd.d LOGB3(%pc),%fp3 # B3+W*B5 8462 fadd.d LOGB2(%pc),%fp2 # B2+W*B4 8463 8464 fmul.x %fp3,%fp1 # W*(B3+W*B5), FP3 RELEASED 8465 8466 fmul.x %fp0,%fp2 # V*(B2+W*B4) 8467 8468 fadd.d LOGB1(%pc),%fp1 # B1+W*(B3+W*B5) 8469 fmul.x SAVEU(%a6),%fp0 # FP0 IS U*V 8470 8471 fadd.x %fp2,%fp1 # B1+W*(B3+W*B5) + V*(B2+W*B4), FP2 RELEASED 8472 fmovm.x (%sp)+,&0x30 # FP2-3 RESTORED 8473 8474 fmul.x %fp1,%fp0 # U*V*( [B1+W*(B3+W*B5)] + [V*(B2+W*B4)] ) 8475 8476 fmov.l %d0,%fpcr 8477 fadd.x SAVEU(%a6),%fp0 8478 bra t_inx2 8479 8480#--REGISTERS SAVED FPCR. LOG(-VE) IS INVALID 8481LOGNEG: 8482 bra t_operr 8483 8484 global slognd 8485slognd: 8486#--ENTRY POINT FOR LOG(X) FOR DENORMALIZED INPUT 8487 8488 mov.l &-100,ADJK(%a6) # INPUT = 2^(ADJK) * FP0 8489 8490#----normalize the input value by left shifting k bits (k to be determined 8491#----below), adjusting exponent and storing -k to ADJK 8492#----the value TWOTO100 is no longer needed. 8493#----Note that this code assumes the denormalized input is NON-ZERO. 8494 8495 movm.l &0x3f00,-(%sp) # save some registers {d2-d7} 8496 mov.l (%a0),%d3 # D3 is exponent of smallest norm. # 8497 mov.l 4(%a0),%d4 8498 mov.l 8(%a0),%d5 # (D4,D5) is (Hi_X,Lo_X) 8499 clr.l %d2 # D2 used for holding K 8500 8501 tst.l %d4 8502 bne.b Hi_not0 8503 8504Hi_0: 8505 mov.l %d5,%d4 8506 clr.l %d5 8507 mov.l &32,%d2 8508 clr.l %d6 8509 bfffo %d4{&0:&32},%d6 8510 lsl.l %d6,%d4 8511 add.l %d6,%d2 # (D3,D4,D5) is normalized 8512 8513 mov.l %d3,X(%a6) 8514 mov.l %d4,XFRAC(%a6) 8515 mov.l %d5,XFRAC+4(%a6) 8516 neg.l %d2 8517 mov.l %d2,ADJK(%a6) 8518 fmov.x X(%a6),%fp0 8519 movm.l (%sp)+,&0xfc # restore registers {d2-d7} 8520 lea X(%a6),%a0 8521 bra.w LOGBGN # begin regular log(X) 8522 8523Hi_not0: 8524 clr.l %d6 8525 bfffo %d4{&0:&32},%d6 # find first 1 8526 mov.l %d6,%d2 # get k 8527 lsl.l %d6,%d4 8528 mov.l %d5,%d7 # a copy of D5 8529 lsl.l %d6,%d5 8530 neg.l %d6 8531 add.l &32,%d6 8532 lsr.l %d6,%d7 8533 or.l %d7,%d4 # (D3,D4,D5) normalized 8534 8535 mov.l %d3,X(%a6) 8536 mov.l %d4,XFRAC(%a6) 8537 mov.l %d5,XFRAC+4(%a6) 8538 neg.l %d2 8539 mov.l %d2,ADJK(%a6) 8540 fmov.x X(%a6),%fp0 8541 movm.l (%sp)+,&0xfc # restore registers {d2-d7} 8542 lea X(%a6),%a0 8543 bra.w LOGBGN # begin regular log(X) 8544 8545 global slognp1 8546#--ENTRY POINT FOR LOG(1+X) FOR X FINITE, NON-ZERO, NOT NAN'S 8547slognp1: 8548 fmov.x (%a0),%fp0 # LOAD INPUT 8549 fabs.x %fp0 # test magnitude 8550 fcmp.x %fp0,LTHOLD(%pc) # compare with min threshold 8551 fbgt.w LP1REAL # if greater, continue 8552 fmov.l %d0,%fpcr 8553 mov.b &FMOV_OP,%d1 # last inst is MOVE 8554 fmov.x (%a0),%fp0 # return signed argument 8555 bra t_catch 8556 8557LP1REAL: 8558 fmov.x (%a0),%fp0 # LOAD INPUT 8559 mov.l &0x00000000,ADJK(%a6) 8560 fmov.x %fp0,%fp1 # FP1 IS INPUT Z 8561 fadd.s one(%pc),%fp0 # X := ROUND(1+Z) 8562 fmov.x %fp0,X(%a6) 8563 mov.w XFRAC(%a6),XDCARE(%a6) 8564 mov.l X(%a6),%d1 8565 cmp.l %d1,&0 8566 ble.w LP1NEG0 # LOG OF ZERO OR -VE 8567 cmp.l %d1,&0x3ffe8000 # IS BOUNDS [1/2,3/2]? 8568 blt.w LOGMAIN 8569 cmp.l %d1,&0x3fffc000 8570 bgt.w LOGMAIN 8571#--IF 1+Z > 3/2 OR 1+Z < 1/2, THEN X, WHICH IS ROUNDING 1+Z, 8572#--CONTAINS AT LEAST 63 BITS OF INFORMATION OF Z. IN THAT CASE, 8573#--SIMPLY INVOKE LOG(X) FOR LOG(1+Z). 8574 8575LP1NEAR1: 8576#--NEXT SEE IF EXP(-1/16) < X < EXP(1/16) 8577 cmp.l %d1,&0x3ffef07d 8578 blt.w LP1CARE 8579 cmp.l %d1,&0x3fff8841 8580 bgt.w LP1CARE 8581 8582LP1ONE16: 8583#--EXP(-1/16) < X < EXP(1/16). LOG(1+Z) = LOG(1+U/2) - LOG(1-U/2) 8584#--WHERE U = 2Z/(2+Z) = 2Z/(1+X). 8585 fadd.x %fp1,%fp1 # FP1 IS 2Z 8586 fadd.s one(%pc),%fp0 # FP0 IS 1+X 8587#--U = FP1/FP0 8588 bra.w LP1CONT2 8589 8590LP1CARE: 8591#--HERE WE USE THE USUAL TABLE DRIVEN APPROACH. CARE HAS TO BE 8592#--TAKEN BECAUSE 1+Z CAN HAVE 67 BITS OF INFORMATION AND WE MUST 8593#--PRESERVE ALL THE INFORMATION. BECAUSE 1+Z IS IN [1/2,3/2], 8594#--THERE ARE ONLY TWO CASES. 8595#--CASE 1: 1+Z < 1, THEN K = -1 AND Y-F = (2-F) + 2Z 8596#--CASE 2: 1+Z > 1, THEN K = 0 AND Y-F = (1-F) + Z 8597#--ON RETURNING TO LP1CONT1, WE MUST HAVE K IN FP1, ADDRESS OF 8598#--(1/F) IN A0, Y-F IN FP0, AND FP2 SAVED. 8599 8600 mov.l XFRAC(%a6),FFRAC(%a6) 8601 and.l &0xFE000000,FFRAC(%a6) 8602 or.l &0x01000000,FFRAC(%a6) # F OBTAINED 8603 cmp.l %d1,&0x3FFF8000 # SEE IF 1+Z > 1 8604 bge.b KISZERO 8605 8606KISNEG1: 8607 fmov.s TWO(%pc),%fp0 8608 mov.l &0x3fff0000,F(%a6) 8609 clr.l F+8(%a6) 8610 fsub.x F(%a6),%fp0 # 2-F 8611 mov.l FFRAC(%a6),%d1 8612 and.l &0x7E000000,%d1 8613 asr.l &8,%d1 8614 asr.l &8,%d1 8615 asr.l &4,%d1 # D0 CONTAINS DISPLACEMENT FOR 1/F 8616 fadd.x %fp1,%fp1 # GET 2Z 8617 fmovm.x &0xc,-(%sp) # SAVE FP2 {%fp2/%fp3} 8618 fadd.x %fp1,%fp0 # FP0 IS Y-F = (2-F)+2Z 8619 lea LOGTBL(%pc),%a0 # A0 IS ADDRESS OF 1/F 8620 add.l %d1,%a0 8621 fmov.s negone(%pc),%fp1 # FP1 IS K = -1 8622 bra.w LP1CONT1 8623 8624KISZERO: 8625 fmov.s one(%pc),%fp0 8626 mov.l &0x3fff0000,F(%a6) 8627 clr.l F+8(%a6) 8628 fsub.x F(%a6),%fp0 # 1-F 8629 mov.l FFRAC(%a6),%d1 8630 and.l &0x7E000000,%d1 8631 asr.l &8,%d1 8632 asr.l &8,%d1 8633 asr.l &4,%d1 8634 fadd.x %fp1,%fp0 # FP0 IS Y-F 8635 fmovm.x &0xc,-(%sp) # FP2 SAVED {%fp2/%fp3} 8636 lea LOGTBL(%pc),%a0 8637 add.l %d1,%a0 # A0 IS ADDRESS OF 1/F 8638 fmov.s zero(%pc),%fp1 # FP1 IS K = 0 8639 bra.w LP1CONT1 8640 8641LP1NEG0: 8642#--FPCR SAVED. D0 IS X IN COMPACT FORM. 8643 cmp.l %d1,&0 8644 blt.b LP1NEG 8645LP1ZERO: 8646 fmov.s negone(%pc),%fp0 8647 8648 fmov.l %d0,%fpcr 8649 bra t_dz 8650 8651LP1NEG: 8652 fmov.s zero(%pc),%fp0 8653 8654 fmov.l %d0,%fpcr 8655 bra t_operr 8656 8657 global slognp1d 8658#--ENTRY POINT FOR LOG(1+Z) FOR DENORMALIZED INPUT 8659# Simply return the denorm 8660slognp1d: 8661 bra t_extdnrm 8662 8663######################################################################### 8664# satanh(): computes the inverse hyperbolic tangent of a norm input # 8665# satanhd(): computes the inverse hyperbolic tangent of a denorm input # 8666# # 8667# INPUT *************************************************************** # 8668# a0 = pointer to extended precision input # 8669# d0 = round precision,mode # 8670# # 8671# OUTPUT ************************************************************** # 8672# fp0 = arctanh(X) # 8673# # 8674# ACCURACY and MONOTONICITY ******************************************* # 8675# The returned result is within 3 ulps in 64 significant bit, # 8676# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 8677# rounded to double precision. The result is provably monotonic # 8678# in double precision. # 8679# # 8680# ALGORITHM *********************************************************** # 8681# # 8682# ATANH # 8683# 1. If |X| >= 1, go to 3. # 8684# # 8685# 2. (|X| < 1) Calculate atanh(X) by # 8686# sgn := sign(X) # 8687# y := |X| # 8688# z := 2y/(1-y) # 8689# atanh(X) := sgn * (1/2) * logp1(z) # 8690# Exit. # 8691# # 8692# 3. If |X| > 1, go to 5. # 8693# # 8694# 4. (|X| = 1) Generate infinity with an appropriate sign and # 8695# divide-by-zero by # 8696# sgn := sign(X) # 8697# atan(X) := sgn / (+0). # 8698# Exit. # 8699# # 8700# 5. (|X| > 1) Generate an invalid operation by 0 * infinity. # 8701# Exit. # 8702# # 8703######################################################################### 8704 8705 global satanh 8706satanh: 8707 mov.l (%a0),%d1 8708 mov.w 4(%a0),%d1 8709 and.l &0x7FFFFFFF,%d1 8710 cmp.l %d1,&0x3FFF8000 8711 bge.b ATANHBIG 8712 8713#--THIS IS THE USUAL CASE, |X| < 1 8714#--Y = |X|, Z = 2Y/(1-Y), ATANH(X) = SIGN(X) * (1/2) * LOG1P(Z). 8715 8716 fabs.x (%a0),%fp0 # Y = |X| 8717 fmov.x %fp0,%fp1 8718 fneg.x %fp1 # -Y 8719 fadd.x %fp0,%fp0 # 2Y 8720 fadd.s &0x3F800000,%fp1 # 1-Y 8721 fdiv.x %fp1,%fp0 # 2Y/(1-Y) 8722 mov.l (%a0),%d1 8723 and.l &0x80000000,%d1 8724 or.l &0x3F000000,%d1 # SIGN(X)*HALF 8725 mov.l %d1,-(%sp) 8726 8727 mov.l %d0,-(%sp) # save rnd prec,mode 8728 clr.l %d0 # pass ext prec,RN 8729 fmovm.x &0x01,-(%sp) # save Z on stack 8730 lea (%sp),%a0 # pass ptr to Z 8731 bsr slognp1 # LOG1P(Z) 8732 add.l &0xc,%sp # clear Z from stack 8733 8734 mov.l (%sp)+,%d0 # fetch old prec,mode 8735 fmov.l %d0,%fpcr # load it 8736 mov.b &FMUL_OP,%d1 # last inst is MUL 8737 fmul.s (%sp)+,%fp0 8738 bra t_catch 8739 8740ATANHBIG: 8741 fabs.x (%a0),%fp0 # |X| 8742 fcmp.s %fp0,&0x3F800000 8743 fbgt t_operr 8744 bra t_dz 8745 8746 global satanhd 8747#--ATANH(X) = X FOR DENORMALIZED X 8748satanhd: 8749 bra t_extdnrm 8750 8751######################################################################### 8752# slog10(): computes the base-10 logarithm of a normalized input # 8753# slog10d(): computes the base-10 logarithm of a denormalized input # 8754# slog2(): computes the base-2 logarithm of a normalized input # 8755# slog2d(): computes the base-2 logarithm of a denormalized input # 8756# # 8757# INPUT *************************************************************** # 8758# a0 = pointer to extended precision input # 8759# d0 = round precision,mode # 8760# # 8761# OUTPUT ************************************************************** # 8762# fp0 = log_10(X) or log_2(X) # 8763# # 8764# ACCURACY and MONOTONICITY ******************************************* # 8765# The returned result is within 1.7 ulps in 64 significant bit, # 8766# i.e. within 0.5003 ulp to 53 bits if the result is subsequently # 8767# rounded to double precision. The result is provably monotonic # 8768# in double precision. # 8769# # 8770# ALGORITHM *********************************************************** # 8771# # 8772# slog10d: # 8773# # 8774# Step 0. If X < 0, create a NaN and raise the invalid operation # 8775# flag. Otherwise, save FPCR in D1; set FpCR to default. # 8776# Notes: Default means round-to-nearest mode, no floating-point # 8777# traps, and precision control = double extended. # 8778# # 8779# Step 1. Call slognd to obtain Y = log(X), the natural log of X. # 8780# Notes: Even if X is denormalized, log(X) is always normalized. # 8781# # 8782# Step 2. Compute log_10(X) = log(X) * (1/log(10)). # 8783# 2.1 Restore the user FPCR # 8784# 2.2 Return ans := Y * INV_L10. # 8785# # 8786# slog10: # 8787# # 8788# Step 0. If X < 0, create a NaN and raise the invalid operation # 8789# flag. Otherwise, save FPCR in D1; set FpCR to default. # 8790# Notes: Default means round-to-nearest mode, no floating-point # 8791# traps, and precision control = double extended. # 8792# # 8793# Step 1. Call sLogN to obtain Y = log(X), the natural log of X. # 8794# # 8795# Step 2. Compute log_10(X) = log(X) * (1/log(10)). # 8796# 2.1 Restore the user FPCR # 8797# 2.2 Return ans := Y * INV_L10. # 8798# # 8799# sLog2d: # 8800# # 8801# Step 0. If X < 0, create a NaN and raise the invalid operation # 8802# flag. Otherwise, save FPCR in D1; set FpCR to default. # 8803# Notes: Default means round-to-nearest mode, no floating-point # 8804# traps, and precision control = double extended. # 8805# # 8806# Step 1. Call slognd to obtain Y = log(X), the natural log of X. # 8807# Notes: Even if X is denormalized, log(X) is always normalized. # 8808# # 8809# Step 2. Compute log_10(X) = log(X) * (1/log(2)). # 8810# 2.1 Restore the user FPCR # 8811# 2.2 Return ans := Y * INV_L2. # 8812# # 8813# sLog2: # 8814# # 8815# Step 0. If X < 0, create a NaN and raise the invalid operation # 8816# flag. Otherwise, save FPCR in D1; set FpCR to default. # 8817# Notes: Default means round-to-nearest mode, no floating-point # 8818# traps, and precision control = double extended. # 8819# # 8820# Step 1. If X is not an integer power of two, i.e., X != 2^k, # 8821# go to Step 3. # 8822# # 8823# Step 2. Return k. # 8824# 2.1 Get integer k, X = 2^k. # 8825# 2.2 Restore the user FPCR. # 8826# 2.3 Return ans := convert-to-double-extended(k). # 8827# # 8828# Step 3. Call sLogN to obtain Y = log(X), the natural log of X. # 8829# # 8830# Step 4. Compute log_2(X) = log(X) * (1/log(2)). # 8831# 4.1 Restore the user FPCR # 8832# 4.2 Return ans := Y * INV_L2. # 8833# # 8834######################################################################### 8835 8836INV_L10: 8837 long 0x3FFD0000,0xDE5BD8A9,0x37287195,0x00000000 8838 8839INV_L2: 8840 long 0x3FFF0000,0xB8AA3B29,0x5C17F0BC,0x00000000 8841 8842 global slog10 8843#--entry point for Log10(X), X is normalized 8844slog10: 8845 fmov.b &0x1,%fp0 8846 fcmp.x %fp0,(%a0) # if operand == 1, 8847 fbeq.l ld_pzero # return an EXACT zero 8848 8849 mov.l (%a0),%d1 8850 blt.w invalid 8851 mov.l %d0,-(%sp) 8852 clr.l %d0 8853 bsr slogn # log(X), X normal. 8854 fmov.l (%sp)+,%fpcr 8855 fmul.x INV_L10(%pc),%fp0 8856 bra t_inx2 8857 8858 global slog10d 8859#--entry point for Log10(X), X is denormalized 8860slog10d: 8861 mov.l (%a0),%d1 8862 blt.w invalid 8863 mov.l %d0,-(%sp) 8864 clr.l %d0 8865 bsr slognd # log(X), X denorm. 8866 fmov.l (%sp)+,%fpcr 8867 fmul.x INV_L10(%pc),%fp0 8868 bra t_minx2 8869 8870 global slog2 8871#--entry point for Log2(X), X is normalized 8872slog2: 8873 mov.l (%a0),%d1 8874 blt.w invalid 8875 8876 mov.l 8(%a0),%d1 8877 bne.b continue # X is not 2^k 8878 8879 mov.l 4(%a0),%d1 8880 and.l &0x7FFFFFFF,%d1 8881 bne.b continue 8882 8883#--X = 2^k. 8884 mov.w (%a0),%d1 8885 and.l &0x00007FFF,%d1 8886 sub.l &0x3FFF,%d1 8887 beq.l ld_pzero 8888 fmov.l %d0,%fpcr 8889 fmov.l %d1,%fp0 8890 bra t_inx2 8891 8892continue: 8893 mov.l %d0,-(%sp) 8894 clr.l %d0 8895 bsr slogn # log(X), X normal. 8896 fmov.l (%sp)+,%fpcr 8897 fmul.x INV_L2(%pc),%fp0 8898 bra t_inx2 8899 8900invalid: 8901 bra t_operr 8902 8903 global slog2d 8904#--entry point for Log2(X), X is denormalized 8905slog2d: 8906 mov.l (%a0),%d1 8907 blt.w invalid 8908 mov.l %d0,-(%sp) 8909 clr.l %d0 8910 bsr slognd # log(X), X denorm. 8911 fmov.l (%sp)+,%fpcr 8912 fmul.x INV_L2(%pc),%fp0 8913 bra t_minx2 8914 8915######################################################################### 8916# stwotox(): computes 2**X for a normalized input # 8917# stwotoxd(): computes 2**X for a denormalized input # 8918# stentox(): computes 10**X for a normalized input # 8919# stentoxd(): computes 10**X for a denormalized input # 8920# # 8921# INPUT *************************************************************** # 8922# a0 = pointer to extended precision input # 8923# d0 = round precision,mode # 8924# # 8925# OUTPUT ************************************************************** # 8926# fp0 = 2**X or 10**X # 8927# # 8928# ACCURACY and MONOTONICITY ******************************************* # 8929# The returned result is within 2 ulps in 64 significant bit, # 8930# i.e. within 0.5001 ulp to 53 bits if the result is subsequently # 8931# rounded to double precision. The result is provably monotonic # 8932# in double precision. # 8933# # 8934# ALGORITHM *********************************************************** # 8935# # 8936# twotox # 8937# 1. If |X| > 16480, go to ExpBig. # 8938# # 8939# 2. If |X| < 2**(-70), go to ExpSm. # 8940# # 8941# 3. Decompose X as X = N/64 + r where |r| <= 1/128. Furthermore # 8942# decompose N as # 8943# N = 64(M + M') + j, j = 0,1,2,...,63. # 8944# # 8945# 4. Overwrite r := r * log2. Then # 8946# 2**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r). # 8947# Go to expr to compute that expression. # 8948# # 8949# tentox # 8950# 1. If |X| > 16480*log_10(2) (base 10 log of 2), go to ExpBig. # 8951# # 8952# 2. If |X| < 2**(-70), go to ExpSm. # 8953# # 8954# 3. Set y := X*log_2(10)*64 (base 2 log of 10). Set # 8955# N := round-to-int(y). Decompose N as # 8956# N = 64(M + M') + j, j = 0,1,2,...,63. # 8957# # 8958# 4. Define r as # 8959# r := ((X - N*L1)-N*L2) * L10 # 8960# where L1, L2 are the leading and trailing parts of # 8961# log_10(2)/64 and L10 is the natural log of 10. Then # 8962# 10**X = 2**(M') * 2**(M) * 2**(j/64) * exp(r). # 8963# Go to expr to compute that expression. # 8964# # 8965# expr # 8966# 1. Fetch 2**(j/64) from table as Fact1 and Fact2. # 8967# # 8968# 2. Overwrite Fact1 and Fact2 by # 8969# Fact1 := 2**(M) * Fact1 # 8970# Fact2 := 2**(M) * Fact2 # 8971# Thus Fact1 + Fact2 = 2**(M) * 2**(j/64). # 8972# # 8973# 3. Calculate P where 1 + P approximates exp(r): # 8974# P = r + r*r*(A1+r*(A2+...+r*A5)). # 8975# # 8976# 4. Let AdjFact := 2**(M'). Return # 8977# AdjFact * ( Fact1 + ((Fact1*P) + Fact2) ). # 8978# Exit. # 8979# # 8980# ExpBig # 8981# 1. Generate overflow by Huge * Huge if X > 0; otherwise, # 8982# generate underflow by Tiny * Tiny. # 8983# # 8984# ExpSm # 8985# 1. Return 1 + X. # 8986# # 8987######################################################################### 8988 8989L2TEN64: 8990 long 0x406A934F,0x0979A371 # 64LOG10/LOG2 8991L10TWO1: 8992 long 0x3F734413,0x509F8000 # LOG2/64LOG10 8993 8994L10TWO2: 8995 long 0xBFCD0000,0xC0219DC1,0xDA994FD2,0x00000000 8996 8997LOG10: long 0x40000000,0x935D8DDD,0xAAA8AC17,0x00000000 8998 8999LOG2: long 0x3FFE0000,0xB17217F7,0xD1CF79AC,0x00000000 9000 9001EXPA5: long 0x3F56C16D,0x6F7BD0B2 9002EXPA4: long 0x3F811112,0x302C712C 9003EXPA3: long 0x3FA55555,0x55554CC1 9004EXPA2: long 0x3FC55555,0x55554A54 9005EXPA1: long 0x3FE00000,0x00000000,0x00000000,0x00000000 9006 9007TEXPTBL: 9008 long 0x3FFF0000,0x80000000,0x00000000,0x3F738000 9009 long 0x3FFF0000,0x8164D1F3,0xBC030773,0x3FBEF7CA 9010 long 0x3FFF0000,0x82CD8698,0xAC2BA1D7,0x3FBDF8A9 9011 long 0x3FFF0000,0x843A28C3,0xACDE4046,0x3FBCD7C9 9012 long 0x3FFF0000,0x85AAC367,0xCC487B15,0xBFBDE8DA 9013 long 0x3FFF0000,0x871F6196,0x9E8D1010,0x3FBDE85C 9014 long 0x3FFF0000,0x88980E80,0x92DA8527,0x3FBEBBF1 9015 long 0x3FFF0000,0x8A14D575,0x496EFD9A,0x3FBB80CA 9016 long 0x3FFF0000,0x8B95C1E3,0xEA8BD6E7,0xBFBA8373 9017 long 0x3FFF0000,0x8D1ADF5B,0x7E5BA9E6,0xBFBE9670 9018 long 0x3FFF0000,0x8EA4398B,0x45CD53C0,0x3FBDB700 9019 long 0x3FFF0000,0x9031DC43,0x1466B1DC,0x3FBEEEB0 9020 long 0x3FFF0000,0x91C3D373,0xAB11C336,0x3FBBFD6D 9021 long 0x3FFF0000,0x935A2B2F,0x13E6E92C,0xBFBDB319 9022 long 0x3FFF0000,0x94F4EFA8,0xFEF70961,0x3FBDBA2B 9023 long 0x3FFF0000,0x96942D37,0x20185A00,0x3FBE91D5 9024 long 0x3FFF0000,0x9837F051,0x8DB8A96F,0x3FBE8D5A 9025 long 0x3FFF0000,0x99E04593,0x20B7FA65,0xBFBCDE7B 9026 long 0x3FFF0000,0x9B8D39B9,0xD54E5539,0xBFBEBAAF 9027 long 0x3FFF0000,0x9D3ED9A7,0x2CFFB751,0xBFBD86DA 9028 long 0x3FFF0000,0x9EF53260,0x91A111AE,0xBFBEBEDD 9029 long 0x3FFF0000,0xA0B0510F,0xB9714FC2,0x3FBCC96E 9030 long 0x3FFF0000,0xA2704303,0x0C496819,0xBFBEC90B 9031 long 0x3FFF0000,0xA43515AE,0x09E6809E,0x3FBBD1DB 9032 long 0x3FFF0000,0xA5FED6A9,0xB15138EA,0x3FBCE5EB 9033 long 0x3FFF0000,0xA7CD93B4,0xE965356A,0xBFBEC274 9034 long 0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x3FBEA83C 9035 long 0x3FFF0000,0xAB7A39B5,0xA93ED337,0x3FBECB00 9036 long 0x3FFF0000,0xAD583EEA,0x42A14AC6,0x3FBE9301 9037 long 0x3FFF0000,0xAF3B78AD,0x690A4375,0xBFBD8367 9038 long 0x3FFF0000,0xB123F581,0xD2AC2590,0xBFBEF05F 9039 long 0x3FFF0000,0xB311C412,0xA9112489,0x3FBDFB3C 9040 long 0x3FFF0000,0xB504F333,0xF9DE6484,0x3FBEB2FB 9041 long 0x3FFF0000,0xB6FD91E3,0x28D17791,0x3FBAE2CB 9042 long 0x3FFF0000,0xB8FBAF47,0x62FB9EE9,0x3FBCDC3C 9043 long 0x3FFF0000,0xBAFF5AB2,0x133E45FB,0x3FBEE9AA 9044 long 0x3FFF0000,0xBD08A39F,0x580C36BF,0xBFBEAEFD 9045 long 0x3FFF0000,0xBF1799B6,0x7A731083,0xBFBCBF51 9046 long 0x3FFF0000,0xC12C4CCA,0x66709456,0x3FBEF88A 9047 long 0x3FFF0000,0xC346CCDA,0x24976407,0x3FBD83B2 9048 long 0x3FFF0000,0xC5672A11,0x5506DADD,0x3FBDF8AB 9049 long 0x3FFF0000,0xC78D74C8,0xABB9B15D,0xBFBDFB17 9050 long 0x3FFF0000,0xC9B9BD86,0x6E2F27A3,0xBFBEFE3C 9051 long 0x3FFF0000,0xCBEC14FE,0xF2727C5D,0xBFBBB6F8 9052 long 0x3FFF0000,0xCE248C15,0x1F8480E4,0xBFBCEE53 9053 long 0x3FFF0000,0xD06333DA,0xEF2B2595,0xBFBDA4AE 9054 long 0x3FFF0000,0xD2A81D91,0xF12AE45A,0x3FBC9124 9055 long 0x3FFF0000,0xD4F35AAB,0xCFEDFA1F,0x3FBEB243 9056 long 0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x3FBDE69A 9057 long 0x3FFF0000,0xD99D15C2,0x78AFD7B6,0xBFB8BC61 9058 long 0x3FFF0000,0xDBFBB797,0xDAF23755,0x3FBDF610 9059 long 0x3FFF0000,0xDE60F482,0x5E0E9124,0xBFBD8BE1 9060 long 0x3FFF0000,0xE0CCDEEC,0x2A94E111,0x3FBACB12 9061 long 0x3FFF0000,0xE33F8972,0xBE8A5A51,0x3FBB9BFE 9062 long 0x3FFF0000,0xE5B906E7,0x7C8348A8,0x3FBCF2F4 9063 long 0x3FFF0000,0xE8396A50,0x3C4BDC68,0x3FBEF22F 9064 long 0x3FFF0000,0xEAC0C6E7,0xDD24392F,0xBFBDBF4A 9065 long 0x3FFF0000,0xED4F301E,0xD9942B84,0x3FBEC01A 9066 long 0x3FFF0000,0xEFE4B99B,0xDCDAF5CB,0x3FBE8CAC 9067 long 0x3FFF0000,0xF281773C,0x59FFB13A,0xBFBCBB3F 9068 long 0x3FFF0000,0xF5257D15,0x2486CC2C,0x3FBEF73A 9069 long 0x3FFF0000,0xF7D0DF73,0x0AD13BB9,0xBFB8B795 9070 long 0x3FFF0000,0xFA83B2DB,0x722A033A,0x3FBEF84B 9071 long 0x3FFF0000,0xFD3E0C0C,0xF486C175,0xBFBEF581 9072 9073 set INT,L_SCR1 9074 9075 set X,FP_SCR0 9076 set XDCARE,X+2 9077 set XFRAC,X+4 9078 9079 set ADJFACT,FP_SCR0 9080 9081 set FACT1,FP_SCR0 9082 set FACT1HI,FACT1+4 9083 set FACT1LOW,FACT1+8 9084 9085 set FACT2,FP_SCR1 9086 set FACT2HI,FACT2+4 9087 set FACT2LOW,FACT2+8 9088 9089 global stwotox 9090#--ENTRY POINT FOR 2**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S 9091stwotox: 9092 fmovm.x (%a0),&0x80 # LOAD INPUT 9093 9094 mov.l (%a0),%d1 9095 mov.w 4(%a0),%d1 9096 fmov.x %fp0,X(%a6) 9097 and.l &0x7FFFFFFF,%d1 9098 9099 cmp.l %d1,&0x3FB98000 # |X| >= 2**(-70)? 9100 bge.b TWOOK1 9101 bra.w EXPBORS 9102 9103TWOOK1: 9104 cmp.l %d1,&0x400D80C0 # |X| > 16480? 9105 ble.b TWOMAIN 9106 bra.w EXPBORS 9107 9108TWOMAIN: 9109#--USUAL CASE, 2^(-70) <= |X| <= 16480 9110 9111 fmov.x %fp0,%fp1 9112 fmul.s &0x42800000,%fp1 # 64 * X 9113 fmov.l %fp1,INT(%a6) # N = ROUND-TO-INT(64 X) 9114 mov.l %d2,-(%sp) 9115 lea TEXPTBL(%pc),%a1 # LOAD ADDRESS OF TABLE OF 2^(J/64) 9116 fmov.l INT(%a6),%fp1 # N --> FLOATING FMT 9117 mov.l INT(%a6),%d1 9118 mov.l %d1,%d2 9119 and.l &0x3F,%d1 # D0 IS J 9120 asl.l &4,%d1 # DISPLACEMENT FOR 2^(J/64) 9121 add.l %d1,%a1 # ADDRESS FOR 2^(J/64) 9122 asr.l &6,%d2 # d2 IS L, N = 64L + J 9123 mov.l %d2,%d1 9124 asr.l &1,%d1 # D0 IS M 9125 sub.l %d1,%d2 # d2 IS M', N = 64(M+M') + J 9126 add.l &0x3FFF,%d2 9127 9128#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64), 9129#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN. 9130#--ADJFACT = 2^(M'). 9131#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2. 9132 9133 fmovm.x &0x0c,-(%sp) # save fp2/fp3 9134 9135 fmul.s &0x3C800000,%fp1 # (1/64)*N 9136 mov.l (%a1)+,FACT1(%a6) 9137 mov.l (%a1)+,FACT1HI(%a6) 9138 mov.l (%a1)+,FACT1LOW(%a6) 9139 mov.w (%a1)+,FACT2(%a6) 9140 9141 fsub.x %fp1,%fp0 # X - (1/64)*INT(64 X) 9142 9143 mov.w (%a1)+,FACT2HI(%a6) 9144 clr.w FACT2HI+2(%a6) 9145 clr.l FACT2LOW(%a6) 9146 add.w %d1,FACT1(%a6) 9147 fmul.x LOG2(%pc),%fp0 # FP0 IS R 9148 add.w %d1,FACT2(%a6) 9149 9150 bra.w expr 9151 9152EXPBORS: 9153#--FPCR, D0 SAVED 9154 cmp.l %d1,&0x3FFF8000 9155 bgt.b TEXPBIG 9156 9157#--|X| IS SMALL, RETURN 1 + X 9158 9159 fmov.l %d0,%fpcr # restore users round prec,mode 9160 fadd.s &0x3F800000,%fp0 # RETURN 1 + X 9161 bra t_pinx2 9162 9163TEXPBIG: 9164#--|X| IS LARGE, GENERATE OVERFLOW IF X > 0; ELSE GENERATE UNDERFLOW 9165#--REGISTERS SAVE SO FAR ARE FPCR AND D0 9166 mov.l X(%a6),%d1 9167 cmp.l %d1,&0 9168 blt.b EXPNEG 9169 9170 bra t_ovfl2 # t_ovfl expects positive value 9171 9172EXPNEG: 9173 bra t_unfl2 # t_unfl expects positive value 9174 9175 global stwotoxd 9176stwotoxd: 9177#--ENTRY POINT FOR 2**(X) FOR DENORMALIZED ARGUMENT 9178 9179 fmov.l %d0,%fpcr # set user's rounding mode/precision 9180 fmov.s &0x3F800000,%fp0 # RETURN 1 + X 9181 mov.l (%a0),%d1 9182 or.l &0x00800001,%d1 9183 fadd.s %d1,%fp0 9184 bra t_pinx2 9185 9186 global stentox 9187#--ENTRY POINT FOR 10**(X), HERE X IS FINITE, NON-ZERO, AND NOT NAN'S 9188stentox: 9189 fmovm.x (%a0),&0x80 # LOAD INPUT 9190 9191 mov.l (%a0),%d1 9192 mov.w 4(%a0),%d1 9193 fmov.x %fp0,X(%a6) 9194 and.l &0x7FFFFFFF,%d1 9195 9196 cmp.l %d1,&0x3FB98000 # |X| >= 2**(-70)? 9197 bge.b TENOK1 9198 bra.w EXPBORS 9199 9200TENOK1: 9201 cmp.l %d1,&0x400B9B07 # |X| <= 16480*log2/log10 ? 9202 ble.b TENMAIN 9203 bra.w EXPBORS 9204 9205TENMAIN: 9206#--USUAL CASE, 2^(-70) <= |X| <= 16480 LOG 2 / LOG 10 9207 9208 fmov.x %fp0,%fp1 9209 fmul.d L2TEN64(%pc),%fp1 # X*64*LOG10/LOG2 9210 fmov.l %fp1,INT(%a6) # N=INT(X*64*LOG10/LOG2) 9211 mov.l %d2,-(%sp) 9212 lea TEXPTBL(%pc),%a1 # LOAD ADDRESS OF TABLE OF 2^(J/64) 9213 fmov.l INT(%a6),%fp1 # N --> FLOATING FMT 9214 mov.l INT(%a6),%d1 9215 mov.l %d1,%d2 9216 and.l &0x3F,%d1 # D0 IS J 9217 asl.l &4,%d1 # DISPLACEMENT FOR 2^(J/64) 9218 add.l %d1,%a1 # ADDRESS FOR 2^(J/64) 9219 asr.l &6,%d2 # d2 IS L, N = 64L + J 9220 mov.l %d2,%d1 9221 asr.l &1,%d1 # D0 IS M 9222 sub.l %d1,%d2 # d2 IS M', N = 64(M+M') + J 9223 add.l &0x3FFF,%d2 9224 9225#--SUMMARY: a1 IS ADDRESS FOR THE LEADING PORTION OF 2^(J/64), 9226#--D0 IS M WHERE N = 64(M+M') + J. NOTE THAT |M| <= 16140 BY DESIGN. 9227#--ADJFACT = 2^(M'). 9228#--REGISTERS SAVED SO FAR ARE (IN ORDER) FPCR, D0, FP1, a1, AND FP2. 9229 fmovm.x &0x0c,-(%sp) # save fp2/fp3 9230 9231 fmov.x %fp1,%fp2 9232 9233 fmul.d L10TWO1(%pc),%fp1 # N*(LOG2/64LOG10)_LEAD 9234 mov.l (%a1)+,FACT1(%a6) 9235 9236 fmul.x L10TWO2(%pc),%fp2 # N*(LOG2/64LOG10)_TRAIL 9237 9238 mov.l (%a1)+,FACT1HI(%a6) 9239 mov.l (%a1)+,FACT1LOW(%a6) 9240 fsub.x %fp1,%fp0 # X - N L_LEAD 9241 mov.w (%a1)+,FACT2(%a6) 9242 9243 fsub.x %fp2,%fp0 # X - N L_TRAIL 9244 9245 mov.w (%a1)+,FACT2HI(%a6) 9246 clr.w FACT2HI+2(%a6) 9247 clr.l FACT2LOW(%a6) 9248 9249 fmul.x LOG10(%pc),%fp0 # FP0 IS R 9250 add.w %d1,FACT1(%a6) 9251 add.w %d1,FACT2(%a6) 9252 9253expr: 9254#--FPCR, FP2, FP3 ARE SAVED IN ORDER AS SHOWN. 9255#--ADJFACT CONTAINS 2**(M'), FACT1 + FACT2 = 2**(M) * 2**(J/64). 9256#--FP0 IS R. THE FOLLOWING CODE COMPUTES 9257#-- 2**(M'+M) * 2**(J/64) * EXP(R) 9258 9259 fmov.x %fp0,%fp1 9260 fmul.x %fp1,%fp1 # FP1 IS S = R*R 9261 9262 fmov.d EXPA5(%pc),%fp2 # FP2 IS A5 9263 fmov.d EXPA4(%pc),%fp3 # FP3 IS A4 9264 9265 fmul.x %fp1,%fp2 # FP2 IS S*A5 9266 fmul.x %fp1,%fp3 # FP3 IS S*A4 9267 9268 fadd.d EXPA3(%pc),%fp2 # FP2 IS A3+S*A5 9269 fadd.d EXPA2(%pc),%fp3 # FP3 IS A2+S*A4 9270 9271 fmul.x %fp1,%fp2 # FP2 IS S*(A3+S*A5) 9272 fmul.x %fp1,%fp3 # FP3 IS S*(A2+S*A4) 9273 9274 fadd.d EXPA1(%pc),%fp2 # FP2 IS A1+S*(A3+S*A5) 9275 fmul.x %fp0,%fp3 # FP3 IS R*S*(A2+S*A4) 9276 9277 fmul.x %fp1,%fp2 # FP2 IS S*(A1+S*(A3+S*A5)) 9278 fadd.x %fp3,%fp0 # FP0 IS R+R*S*(A2+S*A4) 9279 fadd.x %fp2,%fp0 # FP0 IS EXP(R) - 1 9280 9281 fmovm.x (%sp)+,&0x30 # restore fp2/fp3 9282 9283#--FINAL RECONSTRUCTION PROCESS 9284#--EXP(X) = 2^M*2^(J/64) + 2^M*2^(J/64)*(EXP(R)-1) - (1 OR 0) 9285 9286 fmul.x FACT1(%a6),%fp0 9287 fadd.x FACT2(%a6),%fp0 9288 fadd.x FACT1(%a6),%fp0 9289 9290 fmov.l %d0,%fpcr # restore users round prec,mode 9291 mov.w %d2,ADJFACT(%a6) # INSERT EXPONENT 9292 mov.l (%sp)+,%d2 9293 mov.l &0x80000000,ADJFACT+4(%a6) 9294 clr.l ADJFACT+8(%a6) 9295 mov.b &FMUL_OP,%d1 # last inst is MUL 9296 fmul.x ADJFACT(%a6),%fp0 # FINAL ADJUSTMENT 9297 bra t_catch 9298 9299 global stentoxd 9300stentoxd: 9301#--ENTRY POINT FOR 10**(X) FOR DENORMALIZED ARGUMENT 9302 9303 fmov.l %d0,%fpcr # set user's rounding mode/precision 9304 fmov.s &0x3F800000,%fp0 # RETURN 1 + X 9305 mov.l (%a0),%d1 9306 or.l &0x00800001,%d1 9307 fadd.s %d1,%fp0 9308 bra t_pinx2 9309 9310######################################################################### 9311# smovcr(): returns the ROM constant at the offset specified in d1 # 9312# rounded to the mode and precision specified in d0. # 9313# # 9314# INPUT *************************************************************** # 9315# d0 = rnd prec,mode # 9316# d1 = ROM offset # 9317# # 9318# OUTPUT ************************************************************** # 9319# fp0 = the ROM constant rounded to the user's rounding mode,prec # 9320# # 9321######################################################################### 9322 9323 global smovcr 9324smovcr: 9325 mov.l %d1,-(%sp) # save rom offset for a sec 9326 9327 lsr.b &0x4,%d0 # shift ctrl bits to lo 9328 mov.l %d0,%d1 # make a copy 9329 andi.w &0x3,%d1 # extract rnd mode 9330 andi.w &0xc,%d0 # extract rnd prec 9331 swap %d0 # put rnd prec in hi 9332 mov.w %d1,%d0 # put rnd mode in lo 9333 9334 mov.l (%sp)+,%d1 # get rom offset 9335 9336# 9337# check range of offset 9338# 9339 tst.b %d1 # if zero, offset is to pi 9340 beq.b pi_tbl # it is pi 9341 cmpi.b %d1,&0x0a # check range $01 - $0a 9342 ble.b z_val # if in this range, return zero 9343 cmpi.b %d1,&0x0e # check range $0b - $0e 9344 ble.b sm_tbl # valid constants in this range 9345 cmpi.b %d1,&0x2f # check range $10 - $2f 9346 ble.b z_val # if in this range, return zero 9347 cmpi.b %d1,&0x3f # check range $30 - $3f 9348 ble.b bg_tbl # valid constants in this range 9349 9350z_val: 9351 bra.l ld_pzero # return a zero 9352 9353# 9354# the answer is PI rounded to the proper precision. 9355# 9356# fetch a pointer to the answer table relating to the proper rounding 9357# precision. 9358# 9359pi_tbl: 9360 tst.b %d0 # is rmode RN? 9361 bne.b pi_not_rn # no 9362pi_rn: 9363 lea.l PIRN(%pc),%a0 # yes; load PI RN table addr 9364 bra.w set_finx 9365pi_not_rn: 9366 cmpi.b %d0,&rp_mode # is rmode RP? 9367 beq.b pi_rp # yes 9368pi_rzrm: 9369 lea.l PIRZRM(%pc),%a0 # no; load PI RZ,RM table addr 9370 bra.b set_finx 9371pi_rp: 9372 lea.l PIRP(%pc),%a0 # load PI RP table addr 9373 bra.b set_finx 9374 9375# 9376# the answer is one of: 9377# $0B log10(2) (inexact) 9378# $0C e (inexact) 9379# $0D log2(e) (inexact) 9380# $0E log10(e) (exact) 9381# 9382# fetch a pointer to the answer table relating to the proper rounding 9383# precision. 9384# 9385sm_tbl: 9386 subi.b &0xb,%d1 # make offset in 0-4 range 9387 tst.b %d0 # is rmode RN? 9388 bne.b sm_not_rn # no 9389sm_rn: 9390 lea.l SMALRN(%pc),%a0 # yes; load RN table addr 9391sm_tbl_cont: 9392 cmpi.b %d1,&0x2 # is result log10(e)? 9393 ble.b set_finx # no; answer is inexact 9394 bra.b no_finx # yes; answer is exact 9395sm_not_rn: 9396 cmpi.b %d0,&rp_mode # is rmode RP? 9397 beq.b sm_rp # yes 9398sm_rzrm: 9399 lea.l SMALRZRM(%pc),%a0 # no; load RZ,RM table addr 9400 bra.b sm_tbl_cont 9401sm_rp: 9402 lea.l SMALRP(%pc),%a0 # load RP table addr 9403 bra.b sm_tbl_cont 9404 9405# 9406# the answer is one of: 9407# $30 ln(2) (inexact) 9408# $31 ln(10) (inexact) 9409# $32 10^0 (exact) 9410# $33 10^1 (exact) 9411# $34 10^2 (exact) 9412# $35 10^4 (exact) 9413# $36 10^8 (exact) 9414# $37 10^16 (exact) 9415# $38 10^32 (inexact) 9416# $39 10^64 (inexact) 9417# $3A 10^128 (inexact) 9418# $3B 10^256 (inexact) 9419# $3C 10^512 (inexact) 9420# $3D 10^1024 (inexact) 9421# $3E 10^2048 (inexact) 9422# $3F 10^4096 (inexact) 9423# 9424# fetch a pointer to the answer table relating to the proper rounding 9425# precision. 9426# 9427bg_tbl: 9428 subi.b &0x30,%d1 # make offset in 0-f range 9429 tst.b %d0 # is rmode RN? 9430 bne.b bg_not_rn # no 9431bg_rn: 9432 lea.l BIGRN(%pc),%a0 # yes; load RN table addr 9433bg_tbl_cont: 9434 cmpi.b %d1,&0x1 # is offset <= $31? 9435 ble.b set_finx # yes; answer is inexact 9436 cmpi.b %d1,&0x7 # is $32 <= offset <= $37? 9437 ble.b no_finx # yes; answer is exact 9438 bra.b set_finx # no; answer is inexact 9439bg_not_rn: 9440 cmpi.b %d0,&rp_mode # is rmode RP? 9441 beq.b bg_rp # yes 9442bg_rzrm: 9443 lea.l BIGRZRM(%pc),%a0 # no; load RZ,RM table addr 9444 bra.b bg_tbl_cont 9445bg_rp: 9446 lea.l BIGRP(%pc),%a0 # load RP table addr 9447 bra.b bg_tbl_cont 9448 9449# answer is inexact, so set INEX2 and AINEX in the user's FPSR. 9450set_finx: 9451 ori.l &inx2a_mask,USER_FPSR(%a6) # set INEX2/AINEX 9452no_finx: 9453 mulu.w &0xc,%d1 # offset points into tables 9454 swap %d0 # put rnd prec in lo word 9455 tst.b %d0 # is precision extended? 9456 9457 bne.b not_ext # if xprec, do not call round 9458 9459# Precision is extended 9460 fmovm.x (%a0,%d1.w),&0x80 # return result in fp0 9461 rts 9462 9463# Precision is single or double 9464not_ext: 9465 swap %d0 # rnd prec in upper word 9466 9467# call round() to round the answer to the proper precision. 9468# exponents out of range for single or double DO NOT cause underflow 9469# or overflow. 9470 mov.w 0x0(%a0,%d1.w),FP_SCR1_EX(%a6) # load first word 9471 mov.l 0x4(%a0,%d1.w),FP_SCR1_HI(%a6) # load second word 9472 mov.l 0x8(%a0,%d1.w),FP_SCR1_LO(%a6) # load third word 9473 mov.l %d0,%d1 9474 clr.l %d0 # clear g,r,s 9475 lea FP_SCR1(%a6),%a0 # pass ptr to answer 9476 clr.w LOCAL_SGN(%a0) # sign always positive 9477 bsr.l _round # round the mantissa 9478 9479 fmovm.x (%a0),&0x80 # return rounded result in fp0 9480 rts 9481 9482 align 0x4 9483 9484PIRN: long 0x40000000,0xc90fdaa2,0x2168c235 # pi 9485PIRZRM: long 0x40000000,0xc90fdaa2,0x2168c234 # pi 9486PIRP: long 0x40000000,0xc90fdaa2,0x2168c235 # pi 9487 9488SMALRN: long 0x3ffd0000,0x9a209a84,0xfbcff798 # log10(2) 9489 long 0x40000000,0xadf85458,0xa2bb4a9a # e 9490 long 0x3fff0000,0xb8aa3b29,0x5c17f0bc # log2(e) 9491 long 0x3ffd0000,0xde5bd8a9,0x37287195 # log10(e) 9492 long 0x00000000,0x00000000,0x00000000 # 0.0 9493 9494SMALRZRM: 9495 long 0x3ffd0000,0x9a209a84,0xfbcff798 # log10(2) 9496 long 0x40000000,0xadf85458,0xa2bb4a9a # e 9497 long 0x3fff0000,0xb8aa3b29,0x5c17f0bb # log2(e) 9498 long 0x3ffd0000,0xde5bd8a9,0x37287195 # log10(e) 9499 long 0x00000000,0x00000000,0x00000000 # 0.0 9500 9501SMALRP: long 0x3ffd0000,0x9a209a84,0xfbcff799 # log10(2) 9502 long 0x40000000,0xadf85458,0xa2bb4a9b # e 9503 long 0x3fff0000,0xb8aa3b29,0x5c17f0bc # log2(e) 9504 long 0x3ffd0000,0xde5bd8a9,0x37287195 # log10(e) 9505 long 0x00000000,0x00000000,0x00000000 # 0.0 9506 9507BIGRN: long 0x3ffe0000,0xb17217f7,0xd1cf79ac # ln(2) 9508 long 0x40000000,0x935d8ddd,0xaaa8ac17 # ln(10) 9509 9510 long 0x3fff0000,0x80000000,0x00000000 # 10 ^ 0 9511 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 9512 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 9513 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 9514 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 9515 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 9516 long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32 9517 long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64 9518 long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128 9519 long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256 9520 long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512 9521 long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024 9522 long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048 9523 long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096 9524 9525BIGRZRM: 9526 long 0x3ffe0000,0xb17217f7,0xd1cf79ab # ln(2) 9527 long 0x40000000,0x935d8ddd,0xaaa8ac16 # ln(10) 9528 9529 long 0x3fff0000,0x80000000,0x00000000 # 10 ^ 0 9530 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 9531 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 9532 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 9533 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 9534 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 9535 long 0x40690000,0x9DC5ADA8,0x2B70B59D # 10 ^ 32 9536 long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64 9537 long 0x41A80000,0x93BA47C9,0x80E98CDF # 10 ^ 128 9538 long 0x43510000,0xAA7EEBFB,0x9DF9DE8D # 10 ^ 256 9539 long 0x46A30000,0xE319A0AE,0xA60E91C6 # 10 ^ 512 9540 long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024 9541 long 0x5A920000,0x9E8B3B5D,0xC53D5DE4 # 10 ^ 2048 9542 long 0x75250000,0xC4605202,0x8A20979A # 10 ^ 4096 9543 9544BIGRP: 9545 long 0x3ffe0000,0xb17217f7,0xd1cf79ac # ln(2) 9546 long 0x40000000,0x935d8ddd,0xaaa8ac17 # ln(10) 9547 9548 long 0x3fff0000,0x80000000,0x00000000 # 10 ^ 0 9549 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 9550 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 9551 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 9552 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 9553 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 9554 long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32 9555 long 0x40D30000,0xC2781F49,0xFFCFA6D6 # 10 ^ 64 9556 long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128 9557 long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256 9558 long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512 9559 long 0x4D480000,0xC9767586,0x81750C18 # 10 ^ 1024 9560 long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048 9561 long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096 9562 9563######################################################################### 9564# sscale(): computes the destination operand scaled by the source # 9565# operand. If the absoulute value of the source operand is # 9566# >= 2^14, an overflow or underflow is returned. # 9567# # 9568# INPUT *************************************************************** # 9569# a0 = pointer to double-extended source operand X # 9570# a1 = pointer to double-extended destination operand Y # 9571# # 9572# OUTPUT ************************************************************** # 9573# fp0 = scale(X,Y) # 9574# # 9575######################################################################### 9576 9577set SIGN, L_SCR1 9578 9579 global sscale 9580sscale: 9581 mov.l %d0,-(%sp) # store off ctrl bits for now 9582 9583 mov.w DST_EX(%a1),%d1 # get dst exponent 9584 smi.b SIGN(%a6) # use SIGN to hold dst sign 9585 andi.l &0x00007fff,%d1 # strip sign from dst exp 9586 9587 mov.w SRC_EX(%a0),%d0 # check src bounds 9588 andi.w &0x7fff,%d0 # clr src sign bit 9589 cmpi.w %d0,&0x3fff # is src ~ ZERO? 9590 blt.w src_small # yes 9591 cmpi.w %d0,&0x400c # no; is src too big? 9592 bgt.w src_out # yes 9593 9594# 9595# Source is within 2^14 range. 9596# 9597src_ok: 9598 fintrz.x SRC(%a0),%fp0 # calc int of src 9599 fmov.l %fp0,%d0 # int src to d0 9600# don't want any accrued bits from the fintrz showing up later since 9601# we may need to read the fpsr for the last fp op in t_catch2(). 9602 fmov.l &0x0,%fpsr 9603 9604 tst.b DST_HI(%a1) # is dst denormalized? 9605 bmi.b sok_norm 9606 9607# the dst is a DENORM. normalize the DENORM and add the adjustment to 9608# the src value. then, jump to the norm part of the routine. 9609sok_dnrm: 9610 mov.l %d0,-(%sp) # save src for now 9611 9612 mov.w DST_EX(%a1),FP_SCR0_EX(%a6) # make a copy 9613 mov.l DST_HI(%a1),FP_SCR0_HI(%a6) 9614 mov.l DST_LO(%a1),FP_SCR0_LO(%a6) 9615 9616 lea FP_SCR0(%a6),%a0 # pass ptr to DENORM 9617 bsr.l norm # normalize the DENORM 9618 neg.l %d0 9619 add.l (%sp)+,%d0 # add adjustment to src 9620 9621 fmovm.x FP_SCR0(%a6),&0x80 # load normalized DENORM 9622 9623 cmpi.w %d0,&-0x3fff # is the shft amt really low? 9624 bge.b sok_norm2 # thank goodness no 9625 9626# the multiply factor that we're trying to create should be a denorm 9627# for the multiply to work. Therefore, we're going to actually do a 9628# multiply with a denorm which will cause an unimplemented data type 9629# exception to be put into the machine which will be caught and corrected 9630# later. we don't do this with the DENORMs above because this method 9631# is slower. but, don't fret, I don't see it being used much either. 9632 fmov.l (%sp)+,%fpcr # restore user fpcr 9633 mov.l &0x80000000,%d1 # load normalized mantissa 9634 subi.l &-0x3fff,%d0 # how many should we shift? 9635 neg.l %d0 # make it positive 9636 cmpi.b %d0,&0x20 # is it > 32? 9637 bge.b sok_dnrm_32 # yes 9638 lsr.l %d0,%d1 # no; bit stays in upper lw 9639 clr.l -(%sp) # insert zero low mantissa 9640 mov.l %d1,-(%sp) # insert new high mantissa 9641 clr.l -(%sp) # make zero exponent 9642 bra.b sok_norm_cont 9643sok_dnrm_32: 9644 subi.b &0x20,%d0 # get shift count 9645 lsr.l %d0,%d1 # make low mantissa longword 9646 mov.l %d1,-(%sp) # insert new low mantissa 9647 clr.l -(%sp) # insert zero high mantissa 9648 clr.l -(%sp) # make zero exponent 9649 bra.b sok_norm_cont 9650 9651# the src will force the dst to a DENORM value or worse. so, let's 9652# create an fp multiply that will create the result. 9653sok_norm: 9654 fmovm.x DST(%a1),&0x80 # load fp0 with normalized src 9655sok_norm2: 9656 fmov.l (%sp)+,%fpcr # restore user fpcr 9657 9658 addi.w &0x3fff,%d0 # turn src amt into exp value 9659 swap %d0 # put exponent in high word 9660 clr.l -(%sp) # insert new exponent 9661 mov.l &0x80000000,-(%sp) # insert new high mantissa 9662 mov.l %d0,-(%sp) # insert new lo mantissa 9663 9664sok_norm_cont: 9665 fmov.l %fpcr,%d0 # d0 needs fpcr for t_catch2 9666 mov.b &FMUL_OP,%d1 # last inst is MUL 9667 fmul.x (%sp)+,%fp0 # do the multiply 9668 bra t_catch2 # catch any exceptions 9669 9670# 9671# Source is outside of 2^14 range. Test the sign and branch 9672# to the appropriate exception handler. 9673# 9674src_out: 9675 mov.l (%sp)+,%d0 # restore ctrl bits 9676 exg %a0,%a1 # swap src,dst ptrs 9677 tst.b SRC_EX(%a1) # is src negative? 9678 bmi t_unfl # yes; underflow 9679 bra t_ovfl_sc # no; overflow 9680 9681# 9682# The source input is below 1, so we check for denormalized numbers 9683# and set unfl. 9684# 9685src_small: 9686 tst.b DST_HI(%a1) # is dst denormalized? 9687 bpl.b ssmall_done # yes 9688 9689 mov.l (%sp)+,%d0 9690 fmov.l %d0,%fpcr # no; load control bits 9691 mov.b &FMOV_OP,%d1 # last inst is MOVE 9692 fmov.x DST(%a1),%fp0 # simply return dest 9693 bra t_catch2 9694ssmall_done: 9695 mov.l (%sp)+,%d0 # load control bits into d1 9696 mov.l %a1,%a0 # pass ptr to dst 9697 bra t_resdnrm 9698 9699######################################################################### 9700# smod(): computes the fp MOD of the input values X,Y. # 9701# srem(): computes the fp (IEEE) REM of the input values X,Y. # 9702# # 9703# INPUT *************************************************************** # 9704# a0 = pointer to extended precision input X # 9705# a1 = pointer to extended precision input Y # 9706# d0 = round precision,mode # 9707# # 9708# The input operands X and Y can be either normalized or # 9709# denormalized. # 9710# # 9711# OUTPUT ************************************************************** # 9712# fp0 = FREM(X,Y) or FMOD(X,Y) # 9713# # 9714# ALGORITHM *********************************************************** # 9715# # 9716# Step 1. Save and strip signs of X and Y: signX := sign(X), # 9717# signY := sign(Y), X := |X|, Y := |Y|, # 9718# signQ := signX EOR signY. Record whether MOD or REM # 9719# is requested. # 9720# # 9721# Step 2. Set L := expo(X)-expo(Y), k := 0, Q := 0. # 9722# If (L < 0) then # 9723# R := X, go to Step 4. # 9724# else # 9725# R := 2^(-L)X, j := L. # 9726# endif # 9727# # 9728# Step 3. Perform MOD(X,Y) # 9729# 3.1 If R = Y, go to Step 9. # 9730# 3.2 If R > Y, then { R := R - Y, Q := Q + 1} # 9731# 3.3 If j = 0, go to Step 4. # 9732# 3.4 k := k + 1, j := j - 1, Q := 2Q, R := 2R. Go to # 9733# Step 3.1. # 9734# # 9735# Step 4. At this point, R = X - QY = MOD(X,Y). Set # 9736# Last_Subtract := false (used in Step 7 below). If # 9737# MOD is requested, go to Step 6. # 9738# # 9739# Step 5. R = MOD(X,Y), but REM(X,Y) is requested. # 9740# 5.1 If R < Y/2, then R = MOD(X,Y) = REM(X,Y). Go to # 9741# Step 6. # 9742# 5.2 If R > Y/2, then { set Last_Subtract := true, # 9743# Q := Q + 1, Y := signY*Y }. Go to Step 6. # 9744# 5.3 This is the tricky case of R = Y/2. If Q is odd, # 9745# then { Q := Q + 1, signX := -signX }. # 9746# # 9747# Step 6. R := signX*R. # 9748# # 9749# Step 7. If Last_Subtract = true, R := R - Y. # 9750# # 9751# Step 8. Return signQ, last 7 bits of Q, and R as required. # 9752# # 9753# Step 9. At this point, R = 2^(-j)*X - Q Y = Y. Thus, # 9754# X = 2^(j)*(Q+1)Y. set Q := 2^(j)*(Q+1), # 9755# R := 0. Return signQ, last 7 bits of Q, and R. # 9756# # 9757######################################################################### 9758 9759 set Mod_Flag,L_SCR3 9760 set Sc_Flag,L_SCR3+1 9761 9762 set SignY,L_SCR2 9763 set SignX,L_SCR2+2 9764 set SignQ,L_SCR3+2 9765 9766 set Y,FP_SCR0 9767 set Y_Hi,Y+4 9768 set Y_Lo,Y+8 9769 9770 set R,FP_SCR1 9771 set R_Hi,R+4 9772 set R_Lo,R+8 9773 9774Scale: 9775 long 0x00010000,0x80000000,0x00000000,0x00000000 9776 9777 global smod 9778smod: 9779 clr.b FPSR_QBYTE(%a6) 9780 mov.l %d0,-(%sp) # save ctrl bits 9781 clr.b Mod_Flag(%a6) 9782 bra.b Mod_Rem 9783 9784 global srem 9785srem: 9786 clr.b FPSR_QBYTE(%a6) 9787 mov.l %d0,-(%sp) # save ctrl bits 9788 mov.b &0x1,Mod_Flag(%a6) 9789 9790Mod_Rem: 9791#..Save sign of X and Y 9792 movm.l &0x3f00,-(%sp) # save data registers 9793 mov.w SRC_EX(%a0),%d3 9794 mov.w %d3,SignY(%a6) 9795 and.l &0x00007FFF,%d3 # Y := |Y| 9796 9797# 9798 mov.l SRC_HI(%a0),%d4 9799 mov.l SRC_LO(%a0),%d5 # (D3,D4,D5) is |Y| 9800 9801 tst.l %d3 9802 bne.b Y_Normal 9803 9804 mov.l &0x00003FFE,%d3 # $3FFD + 1 9805 tst.l %d4 9806 bne.b HiY_not0 9807 9808HiY_0: 9809 mov.l %d5,%d4 9810 clr.l %d5 9811 sub.l &32,%d3 9812 clr.l %d6 9813 bfffo %d4{&0:&32},%d6 9814 lsl.l %d6,%d4 9815 sub.l %d6,%d3 # (D3,D4,D5) is normalized 9816# ...with bias $7FFD 9817 bra.b Chk_X 9818 9819HiY_not0: 9820 clr.l %d6 9821 bfffo %d4{&0:&32},%d6 9822 sub.l %d6,%d3 9823 lsl.l %d6,%d4 9824 mov.l %d5,%d7 # a copy of D5 9825 lsl.l %d6,%d5 9826 neg.l %d6 9827 add.l &32,%d6 9828 lsr.l %d6,%d7 9829 or.l %d7,%d4 # (D3,D4,D5) normalized 9830# ...with bias $7FFD 9831 bra.b Chk_X 9832 9833Y_Normal: 9834 add.l &0x00003FFE,%d3 # (D3,D4,D5) normalized 9835# ...with bias $7FFD 9836 9837Chk_X: 9838 mov.w DST_EX(%a1),%d0 9839 mov.w %d0,SignX(%a6) 9840 mov.w SignY(%a6),%d1 9841 eor.l %d0,%d1 9842 and.l &0x00008000,%d1 9843 mov.w %d1,SignQ(%a6) # sign(Q) obtained 9844 and.l &0x00007FFF,%d0 9845 mov.l DST_HI(%a1),%d1 9846 mov.l DST_LO(%a1),%d2 # (D0,D1,D2) is |X| 9847 tst.l %d0 9848 bne.b X_Normal 9849 mov.l &0x00003FFE,%d0 9850 tst.l %d1 9851 bne.b HiX_not0 9852 9853HiX_0: 9854 mov.l %d2,%d1 9855 clr.l %d2 9856 sub.l &32,%d0 9857 clr.l %d6 9858 bfffo %d1{&0:&32},%d6 9859 lsl.l %d6,%d1 9860 sub.l %d6,%d0 # (D0,D1,D2) is normalized 9861# ...with bias $7FFD 9862 bra.b Init 9863 9864HiX_not0: 9865 clr.l %d6 9866 bfffo %d1{&0:&32},%d6 9867 sub.l %d6,%d0 9868 lsl.l %d6,%d1 9869 mov.l %d2,%d7 # a copy of D2 9870 lsl.l %d6,%d2 9871 neg.l %d6 9872 add.l &32,%d6 9873 lsr.l %d6,%d7 9874 or.l %d7,%d1 # (D0,D1,D2) normalized 9875# ...with bias $7FFD 9876 bra.b Init 9877 9878X_Normal: 9879 add.l &0x00003FFE,%d0 # (D0,D1,D2) normalized 9880# ...with bias $7FFD 9881 9882Init: 9883# 9884 mov.l %d3,L_SCR1(%a6) # save biased exp(Y) 9885 mov.l %d0,-(%sp) # save biased exp(X) 9886 sub.l %d3,%d0 # L := expo(X)-expo(Y) 9887 9888 clr.l %d6 # D6 := carry <- 0 9889 clr.l %d3 # D3 is Q 9890 mov.l &0,%a1 # A1 is k; j+k=L, Q=0 9891 9892#..(Carry,D1,D2) is R 9893 tst.l %d0 9894 bge.b Mod_Loop_pre 9895 9896#..expo(X) < expo(Y). Thus X = mod(X,Y) 9897# 9898 mov.l (%sp)+,%d0 # restore d0 9899 bra.w Get_Mod 9900 9901Mod_Loop_pre: 9902 addq.l &0x4,%sp # erase exp(X) 9903#..At this point R = 2^(-L)X; Q = 0; k = 0; and k+j = L 9904Mod_Loop: 9905 tst.l %d6 # test carry bit 9906 bgt.b R_GT_Y 9907 9908#..At this point carry = 0, R = (D1,D2), Y = (D4,D5) 9909 cmp.l %d1,%d4 # compare hi(R) and hi(Y) 9910 bne.b R_NE_Y 9911 cmp.l %d2,%d5 # compare lo(R) and lo(Y) 9912 bne.b R_NE_Y 9913 9914#..At this point, R = Y 9915 bra.w Rem_is_0 9916 9917R_NE_Y: 9918#..use the borrow of the previous compare 9919 bcs.b R_LT_Y # borrow is set iff R < Y 9920 9921R_GT_Y: 9922#..If Carry is set, then Y < (Carry,D1,D2) < 2Y. Otherwise, Carry = 0 9923#..and Y < (D1,D2) < 2Y. Either way, perform R - Y 9924 sub.l %d5,%d2 # lo(R) - lo(Y) 9925 subx.l %d4,%d1 # hi(R) - hi(Y) 9926 clr.l %d6 # clear carry 9927 addq.l &1,%d3 # Q := Q + 1 9928 9929R_LT_Y: 9930#..At this point, Carry=0, R < Y. R = 2^(k-L)X - QY; k+j = L; j >= 0. 9931 tst.l %d0 # see if j = 0. 9932 beq.b PostLoop 9933 9934 add.l %d3,%d3 # Q := 2Q 9935 add.l %d2,%d2 # lo(R) = 2lo(R) 9936 roxl.l &1,%d1 # hi(R) = 2hi(R) + carry 9937 scs %d6 # set Carry if 2(R) overflows 9938 addq.l &1,%a1 # k := k+1 9939 subq.l &1,%d0 # j := j - 1 9940#..At this point, R=(Carry,D1,D2) = 2^(k-L)X - QY, j+k=L, j >= 0, R < 2Y. 9941 9942 bra.b Mod_Loop 9943 9944PostLoop: 9945#..k = L, j = 0, Carry = 0, R = (D1,D2) = X - QY, R < Y. 9946 9947#..normalize R. 9948 mov.l L_SCR1(%a6),%d0 # new biased expo of R 9949 tst.l %d1 9950 bne.b HiR_not0 9951 9952HiR_0: 9953 mov.l %d2,%d1 9954 clr.l %d2 9955 sub.l &32,%d0 9956 clr.l %d6 9957 bfffo %d1{&0:&32},%d6 9958 lsl.l %d6,%d1 9959 sub.l %d6,%d0 # (D0,D1,D2) is normalized 9960# ...with bias $7FFD 9961 bra.b Get_Mod 9962 9963HiR_not0: 9964 clr.l %d6 9965 bfffo %d1{&0:&32},%d6 9966 bmi.b Get_Mod # already normalized 9967 sub.l %d6,%d0 9968 lsl.l %d6,%d1 9969 mov.l %d2,%d7 # a copy of D2 9970 lsl.l %d6,%d2 9971 neg.l %d6 9972 add.l &32,%d6 9973 lsr.l %d6,%d7 9974 or.l %d7,%d1 # (D0,D1,D2) normalized 9975 9976# 9977Get_Mod: 9978 cmp.l %d0,&0x000041FE 9979 bge.b No_Scale 9980Do_Scale: 9981 mov.w %d0,R(%a6) 9982 mov.l %d1,R_Hi(%a6) 9983 mov.l %d2,R_Lo(%a6) 9984 mov.l L_SCR1(%a6),%d6 9985 mov.w %d6,Y(%a6) 9986 mov.l %d4,Y_Hi(%a6) 9987 mov.l %d5,Y_Lo(%a6) 9988 fmov.x R(%a6),%fp0 # no exception 9989 mov.b &1,Sc_Flag(%a6) 9990 bra.b ModOrRem 9991No_Scale: 9992 mov.l %d1,R_Hi(%a6) 9993 mov.l %d2,R_Lo(%a6) 9994 sub.l &0x3FFE,%d0 9995 mov.w %d0,R(%a6) 9996 mov.l L_SCR1(%a6),%d6 9997 sub.l &0x3FFE,%d6 9998 mov.l %d6,L_SCR1(%a6) 9999 fmov.x R(%a6),%fp0 10000 mov.w %d6,Y(%a6) 10001 mov.l %d4,Y_Hi(%a6) 10002 mov.l %d5,Y_Lo(%a6) 10003 clr.b Sc_Flag(%a6) 10004 10005# 10006ModOrRem: 10007 tst.b Mod_Flag(%a6) 10008 beq.b Fix_Sign 10009 10010 mov.l L_SCR1(%a6),%d6 # new biased expo(Y) 10011 subq.l &1,%d6 # biased expo(Y/2) 10012 cmp.l %d0,%d6 10013 blt.b Fix_Sign 10014 bgt.b Last_Sub 10015 10016 cmp.l %d1,%d4 10017 bne.b Not_EQ 10018 cmp.l %d2,%d5 10019 bne.b Not_EQ 10020 bra.w Tie_Case 10021 10022Not_EQ: 10023 bcs.b Fix_Sign 10024 10025Last_Sub: 10026# 10027 fsub.x Y(%a6),%fp0 # no exceptions 10028 addq.l &1,%d3 # Q := Q + 1 10029 10030# 10031Fix_Sign: 10032#..Get sign of X 10033 mov.w SignX(%a6),%d6 10034 bge.b Get_Q 10035 fneg.x %fp0 10036 10037#..Get Q 10038# 10039Get_Q: 10040 clr.l %d6 10041 mov.w SignQ(%a6),%d6 # D6 is sign(Q) 10042 mov.l &8,%d7 10043 lsr.l %d7,%d6 10044 and.l &0x0000007F,%d3 # 7 bits of Q 10045 or.l %d6,%d3 # sign and bits of Q 10046# swap %d3 10047# fmov.l %fpsr,%d6 10048# and.l &0xFF00FFFF,%d6 10049# or.l %d3,%d6 10050# fmov.l %d6,%fpsr # put Q in fpsr 10051 mov.b %d3,FPSR_QBYTE(%a6) # put Q in fpsr 10052 10053# 10054Restore: 10055 movm.l (%sp)+,&0xfc # {%d2-%d7} 10056 mov.l (%sp)+,%d0 10057 fmov.l %d0,%fpcr 10058 tst.b Sc_Flag(%a6) 10059 beq.b Finish 10060 mov.b &FMUL_OP,%d1 # last inst is MUL 10061 fmul.x Scale(%pc),%fp0 # may cause underflow 10062 bra t_catch2 10063# the '040 package did this apparently to see if the dst operand for the 10064# preceding fmul was a denorm. but, it better not have been since the 10065# algorithm just got done playing with fp0 and expected no exceptions 10066# as a result. trust me... 10067# bra t_avoid_unsupp # check for denorm as a 10068# ;result of the scaling 10069 10070Finish: 10071 mov.b &FMOV_OP,%d1 # last inst is MOVE 10072 fmov.x %fp0,%fp0 # capture exceptions & round 10073 bra t_catch2 10074 10075Rem_is_0: 10076#..R = 2^(-j)X - Q Y = Y, thus R = 0 and quotient = 2^j (Q+1) 10077 addq.l &1,%d3 10078 cmp.l %d0,&8 # D0 is j 10079 bge.b Q_Big 10080 10081 lsl.l %d0,%d3 10082 bra.b Set_R_0 10083 10084Q_Big: 10085 clr.l %d3 10086 10087Set_R_0: 10088 fmov.s &0x00000000,%fp0 10089 clr.b Sc_Flag(%a6) 10090 bra.w Fix_Sign 10091 10092Tie_Case: 10093#..Check parity of Q 10094 mov.l %d3,%d6 10095 and.l &0x00000001,%d6 10096 tst.l %d6 10097 beq.w Fix_Sign # Q is even 10098 10099#..Q is odd, Q := Q + 1, signX := -signX 10100 addq.l &1,%d3 10101 mov.w SignX(%a6),%d6 10102 eor.l &0x00008000,%d6 10103 mov.w %d6,SignX(%a6) 10104 bra.w Fix_Sign 10105 10106qnan: long 0x7fff0000, 0xffffffff, 0xffffffff 10107 10108######################################################################### 10109# XDEF **************************************************************** # 10110# t_dz(): Handle DZ exception during transcendental emulation. # 10111# Sets N bit according to sign of source operand. # 10112# t_dz2(): Handle DZ exception during transcendental emulation. # 10113# Sets N bit always. # 10114# # 10115# XREF **************************************************************** # 10116# None # 10117# # 10118# INPUT *************************************************************** # 10119# a0 = pointer to source operand # 10120# # 10121# OUTPUT ************************************************************** # 10122# fp0 = default result # 10123# # 10124# ALGORITHM *********************************************************** # 10125# - Store properly signed INF into fp0. # 10126# - Set FPSR exception status dz bit, ccode inf bit, and # 10127# accrued dz bit. # 10128# # 10129######################################################################### 10130 10131 global t_dz 10132t_dz: 10133 tst.b SRC_EX(%a0) # no; is src negative? 10134 bmi.b t_dz2 # yes 10135 10136dz_pinf: 10137 fmov.s &0x7f800000,%fp0 # return +INF in fp0 10138 ori.l &dzinf_mask,USER_FPSR(%a6) # set I/DZ/ADZ 10139 rts 10140 10141 global t_dz2 10142t_dz2: 10143 fmov.s &0xff800000,%fp0 # return -INF in fp0 10144 ori.l &dzinf_mask+neg_mask,USER_FPSR(%a6) # set N/I/DZ/ADZ 10145 rts 10146 10147################################################################# 10148# OPERR exception: # 10149# - set FPSR exception status operr bit, condition code # 10150# nan bit; Store default NAN into fp0 # 10151################################################################# 10152 global t_operr 10153t_operr: 10154 ori.l &opnan_mask,USER_FPSR(%a6) # set NaN/OPERR/AIOP 10155 fmovm.x qnan(%pc),&0x80 # return default NAN in fp0 10156 rts 10157 10158################################################################# 10159# Extended DENORM: # 10160# - For all functions that have a denormalized input and # 10161# that f(x)=x, this is the entry point. # 10162# - we only return the EXOP here if either underflow or # 10163# inexact is enabled. # 10164################################################################# 10165 10166# Entry point for scale w/ extended denorm. The function does 10167# NOT set INEX2/AUNFL/AINEX. 10168 global t_resdnrm 10169t_resdnrm: 10170 ori.l &unfl_mask,USER_FPSR(%a6) # set UNFL 10171 bra.b xdnrm_con 10172 10173 global t_extdnrm 10174t_extdnrm: 10175 ori.l &unfinx_mask,USER_FPSR(%a6) # set UNFL/INEX2/AUNFL/AINEX 10176 10177xdnrm_con: 10178 mov.l %a0,%a1 # make copy of src ptr 10179 mov.l %d0,%d1 # make copy of rnd prec,mode 10180 andi.b &0xc0,%d1 # extended precision? 10181 bne.b xdnrm_sd # no 10182 10183# result precision is extended. 10184 tst.b LOCAL_EX(%a0) # is denorm negative? 10185 bpl.b xdnrm_exit # no 10186 10187 bset &neg_bit,FPSR_CC(%a6) # yes; set 'N' ccode bit 10188 bra.b xdnrm_exit 10189 10190# result precision is single or double 10191xdnrm_sd: 10192 mov.l %a1,-(%sp) 10193 tst.b LOCAL_EX(%a0) # is denorm pos or neg? 10194 smi.b %d1 # set d0 accordingly 10195 bsr.l unf_sub 10196 mov.l (%sp)+,%a1 10197xdnrm_exit: 10198 fmovm.x (%a0),&0x80 # return default result in fp0 10199 10200 mov.b FPCR_ENABLE(%a6),%d0 10201 andi.b &0x0a,%d0 # is UNFL or INEX enabled? 10202 bne.b xdnrm_ena # yes 10203 rts 10204 10205################ 10206# unfl enabled # 10207################ 10208# we have a DENORM that needs to be converted into an EXOP. 10209# so, normalize the mantissa, add 0x6000 to the new exponent, 10210# and return the result in fp1. 10211xdnrm_ena: 10212 mov.w LOCAL_EX(%a1),FP_SCR0_EX(%a6) 10213 mov.l LOCAL_HI(%a1),FP_SCR0_HI(%a6) 10214 mov.l LOCAL_LO(%a1),FP_SCR0_LO(%a6) 10215 10216 lea FP_SCR0(%a6),%a0 10217 bsr.l norm # normalize mantissa 10218 addi.l &0x6000,%d0 # add extra bias 10219 andi.w &0x8000,FP_SCR0_EX(%a6) # keep old sign 10220 or.w %d0,FP_SCR0_EX(%a6) # insert new exponent 10221 10222 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 10223 rts 10224 10225################################################################# 10226# UNFL exception: # 10227# - This routine is for cases where even an EXOP isn't # 10228# large enough to hold the range of this result. # 10229# In such a case, the EXOP equals zero. # 10230# - Return the default result to the proper precision # 10231# with the sign of this result being the same as that # 10232# of the src operand. # 10233# - t_unfl2() is provided to force the result sign to # 10234# positive which is the desired result for fetox(). # 10235################################################################# 10236 global t_unfl 10237t_unfl: 10238 ori.l &unfinx_mask,USER_FPSR(%a6) # set UNFL/INEX2/AUNFL/AINEX 10239 10240 tst.b (%a0) # is result pos or neg? 10241 smi.b %d1 # set d1 accordingly 10242 bsr.l unf_sub # calc default unfl result 10243 fmovm.x (%a0),&0x80 # return default result in fp0 10244 10245 fmov.s &0x00000000,%fp1 # return EXOP in fp1 10246 rts 10247 10248# t_unfl2 ALWAYS tells unf_sub to create a positive result 10249 global t_unfl2 10250t_unfl2: 10251 ori.l &unfinx_mask,USER_FPSR(%a6) # set UNFL/INEX2/AUNFL/AINEX 10252 10253 sf.b %d1 # set d0 to represent positive 10254 bsr.l unf_sub # calc default unfl result 10255 fmovm.x (%a0),&0x80 # return default result in fp0 10256 10257 fmov.s &0x0000000,%fp1 # return EXOP in fp1 10258 rts 10259 10260################################################################# 10261# OVFL exception: # 10262# - This routine is for cases where even an EXOP isn't # 10263# large enough to hold the range of this result. # 10264# - Return the default result to the proper precision # 10265# with the sign of this result being the same as that # 10266# of the src operand. # 10267# - t_ovfl2() is provided to force the result sign to # 10268# positive which is the desired result for fcosh(). # 10269# - t_ovfl_sc() is provided for scale() which only sets # 10270# the inexact bits if the number is inexact for the # 10271# precision indicated. # 10272################################################################# 10273 10274 global t_ovfl_sc 10275t_ovfl_sc: 10276 ori.l &ovfl_inx_mask,USER_FPSR(%a6) # set OVFL/AOVFL/AINEX 10277 10278 mov.b %d0,%d1 # fetch rnd mode/prec 10279 andi.b &0xc0,%d1 # extract rnd prec 10280 beq.b ovfl_work # prec is extended 10281 10282 tst.b LOCAL_HI(%a0) # is dst a DENORM? 10283 bmi.b ovfl_sc_norm # no 10284 10285# dst op is a DENORM. we have to normalize the mantissa to see if the 10286# result would be inexact for the given precision. make a copy of the 10287# dst so we don't screw up the version passed to us. 10288 mov.w LOCAL_EX(%a0),FP_SCR0_EX(%a6) 10289 mov.l LOCAL_HI(%a0),FP_SCR0_HI(%a6) 10290 mov.l LOCAL_LO(%a0),FP_SCR0_LO(%a6) 10291 lea FP_SCR0(%a6),%a0 # pass ptr to FP_SCR0 10292 movm.l &0xc080,-(%sp) # save d0-d1/a0 10293 bsr.l norm # normalize mantissa 10294 movm.l (%sp)+,&0x0103 # restore d0-d1/a0 10295 10296ovfl_sc_norm: 10297 cmpi.b %d1,&0x40 # is prec dbl? 10298 bne.b ovfl_sc_dbl # no; sgl 10299ovfl_sc_sgl: 10300 tst.l LOCAL_LO(%a0) # is lo lw of sgl set? 10301 bne.b ovfl_sc_inx # yes 10302 tst.b 3+LOCAL_HI(%a0) # is lo byte of hi lw set? 10303 bne.b ovfl_sc_inx # yes 10304 bra.b ovfl_work # don't set INEX2 10305ovfl_sc_dbl: 10306 mov.l LOCAL_LO(%a0),%d1 # are any of lo 11 bits of 10307 andi.l &0x7ff,%d1 # dbl mantissa set? 10308 beq.b ovfl_work # no; don't set INEX2 10309ovfl_sc_inx: 10310 ori.l &inex2_mask,USER_FPSR(%a6) # set INEX2 10311 bra.b ovfl_work # continue 10312 10313 global t_ovfl 10314t_ovfl: 10315 ori.l &ovfinx_mask,USER_FPSR(%a6) # set OVFL/INEX2/AOVFL/AINEX 10316 10317ovfl_work: 10318 tst.b LOCAL_EX(%a0) # what is the sign? 10319 smi.b %d1 # set d1 accordingly 10320 bsr.l ovf_res # calc default ovfl result 10321 mov.b %d0,FPSR_CC(%a6) # insert new ccodes 10322 fmovm.x (%a0),&0x80 # return default result in fp0 10323 10324 fmov.s &0x00000000,%fp1 # return EXOP in fp1 10325 rts 10326 10327# t_ovfl2 ALWAYS tells ovf_res to create a positive result 10328 global t_ovfl2 10329t_ovfl2: 10330 ori.l &ovfinx_mask,USER_FPSR(%a6) # set OVFL/INEX2/AOVFL/AINEX 10331 10332 sf.b %d1 # clear sign flag for positive 10333 bsr.l ovf_res # calc default ovfl result 10334 mov.b %d0,FPSR_CC(%a6) # insert new ccodes 10335 fmovm.x (%a0),&0x80 # return default result in fp0 10336 10337 fmov.s &0x00000000,%fp1 # return EXOP in fp1 10338 rts 10339 10340################################################################# 10341# t_catch(): # 10342# - the last operation of a transcendental emulation # 10343# routine may have caused an underflow or overflow. # 10344# we find out if this occurred by doing an fsave and # 10345# checking the exception bit. if one did occur, then we # 10346# jump to fgen_except() which creates the default # 10347# result and EXOP for us. # 10348################################################################# 10349 global t_catch 10350t_catch: 10351 10352 fsave -(%sp) 10353 tst.b 0x2(%sp) 10354 bmi.b catch 10355 add.l &0xc,%sp 10356 10357################################################################# 10358# INEX2 exception: # 10359# - The inex2 and ainex bits are set. # 10360################################################################# 10361 global t_inx2 10362t_inx2: 10363 fblt.w t_minx2 10364 fbeq.w inx2_zero 10365 10366 global t_pinx2 10367t_pinx2: 10368 ori.w &inx2a_mask,2+USER_FPSR(%a6) # set INEX2/AINEX 10369 rts 10370 10371 global t_minx2 10372t_minx2: 10373 ori.l &inx2a_mask+neg_mask,USER_FPSR(%a6) # set N/INEX2/AINEX 10374 rts 10375 10376inx2_zero: 10377 mov.b &z_bmask,FPSR_CC(%a6) 10378 ori.w &inx2a_mask,2+USER_FPSR(%a6) # set INEX2/AINEX 10379 rts 10380 10381# an underflow or overflow exception occurred. 10382# we must set INEX/AINEX since the fmul/fdiv/fmov emulation may not! 10383catch: 10384 ori.w &inx2a_mask,FPSR_EXCEPT(%a6) 10385catch2: 10386 bsr.l fgen_except 10387 add.l &0xc,%sp 10388 rts 10389 10390 global t_catch2 10391t_catch2: 10392 10393 fsave -(%sp) 10394 10395 tst.b 0x2(%sp) 10396 bmi.b catch2 10397 add.l &0xc,%sp 10398 10399 fmov.l %fpsr,%d0 10400 or.l %d0,USER_FPSR(%a6) 10401 10402 rts 10403 10404######################################################################### 10405 10406######################################################################### 10407# unf_res(): underflow default result calculation for transcendentals # 10408# # 10409# INPUT: # 10410# d0 : rnd mode,precision # 10411# d1.b : sign bit of result ('11111111 = (-) ; '00000000 = (+)) # 10412# OUTPUT: # 10413# a0 : points to result (in instruction memory) # 10414######################################################################### 10415unf_sub: 10416 ori.l &unfinx_mask,USER_FPSR(%a6) 10417 10418 andi.w &0x10,%d1 # keep sign bit in 4th spot 10419 10420 lsr.b &0x4,%d0 # shift rnd prec,mode to lo bits 10421 andi.b &0xf,%d0 # strip hi rnd mode bit 10422 or.b %d1,%d0 # concat {sgn,mode,prec} 10423 10424 mov.l %d0,%d1 # make a copy 10425 lsl.b &0x1,%d1 # mult index 2 by 2 10426 10427 mov.b (tbl_unf_cc.b,%pc,%d0.w*1),FPSR_CC(%a6) # insert ccode bits 10428 lea (tbl_unf_result.b,%pc,%d1.w*8),%a0 # grab result ptr 10429 rts 10430 10431tbl_unf_cc: 10432 byte 0x4, 0x4, 0x4, 0x0 10433 byte 0x4, 0x4, 0x4, 0x0 10434 byte 0x4, 0x4, 0x4, 0x0 10435 byte 0x0, 0x0, 0x0, 0x0 10436 byte 0x8+0x4, 0x8+0x4, 0x8, 0x8+0x4 10437 byte 0x8+0x4, 0x8+0x4, 0x8, 0x8+0x4 10438 byte 0x8+0x4, 0x8+0x4, 0x8, 0x8+0x4 10439 10440tbl_unf_result: 10441 long 0x00000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext 10442 long 0x00000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext 10443 long 0x00000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext 10444 long 0x00000000, 0x00000000, 0x00000001, 0x0 # MIN; ext 10445 10446 long 0x3f810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl 10447 long 0x3f810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl 10448 long 0x3f810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl 10449 long 0x3f810000, 0x00000100, 0x00000000, 0x0 # MIN; sgl 10450 10451 long 0x3c010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl 10452 long 0x3c010000, 0x00000000, 0x00000000, 0x0 # ZER0;dbl 10453 long 0x3c010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl 10454 long 0x3c010000, 0x00000000, 0x00000800, 0x0 # MIN; dbl 10455 10456 long 0x0,0x0,0x0,0x0 10457 long 0x0,0x0,0x0,0x0 10458 long 0x0,0x0,0x0,0x0 10459 long 0x0,0x0,0x0,0x0 10460 10461 long 0x80000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext 10462 long 0x80000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext 10463 long 0x80000000, 0x00000000, 0x00000001, 0x0 # MIN; ext 10464 long 0x80000000, 0x00000000, 0x00000000, 0x0 # ZERO;ext 10465 10466 long 0xbf810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl 10467 long 0xbf810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl 10468 long 0xbf810000, 0x00000100, 0x00000000, 0x0 # MIN; sgl 10469 long 0xbf810000, 0x00000000, 0x00000000, 0x0 # ZERO;sgl 10470 10471 long 0xbc010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl 10472 long 0xbc010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl 10473 long 0xbc010000, 0x00000000, 0x00000800, 0x0 # MIN; dbl 10474 long 0xbc010000, 0x00000000, 0x00000000, 0x0 # ZERO;dbl 10475 10476############################################################ 10477 10478######################################################################### 10479# src_zero(): Return signed zero according to sign of src operand. # 10480######################################################################### 10481 global src_zero 10482src_zero: 10483 tst.b SRC_EX(%a0) # get sign of src operand 10484 bmi.b ld_mzero # if neg, load neg zero 10485 10486# 10487# ld_pzero(): return a positive zero. 10488# 10489 global ld_pzero 10490ld_pzero: 10491 fmov.s &0x00000000,%fp0 # load +0 10492 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 10493 rts 10494 10495# ld_mzero(): return a negative zero. 10496 global ld_mzero 10497ld_mzero: 10498 fmov.s &0x80000000,%fp0 # load -0 10499 mov.b &neg_bmask+z_bmask,FPSR_CC(%a6) # set 'N','Z' ccode bits 10500 rts 10501 10502######################################################################### 10503# dst_zero(): Return signed zero according to sign of dst operand. # 10504######################################################################### 10505 global dst_zero 10506dst_zero: 10507 tst.b DST_EX(%a1) # get sign of dst operand 10508 bmi.b ld_mzero # if neg, load neg zero 10509 bra.b ld_pzero # load positive zero 10510 10511######################################################################### 10512# src_inf(): Return signed inf according to sign of src operand. # 10513######################################################################### 10514 global src_inf 10515src_inf: 10516 tst.b SRC_EX(%a0) # get sign of src operand 10517 bmi.b ld_minf # if negative branch 10518 10519# 10520# ld_pinf(): return a positive infinity. 10521# 10522 global ld_pinf 10523ld_pinf: 10524 fmov.s &0x7f800000,%fp0 # load +INF 10525 mov.b &inf_bmask,FPSR_CC(%a6) # set 'INF' ccode bit 10526 rts 10527 10528# 10529# ld_minf():return a negative infinity. 10530# 10531 global ld_minf 10532ld_minf: 10533 fmov.s &0xff800000,%fp0 # load -INF 10534 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits 10535 rts 10536 10537######################################################################### 10538# dst_inf(): Return signed inf according to sign of dst operand. # 10539######################################################################### 10540 global dst_inf 10541dst_inf: 10542 tst.b DST_EX(%a1) # get sign of dst operand 10543 bmi.b ld_minf # if negative branch 10544 bra.b ld_pinf 10545 10546 global szr_inf 10547################################################################# 10548# szr_inf(): Return +ZERO for a negative src operand or # 10549# +INF for a positive src operand. # 10550# Routine used for fetox, ftwotox, and ftentox. # 10551################################################################# 10552szr_inf: 10553 tst.b SRC_EX(%a0) # check sign of source 10554 bmi.b ld_pzero 10555 bra.b ld_pinf 10556 10557######################################################################### 10558# sopr_inf(): Return +INF for a positive src operand or # 10559# jump to operand error routine for a negative src operand. # 10560# Routine used for flogn, flognp1, flog10, and flog2. # 10561######################################################################### 10562 global sopr_inf 10563sopr_inf: 10564 tst.b SRC_EX(%a0) # check sign of source 10565 bmi.w t_operr 10566 bra.b ld_pinf 10567 10568################################################################# 10569# setoxm1i(): Return minus one for a negative src operand or # 10570# positive infinity for a positive src operand. # 10571# Routine used for fetoxm1. # 10572################################################################# 10573 global setoxm1i 10574setoxm1i: 10575 tst.b SRC_EX(%a0) # check sign of source 10576 bmi.b ld_mone 10577 bra.b ld_pinf 10578 10579######################################################################### 10580# src_one(): Return signed one according to sign of src operand. # 10581######################################################################### 10582 global src_one 10583src_one: 10584 tst.b SRC_EX(%a0) # check sign of source 10585 bmi.b ld_mone 10586 10587# 10588# ld_pone(): return positive one. 10589# 10590 global ld_pone 10591ld_pone: 10592 fmov.s &0x3f800000,%fp0 # load +1 10593 clr.b FPSR_CC(%a6) 10594 rts 10595 10596# 10597# ld_mone(): return negative one. 10598# 10599 global ld_mone 10600ld_mone: 10601 fmov.s &0xbf800000,%fp0 # load -1 10602 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 10603 rts 10604 10605ppiby2: long 0x3fff0000, 0xc90fdaa2, 0x2168c235 10606mpiby2: long 0xbfff0000, 0xc90fdaa2, 0x2168c235 10607 10608################################################################# 10609# spi_2(): Return signed PI/2 according to sign of src operand. # 10610################################################################# 10611 global spi_2 10612spi_2: 10613 tst.b SRC_EX(%a0) # check sign of source 10614 bmi.b ld_mpi2 10615 10616# 10617# ld_ppi2(): return positive PI/2. 10618# 10619 global ld_ppi2 10620ld_ppi2: 10621 fmov.l %d0,%fpcr 10622 fmov.x ppiby2(%pc),%fp0 # load +pi/2 10623 bra.w t_pinx2 # set INEX2 10624 10625# 10626# ld_mpi2(): return negative PI/2. 10627# 10628 global ld_mpi2 10629ld_mpi2: 10630 fmov.l %d0,%fpcr 10631 fmov.x mpiby2(%pc),%fp0 # load -pi/2 10632 bra.w t_minx2 # set INEX2 10633 10634#################################################### 10635# The following routines give support for fsincos. # 10636#################################################### 10637 10638# 10639# ssincosz(): When the src operand is ZERO, store a one in the 10640# cosine register and return a ZERO in fp0 w/ the same sign 10641# as the src operand. 10642# 10643 global ssincosz 10644ssincosz: 10645 fmov.s &0x3f800000,%fp1 10646 tst.b SRC_EX(%a0) # test sign 10647 bpl.b sincoszp 10648 fmov.s &0x80000000,%fp0 # return sin result in fp0 10649 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) 10650 bra.b sto_cos # store cosine result 10651sincoszp: 10652 fmov.s &0x00000000,%fp0 # return sin result in fp0 10653 mov.b &z_bmask,FPSR_CC(%a6) 10654 bra.b sto_cos # store cosine result 10655 10656# 10657# ssincosi(): When the src operand is INF, store a QNAN in the cosine 10658# register and jump to the operand error routine for negative 10659# src operands. 10660# 10661 global ssincosi 10662ssincosi: 10663 fmov.x qnan(%pc),%fp1 # load NAN 10664 bsr.l sto_cos # store cosine result 10665 bra.w t_operr 10666 10667# 10668# ssincosqnan(): When the src operand is a QNAN, store the QNAN in the cosine 10669# register and branch to the src QNAN routine. 10670# 10671 global ssincosqnan 10672ssincosqnan: 10673 fmov.x LOCAL_EX(%a0),%fp1 10674 bsr.l sto_cos 10675 bra.w src_qnan 10676 10677# 10678# ssincossnan(): When the src operand is an SNAN, store the SNAN w/ the SNAN bit set 10679# in the cosine register and branch to the src SNAN routine. 10680# 10681 global ssincossnan 10682ssincossnan: 10683 fmov.x LOCAL_EX(%a0),%fp1 10684 bsr.l sto_cos 10685 bra.w src_snan 10686 10687######################################################################## 10688 10689######################################################################### 10690# sto_cos(): store fp1 to the fpreg designated by the CMDREG dst field. # 10691# fp1 holds the result of the cosine portion of ssincos(). # 10692# the value in fp1 will not take any exceptions when moved. # 10693# INPUT: # 10694# fp1 : fp value to store # 10695# MODIFIED: # 10696# d0 # 10697######################################################################### 10698 global sto_cos 10699sto_cos: 10700 mov.b 1+EXC_CMDREG(%a6),%d0 10701 andi.w &0x7,%d0 10702 mov.w (tbl_sto_cos.b,%pc,%d0.w*2),%d0 10703 jmp (tbl_sto_cos.b,%pc,%d0.w*1) 10704 10705tbl_sto_cos: 10706 short sto_cos_0 - tbl_sto_cos 10707 short sto_cos_1 - tbl_sto_cos 10708 short sto_cos_2 - tbl_sto_cos 10709 short sto_cos_3 - tbl_sto_cos 10710 short sto_cos_4 - tbl_sto_cos 10711 short sto_cos_5 - tbl_sto_cos 10712 short sto_cos_6 - tbl_sto_cos 10713 short sto_cos_7 - tbl_sto_cos 10714 10715sto_cos_0: 10716 fmovm.x &0x40,EXC_FP0(%a6) 10717 rts 10718sto_cos_1: 10719 fmovm.x &0x40,EXC_FP1(%a6) 10720 rts 10721sto_cos_2: 10722 fmov.x %fp1,%fp2 10723 rts 10724sto_cos_3: 10725 fmov.x %fp1,%fp3 10726 rts 10727sto_cos_4: 10728 fmov.x %fp1,%fp4 10729 rts 10730sto_cos_5: 10731 fmov.x %fp1,%fp5 10732 rts 10733sto_cos_6: 10734 fmov.x %fp1,%fp6 10735 rts 10736sto_cos_7: 10737 fmov.x %fp1,%fp7 10738 rts 10739 10740################################################################## 10741 global smod_sdnrm 10742 global smod_snorm 10743smod_sdnrm: 10744smod_snorm: 10745 mov.b DTAG(%a6),%d1 10746 beq.l smod 10747 cmpi.b %d1,&ZERO 10748 beq.w smod_zro 10749 cmpi.b %d1,&INF 10750 beq.l t_operr 10751 cmpi.b %d1,&DENORM 10752 beq.l smod 10753 cmpi.b %d1,&SNAN 10754 beq.l dst_snan 10755 bra.l dst_qnan 10756 10757 global smod_szero 10758smod_szero: 10759 mov.b DTAG(%a6),%d1 10760 beq.l t_operr 10761 cmpi.b %d1,&ZERO 10762 beq.l t_operr 10763 cmpi.b %d1,&INF 10764 beq.l t_operr 10765 cmpi.b %d1,&DENORM 10766 beq.l t_operr 10767 cmpi.b %d1,&QNAN 10768 beq.l dst_qnan 10769 bra.l dst_snan 10770 10771 global smod_sinf 10772smod_sinf: 10773 mov.b DTAG(%a6),%d1 10774 beq.l smod_fpn 10775 cmpi.b %d1,&ZERO 10776 beq.l smod_zro 10777 cmpi.b %d1,&INF 10778 beq.l t_operr 10779 cmpi.b %d1,&DENORM 10780 beq.l smod_fpn 10781 cmpi.b %d1,&QNAN 10782 beq.l dst_qnan 10783 bra.l dst_snan 10784 10785smod_zro: 10786srem_zro: 10787 mov.b SRC_EX(%a0),%d1 # get src sign 10788 mov.b DST_EX(%a1),%d0 # get dst sign 10789 eor.b %d0,%d1 # get qbyte sign 10790 andi.b &0x80,%d1 10791 mov.b %d1,FPSR_QBYTE(%a6) 10792 tst.b %d0 10793 bpl.w ld_pzero 10794 bra.w ld_mzero 10795 10796smod_fpn: 10797srem_fpn: 10798 clr.b FPSR_QBYTE(%a6) 10799 mov.l %d0,-(%sp) 10800 mov.b SRC_EX(%a0),%d1 # get src sign 10801 mov.b DST_EX(%a1),%d0 # get dst sign 10802 eor.b %d0,%d1 # get qbyte sign 10803 andi.b &0x80,%d1 10804 mov.b %d1,FPSR_QBYTE(%a6) 10805 cmpi.b DTAG(%a6),&DENORM 10806 bne.b smod_nrm 10807 lea DST(%a1),%a0 10808 mov.l (%sp)+,%d0 10809 bra t_resdnrm 10810smod_nrm: 10811 fmov.l (%sp)+,%fpcr 10812 fmov.x DST(%a1),%fp0 10813 tst.b DST_EX(%a1) 10814 bmi.b smod_nrm_neg 10815 rts 10816 10817smod_nrm_neg: 10818 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode 10819 rts 10820 10821######################################################################### 10822 global srem_snorm 10823 global srem_sdnrm 10824srem_sdnrm: 10825srem_snorm: 10826 mov.b DTAG(%a6),%d1 10827 beq.l srem 10828 cmpi.b %d1,&ZERO 10829 beq.w srem_zro 10830 cmpi.b %d1,&INF 10831 beq.l t_operr 10832 cmpi.b %d1,&DENORM 10833 beq.l srem 10834 cmpi.b %d1,&QNAN 10835 beq.l dst_qnan 10836 bra.l dst_snan 10837 10838 global srem_szero 10839srem_szero: 10840 mov.b DTAG(%a6),%d1 10841 beq.l t_operr 10842 cmpi.b %d1,&ZERO 10843 beq.l t_operr 10844 cmpi.b %d1,&INF 10845 beq.l t_operr 10846 cmpi.b %d1,&DENORM 10847 beq.l t_operr 10848 cmpi.b %d1,&QNAN 10849 beq.l dst_qnan 10850 bra.l dst_snan 10851 10852 global srem_sinf 10853srem_sinf: 10854 mov.b DTAG(%a6),%d1 10855 beq.w srem_fpn 10856 cmpi.b %d1,&ZERO 10857 beq.w srem_zro 10858 cmpi.b %d1,&INF 10859 beq.l t_operr 10860 cmpi.b %d1,&DENORM 10861 beq.l srem_fpn 10862 cmpi.b %d1,&QNAN 10863 beq.l dst_qnan 10864 bra.l dst_snan 10865 10866######################################################################### 10867 global sscale_snorm 10868 global sscale_sdnrm 10869sscale_snorm: 10870sscale_sdnrm: 10871 mov.b DTAG(%a6),%d1 10872 beq.l sscale 10873 cmpi.b %d1,&ZERO 10874 beq.l dst_zero 10875 cmpi.b %d1,&INF 10876 beq.l dst_inf 10877 cmpi.b %d1,&DENORM 10878 beq.l sscale 10879 cmpi.b %d1,&QNAN 10880 beq.l dst_qnan 10881 bra.l dst_snan 10882 10883 global sscale_szero 10884sscale_szero: 10885 mov.b DTAG(%a6),%d1 10886 beq.l sscale 10887 cmpi.b %d1,&ZERO 10888 beq.l dst_zero 10889 cmpi.b %d1,&INF 10890 beq.l dst_inf 10891 cmpi.b %d1,&DENORM 10892 beq.l sscale 10893 cmpi.b %d1,&QNAN 10894 beq.l dst_qnan 10895 bra.l dst_snan 10896 10897 global sscale_sinf 10898sscale_sinf: 10899 mov.b DTAG(%a6),%d1 10900 beq.l t_operr 10901 cmpi.b %d1,&QNAN 10902 beq.l dst_qnan 10903 cmpi.b %d1,&SNAN 10904 beq.l dst_snan 10905 bra.l t_operr 10906 10907######################################################################## 10908 10909# 10910# sop_sqnan(): The src op for frem/fmod/fscale was a QNAN. 10911# 10912 global sop_sqnan 10913sop_sqnan: 10914 mov.b DTAG(%a6),%d1 10915 cmpi.b %d1,&QNAN 10916 beq.b dst_qnan 10917 cmpi.b %d1,&SNAN 10918 beq.b dst_snan 10919 bra.b src_qnan 10920 10921# 10922# sop_ssnan(): The src op for frem/fmod/fscale was an SNAN. 10923# 10924 global sop_ssnan 10925sop_ssnan: 10926 mov.b DTAG(%a6),%d1 10927 cmpi.b %d1,&QNAN 10928 beq.b dst_qnan_src_snan 10929 cmpi.b %d1,&SNAN 10930 beq.b dst_snan 10931 bra.b src_snan 10932 10933dst_qnan_src_snan: 10934 ori.l &snaniop_mask,USER_FPSR(%a6) # set NAN/SNAN/AIOP 10935 bra.b dst_qnan 10936 10937# 10938# dst_qnan(): Return the dst SNAN w/ the SNAN bit set. 10939# 10940 global dst_snan 10941dst_snan: 10942 fmov.x DST(%a1),%fp0 # the fmove sets the SNAN bit 10943 fmov.l %fpsr,%d0 # catch resulting status 10944 or.l %d0,USER_FPSR(%a6) # store status 10945 rts 10946 10947# 10948# dst_qnan(): Return the dst QNAN. 10949# 10950 global dst_qnan 10951dst_qnan: 10952 fmov.x DST(%a1),%fp0 # return the non-signalling nan 10953 tst.b DST_EX(%a1) # set ccodes according to QNAN sign 10954 bmi.b dst_qnan_m 10955dst_qnan_p: 10956 mov.b &nan_bmask,FPSR_CC(%a6) 10957 rts 10958dst_qnan_m: 10959 mov.b &neg_bmask+nan_bmask,FPSR_CC(%a6) 10960 rts 10961 10962# 10963# src_snan(): Return the src SNAN w/ the SNAN bit set. 10964# 10965 global src_snan 10966src_snan: 10967 fmov.x SRC(%a0),%fp0 # the fmove sets the SNAN bit 10968 fmov.l %fpsr,%d0 # catch resulting status 10969 or.l %d0,USER_FPSR(%a6) # store status 10970 rts 10971 10972# 10973# src_qnan(): Return the src QNAN. 10974# 10975 global src_qnan 10976src_qnan: 10977 fmov.x SRC(%a0),%fp0 # return the non-signalling nan 10978 tst.b SRC_EX(%a0) # set ccodes according to QNAN sign 10979 bmi.b dst_qnan_m 10980src_qnan_p: 10981 mov.b &nan_bmask,FPSR_CC(%a6) 10982 rts 10983src_qnan_m: 10984 mov.b &neg_bmask+nan_bmask,FPSR_CC(%a6) 10985 rts 10986 10987# 10988# fkern2.s: 10989# These entry points are used by the exception handler 10990# routines where an instruction is selected by an index into 10991# a large jump table corresponding to a given instruction which 10992# has been decoded. Flow continues here where we now decode 10993# further according to the source operand type. 10994# 10995 10996 global fsinh 10997fsinh: 10998 mov.b STAG(%a6),%d1 10999 beq.l ssinh 11000 cmpi.b %d1,&ZERO 11001 beq.l src_zero 11002 cmpi.b %d1,&INF 11003 beq.l src_inf 11004 cmpi.b %d1,&DENORM 11005 beq.l ssinhd 11006 cmpi.b %d1,&QNAN 11007 beq.l src_qnan 11008 bra.l src_snan 11009 11010 global flognp1 11011flognp1: 11012 mov.b STAG(%a6),%d1 11013 beq.l slognp1 11014 cmpi.b %d1,&ZERO 11015 beq.l src_zero 11016 cmpi.b %d1,&INF 11017 beq.l sopr_inf 11018 cmpi.b %d1,&DENORM 11019 beq.l slognp1d 11020 cmpi.b %d1,&QNAN 11021 beq.l src_qnan 11022 bra.l src_snan 11023 11024 global fetoxm1 11025fetoxm1: 11026 mov.b STAG(%a6),%d1 11027 beq.l setoxm1 11028 cmpi.b %d1,&ZERO 11029 beq.l src_zero 11030 cmpi.b %d1,&INF 11031 beq.l setoxm1i 11032 cmpi.b %d1,&DENORM 11033 beq.l setoxm1d 11034 cmpi.b %d1,&QNAN 11035 beq.l src_qnan 11036 bra.l src_snan 11037 11038 global ftanh 11039ftanh: 11040 mov.b STAG(%a6),%d1 11041 beq.l stanh 11042 cmpi.b %d1,&ZERO 11043 beq.l src_zero 11044 cmpi.b %d1,&INF 11045 beq.l src_one 11046 cmpi.b %d1,&DENORM 11047 beq.l stanhd 11048 cmpi.b %d1,&QNAN 11049 beq.l src_qnan 11050 bra.l src_snan 11051 11052 global fatan 11053fatan: 11054 mov.b STAG(%a6),%d1 11055 beq.l satan 11056 cmpi.b %d1,&ZERO 11057 beq.l src_zero 11058 cmpi.b %d1,&INF 11059 beq.l spi_2 11060 cmpi.b %d1,&DENORM 11061 beq.l satand 11062 cmpi.b %d1,&QNAN 11063 beq.l src_qnan 11064 bra.l src_snan 11065 11066 global fasin 11067fasin: 11068 mov.b STAG(%a6),%d1 11069 beq.l sasin 11070 cmpi.b %d1,&ZERO 11071 beq.l src_zero 11072 cmpi.b %d1,&INF 11073 beq.l t_operr 11074 cmpi.b %d1,&DENORM 11075 beq.l sasind 11076 cmpi.b %d1,&QNAN 11077 beq.l src_qnan 11078 bra.l src_snan 11079 11080 global fatanh 11081fatanh: 11082 mov.b STAG(%a6),%d1 11083 beq.l satanh 11084 cmpi.b %d1,&ZERO 11085 beq.l src_zero 11086 cmpi.b %d1,&INF 11087 beq.l t_operr 11088 cmpi.b %d1,&DENORM 11089 beq.l satanhd 11090 cmpi.b %d1,&QNAN 11091 beq.l src_qnan 11092 bra.l src_snan 11093 11094 global fsine 11095fsine: 11096 mov.b STAG(%a6),%d1 11097 beq.l ssin 11098 cmpi.b %d1,&ZERO 11099 beq.l src_zero 11100 cmpi.b %d1,&INF 11101 beq.l t_operr 11102 cmpi.b %d1,&DENORM 11103 beq.l ssind 11104 cmpi.b %d1,&QNAN 11105 beq.l src_qnan 11106 bra.l src_snan 11107 11108 global ftan 11109ftan: 11110 mov.b STAG(%a6),%d1 11111 beq.l stan 11112 cmpi.b %d1,&ZERO 11113 beq.l src_zero 11114 cmpi.b %d1,&INF 11115 beq.l t_operr 11116 cmpi.b %d1,&DENORM 11117 beq.l stand 11118 cmpi.b %d1,&QNAN 11119 beq.l src_qnan 11120 bra.l src_snan 11121 11122 global fetox 11123fetox: 11124 mov.b STAG(%a6),%d1 11125 beq.l setox 11126 cmpi.b %d1,&ZERO 11127 beq.l ld_pone 11128 cmpi.b %d1,&INF 11129 beq.l szr_inf 11130 cmpi.b %d1,&DENORM 11131 beq.l setoxd 11132 cmpi.b %d1,&QNAN 11133 beq.l src_qnan 11134 bra.l src_snan 11135 11136 global ftwotox 11137ftwotox: 11138 mov.b STAG(%a6),%d1 11139 beq.l stwotox 11140 cmpi.b %d1,&ZERO 11141 beq.l ld_pone 11142 cmpi.b %d1,&INF 11143 beq.l szr_inf 11144 cmpi.b %d1,&DENORM 11145 beq.l stwotoxd 11146 cmpi.b %d1,&QNAN 11147 beq.l src_qnan 11148 bra.l src_snan 11149 11150 global ftentox 11151ftentox: 11152 mov.b STAG(%a6),%d1 11153 beq.l stentox 11154 cmpi.b %d1,&ZERO 11155 beq.l ld_pone 11156 cmpi.b %d1,&INF 11157 beq.l szr_inf 11158 cmpi.b %d1,&DENORM 11159 beq.l stentoxd 11160 cmpi.b %d1,&QNAN 11161 beq.l src_qnan 11162 bra.l src_snan 11163 11164 global flogn 11165flogn: 11166 mov.b STAG(%a6),%d1 11167 beq.l slogn 11168 cmpi.b %d1,&ZERO 11169 beq.l t_dz2 11170 cmpi.b %d1,&INF 11171 beq.l sopr_inf 11172 cmpi.b %d1,&DENORM 11173 beq.l slognd 11174 cmpi.b %d1,&QNAN 11175 beq.l src_qnan 11176 bra.l src_snan 11177 11178 global flog10 11179flog10: 11180 mov.b STAG(%a6),%d1 11181 beq.l slog10 11182 cmpi.b %d1,&ZERO 11183 beq.l t_dz2 11184 cmpi.b %d1,&INF 11185 beq.l sopr_inf 11186 cmpi.b %d1,&DENORM 11187 beq.l slog10d 11188 cmpi.b %d1,&QNAN 11189 beq.l src_qnan 11190 bra.l src_snan 11191 11192 global flog2 11193flog2: 11194 mov.b STAG(%a6),%d1 11195 beq.l slog2 11196 cmpi.b %d1,&ZERO 11197 beq.l t_dz2 11198 cmpi.b %d1,&INF 11199 beq.l sopr_inf 11200 cmpi.b %d1,&DENORM 11201 beq.l slog2d 11202 cmpi.b %d1,&QNAN 11203 beq.l src_qnan 11204 bra.l src_snan 11205 11206 global fcosh 11207fcosh: 11208 mov.b STAG(%a6),%d1 11209 beq.l scosh 11210 cmpi.b %d1,&ZERO 11211 beq.l ld_pone 11212 cmpi.b %d1,&INF 11213 beq.l ld_pinf 11214 cmpi.b %d1,&DENORM 11215 beq.l scoshd 11216 cmpi.b %d1,&QNAN 11217 beq.l src_qnan 11218 bra.l src_snan 11219 11220 global facos 11221facos: 11222 mov.b STAG(%a6),%d1 11223 beq.l sacos 11224 cmpi.b %d1,&ZERO 11225 beq.l ld_ppi2 11226 cmpi.b %d1,&INF 11227 beq.l t_operr 11228 cmpi.b %d1,&DENORM 11229 beq.l sacosd 11230 cmpi.b %d1,&QNAN 11231 beq.l src_qnan 11232 bra.l src_snan 11233 11234 global fcos 11235fcos: 11236 mov.b STAG(%a6),%d1 11237 beq.l scos 11238 cmpi.b %d1,&ZERO 11239 beq.l ld_pone 11240 cmpi.b %d1,&INF 11241 beq.l t_operr 11242 cmpi.b %d1,&DENORM 11243 beq.l scosd 11244 cmpi.b %d1,&QNAN 11245 beq.l src_qnan 11246 bra.l src_snan 11247 11248 global fgetexp 11249fgetexp: 11250 mov.b STAG(%a6),%d1 11251 beq.l sgetexp 11252 cmpi.b %d1,&ZERO 11253 beq.l src_zero 11254 cmpi.b %d1,&INF 11255 beq.l t_operr 11256 cmpi.b %d1,&DENORM 11257 beq.l sgetexpd 11258 cmpi.b %d1,&QNAN 11259 beq.l src_qnan 11260 bra.l src_snan 11261 11262 global fgetman 11263fgetman: 11264 mov.b STAG(%a6),%d1 11265 beq.l sgetman 11266 cmpi.b %d1,&ZERO 11267 beq.l src_zero 11268 cmpi.b %d1,&INF 11269 beq.l t_operr 11270 cmpi.b %d1,&DENORM 11271 beq.l sgetmand 11272 cmpi.b %d1,&QNAN 11273 beq.l src_qnan 11274 bra.l src_snan 11275 11276 global fsincos 11277fsincos: 11278 mov.b STAG(%a6),%d1 11279 beq.l ssincos 11280 cmpi.b %d1,&ZERO 11281 beq.l ssincosz 11282 cmpi.b %d1,&INF 11283 beq.l ssincosi 11284 cmpi.b %d1,&DENORM 11285 beq.l ssincosd 11286 cmpi.b %d1,&QNAN 11287 beq.l ssincosqnan 11288 bra.l ssincossnan 11289 11290 global fmod 11291fmod: 11292 mov.b STAG(%a6),%d1 11293 beq.l smod_snorm 11294 cmpi.b %d1,&ZERO 11295 beq.l smod_szero 11296 cmpi.b %d1,&INF 11297 beq.l smod_sinf 11298 cmpi.b %d1,&DENORM 11299 beq.l smod_sdnrm 11300 cmpi.b %d1,&QNAN 11301 beq.l sop_sqnan 11302 bra.l sop_ssnan 11303 11304 global frem 11305frem: 11306 mov.b STAG(%a6),%d1 11307 beq.l srem_snorm 11308 cmpi.b %d1,&ZERO 11309 beq.l srem_szero 11310 cmpi.b %d1,&INF 11311 beq.l srem_sinf 11312 cmpi.b %d1,&DENORM 11313 beq.l srem_sdnrm 11314 cmpi.b %d1,&QNAN 11315 beq.l sop_sqnan 11316 bra.l sop_ssnan 11317 11318 global fscale 11319fscale: 11320 mov.b STAG(%a6),%d1 11321 beq.l sscale_snorm 11322 cmpi.b %d1,&ZERO 11323 beq.l sscale_szero 11324 cmpi.b %d1,&INF 11325 beq.l sscale_sinf 11326 cmpi.b %d1,&DENORM 11327 beq.l sscale_sdnrm 11328 cmpi.b %d1,&QNAN 11329 beq.l sop_sqnan 11330 bra.l sop_ssnan 11331 11332######################################################################### 11333# XDEF **************************************************************** # 11334# fgen_except(): catch an exception during transcendental # 11335# emulation # 11336# # 11337# XREF **************************************************************** # 11338# fmul() - emulate a multiply instruction # 11339# fadd() - emulate an add instruction # 11340# fin() - emulate an fmove instruction # 11341# # 11342# INPUT *************************************************************** # 11343# fp0 = destination operand # 11344# d0 = type of instruction that took exception # 11345# fsave frame = source operand # 11346# # 11347# OUTPUT ************************************************************** # 11348# fp0 = result # 11349# fp1 = EXOP # 11350# # 11351# ALGORITHM *********************************************************** # 11352# An exception occurred on the last instruction of the # 11353# transcendental emulation. hopefully, this won't be happening much # 11354# because it will be VERY slow. # 11355# The only exceptions capable of passing through here are # 11356# Overflow, Underflow, and Unsupported Data Type. # 11357# # 11358######################################################################### 11359 11360 global fgen_except 11361fgen_except: 11362 cmpi.b 0x3(%sp),&0x7 # is exception UNSUPP? 11363 beq.b fge_unsupp # yes 11364 11365 mov.b &NORM,STAG(%a6) 11366 11367fge_cont: 11368 mov.b &NORM,DTAG(%a6) 11369 11370# ok, I have a problem with putting the dst op at FP_DST. the emulation 11371# routines aren't supposed to alter the operands but we've just squashed 11372# FP_DST here... 11373 11374# 8/17/93 - this turns out to be more of a "cleanliness" standpoint 11375# then a potential bug. to begin with, only the dyadic functions 11376# frem,fmod, and fscale would get the dst trashed here. But, for 11377# the 060SP, the FP_DST is never used again anyways. 11378 fmovm.x &0x80,FP_DST(%a6) # dst op is in fp0 11379 11380 lea 0x4(%sp),%a0 # pass: ptr to src op 11381 lea FP_DST(%a6),%a1 # pass: ptr to dst op 11382 11383 cmpi.b %d1,&FMOV_OP 11384 beq.b fge_fin # it was an "fmov" 11385 cmpi.b %d1,&FADD_OP 11386 beq.b fge_fadd # it was an "fadd" 11387fge_fmul: 11388 bsr.l fmul 11389 rts 11390fge_fadd: 11391 bsr.l fadd 11392 rts 11393fge_fin: 11394 bsr.l fin 11395 rts 11396 11397fge_unsupp: 11398 mov.b &DENORM,STAG(%a6) 11399 bra.b fge_cont 11400 11401# 11402# This table holds the offsets of the emulation routines for each individual 11403# math operation relative to the address of this table. Included are 11404# routines like fadd/fmul/fabs as well as the transcendentals. 11405# The location within the table is determined by the extension bits of the 11406# operation longword. 11407# 11408 11409 swbeg &109 11410tbl_unsupp: 11411 long fin - tbl_unsupp # 00: fmove 11412 long fint - tbl_unsupp # 01: fint 11413 long fsinh - tbl_unsupp # 02: fsinh 11414 long fintrz - tbl_unsupp # 03: fintrz 11415 long fsqrt - tbl_unsupp # 04: fsqrt 11416 long tbl_unsupp - tbl_unsupp 11417 long flognp1 - tbl_unsupp # 06: flognp1 11418 long tbl_unsupp - tbl_unsupp 11419 long fetoxm1 - tbl_unsupp # 08: fetoxm1 11420 long ftanh - tbl_unsupp # 09: ftanh 11421 long fatan - tbl_unsupp # 0a: fatan 11422 long tbl_unsupp - tbl_unsupp 11423 long fasin - tbl_unsupp # 0c: fasin 11424 long fatanh - tbl_unsupp # 0d: fatanh 11425 long fsine - tbl_unsupp # 0e: fsin 11426 long ftan - tbl_unsupp # 0f: ftan 11427 long fetox - tbl_unsupp # 10: fetox 11428 long ftwotox - tbl_unsupp # 11: ftwotox 11429 long ftentox - tbl_unsupp # 12: ftentox 11430 long tbl_unsupp - tbl_unsupp 11431 long flogn - tbl_unsupp # 14: flogn 11432 long flog10 - tbl_unsupp # 15: flog10 11433 long flog2 - tbl_unsupp # 16: flog2 11434 long tbl_unsupp - tbl_unsupp 11435 long fabs - tbl_unsupp # 18: fabs 11436 long fcosh - tbl_unsupp # 19: fcosh 11437 long fneg - tbl_unsupp # 1a: fneg 11438 long tbl_unsupp - tbl_unsupp 11439 long facos - tbl_unsupp # 1c: facos 11440 long fcos - tbl_unsupp # 1d: fcos 11441 long fgetexp - tbl_unsupp # 1e: fgetexp 11442 long fgetman - tbl_unsupp # 1f: fgetman 11443 long fdiv - tbl_unsupp # 20: fdiv 11444 long fmod - tbl_unsupp # 21: fmod 11445 long fadd - tbl_unsupp # 22: fadd 11446 long fmul - tbl_unsupp # 23: fmul 11447 long fsgldiv - tbl_unsupp # 24: fsgldiv 11448 long frem - tbl_unsupp # 25: frem 11449 long fscale - tbl_unsupp # 26: fscale 11450 long fsglmul - tbl_unsupp # 27: fsglmul 11451 long fsub - tbl_unsupp # 28: fsub 11452 long tbl_unsupp - tbl_unsupp 11453 long tbl_unsupp - tbl_unsupp 11454 long tbl_unsupp - tbl_unsupp 11455 long tbl_unsupp - tbl_unsupp 11456 long tbl_unsupp - tbl_unsupp 11457 long tbl_unsupp - tbl_unsupp 11458 long tbl_unsupp - tbl_unsupp 11459 long fsincos - tbl_unsupp # 30: fsincos 11460 long fsincos - tbl_unsupp # 31: fsincos 11461 long fsincos - tbl_unsupp # 32: fsincos 11462 long fsincos - tbl_unsupp # 33: fsincos 11463 long fsincos - tbl_unsupp # 34: fsincos 11464 long fsincos - tbl_unsupp # 35: fsincos 11465 long fsincos - tbl_unsupp # 36: fsincos 11466 long fsincos - tbl_unsupp # 37: fsincos 11467 long fcmp - tbl_unsupp # 38: fcmp 11468 long tbl_unsupp - tbl_unsupp 11469 long ftst - tbl_unsupp # 3a: ftst 11470 long tbl_unsupp - tbl_unsupp 11471 long tbl_unsupp - tbl_unsupp 11472 long tbl_unsupp - tbl_unsupp 11473 long tbl_unsupp - tbl_unsupp 11474 long tbl_unsupp - tbl_unsupp 11475 long fsin - tbl_unsupp # 40: fsmove 11476 long fssqrt - tbl_unsupp # 41: fssqrt 11477 long tbl_unsupp - tbl_unsupp 11478 long tbl_unsupp - tbl_unsupp 11479 long fdin - tbl_unsupp # 44: fdmove 11480 long fdsqrt - tbl_unsupp # 45: fdsqrt 11481 long tbl_unsupp - tbl_unsupp 11482 long tbl_unsupp - tbl_unsupp 11483 long tbl_unsupp - tbl_unsupp 11484 long tbl_unsupp - tbl_unsupp 11485 long tbl_unsupp - tbl_unsupp 11486 long tbl_unsupp - tbl_unsupp 11487 long tbl_unsupp - tbl_unsupp 11488 long tbl_unsupp - tbl_unsupp 11489 long tbl_unsupp - tbl_unsupp 11490 long tbl_unsupp - tbl_unsupp 11491 long tbl_unsupp - tbl_unsupp 11492 long tbl_unsupp - tbl_unsupp 11493 long tbl_unsupp - tbl_unsupp 11494 long tbl_unsupp - tbl_unsupp 11495 long tbl_unsupp - tbl_unsupp 11496 long tbl_unsupp - tbl_unsupp 11497 long tbl_unsupp - tbl_unsupp 11498 long tbl_unsupp - tbl_unsupp 11499 long fsabs - tbl_unsupp # 58: fsabs 11500 long tbl_unsupp - tbl_unsupp 11501 long fsneg - tbl_unsupp # 5a: fsneg 11502 long tbl_unsupp - tbl_unsupp 11503 long fdabs - tbl_unsupp # 5c: fdabs 11504 long tbl_unsupp - tbl_unsupp 11505 long fdneg - tbl_unsupp # 5e: fdneg 11506 long tbl_unsupp - tbl_unsupp 11507 long fsdiv - tbl_unsupp # 60: fsdiv 11508 long tbl_unsupp - tbl_unsupp 11509 long fsadd - tbl_unsupp # 62: fsadd 11510 long fsmul - tbl_unsupp # 63: fsmul 11511 long fddiv - tbl_unsupp # 64: fddiv 11512 long tbl_unsupp - tbl_unsupp 11513 long fdadd - tbl_unsupp # 66: fdadd 11514 long fdmul - tbl_unsupp # 67: fdmul 11515 long fssub - tbl_unsupp # 68: fssub 11516 long tbl_unsupp - tbl_unsupp 11517 long tbl_unsupp - tbl_unsupp 11518 long tbl_unsupp - tbl_unsupp 11519 long fdsub - tbl_unsupp # 6c: fdsub 11520 11521######################################################################### 11522# XDEF **************************************************************** # 11523# fmul(): emulates the fmul instruction # 11524# fsmul(): emulates the fsmul instruction # 11525# fdmul(): emulates the fdmul instruction # 11526# # 11527# XREF **************************************************************** # 11528# scale_to_zero_src() - scale src exponent to zero # 11529# scale_to_zero_dst() - scale dst exponent to zero # 11530# unf_res() - return default underflow result # 11531# ovf_res() - return default overflow result # 11532# res_qnan() - return QNAN result # 11533# res_snan() - return SNAN result # 11534# # 11535# INPUT *************************************************************** # 11536# a0 = pointer to extended precision source operand # 11537# a1 = pointer to extended precision destination operand # 11538# d0 rnd prec,mode # 11539# # 11540# OUTPUT ************************************************************** # 11541# fp0 = result # 11542# fp1 = EXOP (if exception occurred) # 11543# # 11544# ALGORITHM *********************************************************** # 11545# Handle NANs, infinities, and zeroes as special cases. Divide # 11546# norms/denorms into ext/sgl/dbl precision. # 11547# For norms/denorms, scale the exponents such that a multiply # 11548# instruction won't cause an exception. Use the regular fmul to # 11549# compute a result. Check if the regular operands would have taken # 11550# an exception. If so, return the default overflow/underflow result # 11551# and return the EXOP if exceptions are enabled. Else, scale the # 11552# result operand to the proper exponent. # 11553# # 11554######################################################################### 11555 11556 align 0x10 11557tbl_fmul_ovfl: 11558 long 0x3fff - 0x7ffe # ext_max 11559 long 0x3fff - 0x407e # sgl_max 11560 long 0x3fff - 0x43fe # dbl_max 11561tbl_fmul_unfl: 11562 long 0x3fff + 0x0001 # ext_unfl 11563 long 0x3fff - 0x3f80 # sgl_unfl 11564 long 0x3fff - 0x3c00 # dbl_unfl 11565 11566 global fsmul 11567fsmul: 11568 andi.b &0x30,%d0 # clear rnd prec 11569 ori.b &s_mode*0x10,%d0 # insert sgl prec 11570 bra.b fmul 11571 11572 global fdmul 11573fdmul: 11574 andi.b &0x30,%d0 11575 ori.b &d_mode*0x10,%d0 # insert dbl prec 11576 11577 global fmul 11578fmul: 11579 mov.l %d0,L_SCR3(%a6) # store rnd info 11580 11581 clr.w %d1 11582 mov.b DTAG(%a6),%d1 11583 lsl.b &0x3,%d1 11584 or.b STAG(%a6),%d1 # combine src tags 11585 bne.w fmul_not_norm # optimize on non-norm input 11586 11587fmul_norm: 11588 mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 11589 mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 11590 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 11591 11592 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 11593 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 11594 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 11595 11596 bsr.l scale_to_zero_src # scale src exponent 11597 mov.l %d0,-(%sp) # save scale factor 1 11598 11599 bsr.l scale_to_zero_dst # scale dst exponent 11600 11601 add.l %d0,(%sp) # SCALE_FACTOR = scale1 + scale2 11602 11603 mov.w 2+L_SCR3(%a6),%d1 # fetch precision 11604 lsr.b &0x6,%d1 # shift to lo bits 11605 mov.l (%sp)+,%d0 # load S.F. 11606 cmp.l %d0,(tbl_fmul_ovfl.w,%pc,%d1.w*4) # would result ovfl? 11607 beq.w fmul_may_ovfl # result may rnd to overflow 11608 blt.w fmul_ovfl # result will overflow 11609 11610 cmp.l %d0,(tbl_fmul_unfl.w,%pc,%d1.w*4) # would result unfl? 11611 beq.w fmul_may_unfl # result may rnd to no unfl 11612 bgt.w fmul_unfl # result will underflow 11613 11614# 11615# NORMAL: 11616# - the result of the multiply operation will neither overflow nor underflow. 11617# - do the multiply to the proper precision and rounding mode. 11618# - scale the result exponent using the scale factor. if both operands were 11619# normalized then we really don't need to go through this scaling. but for now, 11620# this will do. 11621# 11622fmul_normal: 11623 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 11624 11625 fmov.l L_SCR3(%a6),%fpcr # set FPCR 11626 fmov.l &0x0,%fpsr # clear FPSR 11627 11628 fmul.x FP_SCR0(%a6),%fp0 # execute multiply 11629 11630 fmov.l %fpsr,%d1 # save status 11631 fmov.l &0x0,%fpcr # clear FPCR 11632 11633 or.l %d1,USER_FPSR(%a6) # save INEX2,N 11634 11635fmul_normal_exit: 11636 fmovm.x &0x80,FP_SCR0(%a6) # store out result 11637 mov.l %d2,-(%sp) # save d2 11638 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 11639 mov.l %d1,%d2 # make a copy 11640 andi.l &0x7fff,%d1 # strip sign 11641 andi.w &0x8000,%d2 # keep old sign 11642 sub.l %d0,%d1 # add scale factor 11643 or.w %d2,%d1 # concat old sign,new exp 11644 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 11645 mov.l (%sp)+,%d2 # restore d2 11646 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 11647 rts 11648 11649# 11650# OVERFLOW: 11651# - the result of the multiply operation is an overflow. 11652# - do the multiply to the proper precision and rounding mode in order to 11653# set the inexact bits. 11654# - calculate the default result and return it in fp0. 11655# - if overflow or inexact is enabled, we need a multiply result rounded to 11656# extended precision. if the original operation was extended, then we have this 11657# result. if the original operation was single or double, we have to do another 11658# multiply using extended precision and the correct rounding mode. the result 11659# of this operation then has its exponent scaled by -0x6000 to create the 11660# exceptional operand. 11661# 11662fmul_ovfl: 11663 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 11664 11665 fmov.l L_SCR3(%a6),%fpcr # set FPCR 11666 fmov.l &0x0,%fpsr # clear FPSR 11667 11668 fmul.x FP_SCR0(%a6),%fp0 # execute multiply 11669 11670 fmov.l %fpsr,%d1 # save status 11671 fmov.l &0x0,%fpcr # clear FPCR 11672 11673 or.l %d1,USER_FPSR(%a6) # save INEX2,N 11674 11675# save setting this until now because this is where fmul_may_ovfl may jump in 11676fmul_ovfl_tst: 11677 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 11678 11679 mov.b FPCR_ENABLE(%a6),%d1 11680 andi.b &0x13,%d1 # is OVFL or INEX enabled? 11681 bne.b fmul_ovfl_ena # yes 11682 11683# calculate the default result 11684fmul_ovfl_dis: 11685 btst &neg_bit,FPSR_CC(%a6) # is result negative? 11686 sne %d1 # set sign param accordingly 11687 mov.l L_SCR3(%a6),%d0 # pass rnd prec,mode 11688 bsr.l ovf_res # calculate default result 11689 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 11690 fmovm.x (%a0),&0x80 # return default result in fp0 11691 rts 11692 11693# 11694# OVFL is enabled; Create EXOP: 11695# - if precision is extended, then we have the EXOP. simply bias the exponent 11696# with an extra -0x6000. if the precision is single or double, we need to 11697# calculate a result rounded to extended precision. 11698# 11699fmul_ovfl_ena: 11700 mov.l L_SCR3(%a6),%d1 11701 andi.b &0xc0,%d1 # test the rnd prec 11702 bne.b fmul_ovfl_ena_sd # it's sgl or dbl 11703 11704fmul_ovfl_ena_cont: 11705 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 11706 11707 mov.l %d2,-(%sp) # save d2 11708 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 11709 mov.w %d1,%d2 # make a copy 11710 andi.l &0x7fff,%d1 # strip sign 11711 sub.l %d0,%d1 # add scale factor 11712 subi.l &0x6000,%d1 # subtract bias 11713 andi.w &0x7fff,%d1 # clear sign bit 11714 andi.w &0x8000,%d2 # keep old sign 11715 or.w %d2,%d1 # concat old sign,new exp 11716 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 11717 mov.l (%sp)+,%d2 # restore d2 11718 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 11719 bra.b fmul_ovfl_dis 11720 11721fmul_ovfl_ena_sd: 11722 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 11723 11724 mov.l L_SCR3(%a6),%d1 11725 andi.b &0x30,%d1 # keep rnd mode only 11726 fmov.l %d1,%fpcr # set FPCR 11727 11728 fmul.x FP_SCR0(%a6),%fp0 # execute multiply 11729 11730 fmov.l &0x0,%fpcr # clear FPCR 11731 bra.b fmul_ovfl_ena_cont 11732 11733# 11734# may OVERFLOW: 11735# - the result of the multiply operation MAY overflow. 11736# - do the multiply to the proper precision and rounding mode in order to 11737# set the inexact bits. 11738# - calculate the default result and return it in fp0. 11739# 11740fmul_may_ovfl: 11741 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 11742 11743 fmov.l L_SCR3(%a6),%fpcr # set FPCR 11744 fmov.l &0x0,%fpsr # clear FPSR 11745 11746 fmul.x FP_SCR0(%a6),%fp0 # execute multiply 11747 11748 fmov.l %fpsr,%d1 # save status 11749 fmov.l &0x0,%fpcr # clear FPCR 11750 11751 or.l %d1,USER_FPSR(%a6) # save INEX2,N 11752 11753 fabs.x %fp0,%fp1 # make a copy of result 11754 fcmp.b %fp1,&0x2 # is |result| >= 2.b? 11755 fbge.w fmul_ovfl_tst # yes; overflow has occurred 11756 11757# no, it didn't overflow; we have correct result 11758 bra.w fmul_normal_exit 11759 11760# 11761# UNDERFLOW: 11762# - the result of the multiply operation is an underflow. 11763# - do the multiply to the proper precision and rounding mode in order to 11764# set the inexact bits. 11765# - calculate the default result and return it in fp0. 11766# - if overflow or inexact is enabled, we need a multiply result rounded to 11767# extended precision. if the original operation was extended, then we have this 11768# result. if the original operation was single or double, we have to do another 11769# multiply using extended precision and the correct rounding mode. the result 11770# of this operation then has its exponent scaled by -0x6000 to create the 11771# exceptional operand. 11772# 11773fmul_unfl: 11774 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 11775 11776# for fun, let's use only extended precision, round to zero. then, let 11777# the unf_res() routine figure out all the rest. 11778# will we get the correct answer. 11779 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 11780 11781 fmov.l &rz_mode*0x10,%fpcr # set FPCR 11782 fmov.l &0x0,%fpsr # clear FPSR 11783 11784 fmul.x FP_SCR0(%a6),%fp0 # execute multiply 11785 11786 fmov.l %fpsr,%d1 # save status 11787 fmov.l &0x0,%fpcr # clear FPCR 11788 11789 or.l %d1,USER_FPSR(%a6) # save INEX2,N 11790 11791 mov.b FPCR_ENABLE(%a6),%d1 11792 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 11793 bne.b fmul_unfl_ena # yes 11794 11795fmul_unfl_dis: 11796 fmovm.x &0x80,FP_SCR0(%a6) # store out result 11797 11798 lea FP_SCR0(%a6),%a0 # pass: result addr 11799 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 11800 bsr.l unf_res # calculate default result 11801 or.b %d0,FPSR_CC(%a6) # unf_res2 may have set 'Z' 11802 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 11803 rts 11804 11805# 11806# UNFL is enabled. 11807# 11808fmul_unfl_ena: 11809 fmovm.x FP_SCR1(%a6),&0x40 # load dst op 11810 11811 mov.l L_SCR3(%a6),%d1 11812 andi.b &0xc0,%d1 # is precision extended? 11813 bne.b fmul_unfl_ena_sd # no, sgl or dbl 11814 11815# if the rnd mode is anything but RZ, then we have to re-do the above 11816# multiplication because we used RZ for all. 11817 fmov.l L_SCR3(%a6),%fpcr # set FPCR 11818 11819fmul_unfl_ena_cont: 11820 fmov.l &0x0,%fpsr # clear FPSR 11821 11822 fmul.x FP_SCR0(%a6),%fp1 # execute multiply 11823 11824 fmov.l &0x0,%fpcr # clear FPCR 11825 11826 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 11827 mov.l %d2,-(%sp) # save d2 11828 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 11829 mov.l %d1,%d2 # make a copy 11830 andi.l &0x7fff,%d1 # strip sign 11831 andi.w &0x8000,%d2 # keep old sign 11832 sub.l %d0,%d1 # add scale factor 11833 addi.l &0x6000,%d1 # add bias 11834 andi.w &0x7fff,%d1 11835 or.w %d2,%d1 # concat old sign,new exp 11836 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 11837 mov.l (%sp)+,%d2 # restore d2 11838 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 11839 bra.w fmul_unfl_dis 11840 11841fmul_unfl_ena_sd: 11842 mov.l L_SCR3(%a6),%d1 11843 andi.b &0x30,%d1 # use only rnd mode 11844 fmov.l %d1,%fpcr # set FPCR 11845 11846 bra.b fmul_unfl_ena_cont 11847 11848# MAY UNDERFLOW: 11849# -use the correct rounding mode and precision. this code favors operations 11850# that do not underflow. 11851fmul_may_unfl: 11852 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 11853 11854 fmov.l L_SCR3(%a6),%fpcr # set FPCR 11855 fmov.l &0x0,%fpsr # clear FPSR 11856 11857 fmul.x FP_SCR0(%a6),%fp0 # execute multiply 11858 11859 fmov.l %fpsr,%d1 # save status 11860 fmov.l &0x0,%fpcr # clear FPCR 11861 11862 or.l %d1,USER_FPSR(%a6) # save INEX2,N 11863 11864 fabs.x %fp0,%fp1 # make a copy of result 11865 fcmp.b %fp1,&0x2 # is |result| > 2.b? 11866 fbgt.w fmul_normal_exit # no; no underflow occurred 11867 fblt.w fmul_unfl # yes; underflow occurred 11868 11869# 11870# we still don't know if underflow occurred. result is ~ equal to 2. but, 11871# we don't know if the result was an underflow that rounded up to a 2 or 11872# a normalized number that rounded down to a 2. so, redo the entire operation 11873# using RZ as the rounding mode to see what the pre-rounded result is. 11874# this case should be relatively rare. 11875# 11876 fmovm.x FP_SCR1(%a6),&0x40 # load dst operand 11877 11878 mov.l L_SCR3(%a6),%d1 11879 andi.b &0xc0,%d1 # keep rnd prec 11880 ori.b &rz_mode*0x10,%d1 # insert RZ 11881 11882 fmov.l %d1,%fpcr # set FPCR 11883 fmov.l &0x0,%fpsr # clear FPSR 11884 11885 fmul.x FP_SCR0(%a6),%fp1 # execute multiply 11886 11887 fmov.l &0x0,%fpcr # clear FPCR 11888 fabs.x %fp1 # make absolute value 11889 fcmp.b %fp1,&0x2 # is |result| < 2.b? 11890 fbge.w fmul_normal_exit # no; no underflow occurred 11891 bra.w fmul_unfl # yes, underflow occurred 11892 11893################################################################################ 11894 11895# 11896# Multiply: inputs are not both normalized; what are they? 11897# 11898fmul_not_norm: 11899 mov.w (tbl_fmul_op.b,%pc,%d1.w*2),%d1 11900 jmp (tbl_fmul_op.b,%pc,%d1.w) 11901 11902 swbeg &48 11903tbl_fmul_op: 11904 short fmul_norm - tbl_fmul_op # NORM x NORM 11905 short fmul_zero - tbl_fmul_op # NORM x ZERO 11906 short fmul_inf_src - tbl_fmul_op # NORM x INF 11907 short fmul_res_qnan - tbl_fmul_op # NORM x QNAN 11908 short fmul_norm - tbl_fmul_op # NORM x DENORM 11909 short fmul_res_snan - tbl_fmul_op # NORM x SNAN 11910 short tbl_fmul_op - tbl_fmul_op # 11911 short tbl_fmul_op - tbl_fmul_op # 11912 11913 short fmul_zero - tbl_fmul_op # ZERO x NORM 11914 short fmul_zero - tbl_fmul_op # ZERO x ZERO 11915 short fmul_res_operr - tbl_fmul_op # ZERO x INF 11916 short fmul_res_qnan - tbl_fmul_op # ZERO x QNAN 11917 short fmul_zero - tbl_fmul_op # ZERO x DENORM 11918 short fmul_res_snan - tbl_fmul_op # ZERO x SNAN 11919 short tbl_fmul_op - tbl_fmul_op # 11920 short tbl_fmul_op - tbl_fmul_op # 11921 11922 short fmul_inf_dst - tbl_fmul_op # INF x NORM 11923 short fmul_res_operr - tbl_fmul_op # INF x ZERO 11924 short fmul_inf_dst - tbl_fmul_op # INF x INF 11925 short fmul_res_qnan - tbl_fmul_op # INF x QNAN 11926 short fmul_inf_dst - tbl_fmul_op # INF x DENORM 11927 short fmul_res_snan - tbl_fmul_op # INF x SNAN 11928 short tbl_fmul_op - tbl_fmul_op # 11929 short tbl_fmul_op - tbl_fmul_op # 11930 11931 short fmul_res_qnan - tbl_fmul_op # QNAN x NORM 11932 short fmul_res_qnan - tbl_fmul_op # QNAN x ZERO 11933 short fmul_res_qnan - tbl_fmul_op # QNAN x INF 11934 short fmul_res_qnan - tbl_fmul_op # QNAN x QNAN 11935 short fmul_res_qnan - tbl_fmul_op # QNAN x DENORM 11936 short fmul_res_snan - tbl_fmul_op # QNAN x SNAN 11937 short tbl_fmul_op - tbl_fmul_op # 11938 short tbl_fmul_op - tbl_fmul_op # 11939 11940 short fmul_norm - tbl_fmul_op # NORM x NORM 11941 short fmul_zero - tbl_fmul_op # NORM x ZERO 11942 short fmul_inf_src - tbl_fmul_op # NORM x INF 11943 short fmul_res_qnan - tbl_fmul_op # NORM x QNAN 11944 short fmul_norm - tbl_fmul_op # NORM x DENORM 11945 short fmul_res_snan - tbl_fmul_op # NORM x SNAN 11946 short tbl_fmul_op - tbl_fmul_op # 11947 short tbl_fmul_op - tbl_fmul_op # 11948 11949 short fmul_res_snan - tbl_fmul_op # SNAN x NORM 11950 short fmul_res_snan - tbl_fmul_op # SNAN x ZERO 11951 short fmul_res_snan - tbl_fmul_op # SNAN x INF 11952 short fmul_res_snan - tbl_fmul_op # SNAN x QNAN 11953 short fmul_res_snan - tbl_fmul_op # SNAN x DENORM 11954 short fmul_res_snan - tbl_fmul_op # SNAN x SNAN 11955 short tbl_fmul_op - tbl_fmul_op # 11956 short tbl_fmul_op - tbl_fmul_op # 11957 11958fmul_res_operr: 11959 bra.l res_operr 11960fmul_res_snan: 11961 bra.l res_snan 11962fmul_res_qnan: 11963 bra.l res_qnan 11964 11965# 11966# Multiply: (Zero x Zero) || (Zero x norm) || (Zero x denorm) 11967# 11968 global fmul_zero # global for fsglmul 11969fmul_zero: 11970 mov.b SRC_EX(%a0),%d0 # exclusive or the signs 11971 mov.b DST_EX(%a1),%d1 11972 eor.b %d0,%d1 11973 bpl.b fmul_zero_p # result ZERO is pos. 11974fmul_zero_n: 11975 fmov.s &0x80000000,%fp0 # load -ZERO 11976 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N 11977 rts 11978fmul_zero_p: 11979 fmov.s &0x00000000,%fp0 # load +ZERO 11980 mov.b &z_bmask,FPSR_CC(%a6) # set Z 11981 rts 11982 11983# 11984# Multiply: (inf x inf) || (inf x norm) || (inf x denorm) 11985# 11986# Note: The j-bit for an infinity is a don't-care. However, to be 11987# strictly compatible w/ the 68881/882, we make sure to return an 11988# INF w/ the j-bit set if the input INF j-bit was set. Destination 11989# INFs take priority. 11990# 11991 global fmul_inf_dst # global for fsglmul 11992fmul_inf_dst: 11993 fmovm.x DST(%a1),&0x80 # return INF result in fp0 11994 mov.b SRC_EX(%a0),%d0 # exclusive or the signs 11995 mov.b DST_EX(%a1),%d1 11996 eor.b %d0,%d1 11997 bpl.b fmul_inf_dst_p # result INF is pos. 11998fmul_inf_dst_n: 11999 fabs.x %fp0 # clear result sign 12000 fneg.x %fp0 # set result sign 12001 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N 12002 rts 12003fmul_inf_dst_p: 12004 fabs.x %fp0 # clear result sign 12005 mov.b &inf_bmask,FPSR_CC(%a6) # set INF 12006 rts 12007 12008 global fmul_inf_src # global for fsglmul 12009fmul_inf_src: 12010 fmovm.x SRC(%a0),&0x80 # return INF result in fp0 12011 mov.b SRC_EX(%a0),%d0 # exclusive or the signs 12012 mov.b DST_EX(%a1),%d1 12013 eor.b %d0,%d1 12014 bpl.b fmul_inf_dst_p # result INF is pos. 12015 bra.b fmul_inf_dst_n 12016 12017######################################################################### 12018# XDEF **************************************************************** # 12019# fin(): emulates the fmove instruction # 12020# fsin(): emulates the fsmove instruction # 12021# fdin(): emulates the fdmove instruction # 12022# # 12023# XREF **************************************************************** # 12024# norm() - normalize mantissa for EXOP on denorm # 12025# scale_to_zero_src() - scale src exponent to zero # 12026# ovf_res() - return default overflow result # 12027# unf_res() - return default underflow result # 12028# res_qnan_1op() - return QNAN result # 12029# res_snan_1op() - return SNAN result # 12030# # 12031# INPUT *************************************************************** # 12032# a0 = pointer to extended precision source operand # 12033# d0 = round prec/mode # 12034# # 12035# OUTPUT ************************************************************** # 12036# fp0 = result # 12037# fp1 = EXOP (if exception occurred) # 12038# # 12039# ALGORITHM *********************************************************** # 12040# Handle NANs, infinities, and zeroes as special cases. Divide # 12041# norms into extended, single, and double precision. # 12042# Norms can be emulated w/ a regular fmove instruction. For # 12043# sgl/dbl, must scale exponent and perform an "fmove". Check to see # 12044# if the result would have overflowed/underflowed. If so, use unf_res() # 12045# or ovf_res() to return the default result. Also return EXOP if # 12046# exception is enabled. If no exception, return the default result. # 12047# Unnorms don't pass through here. # 12048# # 12049######################################################################### 12050 12051 global fsin 12052fsin: 12053 andi.b &0x30,%d0 # clear rnd prec 12054 ori.b &s_mode*0x10,%d0 # insert sgl precision 12055 bra.b fin 12056 12057 global fdin 12058fdin: 12059 andi.b &0x30,%d0 # clear rnd prec 12060 ori.b &d_mode*0x10,%d0 # insert dbl precision 12061 12062 global fin 12063fin: 12064 mov.l %d0,L_SCR3(%a6) # store rnd info 12065 12066 mov.b STAG(%a6),%d1 # fetch src optype tag 12067 bne.w fin_not_norm # optimize on non-norm input 12068 12069# 12070# FP MOVE IN: NORMs and DENORMs ONLY! 12071# 12072fin_norm: 12073 andi.b &0xc0,%d0 # is precision extended? 12074 bne.w fin_not_ext # no, so go handle dbl or sgl 12075 12076# 12077# precision selected is extended. so...we cannot get an underflow 12078# or overflow because of rounding to the correct precision. so... 12079# skip the scaling and unscaling... 12080# 12081 tst.b SRC_EX(%a0) # is the operand negative? 12082 bpl.b fin_norm_done # no 12083 bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit 12084fin_norm_done: 12085 fmovm.x SRC(%a0),&0x80 # return result in fp0 12086 rts 12087 12088# 12089# for an extended precision DENORM, the UNFL exception bit is set 12090# the accrued bit is NOT set in this instance(no inexactness!) 12091# 12092fin_denorm: 12093 andi.b &0xc0,%d0 # is precision extended? 12094 bne.w fin_not_ext # no, so go handle dbl or sgl 12095 12096 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 12097 tst.b SRC_EX(%a0) # is the operand negative? 12098 bpl.b fin_denorm_done # no 12099 bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit 12100fin_denorm_done: 12101 fmovm.x SRC(%a0),&0x80 # return result in fp0 12102 btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled? 12103 bne.b fin_denorm_unfl_ena # yes 12104 rts 12105 12106# 12107# the input is an extended DENORM and underflow is enabled in the FPCR. 12108# normalize the mantissa and add the bias of 0x6000 to the resulting negative 12109# exponent and insert back into the operand. 12110# 12111fin_denorm_unfl_ena: 12112 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12113 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12114 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12115 lea FP_SCR0(%a6),%a0 # pass: ptr to operand 12116 bsr.l norm # normalize result 12117 neg.w %d0 # new exponent = -(shft val) 12118 addi.w &0x6000,%d0 # add new bias to exponent 12119 mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp 12120 andi.w &0x8000,%d1 # keep old sign 12121 andi.w &0x7fff,%d0 # clear sign position 12122 or.w %d1,%d0 # concat new exo,old sign 12123 mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent 12124 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 12125 rts 12126 12127# 12128# operand is to be rounded to single or double precision 12129# 12130fin_not_ext: 12131 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 12132 bne.b fin_dbl 12133 12134# 12135# operand is to be rounded to single precision 12136# 12137fin_sgl: 12138 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12139 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12140 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12141 bsr.l scale_to_zero_src # calculate scale factor 12142 12143 cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow? 12144 bge.w fin_sd_unfl # yes; go handle underflow 12145 cmpi.l %d0,&0x3fff-0x407e # will move in overflow? 12146 beq.w fin_sd_may_ovfl # maybe; go check 12147 blt.w fin_sd_ovfl # yes; go handle overflow 12148 12149# 12150# operand will NOT overflow or underflow when moved into the fp reg file 12151# 12152fin_sd_normal: 12153 fmov.l &0x0,%fpsr # clear FPSR 12154 fmov.l L_SCR3(%a6),%fpcr # set FPCR 12155 12156 fmov.x FP_SCR0(%a6),%fp0 # perform move 12157 12158 fmov.l %fpsr,%d1 # save FPSR 12159 fmov.l &0x0,%fpcr # clear FPCR 12160 12161 or.l %d1,USER_FPSR(%a6) # save INEX2,N 12162 12163fin_sd_normal_exit: 12164 mov.l %d2,-(%sp) # save d2 12165 fmovm.x &0x80,FP_SCR0(%a6) # store out result 12166 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 12167 mov.w %d1,%d2 # make a copy 12168 andi.l &0x7fff,%d1 # strip sign 12169 sub.l %d0,%d1 # add scale factor 12170 andi.w &0x8000,%d2 # keep old sign 12171 or.w %d1,%d2 # concat old sign,new exponent 12172 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 12173 mov.l (%sp)+,%d2 # restore d2 12174 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 12175 rts 12176 12177# 12178# operand is to be rounded to double precision 12179# 12180fin_dbl: 12181 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12182 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12183 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12184 bsr.l scale_to_zero_src # calculate scale factor 12185 12186 cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow? 12187 bge.w fin_sd_unfl # yes; go handle underflow 12188 cmpi.l %d0,&0x3fff-0x43fe # will move in overflow? 12189 beq.w fin_sd_may_ovfl # maybe; go check 12190 blt.w fin_sd_ovfl # yes; go handle overflow 12191 bra.w fin_sd_normal # no; ho handle normalized op 12192 12193# 12194# operand WILL underflow when moved in to the fp register file 12195# 12196fin_sd_unfl: 12197 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 12198 12199 tst.b FP_SCR0_EX(%a6) # is operand negative? 12200 bpl.b fin_sd_unfl_tst 12201 bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit 12202 12203# if underflow or inexact is enabled, then go calculate the EXOP first. 12204fin_sd_unfl_tst: 12205 mov.b FPCR_ENABLE(%a6),%d1 12206 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 12207 bne.b fin_sd_unfl_ena # yes 12208 12209fin_sd_unfl_dis: 12210 lea FP_SCR0(%a6),%a0 # pass: result addr 12211 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 12212 bsr.l unf_res # calculate default result 12213 or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z' 12214 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 12215 rts 12216 12217# 12218# operand will underflow AND underflow or inexact is enabled. 12219# Therefore, we must return the result rounded to extended precision. 12220# 12221fin_sd_unfl_ena: 12222 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 12223 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 12224 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 12225 12226 mov.l %d2,-(%sp) # save d2 12227 mov.w %d1,%d2 # make a copy 12228 andi.l &0x7fff,%d1 # strip sign 12229 sub.l %d0,%d1 # subtract scale factor 12230 andi.w &0x8000,%d2 # extract old sign 12231 addi.l &0x6000,%d1 # add new bias 12232 andi.w &0x7fff,%d1 12233 or.w %d1,%d2 # concat old sign,new exp 12234 mov.w %d2,FP_SCR1_EX(%a6) # insert new exponent 12235 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 12236 mov.l (%sp)+,%d2 # restore d2 12237 bra.b fin_sd_unfl_dis 12238 12239# 12240# operand WILL overflow. 12241# 12242fin_sd_ovfl: 12243 fmov.l &0x0,%fpsr # clear FPSR 12244 fmov.l L_SCR3(%a6),%fpcr # set FPCR 12245 12246 fmov.x FP_SCR0(%a6),%fp0 # perform move 12247 12248 fmov.l &0x0,%fpcr # clear FPCR 12249 fmov.l %fpsr,%d1 # save FPSR 12250 12251 or.l %d1,USER_FPSR(%a6) # save INEX2,N 12252 12253fin_sd_ovfl_tst: 12254 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 12255 12256 mov.b FPCR_ENABLE(%a6),%d1 12257 andi.b &0x13,%d1 # is OVFL or INEX enabled? 12258 bne.b fin_sd_ovfl_ena # yes 12259 12260# 12261# OVFL is not enabled; therefore, we must create the default result by 12262# calling ovf_res(). 12263# 12264fin_sd_ovfl_dis: 12265 btst &neg_bit,FPSR_CC(%a6) # is result negative? 12266 sne %d1 # set sign param accordingly 12267 mov.l L_SCR3(%a6),%d0 # pass: prec,mode 12268 bsr.l ovf_res # calculate default result 12269 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 12270 fmovm.x (%a0),&0x80 # return default result in fp0 12271 rts 12272 12273# 12274# OVFL is enabled. 12275# the INEX2 bit has already been updated by the round to the correct precision. 12276# now, round to extended(and don't alter the FPSR). 12277# 12278fin_sd_ovfl_ena: 12279 mov.l %d2,-(%sp) # save d2 12280 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 12281 mov.l %d1,%d2 # make a copy 12282 andi.l &0x7fff,%d1 # strip sign 12283 andi.w &0x8000,%d2 # keep old sign 12284 sub.l %d0,%d1 # add scale factor 12285 sub.l &0x6000,%d1 # subtract bias 12286 andi.w &0x7fff,%d1 12287 or.w %d2,%d1 12288 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 12289 mov.l (%sp)+,%d2 # restore d2 12290 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 12291 bra.b fin_sd_ovfl_dis 12292 12293# 12294# the move in MAY overflow. so... 12295# 12296fin_sd_may_ovfl: 12297 fmov.l &0x0,%fpsr # clear FPSR 12298 fmov.l L_SCR3(%a6),%fpcr # set FPCR 12299 12300 fmov.x FP_SCR0(%a6),%fp0 # perform the move 12301 12302 fmov.l %fpsr,%d1 # save status 12303 fmov.l &0x0,%fpcr # clear FPCR 12304 12305 or.l %d1,USER_FPSR(%a6) # save INEX2,N 12306 12307 fabs.x %fp0,%fp1 # make a copy of result 12308 fcmp.b %fp1,&0x2 # is |result| >= 2.b? 12309 fbge.w fin_sd_ovfl_tst # yes; overflow has occurred 12310 12311# no, it didn't overflow; we have correct result 12312 bra.w fin_sd_normal_exit 12313 12314########################################################################## 12315 12316# 12317# operand is not a NORM: check its optype and branch accordingly 12318# 12319fin_not_norm: 12320 cmpi.b %d1,&DENORM # weed out DENORM 12321 beq.w fin_denorm 12322 cmpi.b %d1,&SNAN # weed out SNANs 12323 beq.l res_snan_1op 12324 cmpi.b %d1,&QNAN # weed out QNANs 12325 beq.l res_qnan_1op 12326 12327# 12328# do the fmove in; at this point, only possible ops are ZERO and INF. 12329# use fmov to determine ccodes. 12330# prec:mode should be zero at this point but it won't affect answer anyways. 12331# 12332 fmov.x SRC(%a0),%fp0 # do fmove in 12333 fmov.l %fpsr,%d0 # no exceptions possible 12334 rol.l &0x8,%d0 # put ccodes in lo byte 12335 mov.b %d0,FPSR_CC(%a6) # insert correct ccodes 12336 rts 12337 12338######################################################################### 12339# XDEF **************************************************************** # 12340# fdiv(): emulates the fdiv instruction # 12341# fsdiv(): emulates the fsdiv instruction # 12342# fddiv(): emulates the fddiv instruction # 12343# # 12344# XREF **************************************************************** # 12345# scale_to_zero_src() - scale src exponent to zero # 12346# scale_to_zero_dst() - scale dst exponent to zero # 12347# unf_res() - return default underflow result # 12348# ovf_res() - return default overflow result # 12349# res_qnan() - return QNAN result # 12350# res_snan() - return SNAN result # 12351# # 12352# INPUT *************************************************************** # 12353# a0 = pointer to extended precision source operand # 12354# a1 = pointer to extended precision destination operand # 12355# d0 rnd prec,mode # 12356# # 12357# OUTPUT ************************************************************** # 12358# fp0 = result # 12359# fp1 = EXOP (if exception occurred) # 12360# # 12361# ALGORITHM *********************************************************** # 12362# Handle NANs, infinities, and zeroes as special cases. Divide # 12363# norms/denorms into ext/sgl/dbl precision. # 12364# For norms/denorms, scale the exponents such that a divide # 12365# instruction won't cause an exception. Use the regular fdiv to # 12366# compute a result. Check if the regular operands would have taken # 12367# an exception. If so, return the default overflow/underflow result # 12368# and return the EXOP if exceptions are enabled. Else, scale the # 12369# result operand to the proper exponent. # 12370# # 12371######################################################################### 12372 12373 align 0x10 12374tbl_fdiv_unfl: 12375 long 0x3fff - 0x0000 # ext_unfl 12376 long 0x3fff - 0x3f81 # sgl_unfl 12377 long 0x3fff - 0x3c01 # dbl_unfl 12378 12379tbl_fdiv_ovfl: 12380 long 0x3fff - 0x7ffe # ext overflow exponent 12381 long 0x3fff - 0x407e # sgl overflow exponent 12382 long 0x3fff - 0x43fe # dbl overflow exponent 12383 12384 global fsdiv 12385fsdiv: 12386 andi.b &0x30,%d0 # clear rnd prec 12387 ori.b &s_mode*0x10,%d0 # insert sgl prec 12388 bra.b fdiv 12389 12390 global fddiv 12391fddiv: 12392 andi.b &0x30,%d0 # clear rnd prec 12393 ori.b &d_mode*0x10,%d0 # insert dbl prec 12394 12395 global fdiv 12396fdiv: 12397 mov.l %d0,L_SCR3(%a6) # store rnd info 12398 12399 clr.w %d1 12400 mov.b DTAG(%a6),%d1 12401 lsl.b &0x3,%d1 12402 or.b STAG(%a6),%d1 # combine src tags 12403 12404 bne.w fdiv_not_norm # optimize on non-norm input 12405 12406# 12407# DIVIDE: NORMs and DENORMs ONLY! 12408# 12409fdiv_norm: 12410 mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 12411 mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 12412 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 12413 12414 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12415 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12416 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12417 12418 bsr.l scale_to_zero_src # scale src exponent 12419 mov.l %d0,-(%sp) # save scale factor 1 12420 12421 bsr.l scale_to_zero_dst # scale dst exponent 12422 12423 neg.l (%sp) # SCALE FACTOR = scale1 - scale2 12424 add.l %d0,(%sp) 12425 12426 mov.w 2+L_SCR3(%a6),%d1 # fetch precision 12427 lsr.b &0x6,%d1 # shift to lo bits 12428 mov.l (%sp)+,%d0 # load S.F. 12429 cmp.l %d0,(tbl_fdiv_ovfl.b,%pc,%d1.w*4) # will result overflow? 12430 ble.w fdiv_may_ovfl # result will overflow 12431 12432 cmp.l %d0,(tbl_fdiv_unfl.w,%pc,%d1.w*4) # will result underflow? 12433 beq.w fdiv_may_unfl # maybe 12434 bgt.w fdiv_unfl # yes; go handle underflow 12435 12436fdiv_normal: 12437 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 12438 12439 fmov.l L_SCR3(%a6),%fpcr # save FPCR 12440 fmov.l &0x0,%fpsr # clear FPSR 12441 12442 fdiv.x FP_SCR0(%a6),%fp0 # perform divide 12443 12444 fmov.l %fpsr,%d1 # save FPSR 12445 fmov.l &0x0,%fpcr # clear FPCR 12446 12447 or.l %d1,USER_FPSR(%a6) # save INEX2,N 12448 12449fdiv_normal_exit: 12450 fmovm.x &0x80,FP_SCR0(%a6) # store result on stack 12451 mov.l %d2,-(%sp) # store d2 12452 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 12453 mov.l %d1,%d2 # make a copy 12454 andi.l &0x7fff,%d1 # strip sign 12455 andi.w &0x8000,%d2 # keep old sign 12456 sub.l %d0,%d1 # add scale factor 12457 or.w %d2,%d1 # concat old sign,new exp 12458 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 12459 mov.l (%sp)+,%d2 # restore d2 12460 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 12461 rts 12462 12463tbl_fdiv_ovfl2: 12464 long 0x7fff 12465 long 0x407f 12466 long 0x43ff 12467 12468fdiv_no_ovfl: 12469 mov.l (%sp)+,%d0 # restore scale factor 12470 bra.b fdiv_normal_exit 12471 12472fdiv_may_ovfl: 12473 mov.l %d0,-(%sp) # save scale factor 12474 12475 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 12476 12477 fmov.l L_SCR3(%a6),%fpcr # set FPCR 12478 fmov.l &0x0,%fpsr # set FPSR 12479 12480 fdiv.x FP_SCR0(%a6),%fp0 # execute divide 12481 12482 fmov.l %fpsr,%d0 12483 fmov.l &0x0,%fpcr 12484 12485 or.l %d0,USER_FPSR(%a6) # save INEX,N 12486 12487 fmovm.x &0x01,-(%sp) # save result to stack 12488 mov.w (%sp),%d0 # fetch new exponent 12489 add.l &0xc,%sp # clear result from stack 12490 andi.l &0x7fff,%d0 # strip sign 12491 sub.l (%sp),%d0 # add scale factor 12492 cmp.l %d0,(tbl_fdiv_ovfl2.b,%pc,%d1.w*4) 12493 blt.b fdiv_no_ovfl 12494 mov.l (%sp)+,%d0 12495 12496fdiv_ovfl_tst: 12497 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 12498 12499 mov.b FPCR_ENABLE(%a6),%d1 12500 andi.b &0x13,%d1 # is OVFL or INEX enabled? 12501 bne.b fdiv_ovfl_ena # yes 12502 12503fdiv_ovfl_dis: 12504 btst &neg_bit,FPSR_CC(%a6) # is result negative? 12505 sne %d1 # set sign param accordingly 12506 mov.l L_SCR3(%a6),%d0 # pass prec:rnd 12507 bsr.l ovf_res # calculate default result 12508 or.b %d0,FPSR_CC(%a6) # set INF if applicable 12509 fmovm.x (%a0),&0x80 # return default result in fp0 12510 rts 12511 12512fdiv_ovfl_ena: 12513 mov.l L_SCR3(%a6),%d1 12514 andi.b &0xc0,%d1 # is precision extended? 12515 bne.b fdiv_ovfl_ena_sd # no, do sgl or dbl 12516 12517fdiv_ovfl_ena_cont: 12518 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 12519 12520 mov.l %d2,-(%sp) # save d2 12521 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 12522 mov.w %d1,%d2 # make a copy 12523 andi.l &0x7fff,%d1 # strip sign 12524 sub.l %d0,%d1 # add scale factor 12525 subi.l &0x6000,%d1 # subtract bias 12526 andi.w &0x7fff,%d1 # clear sign bit 12527 andi.w &0x8000,%d2 # keep old sign 12528 or.w %d2,%d1 # concat old sign,new exp 12529 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 12530 mov.l (%sp)+,%d2 # restore d2 12531 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 12532 bra.b fdiv_ovfl_dis 12533 12534fdiv_ovfl_ena_sd: 12535 fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 12536 12537 mov.l L_SCR3(%a6),%d1 12538 andi.b &0x30,%d1 # keep rnd mode 12539 fmov.l %d1,%fpcr # set FPCR 12540 12541 fdiv.x FP_SCR0(%a6),%fp0 # execute divide 12542 12543 fmov.l &0x0,%fpcr # clear FPCR 12544 bra.b fdiv_ovfl_ena_cont 12545 12546fdiv_unfl: 12547 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 12548 12549 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 12550 12551 fmov.l &rz_mode*0x10,%fpcr # set FPCR 12552 fmov.l &0x0,%fpsr # clear FPSR 12553 12554 fdiv.x FP_SCR0(%a6),%fp0 # execute divide 12555 12556 fmov.l %fpsr,%d1 # save status 12557 fmov.l &0x0,%fpcr # clear FPCR 12558 12559 or.l %d1,USER_FPSR(%a6) # save INEX2,N 12560 12561 mov.b FPCR_ENABLE(%a6),%d1 12562 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 12563 bne.b fdiv_unfl_ena # yes 12564 12565fdiv_unfl_dis: 12566 fmovm.x &0x80,FP_SCR0(%a6) # store out result 12567 12568 lea FP_SCR0(%a6),%a0 # pass: result addr 12569 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 12570 bsr.l unf_res # calculate default result 12571 or.b %d0,FPSR_CC(%a6) # 'Z' may have been set 12572 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 12573 rts 12574 12575# 12576# UNFL is enabled. 12577# 12578fdiv_unfl_ena: 12579 fmovm.x FP_SCR1(%a6),&0x40 # load dst op 12580 12581 mov.l L_SCR3(%a6),%d1 12582 andi.b &0xc0,%d1 # is precision extended? 12583 bne.b fdiv_unfl_ena_sd # no, sgl or dbl 12584 12585 fmov.l L_SCR3(%a6),%fpcr # set FPCR 12586 12587fdiv_unfl_ena_cont: 12588 fmov.l &0x0,%fpsr # clear FPSR 12589 12590 fdiv.x FP_SCR0(%a6),%fp1 # execute divide 12591 12592 fmov.l &0x0,%fpcr # clear FPCR 12593 12594 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 12595 mov.l %d2,-(%sp) # save d2 12596 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 12597 mov.l %d1,%d2 # make a copy 12598 andi.l &0x7fff,%d1 # strip sign 12599 andi.w &0x8000,%d2 # keep old sign 12600 sub.l %d0,%d1 # add scale factoer 12601 addi.l &0x6000,%d1 # add bias 12602 andi.w &0x7fff,%d1 12603 or.w %d2,%d1 # concat old sign,new exp 12604 mov.w %d1,FP_SCR0_EX(%a6) # insert new exp 12605 mov.l (%sp)+,%d2 # restore d2 12606 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 12607 bra.w fdiv_unfl_dis 12608 12609fdiv_unfl_ena_sd: 12610 mov.l L_SCR3(%a6),%d1 12611 andi.b &0x30,%d1 # use only rnd mode 12612 fmov.l %d1,%fpcr # set FPCR 12613 12614 bra.b fdiv_unfl_ena_cont 12615 12616# 12617# the divide operation MAY underflow: 12618# 12619fdiv_may_unfl: 12620 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 12621 12622 fmov.l L_SCR3(%a6),%fpcr # set FPCR 12623 fmov.l &0x0,%fpsr # clear FPSR 12624 12625 fdiv.x FP_SCR0(%a6),%fp0 # execute divide 12626 12627 fmov.l %fpsr,%d1 # save status 12628 fmov.l &0x0,%fpcr # clear FPCR 12629 12630 or.l %d1,USER_FPSR(%a6) # save INEX2,N 12631 12632 fabs.x %fp0,%fp1 # make a copy of result 12633 fcmp.b %fp1,&0x1 # is |result| > 1.b? 12634 fbgt.w fdiv_normal_exit # no; no underflow occurred 12635 fblt.w fdiv_unfl # yes; underflow occurred 12636 12637# 12638# we still don't know if underflow occurred. result is ~ equal to 1. but, 12639# we don't know if the result was an underflow that rounded up to a 1 12640# or a normalized number that rounded down to a 1. so, redo the entire 12641# operation using RZ as the rounding mode to see what the pre-rounded 12642# result is. this case should be relatively rare. 12643# 12644 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 12645 12646 mov.l L_SCR3(%a6),%d1 12647 andi.b &0xc0,%d1 # keep rnd prec 12648 ori.b &rz_mode*0x10,%d1 # insert RZ 12649 12650 fmov.l %d1,%fpcr # set FPCR 12651 fmov.l &0x0,%fpsr # clear FPSR 12652 12653 fdiv.x FP_SCR0(%a6),%fp1 # execute divide 12654 12655 fmov.l &0x0,%fpcr # clear FPCR 12656 fabs.x %fp1 # make absolute value 12657 fcmp.b %fp1,&0x1 # is |result| < 1.b? 12658 fbge.w fdiv_normal_exit # no; no underflow occurred 12659 bra.w fdiv_unfl # yes; underflow occurred 12660 12661############################################################################ 12662 12663# 12664# Divide: inputs are not both normalized; what are they? 12665# 12666fdiv_not_norm: 12667 mov.w (tbl_fdiv_op.b,%pc,%d1.w*2),%d1 12668 jmp (tbl_fdiv_op.b,%pc,%d1.w*1) 12669 12670 swbeg &48 12671tbl_fdiv_op: 12672 short fdiv_norm - tbl_fdiv_op # NORM / NORM 12673 short fdiv_inf_load - tbl_fdiv_op # NORM / ZERO 12674 short fdiv_zero_load - tbl_fdiv_op # NORM / INF 12675 short fdiv_res_qnan - tbl_fdiv_op # NORM / QNAN 12676 short fdiv_norm - tbl_fdiv_op # NORM / DENORM 12677 short fdiv_res_snan - tbl_fdiv_op # NORM / SNAN 12678 short tbl_fdiv_op - tbl_fdiv_op # 12679 short tbl_fdiv_op - tbl_fdiv_op # 12680 12681 short fdiv_zero_load - tbl_fdiv_op # ZERO / NORM 12682 short fdiv_res_operr - tbl_fdiv_op # ZERO / ZERO 12683 short fdiv_zero_load - tbl_fdiv_op # ZERO / INF 12684 short fdiv_res_qnan - tbl_fdiv_op # ZERO / QNAN 12685 short fdiv_zero_load - tbl_fdiv_op # ZERO / DENORM 12686 short fdiv_res_snan - tbl_fdiv_op # ZERO / SNAN 12687 short tbl_fdiv_op - tbl_fdiv_op # 12688 short tbl_fdiv_op - tbl_fdiv_op # 12689 12690 short fdiv_inf_dst - tbl_fdiv_op # INF / NORM 12691 short fdiv_inf_dst - tbl_fdiv_op # INF / ZERO 12692 short fdiv_res_operr - tbl_fdiv_op # INF / INF 12693 short fdiv_res_qnan - tbl_fdiv_op # INF / QNAN 12694 short fdiv_inf_dst - tbl_fdiv_op # INF / DENORM 12695 short fdiv_res_snan - tbl_fdiv_op # INF / SNAN 12696 short tbl_fdiv_op - tbl_fdiv_op # 12697 short tbl_fdiv_op - tbl_fdiv_op # 12698 12699 short fdiv_res_qnan - tbl_fdiv_op # QNAN / NORM 12700 short fdiv_res_qnan - tbl_fdiv_op # QNAN / ZERO 12701 short fdiv_res_qnan - tbl_fdiv_op # QNAN / INF 12702 short fdiv_res_qnan - tbl_fdiv_op # QNAN / QNAN 12703 short fdiv_res_qnan - tbl_fdiv_op # QNAN / DENORM 12704 short fdiv_res_snan - tbl_fdiv_op # QNAN / SNAN 12705 short tbl_fdiv_op - tbl_fdiv_op # 12706 short tbl_fdiv_op - tbl_fdiv_op # 12707 12708 short fdiv_norm - tbl_fdiv_op # DENORM / NORM 12709 short fdiv_inf_load - tbl_fdiv_op # DENORM / ZERO 12710 short fdiv_zero_load - tbl_fdiv_op # DENORM / INF 12711 short fdiv_res_qnan - tbl_fdiv_op # DENORM / QNAN 12712 short fdiv_norm - tbl_fdiv_op # DENORM / DENORM 12713 short fdiv_res_snan - tbl_fdiv_op # DENORM / SNAN 12714 short tbl_fdiv_op - tbl_fdiv_op # 12715 short tbl_fdiv_op - tbl_fdiv_op # 12716 12717 short fdiv_res_snan - tbl_fdiv_op # SNAN / NORM 12718 short fdiv_res_snan - tbl_fdiv_op # SNAN / ZERO 12719 short fdiv_res_snan - tbl_fdiv_op # SNAN / INF 12720 short fdiv_res_snan - tbl_fdiv_op # SNAN / QNAN 12721 short fdiv_res_snan - tbl_fdiv_op # SNAN / DENORM 12722 short fdiv_res_snan - tbl_fdiv_op # SNAN / SNAN 12723 short tbl_fdiv_op - tbl_fdiv_op # 12724 short tbl_fdiv_op - tbl_fdiv_op # 12725 12726fdiv_res_qnan: 12727 bra.l res_qnan 12728fdiv_res_snan: 12729 bra.l res_snan 12730fdiv_res_operr: 12731 bra.l res_operr 12732 12733 global fdiv_zero_load # global for fsgldiv 12734fdiv_zero_load: 12735 mov.b SRC_EX(%a0),%d0 # result sign is exclusive 12736 mov.b DST_EX(%a1),%d1 # or of input signs. 12737 eor.b %d0,%d1 12738 bpl.b fdiv_zero_load_p # result is positive 12739 fmov.s &0x80000000,%fp0 # load a -ZERO 12740 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N 12741 rts 12742fdiv_zero_load_p: 12743 fmov.s &0x00000000,%fp0 # load a +ZERO 12744 mov.b &z_bmask,FPSR_CC(%a6) # set Z 12745 rts 12746 12747# 12748# The destination was In Range and the source was a ZERO. The result, 12749# Therefore, is an INF w/ the proper sign. 12750# So, determine the sign and return a new INF (w/ the j-bit cleared). 12751# 12752 global fdiv_inf_load # global for fsgldiv 12753fdiv_inf_load: 12754 ori.w &dz_mask+adz_mask,2+USER_FPSR(%a6) # no; set DZ/ADZ 12755 mov.b SRC_EX(%a0),%d0 # load both signs 12756 mov.b DST_EX(%a1),%d1 12757 eor.b %d0,%d1 12758 bpl.b fdiv_inf_load_p # result is positive 12759 fmov.s &0xff800000,%fp0 # make result -INF 12760 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N 12761 rts 12762fdiv_inf_load_p: 12763 fmov.s &0x7f800000,%fp0 # make result +INF 12764 mov.b &inf_bmask,FPSR_CC(%a6) # set INF 12765 rts 12766 12767# 12768# The destination was an INF w/ an In Range or ZERO source, the result is 12769# an INF w/ the proper sign. 12770# The 68881/882 returns the destination INF w/ the new sign(if the j-bit of the 12771# dst INF is set, then then j-bit of the result INF is also set). 12772# 12773 global fdiv_inf_dst # global for fsgldiv 12774fdiv_inf_dst: 12775 mov.b DST_EX(%a1),%d0 # load both signs 12776 mov.b SRC_EX(%a0),%d1 12777 eor.b %d0,%d1 12778 bpl.b fdiv_inf_dst_p # result is positive 12779 12780 fmovm.x DST(%a1),&0x80 # return result in fp0 12781 fabs.x %fp0 # clear sign bit 12782 fneg.x %fp0 # set sign bit 12783 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/NEG 12784 rts 12785 12786fdiv_inf_dst_p: 12787 fmovm.x DST(%a1),&0x80 # return result in fp0 12788 fabs.x %fp0 # return positive INF 12789 mov.b &inf_bmask,FPSR_CC(%a6) # set INF 12790 rts 12791 12792######################################################################### 12793# XDEF **************************************************************** # 12794# fneg(): emulates the fneg instruction # 12795# fsneg(): emulates the fsneg instruction # 12796# fdneg(): emulates the fdneg instruction # 12797# # 12798# XREF **************************************************************** # 12799# norm() - normalize a denorm to provide EXOP # 12800# scale_to_zero_src() - scale sgl/dbl source exponent # 12801# ovf_res() - return default overflow result # 12802# unf_res() - return default underflow result # 12803# res_qnan_1op() - return QNAN result # 12804# res_snan_1op() - return SNAN result # 12805# # 12806# INPUT *************************************************************** # 12807# a0 = pointer to extended precision source operand # 12808# d0 = rnd prec,mode # 12809# # 12810# OUTPUT ************************************************************** # 12811# fp0 = result # 12812# fp1 = EXOP (if exception occurred) # 12813# # 12814# ALGORITHM *********************************************************** # 12815# Handle NANs, zeroes, and infinities as special cases. Separate # 12816# norms/denorms into ext/sgl/dbl precisions. Extended precision can be # 12817# emulated by simply setting sign bit. Sgl/dbl operands must be scaled # 12818# and an actual fneg performed to see if overflow/underflow would have # 12819# occurred. If so, return default underflow/overflow result. Else, # 12820# scale the result exponent and return result. FPSR gets set based on # 12821# the result value. # 12822# # 12823######################################################################### 12824 12825 global fsneg 12826fsneg: 12827 andi.b &0x30,%d0 # clear rnd prec 12828 ori.b &s_mode*0x10,%d0 # insert sgl precision 12829 bra.b fneg 12830 12831 global fdneg 12832fdneg: 12833 andi.b &0x30,%d0 # clear rnd prec 12834 ori.b &d_mode*0x10,%d0 # insert dbl prec 12835 12836 global fneg 12837fneg: 12838 mov.l %d0,L_SCR3(%a6) # store rnd info 12839 mov.b STAG(%a6),%d1 12840 bne.w fneg_not_norm # optimize on non-norm input 12841 12842# 12843# NEGATE SIGN : norms and denorms ONLY! 12844# 12845fneg_norm: 12846 andi.b &0xc0,%d0 # is precision extended? 12847 bne.w fneg_not_ext # no; go handle sgl or dbl 12848 12849# 12850# precision selected is extended. so...we can not get an underflow 12851# or overflow because of rounding to the correct precision. so... 12852# skip the scaling and unscaling... 12853# 12854 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12855 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12856 mov.w SRC_EX(%a0),%d0 12857 eori.w &0x8000,%d0 # negate sign 12858 bpl.b fneg_norm_load # sign is positive 12859 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 12860fneg_norm_load: 12861 mov.w %d0,FP_SCR0_EX(%a6) 12862 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 12863 rts 12864 12865# 12866# for an extended precision DENORM, the UNFL exception bit is set 12867# the accrued bit is NOT set in this instance(no inexactness!) 12868# 12869fneg_denorm: 12870 andi.b &0xc0,%d0 # is precision extended? 12871 bne.b fneg_not_ext # no; go handle sgl or dbl 12872 12873 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 12874 12875 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12876 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12877 mov.w SRC_EX(%a0),%d0 12878 eori.w &0x8000,%d0 # negate sign 12879 bpl.b fneg_denorm_done # no 12880 mov.b &neg_bmask,FPSR_CC(%a6) # yes, set 'N' ccode bit 12881fneg_denorm_done: 12882 mov.w %d0,FP_SCR0_EX(%a6) 12883 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 12884 12885 btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled? 12886 bne.b fneg_ext_unfl_ena # yes 12887 rts 12888 12889# 12890# the input is an extended DENORM and underflow is enabled in the FPCR. 12891# normalize the mantissa and add the bias of 0x6000 to the resulting negative 12892# exponent and insert back into the operand. 12893# 12894fneg_ext_unfl_ena: 12895 lea FP_SCR0(%a6),%a0 # pass: ptr to operand 12896 bsr.l norm # normalize result 12897 neg.w %d0 # new exponent = -(shft val) 12898 addi.w &0x6000,%d0 # add new bias to exponent 12899 mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp 12900 andi.w &0x8000,%d1 # keep old sign 12901 andi.w &0x7fff,%d0 # clear sign position 12902 or.w %d1,%d0 # concat old sign, new exponent 12903 mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent 12904 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 12905 rts 12906 12907# 12908# operand is either single or double 12909# 12910fneg_not_ext: 12911 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 12912 bne.b fneg_dbl 12913 12914# 12915# operand is to be rounded to single precision 12916# 12917fneg_sgl: 12918 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12919 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12920 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12921 bsr.l scale_to_zero_src # calculate scale factor 12922 12923 cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow? 12924 bge.w fneg_sd_unfl # yes; go handle underflow 12925 cmpi.l %d0,&0x3fff-0x407e # will move in overflow? 12926 beq.w fneg_sd_may_ovfl # maybe; go check 12927 blt.w fneg_sd_ovfl # yes; go handle overflow 12928 12929# 12930# operand will NOT overflow or underflow when moved in to the fp reg file 12931# 12932fneg_sd_normal: 12933 fmov.l &0x0,%fpsr # clear FPSR 12934 fmov.l L_SCR3(%a6),%fpcr # set FPCR 12935 12936 fneg.x FP_SCR0(%a6),%fp0 # perform negation 12937 12938 fmov.l %fpsr,%d1 # save FPSR 12939 fmov.l &0x0,%fpcr # clear FPCR 12940 12941 or.l %d1,USER_FPSR(%a6) # save INEX2,N 12942 12943fneg_sd_normal_exit: 12944 mov.l %d2,-(%sp) # save d2 12945 fmovm.x &0x80,FP_SCR0(%a6) # store out result 12946 mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp 12947 mov.w %d1,%d2 # make a copy 12948 andi.l &0x7fff,%d1 # strip sign 12949 sub.l %d0,%d1 # add scale factor 12950 andi.w &0x8000,%d2 # keep old sign 12951 or.w %d1,%d2 # concat old sign,new exp 12952 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 12953 mov.l (%sp)+,%d2 # restore d2 12954 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 12955 rts 12956 12957# 12958# operand is to be rounded to double precision 12959# 12960fneg_dbl: 12961 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12962 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12963 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12964 bsr.l scale_to_zero_src # calculate scale factor 12965 12966 cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow? 12967 bge.b fneg_sd_unfl # yes; go handle underflow 12968 cmpi.l %d0,&0x3fff-0x43fe # will move in overflow? 12969 beq.w fneg_sd_may_ovfl # maybe; go check 12970 blt.w fneg_sd_ovfl # yes; go handle overflow 12971 bra.w fneg_sd_normal # no; ho handle normalized op 12972 12973# 12974# operand WILL underflow when moved in to the fp register file 12975# 12976fneg_sd_unfl: 12977 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 12978 12979 eori.b &0x80,FP_SCR0_EX(%a6) # negate sign 12980 bpl.b fneg_sd_unfl_tst 12981 bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit 12982 12983# if underflow or inexact is enabled, go calculate EXOP first. 12984fneg_sd_unfl_tst: 12985 mov.b FPCR_ENABLE(%a6),%d1 12986 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 12987 bne.b fneg_sd_unfl_ena # yes 12988 12989fneg_sd_unfl_dis: 12990 lea FP_SCR0(%a6),%a0 # pass: result addr 12991 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 12992 bsr.l unf_res # calculate default result 12993 or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z' 12994 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 12995 rts 12996 12997# 12998# operand will underflow AND underflow is enabled. 12999# Therefore, we must return the result rounded to extended precision. 13000# 13001fneg_sd_unfl_ena: 13002 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 13003 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 13004 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 13005 13006 mov.l %d2,-(%sp) # save d2 13007 mov.l %d1,%d2 # make a copy 13008 andi.l &0x7fff,%d1 # strip sign 13009 andi.w &0x8000,%d2 # keep old sign 13010 sub.l %d0,%d1 # subtract scale factor 13011 addi.l &0x6000,%d1 # add new bias 13012 andi.w &0x7fff,%d1 13013 or.w %d2,%d1 # concat new sign,new exp 13014 mov.w %d1,FP_SCR1_EX(%a6) # insert new exp 13015 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 13016 mov.l (%sp)+,%d2 # restore d2 13017 bra.b fneg_sd_unfl_dis 13018 13019# 13020# operand WILL overflow. 13021# 13022fneg_sd_ovfl: 13023 fmov.l &0x0,%fpsr # clear FPSR 13024 fmov.l L_SCR3(%a6),%fpcr # set FPCR 13025 13026 fneg.x FP_SCR0(%a6),%fp0 # perform negation 13027 13028 fmov.l &0x0,%fpcr # clear FPCR 13029 fmov.l %fpsr,%d1 # save FPSR 13030 13031 or.l %d1,USER_FPSR(%a6) # save INEX2,N 13032 13033fneg_sd_ovfl_tst: 13034 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 13035 13036 mov.b FPCR_ENABLE(%a6),%d1 13037 andi.b &0x13,%d1 # is OVFL or INEX enabled? 13038 bne.b fneg_sd_ovfl_ena # yes 13039 13040# 13041# OVFL is not enabled; therefore, we must create the default result by 13042# calling ovf_res(). 13043# 13044fneg_sd_ovfl_dis: 13045 btst &neg_bit,FPSR_CC(%a6) # is result negative? 13046 sne %d1 # set sign param accordingly 13047 mov.l L_SCR3(%a6),%d0 # pass: prec,mode 13048 bsr.l ovf_res # calculate default result 13049 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 13050 fmovm.x (%a0),&0x80 # return default result in fp0 13051 rts 13052 13053# 13054# OVFL is enabled. 13055# the INEX2 bit has already been updated by the round to the correct precision. 13056# now, round to extended(and don't alter the FPSR). 13057# 13058fneg_sd_ovfl_ena: 13059 mov.l %d2,-(%sp) # save d2 13060 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 13061 mov.l %d1,%d2 # make a copy 13062 andi.l &0x7fff,%d1 # strip sign 13063 andi.w &0x8000,%d2 # keep old sign 13064 sub.l %d0,%d1 # add scale factor 13065 subi.l &0x6000,%d1 # subtract bias 13066 andi.w &0x7fff,%d1 13067 or.w %d2,%d1 # concat sign,exp 13068 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 13069 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 13070 mov.l (%sp)+,%d2 # restore d2 13071 bra.b fneg_sd_ovfl_dis 13072 13073# 13074# the move in MAY underflow. so... 13075# 13076fneg_sd_may_ovfl: 13077 fmov.l &0x0,%fpsr # clear FPSR 13078 fmov.l L_SCR3(%a6),%fpcr # set FPCR 13079 13080 fneg.x FP_SCR0(%a6),%fp0 # perform negation 13081 13082 fmov.l %fpsr,%d1 # save status 13083 fmov.l &0x0,%fpcr # clear FPCR 13084 13085 or.l %d1,USER_FPSR(%a6) # save INEX2,N 13086 13087 fabs.x %fp0,%fp1 # make a copy of result 13088 fcmp.b %fp1,&0x2 # is |result| >= 2.b? 13089 fbge.w fneg_sd_ovfl_tst # yes; overflow has occurred 13090 13091# no, it didn't overflow; we have correct result 13092 bra.w fneg_sd_normal_exit 13093 13094########################################################################## 13095 13096# 13097# input is not normalized; what is it? 13098# 13099fneg_not_norm: 13100 cmpi.b %d1,&DENORM # weed out DENORM 13101 beq.w fneg_denorm 13102 cmpi.b %d1,&SNAN # weed out SNAN 13103 beq.l res_snan_1op 13104 cmpi.b %d1,&QNAN # weed out QNAN 13105 beq.l res_qnan_1op 13106 13107# 13108# do the fneg; at this point, only possible ops are ZERO and INF. 13109# use fneg to determine ccodes. 13110# prec:mode should be zero at this point but it won't affect answer anyways. 13111# 13112 fneg.x SRC_EX(%a0),%fp0 # do fneg 13113 fmov.l %fpsr,%d0 13114 rol.l &0x8,%d0 # put ccodes in lo byte 13115 mov.b %d0,FPSR_CC(%a6) # insert correct ccodes 13116 rts 13117 13118######################################################################### 13119# XDEF **************************************************************** # 13120# ftst(): emulates the ftest instruction # 13121# # 13122# XREF **************************************************************** # 13123# res{s,q}nan_1op() - set NAN result for monadic instruction # 13124# # 13125# INPUT *************************************************************** # 13126# a0 = pointer to extended precision source operand # 13127# # 13128# OUTPUT ************************************************************** # 13129# none # 13130# # 13131# ALGORITHM *********************************************************** # 13132# Check the source operand tag (STAG) and set the FPCR according # 13133# to the operand type and sign. # 13134# # 13135######################################################################### 13136 13137 global ftst 13138ftst: 13139 mov.b STAG(%a6),%d1 13140 bne.b ftst_not_norm # optimize on non-norm input 13141 13142# 13143# Norm: 13144# 13145ftst_norm: 13146 tst.b SRC_EX(%a0) # is operand negative? 13147 bmi.b ftst_norm_m # yes 13148 rts 13149ftst_norm_m: 13150 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 13151 rts 13152 13153# 13154# input is not normalized; what is it? 13155# 13156ftst_not_norm: 13157 cmpi.b %d1,&ZERO # weed out ZERO 13158 beq.b ftst_zero 13159 cmpi.b %d1,&INF # weed out INF 13160 beq.b ftst_inf 13161 cmpi.b %d1,&SNAN # weed out SNAN 13162 beq.l res_snan_1op 13163 cmpi.b %d1,&QNAN # weed out QNAN 13164 beq.l res_qnan_1op 13165 13166# 13167# Denorm: 13168# 13169ftst_denorm: 13170 tst.b SRC_EX(%a0) # is operand negative? 13171 bmi.b ftst_denorm_m # yes 13172 rts 13173ftst_denorm_m: 13174 mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 13175 rts 13176 13177# 13178# Infinity: 13179# 13180ftst_inf: 13181 tst.b SRC_EX(%a0) # is operand negative? 13182 bmi.b ftst_inf_m # yes 13183ftst_inf_p: 13184 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 13185 rts 13186ftst_inf_m: 13187 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'I','N' ccode bits 13188 rts 13189 13190# 13191# Zero: 13192# 13193ftst_zero: 13194 tst.b SRC_EX(%a0) # is operand negative? 13195 bmi.b ftst_zero_m # yes 13196ftst_zero_p: 13197 mov.b &z_bmask,FPSR_CC(%a6) # set 'N' ccode bit 13198 rts 13199ftst_zero_m: 13200 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 13201 rts 13202 13203######################################################################### 13204# XDEF **************************************************************** # 13205# fint(): emulates the fint instruction # 13206# # 13207# XREF **************************************************************** # 13208# res_{s,q}nan_1op() - set NAN result for monadic operation # 13209# # 13210# INPUT *************************************************************** # 13211# a0 = pointer to extended precision source operand # 13212# d0 = round precision/mode # 13213# # 13214# OUTPUT ************************************************************** # 13215# fp0 = result # 13216# # 13217# ALGORITHM *********************************************************** # 13218# Separate according to operand type. Unnorms don't pass through # 13219# here. For norms, load the rounding mode/prec, execute a "fint", then # 13220# store the resulting FPSR bits. # 13221# For denorms, force the j-bit to a one and do the same as for # 13222# norms. Denorms are so low that the answer will either be a zero or a # 13223# one. # 13224# For zeroes/infs/NANs, return the same while setting the FPSR # 13225# as appropriate. # 13226# # 13227######################################################################### 13228 13229 global fint 13230fint: 13231 mov.b STAG(%a6),%d1 13232 bne.b fint_not_norm # optimize on non-norm input 13233 13234# 13235# Norm: 13236# 13237fint_norm: 13238 andi.b &0x30,%d0 # set prec = ext 13239 13240 fmov.l %d0,%fpcr # set FPCR 13241 fmov.l &0x0,%fpsr # clear FPSR 13242 13243 fint.x SRC(%a0),%fp0 # execute fint 13244 13245 fmov.l &0x0,%fpcr # clear FPCR 13246 fmov.l %fpsr,%d0 # save FPSR 13247 or.l %d0,USER_FPSR(%a6) # set exception bits 13248 13249 rts 13250 13251# 13252# input is not normalized; what is it? 13253# 13254fint_not_norm: 13255 cmpi.b %d1,&ZERO # weed out ZERO 13256 beq.b fint_zero 13257 cmpi.b %d1,&INF # weed out INF 13258 beq.b fint_inf 13259 cmpi.b %d1,&DENORM # weed out DENORM 13260 beq.b fint_denorm 13261 cmpi.b %d1,&SNAN # weed out SNAN 13262 beq.l res_snan_1op 13263 bra.l res_qnan_1op # weed out QNAN 13264 13265# 13266# Denorm: 13267# 13268# for DENORMs, the result will be either (+/-)ZERO or (+/-)1. 13269# also, the INEX2 and AINEX exception bits will be set. 13270# so, we could either set these manually or force the DENORM 13271# to a very small NORM and ship it to the NORM routine. 13272# I do the latter. 13273# 13274fint_denorm: 13275 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp 13276 mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM 13277 lea FP_SCR0(%a6),%a0 13278 bra.b fint_norm 13279 13280# 13281# Zero: 13282# 13283fint_zero: 13284 tst.b SRC_EX(%a0) # is ZERO negative? 13285 bmi.b fint_zero_m # yes 13286fint_zero_p: 13287 fmov.s &0x00000000,%fp0 # return +ZERO in fp0 13288 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 13289 rts 13290fint_zero_m: 13291 fmov.s &0x80000000,%fp0 # return -ZERO in fp0 13292 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 13293 rts 13294 13295# 13296# Infinity: 13297# 13298fint_inf: 13299 fmovm.x SRC(%a0),&0x80 # return result in fp0 13300 tst.b SRC_EX(%a0) # is INF negative? 13301 bmi.b fint_inf_m # yes 13302fint_inf_p: 13303 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 13304 rts 13305fint_inf_m: 13306 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits 13307 rts 13308 13309######################################################################### 13310# XDEF **************************************************************** # 13311# fintrz(): emulates the fintrz instruction # 13312# # 13313# XREF **************************************************************** # 13314# res_{s,q}nan_1op() - set NAN result for monadic operation # 13315# # 13316# INPUT *************************************************************** # 13317# a0 = pointer to extended precision source operand # 13318# d0 = round precision/mode # 13319# # 13320# OUTPUT ************************************************************** # 13321# fp0 = result # 13322# # 13323# ALGORITHM *********************************************************** # 13324# Separate according to operand type. Unnorms don't pass through # 13325# here. For norms, load the rounding mode/prec, execute a "fintrz", # 13326# then store the resulting FPSR bits. # 13327# For denorms, force the j-bit to a one and do the same as for # 13328# norms. Denorms are so low that the answer will either be a zero or a # 13329# one. # 13330# For zeroes/infs/NANs, return the same while setting the FPSR # 13331# as appropriate. # 13332# # 13333######################################################################### 13334 13335 global fintrz 13336fintrz: 13337 mov.b STAG(%a6),%d1 13338 bne.b fintrz_not_norm # optimize on non-norm input 13339 13340# 13341# Norm: 13342# 13343fintrz_norm: 13344 fmov.l &0x0,%fpsr # clear FPSR 13345 13346 fintrz.x SRC(%a0),%fp0 # execute fintrz 13347 13348 fmov.l %fpsr,%d0 # save FPSR 13349 or.l %d0,USER_FPSR(%a6) # set exception bits 13350 13351 rts 13352 13353# 13354# input is not normalized; what is it? 13355# 13356fintrz_not_norm: 13357 cmpi.b %d1,&ZERO # weed out ZERO 13358 beq.b fintrz_zero 13359 cmpi.b %d1,&INF # weed out INF 13360 beq.b fintrz_inf 13361 cmpi.b %d1,&DENORM # weed out DENORM 13362 beq.b fintrz_denorm 13363 cmpi.b %d1,&SNAN # weed out SNAN 13364 beq.l res_snan_1op 13365 bra.l res_qnan_1op # weed out QNAN 13366 13367# 13368# Denorm: 13369# 13370# for DENORMs, the result will be (+/-)ZERO. 13371# also, the INEX2 and AINEX exception bits will be set. 13372# so, we could either set these manually or force the DENORM 13373# to a very small NORM and ship it to the NORM routine. 13374# I do the latter. 13375# 13376fintrz_denorm: 13377 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp 13378 mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM 13379 lea FP_SCR0(%a6),%a0 13380 bra.b fintrz_norm 13381 13382# 13383# Zero: 13384# 13385fintrz_zero: 13386 tst.b SRC_EX(%a0) # is ZERO negative? 13387 bmi.b fintrz_zero_m # yes 13388fintrz_zero_p: 13389 fmov.s &0x00000000,%fp0 # return +ZERO in fp0 13390 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 13391 rts 13392fintrz_zero_m: 13393 fmov.s &0x80000000,%fp0 # return -ZERO in fp0 13394 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 13395 rts 13396 13397# 13398# Infinity: 13399# 13400fintrz_inf: 13401 fmovm.x SRC(%a0),&0x80 # return result in fp0 13402 tst.b SRC_EX(%a0) # is INF negative? 13403 bmi.b fintrz_inf_m # yes 13404fintrz_inf_p: 13405 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 13406 rts 13407fintrz_inf_m: 13408 mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits 13409 rts 13410 13411######################################################################### 13412# XDEF **************************************************************** # 13413# fabs(): emulates the fabs instruction # 13414# fsabs(): emulates the fsabs instruction # 13415# fdabs(): emulates the fdabs instruction # 13416# # 13417# XREF **************************************************************** # 13418# norm() - normalize denorm mantissa to provide EXOP # 13419# scale_to_zero_src() - make exponent. = 0; get scale factor # 13420# unf_res() - calculate underflow result # 13421# ovf_res() - calculate overflow result # 13422# res_{s,q}nan_1op() - set NAN result for monadic operation # 13423# # 13424# INPUT *************************************************************** # 13425# a0 = pointer to extended precision source operand # 13426# d0 = rnd precision/mode # 13427# # 13428# OUTPUT ************************************************************** # 13429# fp0 = result # 13430# fp1 = EXOP (if exception occurred) # 13431# # 13432# ALGORITHM *********************************************************** # 13433# Handle NANs, infinities, and zeroes as special cases. Divide # 13434# norms into extended, single, and double precision. # 13435# Simply clear sign for extended precision norm. Ext prec denorm # 13436# gets an EXOP created for it since it's an underflow. # 13437# Double and single precision can overflow and underflow. First, # 13438# scale the operand such that the exponent is zero. Perform an "fabs" # 13439# using the correct rnd mode/prec. Check to see if the original # 13440# exponent would take an exception. If so, use unf_res() or ovf_res() # 13441# to calculate the default result. Also, create the EXOP for the # 13442# exceptional case. If no exception should occur, insert the correct # 13443# result exponent and return. # 13444# Unnorms don't pass through here. # 13445# # 13446######################################################################### 13447 13448 global fsabs 13449fsabs: 13450 andi.b &0x30,%d0 # clear rnd prec 13451 ori.b &s_mode*0x10,%d0 # insert sgl precision 13452 bra.b fabs 13453 13454 global fdabs 13455fdabs: 13456 andi.b &0x30,%d0 # clear rnd prec 13457 ori.b &d_mode*0x10,%d0 # insert dbl precision 13458 13459 global fabs 13460fabs: 13461 mov.l %d0,L_SCR3(%a6) # store rnd info 13462 mov.b STAG(%a6),%d1 13463 bne.w fabs_not_norm # optimize on non-norm input 13464 13465# 13466# ABSOLUTE VALUE: norms and denorms ONLY! 13467# 13468fabs_norm: 13469 andi.b &0xc0,%d0 # is precision extended? 13470 bne.b fabs_not_ext # no; go handle sgl or dbl 13471 13472# 13473# precision selected is extended. so...we can not get an underflow 13474# or overflow because of rounding to the correct precision. so... 13475# skip the scaling and unscaling... 13476# 13477 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 13478 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 13479 mov.w SRC_EX(%a0),%d1 13480 bclr &15,%d1 # force absolute value 13481 mov.w %d1,FP_SCR0_EX(%a6) # insert exponent 13482 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 13483 rts 13484 13485# 13486# for an extended precision DENORM, the UNFL exception bit is set 13487# the accrued bit is NOT set in this instance(no inexactness!) 13488# 13489fabs_denorm: 13490 andi.b &0xc0,%d0 # is precision extended? 13491 bne.b fabs_not_ext # no 13492 13493 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 13494 13495 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 13496 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 13497 mov.w SRC_EX(%a0),%d0 13498 bclr &15,%d0 # clear sign 13499 mov.w %d0,FP_SCR0_EX(%a6) # insert exponent 13500 13501 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 13502 13503 btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled? 13504 bne.b fabs_ext_unfl_ena 13505 rts 13506 13507# 13508# the input is an extended DENORM and underflow is enabled in the FPCR. 13509# normalize the mantissa and add the bias of 0x6000 to the resulting negative 13510# exponent and insert back into the operand. 13511# 13512fabs_ext_unfl_ena: 13513 lea FP_SCR0(%a6),%a0 # pass: ptr to operand 13514 bsr.l norm # normalize result 13515 neg.w %d0 # new exponent = -(shft val) 13516 addi.w &0x6000,%d0 # add new bias to exponent 13517 mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp 13518 andi.w &0x8000,%d1 # keep old sign 13519 andi.w &0x7fff,%d0 # clear sign position 13520 or.w %d1,%d0 # concat old sign, new exponent 13521 mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent 13522 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 13523 rts 13524 13525# 13526# operand is either single or double 13527# 13528fabs_not_ext: 13529 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 13530 bne.b fabs_dbl 13531 13532# 13533# operand is to be rounded to single precision 13534# 13535fabs_sgl: 13536 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 13537 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 13538 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 13539 bsr.l scale_to_zero_src # calculate scale factor 13540 13541 cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow? 13542 bge.w fabs_sd_unfl # yes; go handle underflow 13543 cmpi.l %d0,&0x3fff-0x407e # will move in overflow? 13544 beq.w fabs_sd_may_ovfl # maybe; go check 13545 blt.w fabs_sd_ovfl # yes; go handle overflow 13546 13547# 13548# operand will NOT overflow or underflow when moved in to the fp reg file 13549# 13550fabs_sd_normal: 13551 fmov.l &0x0,%fpsr # clear FPSR 13552 fmov.l L_SCR3(%a6),%fpcr # set FPCR 13553 13554 fabs.x FP_SCR0(%a6),%fp0 # perform absolute 13555 13556 fmov.l %fpsr,%d1 # save FPSR 13557 fmov.l &0x0,%fpcr # clear FPCR 13558 13559 or.l %d1,USER_FPSR(%a6) # save INEX2,N 13560 13561fabs_sd_normal_exit: 13562 mov.l %d2,-(%sp) # save d2 13563 fmovm.x &0x80,FP_SCR0(%a6) # store out result 13564 mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp 13565 mov.l %d1,%d2 # make a copy 13566 andi.l &0x7fff,%d1 # strip sign 13567 sub.l %d0,%d1 # add scale factor 13568 andi.w &0x8000,%d2 # keep old sign 13569 or.w %d1,%d2 # concat old sign,new exp 13570 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 13571 mov.l (%sp)+,%d2 # restore d2 13572 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 13573 rts 13574 13575# 13576# operand is to be rounded to double precision 13577# 13578fabs_dbl: 13579 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 13580 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 13581 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 13582 bsr.l scale_to_zero_src # calculate scale factor 13583 13584 cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow? 13585 bge.b fabs_sd_unfl # yes; go handle underflow 13586 cmpi.l %d0,&0x3fff-0x43fe # will move in overflow? 13587 beq.w fabs_sd_may_ovfl # maybe; go check 13588 blt.w fabs_sd_ovfl # yes; go handle overflow 13589 bra.w fabs_sd_normal # no; ho handle normalized op 13590 13591# 13592# operand WILL underflow when moved in to the fp register file 13593# 13594fabs_sd_unfl: 13595 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 13596 13597 bclr &0x7,FP_SCR0_EX(%a6) # force absolute value 13598 13599# if underflow or inexact is enabled, go calculate EXOP first. 13600 mov.b FPCR_ENABLE(%a6),%d1 13601 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 13602 bne.b fabs_sd_unfl_ena # yes 13603 13604fabs_sd_unfl_dis: 13605 lea FP_SCR0(%a6),%a0 # pass: result addr 13606 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 13607 bsr.l unf_res # calculate default result 13608 or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode 13609 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 13610 rts 13611 13612# 13613# operand will underflow AND underflow is enabled. 13614# Therefore, we must return the result rounded to extended precision. 13615# 13616fabs_sd_unfl_ena: 13617 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 13618 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 13619 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 13620 13621 mov.l %d2,-(%sp) # save d2 13622 mov.l %d1,%d2 # make a copy 13623 andi.l &0x7fff,%d1 # strip sign 13624 andi.w &0x8000,%d2 # keep old sign 13625 sub.l %d0,%d1 # subtract scale factor 13626 addi.l &0x6000,%d1 # add new bias 13627 andi.w &0x7fff,%d1 13628 or.w %d2,%d1 # concat new sign,new exp 13629 mov.w %d1,FP_SCR1_EX(%a6) # insert new exp 13630 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 13631 mov.l (%sp)+,%d2 # restore d2 13632 bra.b fabs_sd_unfl_dis 13633 13634# 13635# operand WILL overflow. 13636# 13637fabs_sd_ovfl: 13638 fmov.l &0x0,%fpsr # clear FPSR 13639 fmov.l L_SCR3(%a6),%fpcr # set FPCR 13640 13641 fabs.x FP_SCR0(%a6),%fp0 # perform absolute 13642 13643 fmov.l &0x0,%fpcr # clear FPCR 13644 fmov.l %fpsr,%d1 # save FPSR 13645 13646 or.l %d1,USER_FPSR(%a6) # save INEX2,N 13647 13648fabs_sd_ovfl_tst: 13649 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 13650 13651 mov.b FPCR_ENABLE(%a6),%d1 13652 andi.b &0x13,%d1 # is OVFL or INEX enabled? 13653 bne.b fabs_sd_ovfl_ena # yes 13654 13655# 13656# OVFL is not enabled; therefore, we must create the default result by 13657# calling ovf_res(). 13658# 13659fabs_sd_ovfl_dis: 13660 btst &neg_bit,FPSR_CC(%a6) # is result negative? 13661 sne %d1 # set sign param accordingly 13662 mov.l L_SCR3(%a6),%d0 # pass: prec,mode 13663 bsr.l ovf_res # calculate default result 13664 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 13665 fmovm.x (%a0),&0x80 # return default result in fp0 13666 rts 13667 13668# 13669# OVFL is enabled. 13670# the INEX2 bit has already been updated by the round to the correct precision. 13671# now, round to extended(and don't alter the FPSR). 13672# 13673fabs_sd_ovfl_ena: 13674 mov.l %d2,-(%sp) # save d2 13675 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 13676 mov.l %d1,%d2 # make a copy 13677 andi.l &0x7fff,%d1 # strip sign 13678 andi.w &0x8000,%d2 # keep old sign 13679 sub.l %d0,%d1 # add scale factor 13680 subi.l &0x6000,%d1 # subtract bias 13681 andi.w &0x7fff,%d1 13682 or.w %d2,%d1 # concat sign,exp 13683 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 13684 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 13685 mov.l (%sp)+,%d2 # restore d2 13686 bra.b fabs_sd_ovfl_dis 13687 13688# 13689# the move in MAY underflow. so... 13690# 13691fabs_sd_may_ovfl: 13692 fmov.l &0x0,%fpsr # clear FPSR 13693 fmov.l L_SCR3(%a6),%fpcr # set FPCR 13694 13695 fabs.x FP_SCR0(%a6),%fp0 # perform absolute 13696 13697 fmov.l %fpsr,%d1 # save status 13698 fmov.l &0x0,%fpcr # clear FPCR 13699 13700 or.l %d1,USER_FPSR(%a6) # save INEX2,N 13701 13702 fabs.x %fp0,%fp1 # make a copy of result 13703 fcmp.b %fp1,&0x2 # is |result| >= 2.b? 13704 fbge.w fabs_sd_ovfl_tst # yes; overflow has occurred 13705 13706# no, it didn't overflow; we have correct result 13707 bra.w fabs_sd_normal_exit 13708 13709########################################################################## 13710 13711# 13712# input is not normalized; what is it? 13713# 13714fabs_not_norm: 13715 cmpi.b %d1,&DENORM # weed out DENORM 13716 beq.w fabs_denorm 13717 cmpi.b %d1,&SNAN # weed out SNAN 13718 beq.l res_snan_1op 13719 cmpi.b %d1,&QNAN # weed out QNAN 13720 beq.l res_qnan_1op 13721 13722 fabs.x SRC(%a0),%fp0 # force absolute value 13723 13724 cmpi.b %d1,&INF # weed out INF 13725 beq.b fabs_inf 13726fabs_zero: 13727 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 13728 rts 13729fabs_inf: 13730 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 13731 rts 13732 13733######################################################################### 13734# XDEF **************************************************************** # 13735# fcmp(): fp compare op routine # 13736# # 13737# XREF **************************************************************** # 13738# res_qnan() - return QNAN result # 13739# res_snan() - return SNAN result # 13740# # 13741# INPUT *************************************************************** # 13742# a0 = pointer to extended precision source operand # 13743# a1 = pointer to extended precision destination operand # 13744# d0 = round prec/mode # 13745# # 13746# OUTPUT ************************************************************** # 13747# None # 13748# # 13749# ALGORITHM *********************************************************** # 13750# Handle NANs and denorms as special cases. For everything else, # 13751# just use the actual fcmp instruction to produce the correct condition # 13752# codes. # 13753# # 13754######################################################################### 13755 13756 global fcmp 13757fcmp: 13758 clr.w %d1 13759 mov.b DTAG(%a6),%d1 13760 lsl.b &0x3,%d1 13761 or.b STAG(%a6),%d1 13762 bne.b fcmp_not_norm # optimize on non-norm input 13763 13764# 13765# COMPARE FP OPs : NORMs, ZEROs, INFs, and "corrected" DENORMs 13766# 13767fcmp_norm: 13768 fmovm.x DST(%a1),&0x80 # load dst op 13769 13770 fcmp.x %fp0,SRC(%a0) # do compare 13771 13772 fmov.l %fpsr,%d0 # save FPSR 13773 rol.l &0x8,%d0 # extract ccode bits 13774 mov.b %d0,FPSR_CC(%a6) # set ccode bits(no exc bits are set) 13775 13776 rts 13777 13778# 13779# fcmp: inputs are not both normalized; what are they? 13780# 13781fcmp_not_norm: 13782 mov.w (tbl_fcmp_op.b,%pc,%d1.w*2),%d1 13783 jmp (tbl_fcmp_op.b,%pc,%d1.w*1) 13784 13785 swbeg &48 13786tbl_fcmp_op: 13787 short fcmp_norm - tbl_fcmp_op # NORM - NORM 13788 short fcmp_norm - tbl_fcmp_op # NORM - ZERO 13789 short fcmp_norm - tbl_fcmp_op # NORM - INF 13790 short fcmp_res_qnan - tbl_fcmp_op # NORM - QNAN 13791 short fcmp_nrm_dnrm - tbl_fcmp_op # NORM - DENORM 13792 short fcmp_res_snan - tbl_fcmp_op # NORM - SNAN 13793 short tbl_fcmp_op - tbl_fcmp_op # 13794 short tbl_fcmp_op - tbl_fcmp_op # 13795 13796 short fcmp_norm - tbl_fcmp_op # ZERO - NORM 13797 short fcmp_norm - tbl_fcmp_op # ZERO - ZERO 13798 short fcmp_norm - tbl_fcmp_op # ZERO - INF 13799 short fcmp_res_qnan - tbl_fcmp_op # ZERO - QNAN 13800 short fcmp_dnrm_s - tbl_fcmp_op # ZERO - DENORM 13801 short fcmp_res_snan - tbl_fcmp_op # ZERO - SNAN 13802 short tbl_fcmp_op - tbl_fcmp_op # 13803 short tbl_fcmp_op - tbl_fcmp_op # 13804 13805 short fcmp_norm - tbl_fcmp_op # INF - NORM 13806 short fcmp_norm - tbl_fcmp_op # INF - ZERO 13807 short fcmp_norm - tbl_fcmp_op # INF - INF 13808 short fcmp_res_qnan - tbl_fcmp_op # INF - QNAN 13809 short fcmp_dnrm_s - tbl_fcmp_op # INF - DENORM 13810 short fcmp_res_snan - tbl_fcmp_op # INF - SNAN 13811 short tbl_fcmp_op - tbl_fcmp_op # 13812 short tbl_fcmp_op - tbl_fcmp_op # 13813 13814 short fcmp_res_qnan - tbl_fcmp_op # QNAN - NORM 13815 short fcmp_res_qnan - tbl_fcmp_op # QNAN - ZERO 13816 short fcmp_res_qnan - tbl_fcmp_op # QNAN - INF 13817 short fcmp_res_qnan - tbl_fcmp_op # QNAN - QNAN 13818 short fcmp_res_qnan - tbl_fcmp_op # QNAN - DENORM 13819 short fcmp_res_snan - tbl_fcmp_op # QNAN - SNAN 13820 short tbl_fcmp_op - tbl_fcmp_op # 13821 short tbl_fcmp_op - tbl_fcmp_op # 13822 13823 short fcmp_dnrm_nrm - tbl_fcmp_op # DENORM - NORM 13824 short fcmp_dnrm_d - tbl_fcmp_op # DENORM - ZERO 13825 short fcmp_dnrm_d - tbl_fcmp_op # DENORM - INF 13826 short fcmp_res_qnan - tbl_fcmp_op # DENORM - QNAN 13827 short fcmp_dnrm_sd - tbl_fcmp_op # DENORM - DENORM 13828 short fcmp_res_snan - tbl_fcmp_op # DENORM - SNAN 13829 short tbl_fcmp_op - tbl_fcmp_op # 13830 short tbl_fcmp_op - tbl_fcmp_op # 13831 13832 short fcmp_res_snan - tbl_fcmp_op # SNAN - NORM 13833 short fcmp_res_snan - tbl_fcmp_op # SNAN - ZERO 13834 short fcmp_res_snan - tbl_fcmp_op # SNAN - INF 13835 short fcmp_res_snan - tbl_fcmp_op # SNAN - QNAN 13836 short fcmp_res_snan - tbl_fcmp_op # SNAN - DENORM 13837 short fcmp_res_snan - tbl_fcmp_op # SNAN - SNAN 13838 short tbl_fcmp_op - tbl_fcmp_op # 13839 short tbl_fcmp_op - tbl_fcmp_op # 13840 13841# unlike all other functions for QNAN and SNAN, fcmp does NOT set the 13842# 'N' bit for a negative QNAN or SNAN input so we must squelch it here. 13843fcmp_res_qnan: 13844 bsr.l res_qnan 13845 andi.b &0xf7,FPSR_CC(%a6) 13846 rts 13847fcmp_res_snan: 13848 bsr.l res_snan 13849 andi.b &0xf7,FPSR_CC(%a6) 13850 rts 13851 13852# 13853# DENORMs are a little more difficult. 13854# If you have a 2 DENORMs, then you can just force the j-bit to a one 13855# and use the fcmp_norm routine. 13856# If you have a DENORM and an INF or ZERO, just force the DENORM's j-bit to a one 13857# and use the fcmp_norm routine. 13858# If you have a DENORM and a NORM with opposite signs, then use fcmp_norm, also. 13859# But with a DENORM and a NORM of the same sign, the neg bit is set if the 13860# (1) signs are (+) and the DENORM is the dst or 13861# (2) signs are (-) and the DENORM is the src 13862# 13863 13864fcmp_dnrm_s: 13865 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 13866 mov.l SRC_HI(%a0),%d0 13867 bset &31,%d0 # DENORM src; make into small norm 13868 mov.l %d0,FP_SCR0_HI(%a6) 13869 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 13870 lea FP_SCR0(%a6),%a0 13871 bra.w fcmp_norm 13872 13873fcmp_dnrm_d: 13874 mov.l DST_EX(%a1),FP_SCR0_EX(%a6) 13875 mov.l DST_HI(%a1),%d0 13876 bset &31,%d0 # DENORM src; make into small norm 13877 mov.l %d0,FP_SCR0_HI(%a6) 13878 mov.l DST_LO(%a1),FP_SCR0_LO(%a6) 13879 lea FP_SCR0(%a6),%a1 13880 bra.w fcmp_norm 13881 13882fcmp_dnrm_sd: 13883 mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 13884 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 13885 mov.l DST_HI(%a1),%d0 13886 bset &31,%d0 # DENORM dst; make into small norm 13887 mov.l %d0,FP_SCR1_HI(%a6) 13888 mov.l SRC_HI(%a0),%d0 13889 bset &31,%d0 # DENORM dst; make into small norm 13890 mov.l %d0,FP_SCR0_HI(%a6) 13891 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 13892 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 13893 lea FP_SCR1(%a6),%a1 13894 lea FP_SCR0(%a6),%a0 13895 bra.w fcmp_norm 13896 13897fcmp_nrm_dnrm: 13898 mov.b SRC_EX(%a0),%d0 # determine if like signs 13899 mov.b DST_EX(%a1),%d1 13900 eor.b %d0,%d1 13901 bmi.w fcmp_dnrm_s 13902 13903# signs are the same, so must determine the answer ourselves. 13904 tst.b %d0 # is src op negative? 13905 bmi.b fcmp_nrm_dnrm_m # yes 13906 rts 13907fcmp_nrm_dnrm_m: 13908 mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 13909 rts 13910 13911fcmp_dnrm_nrm: 13912 mov.b SRC_EX(%a0),%d0 # determine if like signs 13913 mov.b DST_EX(%a1),%d1 13914 eor.b %d0,%d1 13915 bmi.w fcmp_dnrm_d 13916 13917# signs are the same, so must determine the answer ourselves. 13918 tst.b %d0 # is src op negative? 13919 bpl.b fcmp_dnrm_nrm_m # no 13920 rts 13921fcmp_dnrm_nrm_m: 13922 mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 13923 rts 13924 13925######################################################################### 13926# XDEF **************************************************************** # 13927# fsglmul(): emulates the fsglmul instruction # 13928# # 13929# XREF **************************************************************** # 13930# scale_to_zero_src() - scale src exponent to zero # 13931# scale_to_zero_dst() - scale dst exponent to zero # 13932# unf_res4() - return default underflow result for sglop # 13933# ovf_res() - return default overflow result # 13934# res_qnan() - return QNAN result # 13935# res_snan() - return SNAN result # 13936# # 13937# INPUT *************************************************************** # 13938# a0 = pointer to extended precision source operand # 13939# a1 = pointer to extended precision destination operand # 13940# d0 rnd prec,mode # 13941# # 13942# OUTPUT ************************************************************** # 13943# fp0 = result # 13944# fp1 = EXOP (if exception occurred) # 13945# # 13946# ALGORITHM *********************************************************** # 13947# Handle NANs, infinities, and zeroes as special cases. Divide # 13948# norms/denorms into ext/sgl/dbl precision. # 13949# For norms/denorms, scale the exponents such that a multiply # 13950# instruction won't cause an exception. Use the regular fsglmul to # 13951# compute a result. Check if the regular operands would have taken # 13952# an exception. If so, return the default overflow/underflow result # 13953# and return the EXOP if exceptions are enabled. Else, scale the # 13954# result operand to the proper exponent. # 13955# # 13956######################################################################### 13957 13958 global fsglmul 13959fsglmul: 13960 mov.l %d0,L_SCR3(%a6) # store rnd info 13961 13962 clr.w %d1 13963 mov.b DTAG(%a6),%d1 13964 lsl.b &0x3,%d1 13965 or.b STAG(%a6),%d1 13966 13967 bne.w fsglmul_not_norm # optimize on non-norm input 13968 13969fsglmul_norm: 13970 mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 13971 mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 13972 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 13973 13974 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 13975 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 13976 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 13977 13978 bsr.l scale_to_zero_src # scale exponent 13979 mov.l %d0,-(%sp) # save scale factor 1 13980 13981 bsr.l scale_to_zero_dst # scale dst exponent 13982 13983 add.l (%sp)+,%d0 # SCALE_FACTOR = scale1 + scale2 13984 13985 cmpi.l %d0,&0x3fff-0x7ffe # would result ovfl? 13986 beq.w fsglmul_may_ovfl # result may rnd to overflow 13987 blt.w fsglmul_ovfl # result will overflow 13988 13989 cmpi.l %d0,&0x3fff+0x0001 # would result unfl? 13990 beq.w fsglmul_may_unfl # result may rnd to no unfl 13991 bgt.w fsglmul_unfl # result will underflow 13992 13993fsglmul_normal: 13994 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 13995 13996 fmov.l L_SCR3(%a6),%fpcr # set FPCR 13997 fmov.l &0x0,%fpsr # clear FPSR 13998 13999 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 14000 14001 fmov.l %fpsr,%d1 # save status 14002 fmov.l &0x0,%fpcr # clear FPCR 14003 14004 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14005 14006fsglmul_normal_exit: 14007 fmovm.x &0x80,FP_SCR0(%a6) # store out result 14008 mov.l %d2,-(%sp) # save d2 14009 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 14010 mov.l %d1,%d2 # make a copy 14011 andi.l &0x7fff,%d1 # strip sign 14012 andi.w &0x8000,%d2 # keep old sign 14013 sub.l %d0,%d1 # add scale factor 14014 or.w %d2,%d1 # concat old sign,new exp 14015 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 14016 mov.l (%sp)+,%d2 # restore d2 14017 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 14018 rts 14019 14020fsglmul_ovfl: 14021 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14022 14023 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14024 fmov.l &0x0,%fpsr # clear FPSR 14025 14026 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 14027 14028 fmov.l %fpsr,%d1 # save status 14029 fmov.l &0x0,%fpcr # clear FPCR 14030 14031 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14032 14033fsglmul_ovfl_tst: 14034 14035# save setting this until now because this is where fsglmul_may_ovfl may jump in 14036 or.l &ovfl_inx_mask, USER_FPSR(%a6) # set ovfl/aovfl/ainex 14037 14038 mov.b FPCR_ENABLE(%a6),%d1 14039 andi.b &0x13,%d1 # is OVFL or INEX enabled? 14040 bne.b fsglmul_ovfl_ena # yes 14041 14042fsglmul_ovfl_dis: 14043 btst &neg_bit,FPSR_CC(%a6) # is result negative? 14044 sne %d1 # set sign param accordingly 14045 mov.l L_SCR3(%a6),%d0 # pass prec:rnd 14046 andi.b &0x30,%d0 # force prec = ext 14047 bsr.l ovf_res # calculate default result 14048 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 14049 fmovm.x (%a0),&0x80 # return default result in fp0 14050 rts 14051 14052fsglmul_ovfl_ena: 14053 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 14054 14055 mov.l %d2,-(%sp) # save d2 14056 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 14057 mov.l %d1,%d2 # make a copy 14058 andi.l &0x7fff,%d1 # strip sign 14059 sub.l %d0,%d1 # add scale factor 14060 subi.l &0x6000,%d1 # subtract bias 14061 andi.w &0x7fff,%d1 14062 andi.w &0x8000,%d2 # keep old sign 14063 or.w %d2,%d1 # concat old sign,new exp 14064 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 14065 mov.l (%sp)+,%d2 # restore d2 14066 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 14067 bra.b fsglmul_ovfl_dis 14068 14069fsglmul_may_ovfl: 14070 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14071 14072 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14073 fmov.l &0x0,%fpsr # clear FPSR 14074 14075 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 14076 14077 fmov.l %fpsr,%d1 # save status 14078 fmov.l &0x0,%fpcr # clear FPCR 14079 14080 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14081 14082 fabs.x %fp0,%fp1 # make a copy of result 14083 fcmp.b %fp1,&0x2 # is |result| >= 2.b? 14084 fbge.w fsglmul_ovfl_tst # yes; overflow has occurred 14085 14086# no, it didn't overflow; we have correct result 14087 bra.w fsglmul_normal_exit 14088 14089fsglmul_unfl: 14090 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 14091 14092 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14093 14094 fmov.l &rz_mode*0x10,%fpcr # set FPCR 14095 fmov.l &0x0,%fpsr # clear FPSR 14096 14097 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 14098 14099 fmov.l %fpsr,%d1 # save status 14100 fmov.l &0x0,%fpcr # clear FPCR 14101 14102 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14103 14104 mov.b FPCR_ENABLE(%a6),%d1 14105 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 14106 bne.b fsglmul_unfl_ena # yes 14107 14108fsglmul_unfl_dis: 14109 fmovm.x &0x80,FP_SCR0(%a6) # store out result 14110 14111 lea FP_SCR0(%a6),%a0 # pass: result addr 14112 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 14113 bsr.l unf_res4 # calculate default result 14114 or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set 14115 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 14116 rts 14117 14118# 14119# UNFL is enabled. 14120# 14121fsglmul_unfl_ena: 14122 fmovm.x FP_SCR1(%a6),&0x40 # load dst op 14123 14124 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14125 fmov.l &0x0,%fpsr # clear FPSR 14126 14127 fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply 14128 14129 fmov.l &0x0,%fpcr # clear FPCR 14130 14131 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 14132 mov.l %d2,-(%sp) # save d2 14133 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 14134 mov.l %d1,%d2 # make a copy 14135 andi.l &0x7fff,%d1 # strip sign 14136 andi.w &0x8000,%d2 # keep old sign 14137 sub.l %d0,%d1 # add scale factor 14138 addi.l &0x6000,%d1 # add bias 14139 andi.w &0x7fff,%d1 14140 or.w %d2,%d1 # concat old sign,new exp 14141 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 14142 mov.l (%sp)+,%d2 # restore d2 14143 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 14144 bra.w fsglmul_unfl_dis 14145 14146fsglmul_may_unfl: 14147 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14148 14149 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14150 fmov.l &0x0,%fpsr # clear FPSR 14151 14152 fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 14153 14154 fmov.l %fpsr,%d1 # save status 14155 fmov.l &0x0,%fpcr # clear FPCR 14156 14157 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14158 14159 fabs.x %fp0,%fp1 # make a copy of result 14160 fcmp.b %fp1,&0x2 # is |result| > 2.b? 14161 fbgt.w fsglmul_normal_exit # no; no underflow occurred 14162 fblt.w fsglmul_unfl # yes; underflow occurred 14163 14164# 14165# we still don't know if underflow occurred. result is ~ equal to 2. but, 14166# we don't know if the result was an underflow that rounded up to a 2 or 14167# a normalized number that rounded down to a 2. so, redo the entire operation 14168# using RZ as the rounding mode to see what the pre-rounded result is. 14169# this case should be relatively rare. 14170# 14171 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 14172 14173 mov.l L_SCR3(%a6),%d1 14174 andi.b &0xc0,%d1 # keep rnd prec 14175 ori.b &rz_mode*0x10,%d1 # insert RZ 14176 14177 fmov.l %d1,%fpcr # set FPCR 14178 fmov.l &0x0,%fpsr # clear FPSR 14179 14180 fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply 14181 14182 fmov.l &0x0,%fpcr # clear FPCR 14183 fabs.x %fp1 # make absolute value 14184 fcmp.b %fp1,&0x2 # is |result| < 2.b? 14185 fbge.w fsglmul_normal_exit # no; no underflow occurred 14186 bra.w fsglmul_unfl # yes, underflow occurred 14187 14188############################################################################## 14189 14190# 14191# Single Precision Multiply: inputs are not both normalized; what are they? 14192# 14193fsglmul_not_norm: 14194 mov.w (tbl_fsglmul_op.b,%pc,%d1.w*2),%d1 14195 jmp (tbl_fsglmul_op.b,%pc,%d1.w*1) 14196 14197 swbeg &48 14198tbl_fsglmul_op: 14199 short fsglmul_norm - tbl_fsglmul_op # NORM x NORM 14200 short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO 14201 short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF 14202 short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN 14203 short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM 14204 short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN 14205 short tbl_fsglmul_op - tbl_fsglmul_op # 14206 short tbl_fsglmul_op - tbl_fsglmul_op # 14207 14208 short fsglmul_zero - tbl_fsglmul_op # ZERO x NORM 14209 short fsglmul_zero - tbl_fsglmul_op # ZERO x ZERO 14210 short fsglmul_res_operr - tbl_fsglmul_op # ZERO x INF 14211 short fsglmul_res_qnan - tbl_fsglmul_op # ZERO x QNAN 14212 short fsglmul_zero - tbl_fsglmul_op # ZERO x DENORM 14213 short fsglmul_res_snan - tbl_fsglmul_op # ZERO x SNAN 14214 short tbl_fsglmul_op - tbl_fsglmul_op # 14215 short tbl_fsglmul_op - tbl_fsglmul_op # 14216 14217 short fsglmul_inf_dst - tbl_fsglmul_op # INF x NORM 14218 short fsglmul_res_operr - tbl_fsglmul_op # INF x ZERO 14219 short fsglmul_inf_dst - tbl_fsglmul_op # INF x INF 14220 short fsglmul_res_qnan - tbl_fsglmul_op # INF x QNAN 14221 short fsglmul_inf_dst - tbl_fsglmul_op # INF x DENORM 14222 short fsglmul_res_snan - tbl_fsglmul_op # INF x SNAN 14223 short tbl_fsglmul_op - tbl_fsglmul_op # 14224 short tbl_fsglmul_op - tbl_fsglmul_op # 14225 14226 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x NORM 14227 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x ZERO 14228 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x INF 14229 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x QNAN 14230 short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x DENORM 14231 short fsglmul_res_snan - tbl_fsglmul_op # QNAN x SNAN 14232 short tbl_fsglmul_op - tbl_fsglmul_op # 14233 short tbl_fsglmul_op - tbl_fsglmul_op # 14234 14235 short fsglmul_norm - tbl_fsglmul_op # NORM x NORM 14236 short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO 14237 short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF 14238 short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN 14239 short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM 14240 short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN 14241 short tbl_fsglmul_op - tbl_fsglmul_op # 14242 short tbl_fsglmul_op - tbl_fsglmul_op # 14243 14244 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x NORM 14245 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x ZERO 14246 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x INF 14247 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x QNAN 14248 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x DENORM 14249 short fsglmul_res_snan - tbl_fsglmul_op # SNAN x SNAN 14250 short tbl_fsglmul_op - tbl_fsglmul_op # 14251 short tbl_fsglmul_op - tbl_fsglmul_op # 14252 14253fsglmul_res_operr: 14254 bra.l res_operr 14255fsglmul_res_snan: 14256 bra.l res_snan 14257fsglmul_res_qnan: 14258 bra.l res_qnan 14259fsglmul_zero: 14260 bra.l fmul_zero 14261fsglmul_inf_src: 14262 bra.l fmul_inf_src 14263fsglmul_inf_dst: 14264 bra.l fmul_inf_dst 14265 14266######################################################################### 14267# XDEF **************************************************************** # 14268# fsgldiv(): emulates the fsgldiv instruction # 14269# # 14270# XREF **************************************************************** # 14271# scale_to_zero_src() - scale src exponent to zero # 14272# scale_to_zero_dst() - scale dst exponent to zero # 14273# unf_res4() - return default underflow result for sglop # 14274# ovf_res() - return default overflow result # 14275# res_qnan() - return QNAN result # 14276# res_snan() - return SNAN result # 14277# # 14278# INPUT *************************************************************** # 14279# a0 = pointer to extended precision source operand # 14280# a1 = pointer to extended precision destination operand # 14281# d0 rnd prec,mode # 14282# # 14283# OUTPUT ************************************************************** # 14284# fp0 = result # 14285# fp1 = EXOP (if exception occurred) # 14286# # 14287# ALGORITHM *********************************************************** # 14288# Handle NANs, infinities, and zeroes as special cases. Divide # 14289# norms/denorms into ext/sgl/dbl precision. # 14290# For norms/denorms, scale the exponents such that a divide # 14291# instruction won't cause an exception. Use the regular fsgldiv to # 14292# compute a result. Check if the regular operands would have taken # 14293# an exception. If so, return the default overflow/underflow result # 14294# and return the EXOP if exceptions are enabled. Else, scale the # 14295# result operand to the proper exponent. # 14296# # 14297######################################################################### 14298 14299 global fsgldiv 14300fsgldiv: 14301 mov.l %d0,L_SCR3(%a6) # store rnd info 14302 14303 clr.w %d1 14304 mov.b DTAG(%a6),%d1 14305 lsl.b &0x3,%d1 14306 or.b STAG(%a6),%d1 # combine src tags 14307 14308 bne.w fsgldiv_not_norm # optimize on non-norm input 14309 14310# 14311# DIVIDE: NORMs and DENORMs ONLY! 14312# 14313fsgldiv_norm: 14314 mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 14315 mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 14316 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 14317 14318 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 14319 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 14320 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 14321 14322 bsr.l scale_to_zero_src # calculate scale factor 1 14323 mov.l %d0,-(%sp) # save scale factor 1 14324 14325 bsr.l scale_to_zero_dst # calculate scale factor 2 14326 14327 neg.l (%sp) # S.F. = scale1 - scale2 14328 add.l %d0,(%sp) 14329 14330 mov.w 2+L_SCR3(%a6),%d1 # fetch precision,mode 14331 lsr.b &0x6,%d1 14332 mov.l (%sp)+,%d0 14333 cmpi.l %d0,&0x3fff-0x7ffe 14334 ble.w fsgldiv_may_ovfl 14335 14336 cmpi.l %d0,&0x3fff-0x0000 # will result underflow? 14337 beq.w fsgldiv_may_unfl # maybe 14338 bgt.w fsgldiv_unfl # yes; go handle underflow 14339 14340fsgldiv_normal: 14341 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14342 14343 fmov.l L_SCR3(%a6),%fpcr # save FPCR 14344 fmov.l &0x0,%fpsr # clear FPSR 14345 14346 fsgldiv.x FP_SCR0(%a6),%fp0 # perform sgl divide 14347 14348 fmov.l %fpsr,%d1 # save FPSR 14349 fmov.l &0x0,%fpcr # clear FPCR 14350 14351 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14352 14353fsgldiv_normal_exit: 14354 fmovm.x &0x80,FP_SCR0(%a6) # store result on stack 14355 mov.l %d2,-(%sp) # save d2 14356 mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 14357 mov.l %d1,%d2 # make a copy 14358 andi.l &0x7fff,%d1 # strip sign 14359 andi.w &0x8000,%d2 # keep old sign 14360 sub.l %d0,%d1 # add scale factor 14361 or.w %d2,%d1 # concat old sign,new exp 14362 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 14363 mov.l (%sp)+,%d2 # restore d2 14364 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 14365 rts 14366 14367fsgldiv_may_ovfl: 14368 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14369 14370 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14371 fmov.l &0x0,%fpsr # set FPSR 14372 14373 fsgldiv.x FP_SCR0(%a6),%fp0 # execute divide 14374 14375 fmov.l %fpsr,%d1 14376 fmov.l &0x0,%fpcr 14377 14378 or.l %d1,USER_FPSR(%a6) # save INEX,N 14379 14380 fmovm.x &0x01,-(%sp) # save result to stack 14381 mov.w (%sp),%d1 # fetch new exponent 14382 add.l &0xc,%sp # clear result 14383 andi.l &0x7fff,%d1 # strip sign 14384 sub.l %d0,%d1 # add scale factor 14385 cmp.l %d1,&0x7fff # did divide overflow? 14386 blt.b fsgldiv_normal_exit 14387 14388fsgldiv_ovfl_tst: 14389 or.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex 14390 14391 mov.b FPCR_ENABLE(%a6),%d1 14392 andi.b &0x13,%d1 # is OVFL or INEX enabled? 14393 bne.b fsgldiv_ovfl_ena # yes 14394 14395fsgldiv_ovfl_dis: 14396 btst &neg_bit,FPSR_CC(%a6) # is result negative 14397 sne %d1 # set sign param accordingly 14398 mov.l L_SCR3(%a6),%d0 # pass prec:rnd 14399 andi.b &0x30,%d0 # kill precision 14400 bsr.l ovf_res # calculate default result 14401 or.b %d0,FPSR_CC(%a6) # set INF if applicable 14402 fmovm.x (%a0),&0x80 # return default result in fp0 14403 rts 14404 14405fsgldiv_ovfl_ena: 14406 fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 14407 14408 mov.l %d2,-(%sp) # save d2 14409 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 14410 mov.l %d1,%d2 # make a copy 14411 andi.l &0x7fff,%d1 # strip sign 14412 andi.w &0x8000,%d2 # keep old sign 14413 sub.l %d0,%d1 # add scale factor 14414 subi.l &0x6000,%d1 # subtract new bias 14415 andi.w &0x7fff,%d1 # clear ms bit 14416 or.w %d2,%d1 # concat old sign,new exp 14417 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 14418 mov.l (%sp)+,%d2 # restore d2 14419 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 14420 bra.b fsgldiv_ovfl_dis 14421 14422fsgldiv_unfl: 14423 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 14424 14425 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14426 14427 fmov.l &rz_mode*0x10,%fpcr # set FPCR 14428 fmov.l &0x0,%fpsr # clear FPSR 14429 14430 fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide 14431 14432 fmov.l %fpsr,%d1 # save status 14433 fmov.l &0x0,%fpcr # clear FPCR 14434 14435 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14436 14437 mov.b FPCR_ENABLE(%a6),%d1 14438 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 14439 bne.b fsgldiv_unfl_ena # yes 14440 14441fsgldiv_unfl_dis: 14442 fmovm.x &0x80,FP_SCR0(%a6) # store out result 14443 14444 lea FP_SCR0(%a6),%a0 # pass: result addr 14445 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 14446 bsr.l unf_res4 # calculate default result 14447 or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set 14448 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 14449 rts 14450 14451# 14452# UNFL is enabled. 14453# 14454fsgldiv_unfl_ena: 14455 fmovm.x FP_SCR1(%a6),&0x40 # load dst op 14456 14457 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14458 fmov.l &0x0,%fpsr # clear FPSR 14459 14460 fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide 14461 14462 fmov.l &0x0,%fpcr # clear FPCR 14463 14464 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 14465 mov.l %d2,-(%sp) # save d2 14466 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 14467 mov.l %d1,%d2 # make a copy 14468 andi.l &0x7fff,%d1 # strip sign 14469 andi.w &0x8000,%d2 # keep old sign 14470 sub.l %d0,%d1 # add scale factor 14471 addi.l &0x6000,%d1 # add bias 14472 andi.w &0x7fff,%d1 # clear top bit 14473 or.w %d2,%d1 # concat old sign, new exp 14474 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 14475 mov.l (%sp)+,%d2 # restore d2 14476 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 14477 bra.b fsgldiv_unfl_dis 14478 14479# 14480# the divide operation MAY underflow: 14481# 14482fsgldiv_may_unfl: 14483 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14484 14485 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14486 fmov.l &0x0,%fpsr # clear FPSR 14487 14488 fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide 14489 14490 fmov.l %fpsr,%d1 # save status 14491 fmov.l &0x0,%fpcr # clear FPCR 14492 14493 or.l %d1,USER_FPSR(%a6) # save INEX2,N 14494 14495 fabs.x %fp0,%fp1 # make a copy of result 14496 fcmp.b %fp1,&0x1 # is |result| > 1.b? 14497 fbgt.w fsgldiv_normal_exit # no; no underflow occurred 14498 fblt.w fsgldiv_unfl # yes; underflow occurred 14499 14500# 14501# we still don't know if underflow occurred. result is ~ equal to 1. but, 14502# we don't know if the result was an underflow that rounded up to a 1 14503# or a normalized number that rounded down to a 1. so, redo the entire 14504# operation using RZ as the rounding mode to see what the pre-rounded 14505# result is. this case should be relatively rare. 14506# 14507 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into %fp1 14508 14509 clr.l %d1 # clear scratch register 14510 ori.b &rz_mode*0x10,%d1 # force RZ rnd mode 14511 14512 fmov.l %d1,%fpcr # set FPCR 14513 fmov.l &0x0,%fpsr # clear FPSR 14514 14515 fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide 14516 14517 fmov.l &0x0,%fpcr # clear FPCR 14518 fabs.x %fp1 # make absolute value 14519 fcmp.b %fp1,&0x1 # is |result| < 1.b? 14520 fbge.w fsgldiv_normal_exit # no; no underflow occurred 14521 bra.w fsgldiv_unfl # yes; underflow occurred 14522 14523############################################################################ 14524 14525# 14526# Divide: inputs are not both normalized; what are they? 14527# 14528fsgldiv_not_norm: 14529 mov.w (tbl_fsgldiv_op.b,%pc,%d1.w*2),%d1 14530 jmp (tbl_fsgldiv_op.b,%pc,%d1.w*1) 14531 14532 swbeg &48 14533tbl_fsgldiv_op: 14534 short fsgldiv_norm - tbl_fsgldiv_op # NORM / NORM 14535 short fsgldiv_inf_load - tbl_fsgldiv_op # NORM / ZERO 14536 short fsgldiv_zero_load - tbl_fsgldiv_op # NORM / INF 14537 short fsgldiv_res_qnan - tbl_fsgldiv_op # NORM / QNAN 14538 short fsgldiv_norm - tbl_fsgldiv_op # NORM / DENORM 14539 short fsgldiv_res_snan - tbl_fsgldiv_op # NORM / SNAN 14540 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14541 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14542 14543 short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / NORM 14544 short fsgldiv_res_operr - tbl_fsgldiv_op # ZERO / ZERO 14545 short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / INF 14546 short fsgldiv_res_qnan - tbl_fsgldiv_op # ZERO / QNAN 14547 short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / DENORM 14548 short fsgldiv_res_snan - tbl_fsgldiv_op # ZERO / SNAN 14549 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14550 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14551 14552 short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / NORM 14553 short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / ZERO 14554 short fsgldiv_res_operr - tbl_fsgldiv_op # INF / INF 14555 short fsgldiv_res_qnan - tbl_fsgldiv_op # INF / QNAN 14556 short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / DENORM 14557 short fsgldiv_res_snan - tbl_fsgldiv_op # INF / SNAN 14558 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14559 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14560 14561 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / NORM 14562 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / ZERO 14563 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / INF 14564 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / QNAN 14565 short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / DENORM 14566 short fsgldiv_res_snan - tbl_fsgldiv_op # QNAN / SNAN 14567 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14568 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14569 14570 short fsgldiv_norm - tbl_fsgldiv_op # DENORM / NORM 14571 short fsgldiv_inf_load - tbl_fsgldiv_op # DENORM / ZERO 14572 short fsgldiv_zero_load - tbl_fsgldiv_op # DENORM / INF 14573 short fsgldiv_res_qnan - tbl_fsgldiv_op # DENORM / QNAN 14574 short fsgldiv_norm - tbl_fsgldiv_op # DENORM / DENORM 14575 short fsgldiv_res_snan - tbl_fsgldiv_op # DENORM / SNAN 14576 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14577 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14578 14579 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / NORM 14580 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / ZERO 14581 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / INF 14582 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / QNAN 14583 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / DENORM 14584 short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / SNAN 14585 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14586 short tbl_fsgldiv_op - tbl_fsgldiv_op # 14587 14588fsgldiv_res_qnan: 14589 bra.l res_qnan 14590fsgldiv_res_snan: 14591 bra.l res_snan 14592fsgldiv_res_operr: 14593 bra.l res_operr 14594fsgldiv_inf_load: 14595 bra.l fdiv_inf_load 14596fsgldiv_zero_load: 14597 bra.l fdiv_zero_load 14598fsgldiv_inf_dst: 14599 bra.l fdiv_inf_dst 14600 14601######################################################################### 14602# XDEF **************************************************************** # 14603# fadd(): emulates the fadd instruction # 14604# fsadd(): emulates the fadd instruction # 14605# fdadd(): emulates the fdadd instruction # 14606# # 14607# XREF **************************************************************** # 14608# addsub_scaler2() - scale the operands so they won't take exc # 14609# ovf_res() - return default overflow result # 14610# unf_res() - return default underflow result # 14611# res_qnan() - set QNAN result # 14612# res_snan() - set SNAN result # 14613# res_operr() - set OPERR result # 14614# scale_to_zero_src() - set src operand exponent equal to zero # 14615# scale_to_zero_dst() - set dst operand exponent equal to zero # 14616# # 14617# INPUT *************************************************************** # 14618# a0 = pointer to extended precision source operand # 14619# a1 = pointer to extended precision destination operand # 14620# # 14621# OUTPUT ************************************************************** # 14622# fp0 = result # 14623# fp1 = EXOP (if exception occurred) # 14624# # 14625# ALGORITHM *********************************************************** # 14626# Handle NANs, infinities, and zeroes as special cases. Divide # 14627# norms into extended, single, and double precision. # 14628# Do addition after scaling exponents such that exception won't # 14629# occur. Then, check result exponent to see if exception would have # 14630# occurred. If so, return default result and maybe EXOP. Else, insert # 14631# the correct result exponent and return. Set FPSR bits as appropriate. # 14632# # 14633######################################################################### 14634 14635 global fsadd 14636fsadd: 14637 andi.b &0x30,%d0 # clear rnd prec 14638 ori.b &s_mode*0x10,%d0 # insert sgl prec 14639 bra.b fadd 14640 14641 global fdadd 14642fdadd: 14643 andi.b &0x30,%d0 # clear rnd prec 14644 ori.b &d_mode*0x10,%d0 # insert dbl prec 14645 14646 global fadd 14647fadd: 14648 mov.l %d0,L_SCR3(%a6) # store rnd info 14649 14650 clr.w %d1 14651 mov.b DTAG(%a6),%d1 14652 lsl.b &0x3,%d1 14653 or.b STAG(%a6),%d1 # combine src tags 14654 14655 bne.w fadd_not_norm # optimize on non-norm input 14656 14657# 14658# ADD: norms and denorms 14659# 14660fadd_norm: 14661 bsr.l addsub_scaler2 # scale exponents 14662 14663fadd_zero_entry: 14664 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14665 14666 fmov.l &0x0,%fpsr # clear FPSR 14667 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14668 14669 fadd.x FP_SCR0(%a6),%fp0 # execute add 14670 14671 fmov.l &0x0,%fpcr # clear FPCR 14672 fmov.l %fpsr,%d1 # fetch INEX2,N,Z 14673 14674 or.l %d1,USER_FPSR(%a6) # save exc and ccode bits 14675 14676 fbeq.w fadd_zero_exit # if result is zero, end now 14677 14678 mov.l %d2,-(%sp) # save d2 14679 14680 fmovm.x &0x01,-(%sp) # save result to stack 14681 14682 mov.w 2+L_SCR3(%a6),%d1 14683 lsr.b &0x6,%d1 14684 14685 mov.w (%sp),%d2 # fetch new sign, exp 14686 andi.l &0x7fff,%d2 # strip sign 14687 sub.l %d0,%d2 # add scale factor 14688 14689 cmp.l %d2,(tbl_fadd_ovfl.b,%pc,%d1.w*4) # is it an overflow? 14690 bge.b fadd_ovfl # yes 14691 14692 cmp.l %d2,(tbl_fadd_unfl.b,%pc,%d1.w*4) # is it an underflow? 14693 blt.w fadd_unfl # yes 14694 beq.w fadd_may_unfl # maybe; go find out 14695 14696fadd_normal: 14697 mov.w (%sp),%d1 14698 andi.w &0x8000,%d1 # keep sign 14699 or.w %d2,%d1 # concat sign,new exp 14700 mov.w %d1,(%sp) # insert new exponent 14701 14702 fmovm.x (%sp)+,&0x80 # return result in fp0 14703 14704 mov.l (%sp)+,%d2 # restore d2 14705 rts 14706 14707fadd_zero_exit: 14708# fmov.s &0x00000000,%fp0 # return zero in fp0 14709 rts 14710 14711tbl_fadd_ovfl: 14712 long 0x7fff # ext ovfl 14713 long 0x407f # sgl ovfl 14714 long 0x43ff # dbl ovfl 14715 14716tbl_fadd_unfl: 14717 long 0x0000 # ext unfl 14718 long 0x3f81 # sgl unfl 14719 long 0x3c01 # dbl unfl 14720 14721fadd_ovfl: 14722 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 14723 14724 mov.b FPCR_ENABLE(%a6),%d1 14725 andi.b &0x13,%d1 # is OVFL or INEX enabled? 14726 bne.b fadd_ovfl_ena # yes 14727 14728 add.l &0xc,%sp 14729fadd_ovfl_dis: 14730 btst &neg_bit,FPSR_CC(%a6) # is result negative? 14731 sne %d1 # set sign param accordingly 14732 mov.l L_SCR3(%a6),%d0 # pass prec:rnd 14733 bsr.l ovf_res # calculate default result 14734 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 14735 fmovm.x (%a0),&0x80 # return default result in fp0 14736 mov.l (%sp)+,%d2 # restore d2 14737 rts 14738 14739fadd_ovfl_ena: 14740 mov.b L_SCR3(%a6),%d1 14741 andi.b &0xc0,%d1 # is precision extended? 14742 bne.b fadd_ovfl_ena_sd # no; prec = sgl or dbl 14743 14744fadd_ovfl_ena_cont: 14745 mov.w (%sp),%d1 14746 andi.w &0x8000,%d1 # keep sign 14747 subi.l &0x6000,%d2 # add extra bias 14748 andi.w &0x7fff,%d2 14749 or.w %d2,%d1 # concat sign,new exp 14750 mov.w %d1,(%sp) # insert new exponent 14751 14752 fmovm.x (%sp)+,&0x40 # return EXOP in fp1 14753 bra.b fadd_ovfl_dis 14754 14755fadd_ovfl_ena_sd: 14756 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14757 14758 mov.l L_SCR3(%a6),%d1 14759 andi.b &0x30,%d1 # keep rnd mode 14760 fmov.l %d1,%fpcr # set FPCR 14761 14762 fadd.x FP_SCR0(%a6),%fp0 # execute add 14763 14764 fmov.l &0x0,%fpcr # clear FPCR 14765 14766 add.l &0xc,%sp 14767 fmovm.x &0x01,-(%sp) 14768 bra.b fadd_ovfl_ena_cont 14769 14770fadd_unfl: 14771 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 14772 14773 add.l &0xc,%sp 14774 14775 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 14776 14777 fmov.l &rz_mode*0x10,%fpcr # set FPCR 14778 fmov.l &0x0,%fpsr # clear FPSR 14779 14780 fadd.x FP_SCR0(%a6),%fp0 # execute add 14781 14782 fmov.l &0x0,%fpcr # clear FPCR 14783 fmov.l %fpsr,%d1 # save status 14784 14785 or.l %d1,USER_FPSR(%a6) # save INEX,N 14786 14787 mov.b FPCR_ENABLE(%a6),%d1 14788 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 14789 bne.b fadd_unfl_ena # yes 14790 14791fadd_unfl_dis: 14792 fmovm.x &0x80,FP_SCR0(%a6) # store out result 14793 14794 lea FP_SCR0(%a6),%a0 # pass: result addr 14795 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 14796 bsr.l unf_res # calculate default result 14797 or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set 14798 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 14799 mov.l (%sp)+,%d2 # restore d2 14800 rts 14801 14802fadd_unfl_ena: 14803 fmovm.x FP_SCR1(%a6),&0x40 # load dst op 14804 14805 mov.l L_SCR3(%a6),%d1 14806 andi.b &0xc0,%d1 # is precision extended? 14807 bne.b fadd_unfl_ena_sd # no; sgl or dbl 14808 14809 fmov.l L_SCR3(%a6),%fpcr # set FPCR 14810 14811fadd_unfl_ena_cont: 14812 fmov.l &0x0,%fpsr # clear FPSR 14813 14814 fadd.x FP_SCR0(%a6),%fp1 # execute multiply 14815 14816 fmov.l &0x0,%fpcr # clear FPCR 14817 14818 fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 14819 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 14820 mov.l %d1,%d2 # make a copy 14821 andi.l &0x7fff,%d1 # strip sign 14822 andi.w &0x8000,%d2 # keep old sign 14823 sub.l %d0,%d1 # add scale factor 14824 addi.l &0x6000,%d1 # add new bias 14825 andi.w &0x7fff,%d1 # clear top bit 14826 or.w %d2,%d1 # concat sign,new exp 14827 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 14828 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 14829 bra.w fadd_unfl_dis 14830 14831fadd_unfl_ena_sd: 14832 mov.l L_SCR3(%a6),%d1 14833 andi.b &0x30,%d1 # use only rnd mode 14834 fmov.l %d1,%fpcr # set FPCR 14835 14836 bra.b fadd_unfl_ena_cont 14837 14838# 14839# result is equal to the smallest normalized number in the selected precision 14840# if the precision is extended, this result could not have come from an 14841# underflow that rounded up. 14842# 14843fadd_may_unfl: 14844 mov.l L_SCR3(%a6),%d1 14845 andi.b &0xc0,%d1 14846 beq.w fadd_normal # yes; no underflow occurred 14847 14848 mov.l 0x4(%sp),%d1 # extract hi(man) 14849 cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000? 14850 bne.w fadd_normal # no; no underflow occurred 14851 14852 tst.l 0x8(%sp) # is lo(man) = 0x0? 14853 bne.w fadd_normal # no; no underflow occurred 14854 14855 btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set? 14856 beq.w fadd_normal # no; no underflow occurred 14857 14858# 14859# ok, so now the result has a exponent equal to the smallest normalized 14860# exponent for the selected precision. also, the mantissa is equal to 14861# 0x8000000000000000 and this mantissa is the result of rounding non-zero 14862# g,r,s. 14863# now, we must determine whether the pre-rounded result was an underflow 14864# rounded "up" or a normalized number rounded "down". 14865# so, we do this be re-executing the add using RZ as the rounding mode and 14866# seeing if the new result is smaller or equal to the current result. 14867# 14868 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 14869 14870 mov.l L_SCR3(%a6),%d1 14871 andi.b &0xc0,%d1 # keep rnd prec 14872 ori.b &rz_mode*0x10,%d1 # insert rnd mode 14873 fmov.l %d1,%fpcr # set FPCR 14874 fmov.l &0x0,%fpsr # clear FPSR 14875 14876 fadd.x FP_SCR0(%a6),%fp1 # execute add 14877 14878 fmov.l &0x0,%fpcr # clear FPCR 14879 14880 fabs.x %fp0 # compare absolute values 14881 fabs.x %fp1 14882 fcmp.x %fp0,%fp1 # is first result > second? 14883 14884 fbgt.w fadd_unfl # yes; it's an underflow 14885 bra.w fadd_normal # no; it's not an underflow 14886 14887########################################################################## 14888 14889# 14890# Add: inputs are not both normalized; what are they? 14891# 14892fadd_not_norm: 14893 mov.w (tbl_fadd_op.b,%pc,%d1.w*2),%d1 14894 jmp (tbl_fadd_op.b,%pc,%d1.w*1) 14895 14896 swbeg &48 14897tbl_fadd_op: 14898 short fadd_norm - tbl_fadd_op # NORM + NORM 14899 short fadd_zero_src - tbl_fadd_op # NORM + ZERO 14900 short fadd_inf_src - tbl_fadd_op # NORM + INF 14901 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 14902 short fadd_norm - tbl_fadd_op # NORM + DENORM 14903 short fadd_res_snan - tbl_fadd_op # NORM + SNAN 14904 short tbl_fadd_op - tbl_fadd_op # 14905 short tbl_fadd_op - tbl_fadd_op # 14906 14907 short fadd_zero_dst - tbl_fadd_op # ZERO + NORM 14908 short fadd_zero_2 - tbl_fadd_op # ZERO + ZERO 14909 short fadd_inf_src - tbl_fadd_op # ZERO + INF 14910 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 14911 short fadd_zero_dst - tbl_fadd_op # ZERO + DENORM 14912 short fadd_res_snan - tbl_fadd_op # NORM + SNAN 14913 short tbl_fadd_op - tbl_fadd_op # 14914 short tbl_fadd_op - tbl_fadd_op # 14915 14916 short fadd_inf_dst - tbl_fadd_op # INF + NORM 14917 short fadd_inf_dst - tbl_fadd_op # INF + ZERO 14918 short fadd_inf_2 - tbl_fadd_op # INF + INF 14919 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 14920 short fadd_inf_dst - tbl_fadd_op # INF + DENORM 14921 short fadd_res_snan - tbl_fadd_op # NORM + SNAN 14922 short tbl_fadd_op - tbl_fadd_op # 14923 short tbl_fadd_op - tbl_fadd_op # 14924 14925 short fadd_res_qnan - tbl_fadd_op # QNAN + NORM 14926 short fadd_res_qnan - tbl_fadd_op # QNAN + ZERO 14927 short fadd_res_qnan - tbl_fadd_op # QNAN + INF 14928 short fadd_res_qnan - tbl_fadd_op # QNAN + QNAN 14929 short fadd_res_qnan - tbl_fadd_op # QNAN + DENORM 14930 short fadd_res_snan - tbl_fadd_op # QNAN + SNAN 14931 short tbl_fadd_op - tbl_fadd_op # 14932 short tbl_fadd_op - tbl_fadd_op # 14933 14934 short fadd_norm - tbl_fadd_op # DENORM + NORM 14935 short fadd_zero_src - tbl_fadd_op # DENORM + ZERO 14936 short fadd_inf_src - tbl_fadd_op # DENORM + INF 14937 short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 14938 short fadd_norm - tbl_fadd_op # DENORM + DENORM 14939 short fadd_res_snan - tbl_fadd_op # NORM + SNAN 14940 short tbl_fadd_op - tbl_fadd_op # 14941 short tbl_fadd_op - tbl_fadd_op # 14942 14943 short fadd_res_snan - tbl_fadd_op # SNAN + NORM 14944 short fadd_res_snan - tbl_fadd_op # SNAN + ZERO 14945 short fadd_res_snan - tbl_fadd_op # SNAN + INF 14946 short fadd_res_snan - tbl_fadd_op # SNAN + QNAN 14947 short fadd_res_snan - tbl_fadd_op # SNAN + DENORM 14948 short fadd_res_snan - tbl_fadd_op # SNAN + SNAN 14949 short tbl_fadd_op - tbl_fadd_op # 14950 short tbl_fadd_op - tbl_fadd_op # 14951 14952fadd_res_qnan: 14953 bra.l res_qnan 14954fadd_res_snan: 14955 bra.l res_snan 14956 14957# 14958# both operands are ZEROes 14959# 14960fadd_zero_2: 14961 mov.b SRC_EX(%a0),%d0 # are the signs opposite 14962 mov.b DST_EX(%a1),%d1 14963 eor.b %d0,%d1 14964 bmi.w fadd_zero_2_chk_rm # weed out (-ZERO)+(+ZERO) 14965 14966# the signs are the same. so determine whether they are positive or negative 14967# and return the appropriately signed zero. 14968 tst.b %d0 # are ZEROes positive or negative? 14969 bmi.b fadd_zero_rm # negative 14970 fmov.s &0x00000000,%fp0 # return +ZERO 14971 mov.b &z_bmask,FPSR_CC(%a6) # set Z 14972 rts 14973 14974# 14975# the ZEROes have opposite signs: 14976# - Therefore, we return +ZERO if the rounding modes are RN,RZ, or RP. 14977# - -ZERO is returned in the case of RM. 14978# 14979fadd_zero_2_chk_rm: 14980 mov.b 3+L_SCR3(%a6),%d1 14981 andi.b &0x30,%d1 # extract rnd mode 14982 cmpi.b %d1,&rm_mode*0x10 # is rnd mode == RM? 14983 beq.b fadd_zero_rm # yes 14984 fmov.s &0x00000000,%fp0 # return +ZERO 14985 mov.b &z_bmask,FPSR_CC(%a6) # set Z 14986 rts 14987 14988fadd_zero_rm: 14989 fmov.s &0x80000000,%fp0 # return -ZERO 14990 mov.b &neg_bmask+z_bmask,FPSR_CC(%a6) # set NEG/Z 14991 rts 14992 14993# 14994# one operand is a ZERO and the other is a DENORM or NORM. scale 14995# the DENORM or NORM and jump to the regular fadd routine. 14996# 14997fadd_zero_dst: 14998 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 14999 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 15000 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 15001 bsr.l scale_to_zero_src # scale the operand 15002 clr.w FP_SCR1_EX(%a6) 15003 clr.l FP_SCR1_HI(%a6) 15004 clr.l FP_SCR1_LO(%a6) 15005 bra.w fadd_zero_entry # go execute fadd 15006 15007fadd_zero_src: 15008 mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 15009 mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 15010 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 15011 bsr.l scale_to_zero_dst # scale the operand 15012 clr.w FP_SCR0_EX(%a6) 15013 clr.l FP_SCR0_HI(%a6) 15014 clr.l FP_SCR0_LO(%a6) 15015 bra.w fadd_zero_entry # go execute fadd 15016 15017# 15018# both operands are INFs. an OPERR will result if the INFs have 15019# different signs. else, an INF of the same sign is returned 15020# 15021fadd_inf_2: 15022 mov.b SRC_EX(%a0),%d0 # exclusive or the signs 15023 mov.b DST_EX(%a1),%d1 15024 eor.b %d1,%d0 15025 bmi.l res_operr # weed out (-INF)+(+INF) 15026 15027# ok, so it's not an OPERR. but, we do have to remember to return the 15028# src INF since that's where the 881/882 gets the j-bit from... 15029 15030# 15031# operands are INF and one of {ZERO, INF, DENORM, NORM} 15032# 15033fadd_inf_src: 15034 fmovm.x SRC(%a0),&0x80 # return src INF 15035 tst.b SRC_EX(%a0) # is INF positive? 15036 bpl.b fadd_inf_done # yes; we're done 15037 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 15038 rts 15039 15040# 15041# operands are INF and one of {ZERO, INF, DENORM, NORM} 15042# 15043fadd_inf_dst: 15044 fmovm.x DST(%a1),&0x80 # return dst INF 15045 tst.b DST_EX(%a1) # is INF positive? 15046 bpl.b fadd_inf_done # yes; we're done 15047 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 15048 rts 15049 15050fadd_inf_done: 15051 mov.b &inf_bmask,FPSR_CC(%a6) # set INF 15052 rts 15053 15054######################################################################### 15055# XDEF **************************************************************** # 15056# fsub(): emulates the fsub instruction # 15057# fssub(): emulates the fssub instruction # 15058# fdsub(): emulates the fdsub instruction # 15059# # 15060# XREF **************************************************************** # 15061# addsub_scaler2() - scale the operands so they won't take exc # 15062# ovf_res() - return default overflow result # 15063# unf_res() - return default underflow result # 15064# res_qnan() - set QNAN result # 15065# res_snan() - set SNAN result # 15066# res_operr() - set OPERR result # 15067# scale_to_zero_src() - set src operand exponent equal to zero # 15068# scale_to_zero_dst() - set dst operand exponent equal to zero # 15069# # 15070# INPUT *************************************************************** # 15071# a0 = pointer to extended precision source operand # 15072# a1 = pointer to extended precision destination operand # 15073# # 15074# OUTPUT ************************************************************** # 15075# fp0 = result # 15076# fp1 = EXOP (if exception occurred) # 15077# # 15078# ALGORITHM *********************************************************** # 15079# Handle NANs, infinities, and zeroes as special cases. Divide # 15080# norms into extended, single, and double precision. # 15081# Do subtraction after scaling exponents such that exception won't# 15082# occur. Then, check result exponent to see if exception would have # 15083# occurred. If so, return default result and maybe EXOP. Else, insert # 15084# the correct result exponent and return. Set FPSR bits as appropriate. # 15085# # 15086######################################################################### 15087 15088 global fssub 15089fssub: 15090 andi.b &0x30,%d0 # clear rnd prec 15091 ori.b &s_mode*0x10,%d0 # insert sgl prec 15092 bra.b fsub 15093 15094 global fdsub 15095fdsub: 15096 andi.b &0x30,%d0 # clear rnd prec 15097 ori.b &d_mode*0x10,%d0 # insert dbl prec 15098 15099 global fsub 15100fsub: 15101 mov.l %d0,L_SCR3(%a6) # store rnd info 15102 15103 clr.w %d1 15104 mov.b DTAG(%a6),%d1 15105 lsl.b &0x3,%d1 15106 or.b STAG(%a6),%d1 # combine src tags 15107 15108 bne.w fsub_not_norm # optimize on non-norm input 15109 15110# 15111# SUB: norms and denorms 15112# 15113fsub_norm: 15114 bsr.l addsub_scaler2 # scale exponents 15115 15116fsub_zero_entry: 15117 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 15118 15119 fmov.l &0x0,%fpsr # clear FPSR 15120 fmov.l L_SCR3(%a6),%fpcr # set FPCR 15121 15122 fsub.x FP_SCR0(%a6),%fp0 # execute subtract 15123 15124 fmov.l &0x0,%fpcr # clear FPCR 15125 fmov.l %fpsr,%d1 # fetch INEX2, N, Z 15126 15127 or.l %d1,USER_FPSR(%a6) # save exc and ccode bits 15128 15129 fbeq.w fsub_zero_exit # if result zero, end now 15130 15131 mov.l %d2,-(%sp) # save d2 15132 15133 fmovm.x &0x01,-(%sp) # save result to stack 15134 15135 mov.w 2+L_SCR3(%a6),%d1 15136 lsr.b &0x6,%d1 15137 15138 mov.w (%sp),%d2 # fetch new exponent 15139 andi.l &0x7fff,%d2 # strip sign 15140 sub.l %d0,%d2 # add scale factor 15141 15142 cmp.l %d2,(tbl_fsub_ovfl.b,%pc,%d1.w*4) # is it an overflow? 15143 bge.b fsub_ovfl # yes 15144 15145 cmp.l %d2,(tbl_fsub_unfl.b,%pc,%d1.w*4) # is it an underflow? 15146 blt.w fsub_unfl # yes 15147 beq.w fsub_may_unfl # maybe; go find out 15148 15149fsub_normal: 15150 mov.w (%sp),%d1 15151 andi.w &0x8000,%d1 # keep sign 15152 or.w %d2,%d1 # insert new exponent 15153 mov.w %d1,(%sp) # insert new exponent 15154 15155 fmovm.x (%sp)+,&0x80 # return result in fp0 15156 15157 mov.l (%sp)+,%d2 # restore d2 15158 rts 15159 15160fsub_zero_exit: 15161# fmov.s &0x00000000,%fp0 # return zero in fp0 15162 rts 15163 15164tbl_fsub_ovfl: 15165 long 0x7fff # ext ovfl 15166 long 0x407f # sgl ovfl 15167 long 0x43ff # dbl ovfl 15168 15169tbl_fsub_unfl: 15170 long 0x0000 # ext unfl 15171 long 0x3f81 # sgl unfl 15172 long 0x3c01 # dbl unfl 15173 15174fsub_ovfl: 15175 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 15176 15177 mov.b FPCR_ENABLE(%a6),%d1 15178 andi.b &0x13,%d1 # is OVFL or INEX enabled? 15179 bne.b fsub_ovfl_ena # yes 15180 15181 add.l &0xc,%sp 15182fsub_ovfl_dis: 15183 btst &neg_bit,FPSR_CC(%a6) # is result negative? 15184 sne %d1 # set sign param accordingly 15185 mov.l L_SCR3(%a6),%d0 # pass prec:rnd 15186 bsr.l ovf_res # calculate default result 15187 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 15188 fmovm.x (%a0),&0x80 # return default result in fp0 15189 mov.l (%sp)+,%d2 # restore d2 15190 rts 15191 15192fsub_ovfl_ena: 15193 mov.b L_SCR3(%a6),%d1 15194 andi.b &0xc0,%d1 # is precision extended? 15195 bne.b fsub_ovfl_ena_sd # no 15196 15197fsub_ovfl_ena_cont: 15198 mov.w (%sp),%d1 # fetch {sgn,exp} 15199 andi.w &0x8000,%d1 # keep sign 15200 subi.l &0x6000,%d2 # subtract new bias 15201 andi.w &0x7fff,%d2 # clear top bit 15202 or.w %d2,%d1 # concat sign,exp 15203 mov.w %d1,(%sp) # insert new exponent 15204 15205 fmovm.x (%sp)+,&0x40 # return EXOP in fp1 15206 bra.b fsub_ovfl_dis 15207 15208fsub_ovfl_ena_sd: 15209 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 15210 15211 mov.l L_SCR3(%a6),%d1 15212 andi.b &0x30,%d1 # clear rnd prec 15213 fmov.l %d1,%fpcr # set FPCR 15214 15215 fsub.x FP_SCR0(%a6),%fp0 # execute subtract 15216 15217 fmov.l &0x0,%fpcr # clear FPCR 15218 15219 add.l &0xc,%sp 15220 fmovm.x &0x01,-(%sp) 15221 bra.b fsub_ovfl_ena_cont 15222 15223fsub_unfl: 15224 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 15225 15226 add.l &0xc,%sp 15227 15228 fmovm.x FP_SCR1(%a6),&0x80 # load dst op 15229 15230 fmov.l &rz_mode*0x10,%fpcr # set FPCR 15231 fmov.l &0x0,%fpsr # clear FPSR 15232 15233 fsub.x FP_SCR0(%a6),%fp0 # execute subtract 15234 15235 fmov.l &0x0,%fpcr # clear FPCR 15236 fmov.l %fpsr,%d1 # save status 15237 15238 or.l %d1,USER_FPSR(%a6) 15239 15240 mov.b FPCR_ENABLE(%a6),%d1 15241 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 15242 bne.b fsub_unfl_ena # yes 15243 15244fsub_unfl_dis: 15245 fmovm.x &0x80,FP_SCR0(%a6) # store out result 15246 15247 lea FP_SCR0(%a6),%a0 # pass: result addr 15248 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 15249 bsr.l unf_res # calculate default result 15250 or.b %d0,FPSR_CC(%a6) # 'Z' may have been set 15251 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 15252 mov.l (%sp)+,%d2 # restore d2 15253 rts 15254 15255fsub_unfl_ena: 15256 fmovm.x FP_SCR1(%a6),&0x40 15257 15258 mov.l L_SCR3(%a6),%d1 15259 andi.b &0xc0,%d1 # is precision extended? 15260 bne.b fsub_unfl_ena_sd # no 15261 15262 fmov.l L_SCR3(%a6),%fpcr # set FPCR 15263 15264fsub_unfl_ena_cont: 15265 fmov.l &0x0,%fpsr # clear FPSR 15266 15267 fsub.x FP_SCR0(%a6),%fp1 # execute subtract 15268 15269 fmov.l &0x0,%fpcr # clear FPCR 15270 15271 fmovm.x &0x40,FP_SCR0(%a6) # store result to stack 15272 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 15273 mov.l %d1,%d2 # make a copy 15274 andi.l &0x7fff,%d1 # strip sign 15275 andi.w &0x8000,%d2 # keep old sign 15276 sub.l %d0,%d1 # add scale factor 15277 addi.l &0x6000,%d1 # subtract new bias 15278 andi.w &0x7fff,%d1 # clear top bit 15279 or.w %d2,%d1 # concat sgn,exp 15280 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 15281 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 15282 bra.w fsub_unfl_dis 15283 15284fsub_unfl_ena_sd: 15285 mov.l L_SCR3(%a6),%d1 15286 andi.b &0x30,%d1 # clear rnd prec 15287 fmov.l %d1,%fpcr # set FPCR 15288 15289 bra.b fsub_unfl_ena_cont 15290 15291# 15292# result is equal to the smallest normalized number in the selected precision 15293# if the precision is extended, this result could not have come from an 15294# underflow that rounded up. 15295# 15296fsub_may_unfl: 15297 mov.l L_SCR3(%a6),%d1 15298 andi.b &0xc0,%d1 # fetch rnd prec 15299 beq.w fsub_normal # yes; no underflow occurred 15300 15301 mov.l 0x4(%sp),%d1 15302 cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000? 15303 bne.w fsub_normal # no; no underflow occurred 15304 15305 tst.l 0x8(%sp) # is lo(man) = 0x0? 15306 bne.w fsub_normal # no; no underflow occurred 15307 15308 btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set? 15309 beq.w fsub_normal # no; no underflow occurred 15310 15311# 15312# ok, so now the result has a exponent equal to the smallest normalized 15313# exponent for the selected precision. also, the mantissa is equal to 15314# 0x8000000000000000 and this mantissa is the result of rounding non-zero 15315# g,r,s. 15316# now, we must determine whether the pre-rounded result was an underflow 15317# rounded "up" or a normalized number rounded "down". 15318# so, we do this be re-executing the add using RZ as the rounding mode and 15319# seeing if the new result is smaller or equal to the current result. 15320# 15321 fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 15322 15323 mov.l L_SCR3(%a6),%d1 15324 andi.b &0xc0,%d1 # keep rnd prec 15325 ori.b &rz_mode*0x10,%d1 # insert rnd mode 15326 fmov.l %d1,%fpcr # set FPCR 15327 fmov.l &0x0,%fpsr # clear FPSR 15328 15329 fsub.x FP_SCR0(%a6),%fp1 # execute subtract 15330 15331 fmov.l &0x0,%fpcr # clear FPCR 15332 15333 fabs.x %fp0 # compare absolute values 15334 fabs.x %fp1 15335 fcmp.x %fp0,%fp1 # is first result > second? 15336 15337 fbgt.w fsub_unfl # yes; it's an underflow 15338 bra.w fsub_normal # no; it's not an underflow 15339 15340########################################################################## 15341 15342# 15343# Sub: inputs are not both normalized; what are they? 15344# 15345fsub_not_norm: 15346 mov.w (tbl_fsub_op.b,%pc,%d1.w*2),%d1 15347 jmp (tbl_fsub_op.b,%pc,%d1.w*1) 15348 15349 swbeg &48 15350tbl_fsub_op: 15351 short fsub_norm - tbl_fsub_op # NORM - NORM 15352 short fsub_zero_src - tbl_fsub_op # NORM - ZERO 15353 short fsub_inf_src - tbl_fsub_op # NORM - INF 15354 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 15355 short fsub_norm - tbl_fsub_op # NORM - DENORM 15356 short fsub_res_snan - tbl_fsub_op # NORM - SNAN 15357 short tbl_fsub_op - tbl_fsub_op # 15358 short tbl_fsub_op - tbl_fsub_op # 15359 15360 short fsub_zero_dst - tbl_fsub_op # ZERO - NORM 15361 short fsub_zero_2 - tbl_fsub_op # ZERO - ZERO 15362 short fsub_inf_src - tbl_fsub_op # ZERO - INF 15363 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 15364 short fsub_zero_dst - tbl_fsub_op # ZERO - DENORM 15365 short fsub_res_snan - tbl_fsub_op # NORM - SNAN 15366 short tbl_fsub_op - tbl_fsub_op # 15367 short tbl_fsub_op - tbl_fsub_op # 15368 15369 short fsub_inf_dst - tbl_fsub_op # INF - NORM 15370 short fsub_inf_dst - tbl_fsub_op # INF - ZERO 15371 short fsub_inf_2 - tbl_fsub_op # INF - INF 15372 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 15373 short fsub_inf_dst - tbl_fsub_op # INF - DENORM 15374 short fsub_res_snan - tbl_fsub_op # NORM - SNAN 15375 short tbl_fsub_op - tbl_fsub_op # 15376 short tbl_fsub_op - tbl_fsub_op # 15377 15378 short fsub_res_qnan - tbl_fsub_op # QNAN - NORM 15379 short fsub_res_qnan - tbl_fsub_op # QNAN - ZERO 15380 short fsub_res_qnan - tbl_fsub_op # QNAN - INF 15381 short fsub_res_qnan - tbl_fsub_op # QNAN - QNAN 15382 short fsub_res_qnan - tbl_fsub_op # QNAN - DENORM 15383 short fsub_res_snan - tbl_fsub_op # QNAN - SNAN 15384 short tbl_fsub_op - tbl_fsub_op # 15385 short tbl_fsub_op - tbl_fsub_op # 15386 15387 short fsub_norm - tbl_fsub_op # DENORM - NORM 15388 short fsub_zero_src - tbl_fsub_op # DENORM - ZERO 15389 short fsub_inf_src - tbl_fsub_op # DENORM - INF 15390 short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 15391 short fsub_norm - tbl_fsub_op # DENORM - DENORM 15392 short fsub_res_snan - tbl_fsub_op # NORM - SNAN 15393 short tbl_fsub_op - tbl_fsub_op # 15394 short tbl_fsub_op - tbl_fsub_op # 15395 15396 short fsub_res_snan - tbl_fsub_op # SNAN - NORM 15397 short fsub_res_snan - tbl_fsub_op # SNAN - ZERO 15398 short fsub_res_snan - tbl_fsub_op # SNAN - INF 15399 short fsub_res_snan - tbl_fsub_op # SNAN - QNAN 15400 short fsub_res_snan - tbl_fsub_op # SNAN - DENORM 15401 short fsub_res_snan - tbl_fsub_op # SNAN - SNAN 15402 short tbl_fsub_op - tbl_fsub_op # 15403 short tbl_fsub_op - tbl_fsub_op # 15404 15405fsub_res_qnan: 15406 bra.l res_qnan 15407fsub_res_snan: 15408 bra.l res_snan 15409 15410# 15411# both operands are ZEROes 15412# 15413fsub_zero_2: 15414 mov.b SRC_EX(%a0),%d0 15415 mov.b DST_EX(%a1),%d1 15416 eor.b %d1,%d0 15417 bpl.b fsub_zero_2_chk_rm 15418 15419# the signs are opposite, so, return a ZERO w/ the sign of the dst ZERO 15420 tst.b %d0 # is dst negative? 15421 bmi.b fsub_zero_2_rm # yes 15422 fmov.s &0x00000000,%fp0 # no; return +ZERO 15423 mov.b &z_bmask,FPSR_CC(%a6) # set Z 15424 rts 15425 15426# 15427# the ZEROes have the same signs: 15428# - Therefore, we return +ZERO if the rounding mode is RN,RZ, or RP 15429# - -ZERO is returned in the case of RM. 15430# 15431fsub_zero_2_chk_rm: 15432 mov.b 3+L_SCR3(%a6),%d1 15433 andi.b &0x30,%d1 # extract rnd mode 15434 cmpi.b %d1,&rm_mode*0x10 # is rnd mode = RM? 15435 beq.b fsub_zero_2_rm # yes 15436 fmov.s &0x00000000,%fp0 # no; return +ZERO 15437 mov.b &z_bmask,FPSR_CC(%a6) # set Z 15438 rts 15439 15440fsub_zero_2_rm: 15441 fmov.s &0x80000000,%fp0 # return -ZERO 15442 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/NEG 15443 rts 15444 15445# 15446# one operand is a ZERO and the other is a DENORM or a NORM. 15447# scale the DENORM or NORM and jump to the regular fsub routine. 15448# 15449fsub_zero_dst: 15450 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 15451 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 15452 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 15453 bsr.l scale_to_zero_src # scale the operand 15454 clr.w FP_SCR1_EX(%a6) 15455 clr.l FP_SCR1_HI(%a6) 15456 clr.l FP_SCR1_LO(%a6) 15457 bra.w fsub_zero_entry # go execute fsub 15458 15459fsub_zero_src: 15460 mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 15461 mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 15462 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 15463 bsr.l scale_to_zero_dst # scale the operand 15464 clr.w FP_SCR0_EX(%a6) 15465 clr.l FP_SCR0_HI(%a6) 15466 clr.l FP_SCR0_LO(%a6) 15467 bra.w fsub_zero_entry # go execute fsub 15468 15469# 15470# both operands are INFs. an OPERR will result if the INFs have the 15471# same signs. else, 15472# 15473fsub_inf_2: 15474 mov.b SRC_EX(%a0),%d0 # exclusive or the signs 15475 mov.b DST_EX(%a1),%d1 15476 eor.b %d1,%d0 15477 bpl.l res_operr # weed out (-INF)+(+INF) 15478 15479# ok, so it's not an OPERR. but we do have to remember to return 15480# the src INF since that's where the 881/882 gets the j-bit. 15481 15482fsub_inf_src: 15483 fmovm.x SRC(%a0),&0x80 # return src INF 15484 fneg.x %fp0 # invert sign 15485 fbge.w fsub_inf_done # sign is now positive 15486 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 15487 rts 15488 15489fsub_inf_dst: 15490 fmovm.x DST(%a1),&0x80 # return dst INF 15491 tst.b DST_EX(%a1) # is INF negative? 15492 bpl.b fsub_inf_done # no 15493 mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 15494 rts 15495 15496fsub_inf_done: 15497 mov.b &inf_bmask,FPSR_CC(%a6) # set INF 15498 rts 15499 15500######################################################################### 15501# XDEF **************************************************************** # 15502# fsqrt(): emulates the fsqrt instruction # 15503# fssqrt(): emulates the fssqrt instruction # 15504# fdsqrt(): emulates the fdsqrt instruction # 15505# # 15506# XREF **************************************************************** # 15507# scale_sqrt() - scale the source operand # 15508# unf_res() - return default underflow result # 15509# ovf_res() - return default overflow result # 15510# res_qnan_1op() - return QNAN result # 15511# res_snan_1op() - return SNAN result # 15512# # 15513# INPUT *************************************************************** # 15514# a0 = pointer to extended precision source operand # 15515# d0 rnd prec,mode # 15516# # 15517# OUTPUT ************************************************************** # 15518# fp0 = result # 15519# fp1 = EXOP (if exception occurred) # 15520# # 15521# ALGORITHM *********************************************************** # 15522# Handle NANs, infinities, and zeroes as special cases. Divide # 15523# norms/denorms into ext/sgl/dbl precision. # 15524# For norms/denorms, scale the exponents such that a sqrt # 15525# instruction won't cause an exception. Use the regular fsqrt to # 15526# compute a result. Check if the regular operands would have taken # 15527# an exception. If so, return the default overflow/underflow result # 15528# and return the EXOP if exceptions are enabled. Else, scale the # 15529# result operand to the proper exponent. # 15530# # 15531######################################################################### 15532 15533 global fssqrt 15534fssqrt: 15535 andi.b &0x30,%d0 # clear rnd prec 15536 ori.b &s_mode*0x10,%d0 # insert sgl precision 15537 bra.b fsqrt 15538 15539 global fdsqrt 15540fdsqrt: 15541 andi.b &0x30,%d0 # clear rnd prec 15542 ori.b &d_mode*0x10,%d0 # insert dbl precision 15543 15544 global fsqrt 15545fsqrt: 15546 mov.l %d0,L_SCR3(%a6) # store rnd info 15547 clr.w %d1 15548 mov.b STAG(%a6),%d1 15549 bne.w fsqrt_not_norm # optimize on non-norm input 15550 15551# 15552# SQUARE ROOT: norms and denorms ONLY! 15553# 15554fsqrt_norm: 15555 tst.b SRC_EX(%a0) # is operand negative? 15556 bmi.l res_operr # yes 15557 15558 andi.b &0xc0,%d0 # is precision extended? 15559 bne.b fsqrt_not_ext # no; go handle sgl or dbl 15560 15561 fmov.l L_SCR3(%a6),%fpcr # set FPCR 15562 fmov.l &0x0,%fpsr # clear FPSR 15563 15564 fsqrt.x (%a0),%fp0 # execute square root 15565 15566 fmov.l %fpsr,%d1 15567 or.l %d1,USER_FPSR(%a6) # set N,INEX 15568 15569 rts 15570 15571fsqrt_denorm: 15572 tst.b SRC_EX(%a0) # is operand negative? 15573 bmi.l res_operr # yes 15574 15575 andi.b &0xc0,%d0 # is precision extended? 15576 bne.b fsqrt_not_ext # no; go handle sgl or dbl 15577 15578 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 15579 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 15580 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 15581 15582 bsr.l scale_sqrt # calculate scale factor 15583 15584 bra.w fsqrt_sd_normal 15585 15586# 15587# operand is either single or double 15588# 15589fsqrt_not_ext: 15590 cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 15591 bne.w fsqrt_dbl 15592 15593# 15594# operand is to be rounded to single precision 15595# 15596fsqrt_sgl: 15597 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 15598 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 15599 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 15600 15601 bsr.l scale_sqrt # calculate scale factor 15602 15603 cmpi.l %d0,&0x3fff-0x3f81 # will move in underflow? 15604 beq.w fsqrt_sd_may_unfl 15605 bgt.w fsqrt_sd_unfl # yes; go handle underflow 15606 cmpi.l %d0,&0x3fff-0x407f # will move in overflow? 15607 beq.w fsqrt_sd_may_ovfl # maybe; go check 15608 blt.w fsqrt_sd_ovfl # yes; go handle overflow 15609 15610# 15611# operand will NOT overflow or underflow when moved in to the fp reg file 15612# 15613fsqrt_sd_normal: 15614 fmov.l &0x0,%fpsr # clear FPSR 15615 fmov.l L_SCR3(%a6),%fpcr # set FPCR 15616 15617 fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute 15618 15619 fmov.l %fpsr,%d1 # save FPSR 15620 fmov.l &0x0,%fpcr # clear FPCR 15621 15622 or.l %d1,USER_FPSR(%a6) # save INEX2,N 15623 15624fsqrt_sd_normal_exit: 15625 mov.l %d2,-(%sp) # save d2 15626 fmovm.x &0x80,FP_SCR0(%a6) # store out result 15627 mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp 15628 mov.l %d1,%d2 # make a copy 15629 andi.l &0x7fff,%d1 # strip sign 15630 sub.l %d0,%d1 # add scale factor 15631 andi.w &0x8000,%d2 # keep old sign 15632 or.w %d1,%d2 # concat old sign,new exp 15633 mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 15634 mov.l (%sp)+,%d2 # restore d2 15635 fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 15636 rts 15637 15638# 15639# operand is to be rounded to double precision 15640# 15641fsqrt_dbl: 15642 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 15643 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 15644 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 15645 15646 bsr.l scale_sqrt # calculate scale factor 15647 15648 cmpi.l %d0,&0x3fff-0x3c01 # will move in underflow? 15649 beq.w fsqrt_sd_may_unfl 15650 bgt.b fsqrt_sd_unfl # yes; go handle underflow 15651 cmpi.l %d0,&0x3fff-0x43ff # will move in overflow? 15652 beq.w fsqrt_sd_may_ovfl # maybe; go check 15653 blt.w fsqrt_sd_ovfl # yes; go handle overflow 15654 bra.w fsqrt_sd_normal # no; ho handle normalized op 15655 15656# we're on the line here and the distinguising characteristic is whether 15657# the exponent is 3fff or 3ffe. if it's 3ffe, then it's a safe number 15658# elsewise fall through to underflow. 15659fsqrt_sd_may_unfl: 15660 btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff? 15661 bne.w fsqrt_sd_normal # yes, so no underflow 15662 15663# 15664# operand WILL underflow when moved in to the fp register file 15665# 15666fsqrt_sd_unfl: 15667 bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 15668 15669 fmov.l &rz_mode*0x10,%fpcr # set FPCR 15670 fmov.l &0x0,%fpsr # clear FPSR 15671 15672 fsqrt.x FP_SCR0(%a6),%fp0 # execute square root 15673 15674 fmov.l %fpsr,%d1 # save status 15675 fmov.l &0x0,%fpcr # clear FPCR 15676 15677 or.l %d1,USER_FPSR(%a6) # save INEX2,N 15678 15679# if underflow or inexact is enabled, go calculate EXOP first. 15680 mov.b FPCR_ENABLE(%a6),%d1 15681 andi.b &0x0b,%d1 # is UNFL or INEX enabled? 15682 bne.b fsqrt_sd_unfl_ena # yes 15683 15684fsqrt_sd_unfl_dis: 15685 fmovm.x &0x80,FP_SCR0(%a6) # store out result 15686 15687 lea FP_SCR0(%a6),%a0 # pass: result addr 15688 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 15689 bsr.l unf_res # calculate default result 15690 or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode 15691 fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 15692 rts 15693 15694# 15695# operand will underflow AND underflow is enabled. 15696# Therefore, we must return the result rounded to extended precision. 15697# 15698fsqrt_sd_unfl_ena: 15699 mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 15700 mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 15701 mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 15702 15703 mov.l %d2,-(%sp) # save d2 15704 mov.l %d1,%d2 # make a copy 15705 andi.l &0x7fff,%d1 # strip sign 15706 andi.w &0x8000,%d2 # keep old sign 15707 sub.l %d0,%d1 # subtract scale factor 15708 addi.l &0x6000,%d1 # add new bias 15709 andi.w &0x7fff,%d1 15710 or.w %d2,%d1 # concat new sign,new exp 15711 mov.w %d1,FP_SCR1_EX(%a6) # insert new exp 15712 fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 15713 mov.l (%sp)+,%d2 # restore d2 15714 bra.b fsqrt_sd_unfl_dis 15715 15716# 15717# operand WILL overflow. 15718# 15719fsqrt_sd_ovfl: 15720 fmov.l &0x0,%fpsr # clear FPSR 15721 fmov.l L_SCR3(%a6),%fpcr # set FPCR 15722 15723 fsqrt.x FP_SCR0(%a6),%fp0 # perform square root 15724 15725 fmov.l &0x0,%fpcr # clear FPCR 15726 fmov.l %fpsr,%d1 # save FPSR 15727 15728 or.l %d1,USER_FPSR(%a6) # save INEX2,N 15729 15730fsqrt_sd_ovfl_tst: 15731 or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 15732 15733 mov.b FPCR_ENABLE(%a6),%d1 15734 andi.b &0x13,%d1 # is OVFL or INEX enabled? 15735 bne.b fsqrt_sd_ovfl_ena # yes 15736 15737# 15738# OVFL is not enabled; therefore, we must create the default result by 15739# calling ovf_res(). 15740# 15741fsqrt_sd_ovfl_dis: 15742 btst &neg_bit,FPSR_CC(%a6) # is result negative? 15743 sne %d1 # set sign param accordingly 15744 mov.l L_SCR3(%a6),%d0 # pass: prec,mode 15745 bsr.l ovf_res # calculate default result 15746 or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 15747 fmovm.x (%a0),&0x80 # return default result in fp0 15748 rts 15749 15750# 15751# OVFL is enabled. 15752# the INEX2 bit has already been updated by the round to the correct precision. 15753# now, round to extended(and don't alter the FPSR). 15754# 15755fsqrt_sd_ovfl_ena: 15756 mov.l %d2,-(%sp) # save d2 15757 mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 15758 mov.l %d1,%d2 # make a copy 15759 andi.l &0x7fff,%d1 # strip sign 15760 andi.w &0x8000,%d2 # keep old sign 15761 sub.l %d0,%d1 # add scale factor 15762 subi.l &0x6000,%d1 # subtract bias 15763 andi.w &0x7fff,%d1 15764 or.w %d2,%d1 # concat sign,exp 15765 mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 15766 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 15767 mov.l (%sp)+,%d2 # restore d2 15768 bra.b fsqrt_sd_ovfl_dis 15769 15770# 15771# the move in MAY underflow. so... 15772# 15773fsqrt_sd_may_ovfl: 15774 btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff? 15775 bne.w fsqrt_sd_ovfl # yes, so overflow 15776 15777 fmov.l &0x0,%fpsr # clear FPSR 15778 fmov.l L_SCR3(%a6),%fpcr # set FPCR 15779 15780 fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute 15781 15782 fmov.l %fpsr,%d1 # save status 15783 fmov.l &0x0,%fpcr # clear FPCR 15784 15785 or.l %d1,USER_FPSR(%a6) # save INEX2,N 15786 15787 fmov.x %fp0,%fp1 # make a copy of result 15788 fcmp.b %fp1,&0x1 # is |result| >= 1.b? 15789 fbge.w fsqrt_sd_ovfl_tst # yes; overflow has occurred 15790 15791# no, it didn't overflow; we have correct result 15792 bra.w fsqrt_sd_normal_exit 15793 15794########################################################################## 15795 15796# 15797# input is not normalized; what is it? 15798# 15799fsqrt_not_norm: 15800 cmpi.b %d1,&DENORM # weed out DENORM 15801 beq.w fsqrt_denorm 15802 cmpi.b %d1,&ZERO # weed out ZERO 15803 beq.b fsqrt_zero 15804 cmpi.b %d1,&INF # weed out INF 15805 beq.b fsqrt_inf 15806 cmpi.b %d1,&SNAN # weed out SNAN 15807 beq.l res_snan_1op 15808 bra.l res_qnan_1op 15809 15810# 15811# fsqrt(+0) = +0 15812# fsqrt(-0) = -0 15813# fsqrt(+INF) = +INF 15814# fsqrt(-INF) = OPERR 15815# 15816fsqrt_zero: 15817 tst.b SRC_EX(%a0) # is ZERO positive or negative? 15818 bmi.b fsqrt_zero_m # negative 15819fsqrt_zero_p: 15820 fmov.s &0x00000000,%fp0 # return +ZERO 15821 mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 15822 rts 15823fsqrt_zero_m: 15824 fmov.s &0x80000000,%fp0 # return -ZERO 15825 mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 15826 rts 15827 15828fsqrt_inf: 15829 tst.b SRC_EX(%a0) # is INF positive or negative? 15830 bmi.l res_operr # negative 15831fsqrt_inf_p: 15832 fmovm.x SRC(%a0),&0x80 # return +INF in fp0 15833 mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 15834 rts 15835 15836########################################################################## 15837 15838######################################################################### 15839# XDEF **************************************************************** # 15840# addsub_scaler2(): scale inputs to fadd/fsub such that no # 15841# OVFL/UNFL exceptions will result # 15842# # 15843# XREF **************************************************************** # 15844# norm() - normalize mantissa after adjusting exponent # 15845# # 15846# INPUT *************************************************************** # 15847# FP_SRC(a6) = fp op1(src) # 15848# FP_DST(a6) = fp op2(dst) # 15849# # 15850# OUTPUT ************************************************************** # 15851# FP_SRC(a6) = fp op1 scaled(src) # 15852# FP_DST(a6) = fp op2 scaled(dst) # 15853# d0 = scale amount # 15854# # 15855# ALGORITHM *********************************************************** # 15856# If the DST exponent is > the SRC exponent, set the DST exponent # 15857# equal to 0x3fff and scale the SRC exponent by the value that the # 15858# DST exponent was scaled by. If the SRC exponent is greater or equal, # 15859# do the opposite. Return this scale factor in d0. # 15860# If the two exponents differ by > the number of mantissa bits # 15861# plus two, then set the smallest exponent to a very small value as a # 15862# quick shortcut. # 15863# # 15864######################################################################### 15865 15866 global addsub_scaler2 15867addsub_scaler2: 15868 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 15869 mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 15870 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 15871 mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 15872 mov.w SRC_EX(%a0),%d0 15873 mov.w DST_EX(%a1),%d1 15874 mov.w %d0,FP_SCR0_EX(%a6) 15875 mov.w %d1,FP_SCR1_EX(%a6) 15876 15877 andi.w &0x7fff,%d0 15878 andi.w &0x7fff,%d1 15879 mov.w %d0,L_SCR1(%a6) # store src exponent 15880 mov.w %d1,2+L_SCR1(%a6) # store dst exponent 15881 15882 cmp.w %d0, %d1 # is src exp >= dst exp? 15883 bge.l src_exp_ge2 15884 15885# dst exp is > src exp; scale dst to exp = 0x3fff 15886dst_exp_gt2: 15887 bsr.l scale_to_zero_dst 15888 mov.l %d0,-(%sp) # save scale factor 15889 15890 cmpi.b STAG(%a6),&DENORM # is dst denormalized? 15891 bne.b cmpexp12 15892 15893 lea FP_SCR0(%a6),%a0 15894 bsr.l norm # normalize the denorm; result is new exp 15895 neg.w %d0 # new exp = -(shft val) 15896 mov.w %d0,L_SCR1(%a6) # inset new exp 15897 15898cmpexp12: 15899 mov.w 2+L_SCR1(%a6),%d0 15900 subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp 15901 15902 cmp.w %d0,L_SCR1(%a6) # is difference >= len(mantissa)+2? 15903 bge.b quick_scale12 15904 15905 mov.w L_SCR1(%a6),%d0 15906 add.w 0x2(%sp),%d0 # scale src exponent by scale factor 15907 mov.w FP_SCR0_EX(%a6),%d1 15908 and.w &0x8000,%d1 15909 or.w %d1,%d0 # concat {sgn,new exp} 15910 mov.w %d0,FP_SCR0_EX(%a6) # insert new dst exponent 15911 15912 mov.l (%sp)+,%d0 # return SCALE factor 15913 rts 15914 15915quick_scale12: 15916 andi.w &0x8000,FP_SCR0_EX(%a6) # zero src exponent 15917 bset &0x0,1+FP_SCR0_EX(%a6) # set exp = 1 15918 15919 mov.l (%sp)+,%d0 # return SCALE factor 15920 rts 15921 15922# src exp is >= dst exp; scale src to exp = 0x3fff 15923src_exp_ge2: 15924 bsr.l scale_to_zero_src 15925 mov.l %d0,-(%sp) # save scale factor 15926 15927 cmpi.b DTAG(%a6),&DENORM # is dst denormalized? 15928 bne.b cmpexp22 15929 lea FP_SCR1(%a6),%a0 15930 bsr.l norm # normalize the denorm; result is new exp 15931 neg.w %d0 # new exp = -(shft val) 15932 mov.w %d0,2+L_SCR1(%a6) # inset new exp 15933 15934cmpexp22: 15935 mov.w L_SCR1(%a6),%d0 15936 subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp 15937 15938 cmp.w %d0,2+L_SCR1(%a6) # is difference >= len(mantissa)+2? 15939 bge.b quick_scale22 15940 15941 mov.w 2+L_SCR1(%a6),%d0 15942 add.w 0x2(%sp),%d0 # scale dst exponent by scale factor 15943 mov.w FP_SCR1_EX(%a6),%d1 15944 andi.w &0x8000,%d1 15945 or.w %d1,%d0 # concat {sgn,new exp} 15946 mov.w %d0,FP_SCR1_EX(%a6) # insert new dst exponent 15947 15948 mov.l (%sp)+,%d0 # return SCALE factor 15949 rts 15950 15951quick_scale22: 15952 andi.w &0x8000,FP_SCR1_EX(%a6) # zero dst exponent 15953 bset &0x0,1+FP_SCR1_EX(%a6) # set exp = 1 15954 15955 mov.l (%sp)+,%d0 # return SCALE factor 15956 rts 15957 15958########################################################################## 15959 15960######################################################################### 15961# XDEF **************************************************************** # 15962# scale_to_zero_src(): scale the exponent of extended precision # 15963# value at FP_SCR0(a6). # 15964# # 15965# XREF **************************************************************** # 15966# norm() - normalize the mantissa if the operand was a DENORM # 15967# # 15968# INPUT *************************************************************** # 15969# FP_SCR0(a6) = extended precision operand to be scaled # 15970# # 15971# OUTPUT ************************************************************** # 15972# FP_SCR0(a6) = scaled extended precision operand # 15973# d0 = scale value # 15974# # 15975# ALGORITHM *********************************************************** # 15976# Set the exponent of the input operand to 0x3fff. Save the value # 15977# of the difference between the original and new exponent. Then, # 15978# normalize the operand if it was a DENORM. Add this normalization # 15979# value to the previous value. Return the result. # 15980# # 15981######################################################################### 15982 15983 global scale_to_zero_src 15984scale_to_zero_src: 15985 mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp} 15986 mov.w %d1,%d0 # make a copy 15987 15988 andi.l &0x7fff,%d1 # extract operand's exponent 15989 15990 andi.w &0x8000,%d0 # extract operand's sgn 15991 or.w &0x3fff,%d0 # insert new operand's exponent(=0) 15992 15993 mov.w %d0,FP_SCR0_EX(%a6) # insert biased exponent 15994 15995 cmpi.b STAG(%a6),&DENORM # is operand normalized? 15996 beq.b stzs_denorm # normalize the DENORM 15997 15998stzs_norm: 15999 mov.l &0x3fff,%d0 16000 sub.l %d1,%d0 # scale = BIAS + (-exp) 16001 16002 rts 16003 16004stzs_denorm: 16005 lea FP_SCR0(%a6),%a0 # pass ptr to src op 16006 bsr.l norm # normalize denorm 16007 neg.l %d0 # new exponent = -(shft val) 16008 mov.l %d0,%d1 # prepare for op_norm call 16009 bra.b stzs_norm # finish scaling 16010 16011### 16012 16013######################################################################### 16014# XDEF **************************************************************** # 16015# scale_sqrt(): scale the input operand exponent so a subsequent # 16016# fsqrt operation won't take an exception. # 16017# # 16018# XREF **************************************************************** # 16019# norm() - normalize the mantissa if the operand was a DENORM # 16020# # 16021# INPUT *************************************************************** # 16022# FP_SCR0(a6) = extended precision operand to be scaled # 16023# # 16024# OUTPUT ************************************************************** # 16025# FP_SCR0(a6) = scaled extended precision operand # 16026# d0 = scale value # 16027# # 16028# ALGORITHM *********************************************************** # 16029# If the input operand is a DENORM, normalize it. # 16030# If the exponent of the input operand is even, set the exponent # 16031# to 0x3ffe and return a scale factor of "(exp-0x3ffe)/2". If the # 16032# exponent of the input operand is off, set the exponent to ox3fff and # 16033# return a scale factor of "(exp-0x3fff)/2". # 16034# # 16035######################################################################### 16036 16037 global scale_sqrt 16038scale_sqrt: 16039 cmpi.b STAG(%a6),&DENORM # is operand normalized? 16040 beq.b ss_denorm # normalize the DENORM 16041 16042 mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp} 16043 andi.l &0x7fff,%d1 # extract operand's exponent 16044 16045 andi.w &0x8000,FP_SCR0_EX(%a6) # extract operand's sgn 16046 16047 btst &0x0,%d1 # is exp even or odd? 16048 beq.b ss_norm_even 16049 16050 ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 16051 16052 mov.l &0x3fff,%d0 16053 sub.l %d1,%d0 # scale = BIAS + (-exp) 16054 asr.l &0x1,%d0 # divide scale factor by 2 16055 rts 16056 16057ss_norm_even: 16058 ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 16059 16060 mov.l &0x3ffe,%d0 16061 sub.l %d1,%d0 # scale = BIAS + (-exp) 16062 asr.l &0x1,%d0 # divide scale factor by 2 16063 rts 16064 16065ss_denorm: 16066 lea FP_SCR0(%a6),%a0 # pass ptr to src op 16067 bsr.l norm # normalize denorm 16068 16069 btst &0x0,%d0 # is exp even or odd? 16070 beq.b ss_denorm_even 16071 16072 ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 16073 16074 add.l &0x3fff,%d0 16075 asr.l &0x1,%d0 # divide scale factor by 2 16076 rts 16077 16078ss_denorm_even: 16079 ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 16080 16081 add.l &0x3ffe,%d0 16082 asr.l &0x1,%d0 # divide scale factor by 2 16083 rts 16084 16085### 16086 16087######################################################################### 16088# XDEF **************************************************************** # 16089# scale_to_zero_dst(): scale the exponent of extended precision # 16090# value at FP_SCR1(a6). # 16091# # 16092# XREF **************************************************************** # 16093# norm() - normalize the mantissa if the operand was a DENORM # 16094# # 16095# INPUT *************************************************************** # 16096# FP_SCR1(a6) = extended precision operand to be scaled # 16097# # 16098# OUTPUT ************************************************************** # 16099# FP_SCR1(a6) = scaled extended precision operand # 16100# d0 = scale value # 16101# # 16102# ALGORITHM *********************************************************** # 16103# Set the exponent of the input operand to 0x3fff. Save the value # 16104# of the difference between the original and new exponent. Then, # 16105# normalize the operand if it was a DENORM. Add this normalization # 16106# value to the previous value. Return the result. # 16107# # 16108######################################################################### 16109 16110 global scale_to_zero_dst 16111scale_to_zero_dst: 16112 mov.w FP_SCR1_EX(%a6),%d1 # extract operand's {sgn,exp} 16113 mov.w %d1,%d0 # make a copy 16114 16115 andi.l &0x7fff,%d1 # extract operand's exponent 16116 16117 andi.w &0x8000,%d0 # extract operand's sgn 16118 or.w &0x3fff,%d0 # insert new operand's exponent(=0) 16119 16120 mov.w %d0,FP_SCR1_EX(%a6) # insert biased exponent 16121 16122 cmpi.b DTAG(%a6),&DENORM # is operand normalized? 16123 beq.b stzd_denorm # normalize the DENORM 16124 16125stzd_norm: 16126 mov.l &0x3fff,%d0 16127 sub.l %d1,%d0 # scale = BIAS + (-exp) 16128 rts 16129 16130stzd_denorm: 16131 lea FP_SCR1(%a6),%a0 # pass ptr to dst op 16132 bsr.l norm # normalize denorm 16133 neg.l %d0 # new exponent = -(shft val) 16134 mov.l %d0,%d1 # prepare for op_norm call 16135 bra.b stzd_norm # finish scaling 16136 16137########################################################################## 16138 16139######################################################################### 16140# XDEF **************************************************************** # 16141# res_qnan(): return default result w/ QNAN operand for dyadic # 16142# res_snan(): return default result w/ SNAN operand for dyadic # 16143# res_qnan_1op(): return dflt result w/ QNAN operand for monadic # 16144# res_snan_1op(): return dflt result w/ SNAN operand for monadic # 16145# # 16146# XREF **************************************************************** # 16147# None # 16148# # 16149# INPUT *************************************************************** # 16150# FP_SRC(a6) = pointer to extended precision src operand # 16151# FP_DST(a6) = pointer to extended precision dst operand # 16152# # 16153# OUTPUT ************************************************************** # 16154# fp0 = default result # 16155# # 16156# ALGORITHM *********************************************************** # 16157# If either operand (but not both operands) of an operation is a # 16158# nonsignalling NAN, then that NAN is returned as the result. If both # 16159# operands are nonsignalling NANs, then the destination operand # 16160# nonsignalling NAN is returned as the result. # 16161# If either operand to an operation is a signalling NAN (SNAN), # 16162# then, the SNAN bit is set in the FPSR EXC byte. If the SNAN trap # 16163# enable bit is set in the FPCR, then the trap is taken and the # 16164# destination is not modified. If the SNAN trap enable bit is not set, # 16165# then the SNAN is converted to a nonsignalling NAN (by setting the # 16166# SNAN bit in the operand to one), and the operation continues as # 16167# described in the preceding paragraph, for nonsignalling NANs. # 16168# Make sure the appropriate FPSR bits are set before exiting. # 16169# # 16170######################################################################### 16171 16172 global res_qnan 16173 global res_snan 16174res_qnan: 16175res_snan: 16176 cmp.b DTAG(%a6), &SNAN # is the dst an SNAN? 16177 beq.b dst_snan2 16178 cmp.b DTAG(%a6), &QNAN # is the dst a QNAN? 16179 beq.b dst_qnan2 16180src_nan: 16181 cmp.b STAG(%a6), &QNAN 16182 beq.b src_qnan2 16183 global res_snan_1op 16184res_snan_1op: 16185src_snan2: 16186 bset &0x6, FP_SRC_HI(%a6) # set SNAN bit 16187 or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6) 16188 lea FP_SRC(%a6), %a0 16189 bra.b nan_comp 16190 global res_qnan_1op 16191res_qnan_1op: 16192src_qnan2: 16193 or.l &nan_mask, USER_FPSR(%a6) 16194 lea FP_SRC(%a6), %a0 16195 bra.b nan_comp 16196dst_snan2: 16197 or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6) 16198 bset &0x6, FP_DST_HI(%a6) # set SNAN bit 16199 lea FP_DST(%a6), %a0 16200 bra.b nan_comp 16201dst_qnan2: 16202 lea FP_DST(%a6), %a0 16203 cmp.b STAG(%a6), &SNAN 16204 bne nan_done 16205 or.l &aiop_mask+snan_mask, USER_FPSR(%a6) 16206nan_done: 16207 or.l &nan_mask, USER_FPSR(%a6) 16208nan_comp: 16209 btst &0x7, FTEMP_EX(%a0) # is NAN neg? 16210 beq.b nan_not_neg 16211 or.l &neg_mask, USER_FPSR(%a6) 16212nan_not_neg: 16213 fmovm.x (%a0), &0x80 16214 rts 16215 16216######################################################################### 16217# XDEF **************************************************************** # 16218# res_operr(): return default result during operand error # 16219# # 16220# XREF **************************************************************** # 16221# None # 16222# # 16223# INPUT *************************************************************** # 16224# None # 16225# # 16226# OUTPUT ************************************************************** # 16227# fp0 = default operand error result # 16228# # 16229# ALGORITHM *********************************************************** # 16230# An nonsignalling NAN is returned as the default result when # 16231# an operand error occurs for the following cases: # 16232# # 16233# Multiply: (Infinity x Zero) # 16234# Divide : (Zero / Zero) || (Infinity / Infinity) # 16235# # 16236######################################################################### 16237 16238 global res_operr 16239res_operr: 16240 or.l &nan_mask+operr_mask+aiop_mask, USER_FPSR(%a6) 16241 fmovm.x nan_return(%pc), &0x80 16242 rts 16243 16244nan_return: 16245 long 0x7fff0000, 0xffffffff, 0xffffffff 16246 16247######################################################################### 16248# fdbcc(): routine to emulate the fdbcc instruction # 16249# # 16250# XDEF **************************************************************** # 16251# _fdbcc() # 16252# # 16253# XREF **************************************************************** # 16254# fetch_dreg() - fetch Dn value # 16255# store_dreg_l() - store updated Dn value # 16256# # 16257# INPUT *************************************************************** # 16258# d0 = displacement # 16259# # 16260# OUTPUT ************************************************************** # 16261# none # 16262# # 16263# ALGORITHM *********************************************************** # 16264# This routine checks which conditional predicate is specified by # 16265# the stacked fdbcc instruction opcode and then branches to a routine # 16266# for that predicate. The corresponding fbcc instruction is then used # 16267# to see whether the condition (specified by the stacked FPSR) is true # 16268# or false. # 16269# If a BSUN exception should be indicated, the BSUN and ABSUN # 16270# bits are set in the stacked FPSR. If the BSUN exception is enabled, # 16271# the fbsun_flg is set in the SPCOND_FLG location on the stack. If an # 16272# enabled BSUN should not be flagged and the predicate is true, then # 16273# Dn is fetched and decremented by one. If Dn is not equal to -1, add # 16274# the displacement value to the stacked PC so that when an "rte" is # 16275# finally executed, the branch occurs. # 16276# # 16277######################################################################### 16278 global _fdbcc 16279_fdbcc: 16280 mov.l %d0,L_SCR1(%a6) # save displacement 16281 16282 mov.w EXC_CMDREG(%a6),%d0 # fetch predicate 16283 16284 clr.l %d1 # clear scratch reg 16285 mov.b FPSR_CC(%a6),%d1 # fetch fp ccodes 16286 ror.l &0x8,%d1 # rotate to top byte 16287 fmov.l %d1,%fpsr # insert into FPSR 16288 16289 mov.w (tbl_fdbcc.b,%pc,%d0.w*2),%d1 # load table 16290 jmp (tbl_fdbcc.b,%pc,%d1.w) # jump to fdbcc routine 16291 16292tbl_fdbcc: 16293 short fdbcc_f - tbl_fdbcc # 00 16294 short fdbcc_eq - tbl_fdbcc # 01 16295 short fdbcc_ogt - tbl_fdbcc # 02 16296 short fdbcc_oge - tbl_fdbcc # 03 16297 short fdbcc_olt - tbl_fdbcc # 04 16298 short fdbcc_ole - tbl_fdbcc # 05 16299 short fdbcc_ogl - tbl_fdbcc # 06 16300 short fdbcc_or - tbl_fdbcc # 07 16301 short fdbcc_un - tbl_fdbcc # 08 16302 short fdbcc_ueq - tbl_fdbcc # 09 16303 short fdbcc_ugt - tbl_fdbcc # 10 16304 short fdbcc_uge - tbl_fdbcc # 11 16305 short fdbcc_ult - tbl_fdbcc # 12 16306 short fdbcc_ule - tbl_fdbcc # 13 16307 short fdbcc_neq - tbl_fdbcc # 14 16308 short fdbcc_t - tbl_fdbcc # 15 16309 short fdbcc_sf - tbl_fdbcc # 16 16310 short fdbcc_seq - tbl_fdbcc # 17 16311 short fdbcc_gt - tbl_fdbcc # 18 16312 short fdbcc_ge - tbl_fdbcc # 19 16313 short fdbcc_lt - tbl_fdbcc # 20 16314 short fdbcc_le - tbl_fdbcc # 21 16315 short fdbcc_gl - tbl_fdbcc # 22 16316 short fdbcc_gle - tbl_fdbcc # 23 16317 short fdbcc_ngle - tbl_fdbcc # 24 16318 short fdbcc_ngl - tbl_fdbcc # 25 16319 short fdbcc_nle - tbl_fdbcc # 26 16320 short fdbcc_nlt - tbl_fdbcc # 27 16321 short fdbcc_nge - tbl_fdbcc # 28 16322 short fdbcc_ngt - tbl_fdbcc # 29 16323 short fdbcc_sneq - tbl_fdbcc # 30 16324 short fdbcc_st - tbl_fdbcc # 31 16325 16326######################################################################### 16327# # 16328# IEEE Nonaware tests # 16329# # 16330# For the IEEE nonaware tests, only the false branch changes the # 16331# counter. However, the true branch may set bsun so we check to see # 16332# if the NAN bit is set, in which case BSUN and AIOP will be set. # 16333# # 16334# The cases EQ and NE are shared by the Aware and Nonaware groups # 16335# and are incapable of setting the BSUN exception bit. # 16336# # 16337# Typically, only one of the two possible branch directions could # 16338# have the NAN bit set. # 16339# (This is assuming the mutual exclusiveness of FPSR cc bit groupings # 16340# is preserved.) # 16341# # 16342######################################################################### 16343 16344# 16345# equal: 16346# 16347# Z 16348# 16349fdbcc_eq: 16350 fbeq.w fdbcc_eq_yes # equal? 16351fdbcc_eq_no: 16352 bra.w fdbcc_false # no; go handle counter 16353fdbcc_eq_yes: 16354 rts 16355 16356# 16357# not equal: 16358# _ 16359# Z 16360# 16361fdbcc_neq: 16362 fbneq.w fdbcc_neq_yes # not equal? 16363fdbcc_neq_no: 16364 bra.w fdbcc_false # no; go handle counter 16365fdbcc_neq_yes: 16366 rts 16367 16368# 16369# greater than: 16370# _______ 16371# NANvZvN 16372# 16373fdbcc_gt: 16374 fbgt.w fdbcc_gt_yes # greater than? 16375 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16376 beq.w fdbcc_false # no;go handle counter 16377 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16378 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16379 bne.w fdbcc_bsun # yes; we have an exception 16380 bra.w fdbcc_false # no; go handle counter 16381fdbcc_gt_yes: 16382 rts # do nothing 16383 16384# 16385# not greater than: 16386# 16387# NANvZvN 16388# 16389fdbcc_ngt: 16390 fbngt.w fdbcc_ngt_yes # not greater than? 16391fdbcc_ngt_no: 16392 bra.w fdbcc_false # no; go handle counter 16393fdbcc_ngt_yes: 16394 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16395 beq.b fdbcc_ngt_done # no;go finish 16396 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16397 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16398 bne.w fdbcc_bsun # yes; we have an exception 16399fdbcc_ngt_done: 16400 rts # no; do nothing 16401 16402# 16403# greater than or equal: 16404# _____ 16405# Zv(NANvN) 16406# 16407fdbcc_ge: 16408 fbge.w fdbcc_ge_yes # greater than or equal? 16409fdbcc_ge_no: 16410 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16411 beq.w fdbcc_false # no;go handle counter 16412 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16413 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16414 bne.w fdbcc_bsun # yes; we have an exception 16415 bra.w fdbcc_false # no; go handle counter 16416fdbcc_ge_yes: 16417 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16418 beq.b fdbcc_ge_yes_done # no;go do nothing 16419 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16420 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16421 bne.w fdbcc_bsun # yes; we have an exception 16422fdbcc_ge_yes_done: 16423 rts # do nothing 16424 16425# 16426# not (greater than or equal): 16427# _ 16428# NANv(N^Z) 16429# 16430fdbcc_nge: 16431 fbnge.w fdbcc_nge_yes # not (greater than or equal)? 16432fdbcc_nge_no: 16433 bra.w fdbcc_false # no; go handle counter 16434fdbcc_nge_yes: 16435 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16436 beq.b fdbcc_nge_done # no;go finish 16437 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16438 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16439 bne.w fdbcc_bsun # yes; we have an exception 16440fdbcc_nge_done: 16441 rts # no; do nothing 16442 16443# 16444# less than: 16445# _____ 16446# N^(NANvZ) 16447# 16448fdbcc_lt: 16449 fblt.w fdbcc_lt_yes # less than? 16450fdbcc_lt_no: 16451 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16452 beq.w fdbcc_false # no; go handle counter 16453 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16454 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16455 bne.w fdbcc_bsun # yes; we have an exception 16456 bra.w fdbcc_false # no; go handle counter 16457fdbcc_lt_yes: 16458 rts # do nothing 16459 16460# 16461# not less than: 16462# _ 16463# NANv(ZvN) 16464# 16465fdbcc_nlt: 16466 fbnlt.w fdbcc_nlt_yes # not less than? 16467fdbcc_nlt_no: 16468 bra.w fdbcc_false # no; go handle counter 16469fdbcc_nlt_yes: 16470 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16471 beq.b fdbcc_nlt_done # no;go finish 16472 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16473 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16474 bne.w fdbcc_bsun # yes; we have an exception 16475fdbcc_nlt_done: 16476 rts # no; do nothing 16477 16478# 16479# less than or equal: 16480# ___ 16481# Zv(N^NAN) 16482# 16483fdbcc_le: 16484 fble.w fdbcc_le_yes # less than or equal? 16485fdbcc_le_no: 16486 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16487 beq.w fdbcc_false # no; go handle counter 16488 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16489 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16490 bne.w fdbcc_bsun # yes; we have an exception 16491 bra.w fdbcc_false # no; go handle counter 16492fdbcc_le_yes: 16493 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16494 beq.b fdbcc_le_yes_done # no; go do nothing 16495 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16496 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16497 bne.w fdbcc_bsun # yes; we have an exception 16498fdbcc_le_yes_done: 16499 rts # do nothing 16500 16501# 16502# not (less than or equal): 16503# ___ 16504# NANv(NvZ) 16505# 16506fdbcc_nle: 16507 fbnle.w fdbcc_nle_yes # not (less than or equal)? 16508fdbcc_nle_no: 16509 bra.w fdbcc_false # no; go handle counter 16510fdbcc_nle_yes: 16511 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16512 beq.w fdbcc_nle_done # no; go finish 16513 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16514 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16515 bne.w fdbcc_bsun # yes; we have an exception 16516fdbcc_nle_done: 16517 rts # no; do nothing 16518 16519# 16520# greater or less than: 16521# _____ 16522# NANvZ 16523# 16524fdbcc_gl: 16525 fbgl.w fdbcc_gl_yes # greater or less than? 16526fdbcc_gl_no: 16527 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16528 beq.w fdbcc_false # no; handle counter 16529 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16530 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16531 bne.w fdbcc_bsun # yes; we have an exception 16532 bra.w fdbcc_false # no; go handle counter 16533fdbcc_gl_yes: 16534 rts # do nothing 16535 16536# 16537# not (greater or less than): 16538# 16539# NANvZ 16540# 16541fdbcc_ngl: 16542 fbngl.w fdbcc_ngl_yes # not (greater or less than)? 16543fdbcc_ngl_no: 16544 bra.w fdbcc_false # no; go handle counter 16545fdbcc_ngl_yes: 16546 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16547 beq.b fdbcc_ngl_done # no; go finish 16548 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16549 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16550 bne.w fdbcc_bsun # yes; we have an exception 16551fdbcc_ngl_done: 16552 rts # no; do nothing 16553 16554# 16555# greater, less, or equal: 16556# ___ 16557# NAN 16558# 16559fdbcc_gle: 16560 fbgle.w fdbcc_gle_yes # greater, less, or equal? 16561fdbcc_gle_no: 16562 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16563 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16564 bne.w fdbcc_bsun # yes; we have an exception 16565 bra.w fdbcc_false # no; go handle counter 16566fdbcc_gle_yes: 16567 rts # do nothing 16568 16569# 16570# not (greater, less, or equal): 16571# 16572# NAN 16573# 16574fdbcc_ngle: 16575 fbngle.w fdbcc_ngle_yes # not (greater, less, or equal)? 16576fdbcc_ngle_no: 16577 bra.w fdbcc_false # no; go handle counter 16578fdbcc_ngle_yes: 16579 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16580 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16581 bne.w fdbcc_bsun # yes; we have an exception 16582 rts # no; do nothing 16583 16584######################################################################### 16585# # 16586# Miscellaneous tests # 16587# # 16588# For the IEEE miscellaneous tests, all but fdbf and fdbt can set bsun. # 16589# # 16590######################################################################### 16591 16592# 16593# false: 16594# 16595# False 16596# 16597fdbcc_f: # no bsun possible 16598 bra.w fdbcc_false # go handle counter 16599 16600# 16601# true: 16602# 16603# True 16604# 16605fdbcc_t: # no bsun possible 16606 rts # do nothing 16607 16608# 16609# signalling false: 16610# 16611# False 16612# 16613fdbcc_sf: 16614 btst &nan_bit, FPSR_CC(%a6) # is NAN set? 16615 beq.w fdbcc_false # no;go handle counter 16616 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16617 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16618 bne.w fdbcc_bsun # yes; we have an exception 16619 bra.w fdbcc_false # go handle counter 16620 16621# 16622# signalling true: 16623# 16624# True 16625# 16626fdbcc_st: 16627 btst &nan_bit, FPSR_CC(%a6) # is NAN set? 16628 beq.b fdbcc_st_done # no;go finish 16629 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16630 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16631 bne.w fdbcc_bsun # yes; we have an exception 16632fdbcc_st_done: 16633 rts 16634 16635# 16636# signalling equal: 16637# 16638# Z 16639# 16640fdbcc_seq: 16641 fbseq.w fdbcc_seq_yes # signalling equal? 16642fdbcc_seq_no: 16643 btst &nan_bit, FPSR_CC(%a6) # is NAN set? 16644 beq.w fdbcc_false # no;go handle counter 16645 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16646 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16647 bne.w fdbcc_bsun # yes; we have an exception 16648 bra.w fdbcc_false # go handle counter 16649fdbcc_seq_yes: 16650 btst &nan_bit, FPSR_CC(%a6) # is NAN set? 16651 beq.b fdbcc_seq_yes_done # no;go do nothing 16652 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16653 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16654 bne.w fdbcc_bsun # yes; we have an exception 16655fdbcc_seq_yes_done: 16656 rts # yes; do nothing 16657 16658# 16659# signalling not equal: 16660# _ 16661# Z 16662# 16663fdbcc_sneq: 16664 fbsneq.w fdbcc_sneq_yes # signalling not equal? 16665fdbcc_sneq_no: 16666 btst &nan_bit, FPSR_CC(%a6) # is NAN set? 16667 beq.w fdbcc_false # no;go handle counter 16668 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16669 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16670 bne.w fdbcc_bsun # yes; we have an exception 16671 bra.w fdbcc_false # go handle counter 16672fdbcc_sneq_yes: 16673 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 16674 beq.w fdbcc_sneq_done # no;go finish 16675 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 16676 btst &bsun_bit, FPCR_ENABLE(%a6) # is BSUN enabled? 16677 bne.w fdbcc_bsun # yes; we have an exception 16678fdbcc_sneq_done: 16679 rts 16680 16681######################################################################### 16682# # 16683# IEEE Aware tests # 16684# # 16685# For the IEEE aware tests, action is only taken if the result is false.# 16686# Therefore, the opposite branch type is used to jump to the decrement # 16687# routine. # 16688# The BSUN exception will not be set for any of these tests. # 16689# # 16690######################################################################### 16691 16692# 16693# ordered greater than: 16694# _______ 16695# NANvZvN 16696# 16697fdbcc_ogt: 16698 fbogt.w fdbcc_ogt_yes # ordered greater than? 16699fdbcc_ogt_no: 16700 bra.w fdbcc_false # no; go handle counter 16701fdbcc_ogt_yes: 16702 rts # yes; do nothing 16703 16704# 16705# unordered or less or equal: 16706# _______ 16707# NANvZvN 16708# 16709fdbcc_ule: 16710 fbule.w fdbcc_ule_yes # unordered or less or equal? 16711fdbcc_ule_no: 16712 bra.w fdbcc_false # no; go handle counter 16713fdbcc_ule_yes: 16714 rts # yes; do nothing 16715 16716# 16717# ordered greater than or equal: 16718# _____ 16719# Zv(NANvN) 16720# 16721fdbcc_oge: 16722 fboge.w fdbcc_oge_yes # ordered greater than or equal? 16723fdbcc_oge_no: 16724 bra.w fdbcc_false # no; go handle counter 16725fdbcc_oge_yes: 16726 rts # yes; do nothing 16727 16728# 16729# unordered or less than: 16730# _ 16731# NANv(N^Z) 16732# 16733fdbcc_ult: 16734 fbult.w fdbcc_ult_yes # unordered or less than? 16735fdbcc_ult_no: 16736 bra.w fdbcc_false # no; go handle counter 16737fdbcc_ult_yes: 16738 rts # yes; do nothing 16739 16740# 16741# ordered less than: 16742# _____ 16743# N^(NANvZ) 16744# 16745fdbcc_olt: 16746 fbolt.w fdbcc_olt_yes # ordered less than? 16747fdbcc_olt_no: 16748 bra.w fdbcc_false # no; go handle counter 16749fdbcc_olt_yes: 16750 rts # yes; do nothing 16751 16752# 16753# unordered or greater or equal: 16754# 16755# NANvZvN 16756# 16757fdbcc_uge: 16758 fbuge.w fdbcc_uge_yes # unordered or greater than? 16759fdbcc_uge_no: 16760 bra.w fdbcc_false # no; go handle counter 16761fdbcc_uge_yes: 16762 rts # yes; do nothing 16763 16764# 16765# ordered less than or equal: 16766# ___ 16767# Zv(N^NAN) 16768# 16769fdbcc_ole: 16770 fbole.w fdbcc_ole_yes # ordered greater or less than? 16771fdbcc_ole_no: 16772 bra.w fdbcc_false # no; go handle counter 16773fdbcc_ole_yes: 16774 rts # yes; do nothing 16775 16776# 16777# unordered or greater than: 16778# ___ 16779# NANv(NvZ) 16780# 16781fdbcc_ugt: 16782 fbugt.w fdbcc_ugt_yes # unordered or greater than? 16783fdbcc_ugt_no: 16784 bra.w fdbcc_false # no; go handle counter 16785fdbcc_ugt_yes: 16786 rts # yes; do nothing 16787 16788# 16789# ordered greater or less than: 16790# _____ 16791# NANvZ 16792# 16793fdbcc_ogl: 16794 fbogl.w fdbcc_ogl_yes # ordered greater or less than? 16795fdbcc_ogl_no: 16796 bra.w fdbcc_false # no; go handle counter 16797fdbcc_ogl_yes: 16798 rts # yes; do nothing 16799 16800# 16801# unordered or equal: 16802# 16803# NANvZ 16804# 16805fdbcc_ueq: 16806 fbueq.w fdbcc_ueq_yes # unordered or equal? 16807fdbcc_ueq_no: 16808 bra.w fdbcc_false # no; go handle counter 16809fdbcc_ueq_yes: 16810 rts # yes; do nothing 16811 16812# 16813# ordered: 16814# ___ 16815# NAN 16816# 16817fdbcc_or: 16818 fbor.w fdbcc_or_yes # ordered? 16819fdbcc_or_no: 16820 bra.w fdbcc_false # no; go handle counter 16821fdbcc_or_yes: 16822 rts # yes; do nothing 16823 16824# 16825# unordered: 16826# 16827# NAN 16828# 16829fdbcc_un: 16830 fbun.w fdbcc_un_yes # unordered? 16831fdbcc_un_no: 16832 bra.w fdbcc_false # no; go handle counter 16833fdbcc_un_yes: 16834 rts # yes; do nothing 16835 16836####################################################################### 16837 16838# 16839# the bsun exception bit was not set. 16840# 16841# (1) subtract 1 from the count register 16842# (2) if (cr == -1) then 16843# pc = pc of next instruction 16844# else 16845# pc += sign_ext(16-bit displacement) 16846# 16847fdbcc_false: 16848 mov.b 1+EXC_OPWORD(%a6), %d1 # fetch lo opword 16849 andi.w &0x7, %d1 # extract count register 16850 16851 bsr.l fetch_dreg # fetch count value 16852# make sure that d0 isn't corrupted between calls... 16853 16854 subq.w &0x1, %d0 # Dn - 1 -> Dn 16855 16856 bsr.l store_dreg_l # store new count value 16857 16858 cmpi.w %d0, &-0x1 # is (Dn == -1)? 16859 bne.b fdbcc_false_cont # no; 16860 rts 16861 16862fdbcc_false_cont: 16863 mov.l L_SCR1(%a6),%d0 # fetch displacement 16864 add.l USER_FPIAR(%a6),%d0 # add instruction PC 16865 addq.l &0x4,%d0 # add instruction length 16866 mov.l %d0,EXC_PC(%a6) # set new PC 16867 rts 16868 16869# the emulation routine set bsun and BSUN was enabled. have to 16870# fix stack and jump to the bsun handler. 16871# let the caller of this routine shift the stack frame up to 16872# eliminate the effective address field. 16873fdbcc_bsun: 16874 mov.b &fbsun_flg,SPCOND_FLG(%a6) 16875 rts 16876 16877######################################################################### 16878# ftrapcc(): routine to emulate the ftrapcc instruction # 16879# # 16880# XDEF **************************************************************** # 16881# _ftrapcc() # 16882# # 16883# XREF **************************************************************** # 16884# none # 16885# # 16886# INPUT *************************************************************** # 16887# none # 16888# # 16889# OUTPUT ************************************************************** # 16890# none # 16891# # 16892# ALGORITHM *********************************************************** # 16893# This routine checks which conditional predicate is specified by # 16894# the stacked ftrapcc instruction opcode and then branches to a routine # 16895# for that predicate. The corresponding fbcc instruction is then used # 16896# to see whether the condition (specified by the stacked FPSR) is true # 16897# or false. # 16898# If a BSUN exception should be indicated, the BSUN and ABSUN # 16899# bits are set in the stacked FPSR. If the BSUN exception is enabled, # 16900# the fbsun_flg is set in the SPCOND_FLG location on the stack. If an # 16901# enabled BSUN should not be flagged and the predicate is true, then # 16902# the ftrapcc_flg is set in the SPCOND_FLG location. These special # 16903# flags indicate to the calling routine to emulate the exceptional # 16904# condition. # 16905# # 16906######################################################################### 16907 16908 global _ftrapcc 16909_ftrapcc: 16910 mov.w EXC_CMDREG(%a6),%d0 # fetch predicate 16911 16912 clr.l %d1 # clear scratch reg 16913 mov.b FPSR_CC(%a6),%d1 # fetch fp ccodes 16914 ror.l &0x8,%d1 # rotate to top byte 16915 fmov.l %d1,%fpsr # insert into FPSR 16916 16917 mov.w (tbl_ftrapcc.b,%pc,%d0.w*2), %d1 # load table 16918 jmp (tbl_ftrapcc.b,%pc,%d1.w) # jump to ftrapcc routine 16919 16920tbl_ftrapcc: 16921 short ftrapcc_f - tbl_ftrapcc # 00 16922 short ftrapcc_eq - tbl_ftrapcc # 01 16923 short ftrapcc_ogt - tbl_ftrapcc # 02 16924 short ftrapcc_oge - tbl_ftrapcc # 03 16925 short ftrapcc_olt - tbl_ftrapcc # 04 16926 short ftrapcc_ole - tbl_ftrapcc # 05 16927 short ftrapcc_ogl - tbl_ftrapcc # 06 16928 short ftrapcc_or - tbl_ftrapcc # 07 16929 short ftrapcc_un - tbl_ftrapcc # 08 16930 short ftrapcc_ueq - tbl_ftrapcc # 09 16931 short ftrapcc_ugt - tbl_ftrapcc # 10 16932 short ftrapcc_uge - tbl_ftrapcc # 11 16933 short ftrapcc_ult - tbl_ftrapcc # 12 16934 short ftrapcc_ule - tbl_ftrapcc # 13 16935 short ftrapcc_neq - tbl_ftrapcc # 14 16936 short ftrapcc_t - tbl_ftrapcc # 15 16937 short ftrapcc_sf - tbl_ftrapcc # 16 16938 short ftrapcc_seq - tbl_ftrapcc # 17 16939 short ftrapcc_gt - tbl_ftrapcc # 18 16940 short ftrapcc_ge - tbl_ftrapcc # 19 16941 short ftrapcc_lt - tbl_ftrapcc # 20 16942 short ftrapcc_le - tbl_ftrapcc # 21 16943 short ftrapcc_gl - tbl_ftrapcc # 22 16944 short ftrapcc_gle - tbl_ftrapcc # 23 16945 short ftrapcc_ngle - tbl_ftrapcc # 24 16946 short ftrapcc_ngl - tbl_ftrapcc # 25 16947 short ftrapcc_nle - tbl_ftrapcc # 26 16948 short ftrapcc_nlt - tbl_ftrapcc # 27 16949 short ftrapcc_nge - tbl_ftrapcc # 28 16950 short ftrapcc_ngt - tbl_ftrapcc # 29 16951 short ftrapcc_sneq - tbl_ftrapcc # 30 16952 short ftrapcc_st - tbl_ftrapcc # 31 16953 16954######################################################################### 16955# # 16956# IEEE Nonaware tests # 16957# # 16958# For the IEEE nonaware tests, we set the result based on the # 16959# floating point condition codes. In addition, we check to see # 16960# if the NAN bit is set, in which case BSUN and AIOP will be set. # 16961# # 16962# The cases EQ and NE are shared by the Aware and Nonaware groups # 16963# and are incapable of setting the BSUN exception bit. # 16964# # 16965# Typically, only one of the two possible branch directions could # 16966# have the NAN bit set. # 16967# # 16968######################################################################### 16969 16970# 16971# equal: 16972# 16973# Z 16974# 16975ftrapcc_eq: 16976 fbeq.w ftrapcc_trap # equal? 16977ftrapcc_eq_no: 16978 rts # do nothing 16979 16980# 16981# not equal: 16982# _ 16983# Z 16984# 16985ftrapcc_neq: 16986 fbneq.w ftrapcc_trap # not equal? 16987ftrapcc_neq_no: 16988 rts # do nothing 16989 16990# 16991# greater than: 16992# _______ 16993# NANvZvN 16994# 16995ftrapcc_gt: 16996 fbgt.w ftrapcc_trap # greater than? 16997ftrapcc_gt_no: 16998 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 16999 beq.b ftrapcc_gt_done # no 17000 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17001 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17002 bne.w ftrapcc_bsun # yes 17003ftrapcc_gt_done: 17004 rts # no; do nothing 17005 17006# 17007# not greater than: 17008# 17009# NANvZvN 17010# 17011ftrapcc_ngt: 17012 fbngt.w ftrapcc_ngt_yes # not greater than? 17013ftrapcc_ngt_no: 17014 rts # do nothing 17015ftrapcc_ngt_yes: 17016 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17017 beq.w ftrapcc_trap # no; go take trap 17018 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17019 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17020 bne.w ftrapcc_bsun # yes 17021 bra.w ftrapcc_trap # no; go take trap 17022 17023# 17024# greater than or equal: 17025# _____ 17026# Zv(NANvN) 17027# 17028ftrapcc_ge: 17029 fbge.w ftrapcc_ge_yes # greater than or equal? 17030ftrapcc_ge_no: 17031 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17032 beq.b ftrapcc_ge_done # no; go finish 17033 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17034 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17035 bne.w ftrapcc_bsun # yes 17036ftrapcc_ge_done: 17037 rts # no; do nothing 17038ftrapcc_ge_yes: 17039 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17040 beq.w ftrapcc_trap # no; go take trap 17041 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17042 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17043 bne.w ftrapcc_bsun # yes 17044 bra.w ftrapcc_trap # no; go take trap 17045 17046# 17047# not (greater than or equal): 17048# _ 17049# NANv(N^Z) 17050# 17051ftrapcc_nge: 17052 fbnge.w ftrapcc_nge_yes # not (greater than or equal)? 17053ftrapcc_nge_no: 17054 rts # do nothing 17055ftrapcc_nge_yes: 17056 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17057 beq.w ftrapcc_trap # no; go take trap 17058 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17059 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17060 bne.w ftrapcc_bsun # yes 17061 bra.w ftrapcc_trap # no; go take trap 17062 17063# 17064# less than: 17065# _____ 17066# N^(NANvZ) 17067# 17068ftrapcc_lt: 17069 fblt.w ftrapcc_trap # less than? 17070ftrapcc_lt_no: 17071 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17072 beq.b ftrapcc_lt_done # no; go finish 17073 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17074 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17075 bne.w ftrapcc_bsun # yes 17076ftrapcc_lt_done: 17077 rts # no; do nothing 17078 17079# 17080# not less than: 17081# _ 17082# NANv(ZvN) 17083# 17084ftrapcc_nlt: 17085 fbnlt.w ftrapcc_nlt_yes # not less than? 17086ftrapcc_nlt_no: 17087 rts # do nothing 17088ftrapcc_nlt_yes: 17089 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17090 beq.w ftrapcc_trap # no; go take trap 17091 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17092 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17093 bne.w ftrapcc_bsun # yes 17094 bra.w ftrapcc_trap # no; go take trap 17095 17096# 17097# less than or equal: 17098# ___ 17099# Zv(N^NAN) 17100# 17101ftrapcc_le: 17102 fble.w ftrapcc_le_yes # less than or equal? 17103ftrapcc_le_no: 17104 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17105 beq.b ftrapcc_le_done # no; go finish 17106 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17107 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17108 bne.w ftrapcc_bsun # yes 17109ftrapcc_le_done: 17110 rts # no; do nothing 17111ftrapcc_le_yes: 17112 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17113 beq.w ftrapcc_trap # no; go take trap 17114 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17115 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17116 bne.w ftrapcc_bsun # yes 17117 bra.w ftrapcc_trap # no; go take trap 17118 17119# 17120# not (less than or equal): 17121# ___ 17122# NANv(NvZ) 17123# 17124ftrapcc_nle: 17125 fbnle.w ftrapcc_nle_yes # not (less than or equal)? 17126ftrapcc_nle_no: 17127 rts # do nothing 17128ftrapcc_nle_yes: 17129 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17130 beq.w ftrapcc_trap # no; go take trap 17131 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17132 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17133 bne.w ftrapcc_bsun # yes 17134 bra.w ftrapcc_trap # no; go take trap 17135 17136# 17137# greater or less than: 17138# _____ 17139# NANvZ 17140# 17141ftrapcc_gl: 17142 fbgl.w ftrapcc_trap # greater or less than? 17143ftrapcc_gl_no: 17144 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17145 beq.b ftrapcc_gl_done # no; go finish 17146 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17147 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17148 bne.w ftrapcc_bsun # yes 17149ftrapcc_gl_done: 17150 rts # no; do nothing 17151 17152# 17153# not (greater or less than): 17154# 17155# NANvZ 17156# 17157ftrapcc_ngl: 17158 fbngl.w ftrapcc_ngl_yes # not (greater or less than)? 17159ftrapcc_ngl_no: 17160 rts # do nothing 17161ftrapcc_ngl_yes: 17162 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17163 beq.w ftrapcc_trap # no; go take trap 17164 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17165 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17166 bne.w ftrapcc_bsun # yes 17167 bra.w ftrapcc_trap # no; go take trap 17168 17169# 17170# greater, less, or equal: 17171# ___ 17172# NAN 17173# 17174ftrapcc_gle: 17175 fbgle.w ftrapcc_trap # greater, less, or equal? 17176ftrapcc_gle_no: 17177 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17178 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17179 bne.w ftrapcc_bsun # yes 17180 rts # no; do nothing 17181 17182# 17183# not (greater, less, or equal): 17184# 17185# NAN 17186# 17187ftrapcc_ngle: 17188 fbngle.w ftrapcc_ngle_yes # not (greater, less, or equal)? 17189ftrapcc_ngle_no: 17190 rts # do nothing 17191ftrapcc_ngle_yes: 17192 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17193 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17194 bne.w ftrapcc_bsun # yes 17195 bra.w ftrapcc_trap # no; go take trap 17196 17197######################################################################### 17198# # 17199# Miscellaneous tests # 17200# # 17201# For the IEEE aware tests, we only have to set the result based on the # 17202# floating point condition codes. The BSUN exception will not be # 17203# set for any of these tests. # 17204# # 17205######################################################################### 17206 17207# 17208# false: 17209# 17210# False 17211# 17212ftrapcc_f: 17213 rts # do nothing 17214 17215# 17216# true: 17217# 17218# True 17219# 17220ftrapcc_t: 17221 bra.w ftrapcc_trap # go take trap 17222 17223# 17224# signalling false: 17225# 17226# False 17227# 17228ftrapcc_sf: 17229 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17230 beq.b ftrapcc_sf_done # no; go finish 17231 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17232 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17233 bne.w ftrapcc_bsun # yes 17234ftrapcc_sf_done: 17235 rts # no; do nothing 17236 17237# 17238# signalling true: 17239# 17240# True 17241# 17242ftrapcc_st: 17243 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17244 beq.w ftrapcc_trap # no; go take trap 17245 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17246 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17247 bne.w ftrapcc_bsun # yes 17248 bra.w ftrapcc_trap # no; go take trap 17249 17250# 17251# signalling equal: 17252# 17253# Z 17254# 17255ftrapcc_seq: 17256 fbseq.w ftrapcc_seq_yes # signalling equal? 17257ftrapcc_seq_no: 17258 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17259 beq.w ftrapcc_seq_done # no; go finish 17260 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17261 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17262 bne.w ftrapcc_bsun # yes 17263ftrapcc_seq_done: 17264 rts # no; do nothing 17265ftrapcc_seq_yes: 17266 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17267 beq.w ftrapcc_trap # no; go take trap 17268 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17269 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17270 bne.w ftrapcc_bsun # yes 17271 bra.w ftrapcc_trap # no; go take trap 17272 17273# 17274# signalling not equal: 17275# _ 17276# Z 17277# 17278ftrapcc_sneq: 17279 fbsneq.w ftrapcc_sneq_yes # signalling equal? 17280ftrapcc_sneq_no: 17281 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17282 beq.w ftrapcc_sneq_no_done # no; go finish 17283 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17284 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17285 bne.w ftrapcc_bsun # yes 17286ftrapcc_sneq_no_done: 17287 rts # do nothing 17288ftrapcc_sneq_yes: 17289 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17290 beq.w ftrapcc_trap # no; go take trap 17291 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17292 btst &bsun_bit, FPCR_ENABLE(%a6) # was BSUN set? 17293 bne.w ftrapcc_bsun # yes 17294 bra.w ftrapcc_trap # no; go take trap 17295 17296######################################################################### 17297# # 17298# IEEE Aware tests # 17299# # 17300# For the IEEE aware tests, we only have to set the result based on the # 17301# floating point condition codes. The BSUN exception will not be # 17302# set for any of these tests. # 17303# # 17304######################################################################### 17305 17306# 17307# ordered greater than: 17308# _______ 17309# NANvZvN 17310# 17311ftrapcc_ogt: 17312 fbogt.w ftrapcc_trap # ordered greater than? 17313ftrapcc_ogt_no: 17314 rts # do nothing 17315 17316# 17317# unordered or less or equal: 17318# _______ 17319# NANvZvN 17320# 17321ftrapcc_ule: 17322 fbule.w ftrapcc_trap # unordered or less or equal? 17323ftrapcc_ule_no: 17324 rts # do nothing 17325 17326# 17327# ordered greater than or equal: 17328# _____ 17329# Zv(NANvN) 17330# 17331ftrapcc_oge: 17332 fboge.w ftrapcc_trap # ordered greater than or equal? 17333ftrapcc_oge_no: 17334 rts # do nothing 17335 17336# 17337# unordered or less than: 17338# _ 17339# NANv(N^Z) 17340# 17341ftrapcc_ult: 17342 fbult.w ftrapcc_trap # unordered or less than? 17343ftrapcc_ult_no: 17344 rts # do nothing 17345 17346# 17347# ordered less than: 17348# _____ 17349# N^(NANvZ) 17350# 17351ftrapcc_olt: 17352 fbolt.w ftrapcc_trap # ordered less than? 17353ftrapcc_olt_no: 17354 rts # do nothing 17355 17356# 17357# unordered or greater or equal: 17358# 17359# NANvZvN 17360# 17361ftrapcc_uge: 17362 fbuge.w ftrapcc_trap # unordered or greater than? 17363ftrapcc_uge_no: 17364 rts # do nothing 17365 17366# 17367# ordered less than or equal: 17368# ___ 17369# Zv(N^NAN) 17370# 17371ftrapcc_ole: 17372 fbole.w ftrapcc_trap # ordered greater or less than? 17373ftrapcc_ole_no: 17374 rts # do nothing 17375 17376# 17377# unordered or greater than: 17378# ___ 17379# NANv(NvZ) 17380# 17381ftrapcc_ugt: 17382 fbugt.w ftrapcc_trap # unordered or greater than? 17383ftrapcc_ugt_no: 17384 rts # do nothing 17385 17386# 17387# ordered greater or less than: 17388# _____ 17389# NANvZ 17390# 17391ftrapcc_ogl: 17392 fbogl.w ftrapcc_trap # ordered greater or less than? 17393ftrapcc_ogl_no: 17394 rts # do nothing 17395 17396# 17397# unordered or equal: 17398# 17399# NANvZ 17400# 17401ftrapcc_ueq: 17402 fbueq.w ftrapcc_trap # unordered or equal? 17403ftrapcc_ueq_no: 17404 rts # do nothing 17405 17406# 17407# ordered: 17408# ___ 17409# NAN 17410# 17411ftrapcc_or: 17412 fbor.w ftrapcc_trap # ordered? 17413ftrapcc_or_no: 17414 rts # do nothing 17415 17416# 17417# unordered: 17418# 17419# NAN 17420# 17421ftrapcc_un: 17422 fbun.w ftrapcc_trap # unordered? 17423ftrapcc_un_no: 17424 rts # do nothing 17425 17426####################################################################### 17427 17428# the bsun exception bit was not set. 17429# we will need to jump to the ftrapcc vector. the stack frame 17430# is the same size as that of the fp unimp instruction. the 17431# only difference is that the <ea> field should hold the PC 17432# of the ftrapcc instruction and the vector offset field 17433# should denote the ftrapcc trap. 17434ftrapcc_trap: 17435 mov.b &ftrapcc_flg,SPCOND_FLG(%a6) 17436 rts 17437 17438# the emulation routine set bsun and BSUN was enabled. have to 17439# fix stack and jump to the bsun handler. 17440# let the caller of this routine shift the stack frame up to 17441# eliminate the effective address field. 17442ftrapcc_bsun: 17443 mov.b &fbsun_flg,SPCOND_FLG(%a6) 17444 rts 17445 17446######################################################################### 17447# fscc(): routine to emulate the fscc instruction # 17448# # 17449# XDEF **************************************************************** # 17450# _fscc() # 17451# # 17452# XREF **************************************************************** # 17453# store_dreg_b() - store result to data register file # 17454# dec_areg() - decrement an areg for -(an) mode # 17455# inc_areg() - increment an areg for (an)+ mode # 17456# _dmem_write_byte() - store result to memory # 17457# # 17458# INPUT *************************************************************** # 17459# none # 17460# # 17461# OUTPUT ************************************************************** # 17462# none # 17463# # 17464# ALGORITHM *********************************************************** # 17465# This routine checks which conditional predicate is specified by # 17466# the stacked fscc instruction opcode and then branches to a routine # 17467# for that predicate. The corresponding fbcc instruction is then used # 17468# to see whether the condition (specified by the stacked FPSR) is true # 17469# or false. # 17470# If a BSUN exception should be indicated, the BSUN and ABSUN # 17471# bits are set in the stacked FPSR. If the BSUN exception is enabled, # 17472# the fbsun_flg is set in the SPCOND_FLG location on the stack. If an # 17473# enabled BSUN should not be flagged and the predicate is true, then # 17474# the result is stored to the data register file or memory # 17475# # 17476######################################################################### 17477 17478 global _fscc 17479_fscc: 17480 mov.w EXC_CMDREG(%a6),%d0 # fetch predicate 17481 17482 clr.l %d1 # clear scratch reg 17483 mov.b FPSR_CC(%a6),%d1 # fetch fp ccodes 17484 ror.l &0x8,%d1 # rotate to top byte 17485 fmov.l %d1,%fpsr # insert into FPSR 17486 17487 mov.w (tbl_fscc.b,%pc,%d0.w*2),%d1 # load table 17488 jmp (tbl_fscc.b,%pc,%d1.w) # jump to fscc routine 17489 17490tbl_fscc: 17491 short fscc_f - tbl_fscc # 00 17492 short fscc_eq - tbl_fscc # 01 17493 short fscc_ogt - tbl_fscc # 02 17494 short fscc_oge - tbl_fscc # 03 17495 short fscc_olt - tbl_fscc # 04 17496 short fscc_ole - tbl_fscc # 05 17497 short fscc_ogl - tbl_fscc # 06 17498 short fscc_or - tbl_fscc # 07 17499 short fscc_un - tbl_fscc # 08 17500 short fscc_ueq - tbl_fscc # 09 17501 short fscc_ugt - tbl_fscc # 10 17502 short fscc_uge - tbl_fscc # 11 17503 short fscc_ult - tbl_fscc # 12 17504 short fscc_ule - tbl_fscc # 13 17505 short fscc_neq - tbl_fscc # 14 17506 short fscc_t - tbl_fscc # 15 17507 short fscc_sf - tbl_fscc # 16 17508 short fscc_seq - tbl_fscc # 17 17509 short fscc_gt - tbl_fscc # 18 17510 short fscc_ge - tbl_fscc # 19 17511 short fscc_lt - tbl_fscc # 20 17512 short fscc_le - tbl_fscc # 21 17513 short fscc_gl - tbl_fscc # 22 17514 short fscc_gle - tbl_fscc # 23 17515 short fscc_ngle - tbl_fscc # 24 17516 short fscc_ngl - tbl_fscc # 25 17517 short fscc_nle - tbl_fscc # 26 17518 short fscc_nlt - tbl_fscc # 27 17519 short fscc_nge - tbl_fscc # 28 17520 short fscc_ngt - tbl_fscc # 29 17521 short fscc_sneq - tbl_fscc # 30 17522 short fscc_st - tbl_fscc # 31 17523 17524######################################################################### 17525# # 17526# IEEE Nonaware tests # 17527# # 17528# For the IEEE nonaware tests, we set the result based on the # 17529# floating point condition codes. In addition, we check to see # 17530# if the NAN bit is set, in which case BSUN and AIOP will be set. # 17531# # 17532# The cases EQ and NE are shared by the Aware and Nonaware groups # 17533# and are incapable of setting the BSUN exception bit. # 17534# # 17535# Typically, only one of the two possible branch directions could # 17536# have the NAN bit set. # 17537# # 17538######################################################################### 17539 17540# 17541# equal: 17542# 17543# Z 17544# 17545fscc_eq: 17546 fbeq.w fscc_eq_yes # equal? 17547fscc_eq_no: 17548 clr.b %d0 # set false 17549 bra.w fscc_done # go finish 17550fscc_eq_yes: 17551 st %d0 # set true 17552 bra.w fscc_done # go finish 17553 17554# 17555# not equal: 17556# _ 17557# Z 17558# 17559fscc_neq: 17560 fbneq.w fscc_neq_yes # not equal? 17561fscc_neq_no: 17562 clr.b %d0 # set false 17563 bra.w fscc_done # go finish 17564fscc_neq_yes: 17565 st %d0 # set true 17566 bra.w fscc_done # go finish 17567 17568# 17569# greater than: 17570# _______ 17571# NANvZvN 17572# 17573fscc_gt: 17574 fbgt.w fscc_gt_yes # greater than? 17575fscc_gt_no: 17576 clr.b %d0 # set false 17577 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17578 beq.w fscc_done # no;go finish 17579 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17580 bra.w fscc_chk_bsun # go finish 17581fscc_gt_yes: 17582 st %d0 # set true 17583 bra.w fscc_done # go finish 17584 17585# 17586# not greater than: 17587# 17588# NANvZvN 17589# 17590fscc_ngt: 17591 fbngt.w fscc_ngt_yes # not greater than? 17592fscc_ngt_no: 17593 clr.b %d0 # set false 17594 bra.w fscc_done # go finish 17595fscc_ngt_yes: 17596 st %d0 # set true 17597 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17598 beq.w fscc_done # no;go finish 17599 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17600 bra.w fscc_chk_bsun # go finish 17601 17602# 17603# greater than or equal: 17604# _____ 17605# Zv(NANvN) 17606# 17607fscc_ge: 17608 fbge.w fscc_ge_yes # greater than or equal? 17609fscc_ge_no: 17610 clr.b %d0 # set false 17611 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17612 beq.w fscc_done # no;go finish 17613 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17614 bra.w fscc_chk_bsun # go finish 17615fscc_ge_yes: 17616 st %d0 # set true 17617 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17618 beq.w fscc_done # no;go finish 17619 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17620 bra.w fscc_chk_bsun # go finish 17621 17622# 17623# not (greater than or equal): 17624# _ 17625# NANv(N^Z) 17626# 17627fscc_nge: 17628 fbnge.w fscc_nge_yes # not (greater than or equal)? 17629fscc_nge_no: 17630 clr.b %d0 # set false 17631 bra.w fscc_done # go finish 17632fscc_nge_yes: 17633 st %d0 # set true 17634 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17635 beq.w fscc_done # no;go finish 17636 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17637 bra.w fscc_chk_bsun # go finish 17638 17639# 17640# less than: 17641# _____ 17642# N^(NANvZ) 17643# 17644fscc_lt: 17645 fblt.w fscc_lt_yes # less than? 17646fscc_lt_no: 17647 clr.b %d0 # set false 17648 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17649 beq.w fscc_done # no;go finish 17650 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17651 bra.w fscc_chk_bsun # go finish 17652fscc_lt_yes: 17653 st %d0 # set true 17654 bra.w fscc_done # go finish 17655 17656# 17657# not less than: 17658# _ 17659# NANv(ZvN) 17660# 17661fscc_nlt: 17662 fbnlt.w fscc_nlt_yes # not less than? 17663fscc_nlt_no: 17664 clr.b %d0 # set false 17665 bra.w fscc_done # go finish 17666fscc_nlt_yes: 17667 st %d0 # set true 17668 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17669 beq.w fscc_done # no;go finish 17670 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17671 bra.w fscc_chk_bsun # go finish 17672 17673# 17674# less than or equal: 17675# ___ 17676# Zv(N^NAN) 17677# 17678fscc_le: 17679 fble.w fscc_le_yes # less than or equal? 17680fscc_le_no: 17681 clr.b %d0 # set false 17682 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17683 beq.w fscc_done # no;go finish 17684 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17685 bra.w fscc_chk_bsun # go finish 17686fscc_le_yes: 17687 st %d0 # set true 17688 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17689 beq.w fscc_done # no;go finish 17690 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17691 bra.w fscc_chk_bsun # go finish 17692 17693# 17694# not (less than or equal): 17695# ___ 17696# NANv(NvZ) 17697# 17698fscc_nle: 17699 fbnle.w fscc_nle_yes # not (less than or equal)? 17700fscc_nle_no: 17701 clr.b %d0 # set false 17702 bra.w fscc_done # go finish 17703fscc_nle_yes: 17704 st %d0 # set true 17705 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17706 beq.w fscc_done # no;go finish 17707 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17708 bra.w fscc_chk_bsun # go finish 17709 17710# 17711# greater or less than: 17712# _____ 17713# NANvZ 17714# 17715fscc_gl: 17716 fbgl.w fscc_gl_yes # greater or less than? 17717fscc_gl_no: 17718 clr.b %d0 # set false 17719 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17720 beq.w fscc_done # no;go finish 17721 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17722 bra.w fscc_chk_bsun # go finish 17723fscc_gl_yes: 17724 st %d0 # set true 17725 bra.w fscc_done # go finish 17726 17727# 17728# not (greater or less than): 17729# 17730# NANvZ 17731# 17732fscc_ngl: 17733 fbngl.w fscc_ngl_yes # not (greater or less than)? 17734fscc_ngl_no: 17735 clr.b %d0 # set false 17736 bra.w fscc_done # go finish 17737fscc_ngl_yes: 17738 st %d0 # set true 17739 btst &nan_bit, FPSR_CC(%a6) # is NAN set in cc? 17740 beq.w fscc_done # no;go finish 17741 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17742 bra.w fscc_chk_bsun # go finish 17743 17744# 17745# greater, less, or equal: 17746# ___ 17747# NAN 17748# 17749fscc_gle: 17750 fbgle.w fscc_gle_yes # greater, less, or equal? 17751fscc_gle_no: 17752 clr.b %d0 # set false 17753 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17754 bra.w fscc_chk_bsun # go finish 17755fscc_gle_yes: 17756 st %d0 # set true 17757 bra.w fscc_done # go finish 17758 17759# 17760# not (greater, less, or equal): 17761# 17762# NAN 17763# 17764fscc_ngle: 17765 fbngle.w fscc_ngle_yes # not (greater, less, or equal)? 17766fscc_ngle_no: 17767 clr.b %d0 # set false 17768 bra.w fscc_done # go finish 17769fscc_ngle_yes: 17770 st %d0 # set true 17771 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17772 bra.w fscc_chk_bsun # go finish 17773 17774######################################################################### 17775# # 17776# Miscellaneous tests # 17777# # 17778# For the IEEE aware tests, we only have to set the result based on the # 17779# floating point condition codes. The BSUN exception will not be # 17780# set for any of these tests. # 17781# # 17782######################################################################### 17783 17784# 17785# false: 17786# 17787# False 17788# 17789fscc_f: 17790 clr.b %d0 # set false 17791 bra.w fscc_done # go finish 17792 17793# 17794# true: 17795# 17796# True 17797# 17798fscc_t: 17799 st %d0 # set true 17800 bra.w fscc_done # go finish 17801 17802# 17803# signalling false: 17804# 17805# False 17806# 17807fscc_sf: 17808 clr.b %d0 # set false 17809 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17810 beq.w fscc_done # no;go finish 17811 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17812 bra.w fscc_chk_bsun # go finish 17813 17814# 17815# signalling true: 17816# 17817# True 17818# 17819fscc_st: 17820 st %d0 # set false 17821 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17822 beq.w fscc_done # no;go finish 17823 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17824 bra.w fscc_chk_bsun # go finish 17825 17826# 17827# signalling equal: 17828# 17829# Z 17830# 17831fscc_seq: 17832 fbseq.w fscc_seq_yes # signalling equal? 17833fscc_seq_no: 17834 clr.b %d0 # set false 17835 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17836 beq.w fscc_done # no;go finish 17837 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17838 bra.w fscc_chk_bsun # go finish 17839fscc_seq_yes: 17840 st %d0 # set true 17841 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17842 beq.w fscc_done # no;go finish 17843 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17844 bra.w fscc_chk_bsun # go finish 17845 17846# 17847# signalling not equal: 17848# _ 17849# Z 17850# 17851fscc_sneq: 17852 fbsneq.w fscc_sneq_yes # signalling equal? 17853fscc_sneq_no: 17854 clr.b %d0 # set false 17855 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17856 beq.w fscc_done # no;go finish 17857 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17858 bra.w fscc_chk_bsun # go finish 17859fscc_sneq_yes: 17860 st %d0 # set true 17861 btst &nan_bit, FPSR_CC(%a6) # set BSUN exc bit 17862 beq.w fscc_done # no;go finish 17863 ori.l &bsun_mask+aiop_mask, USER_FPSR(%a6) # set BSUN exc bit 17864 bra.w fscc_chk_bsun # go finish 17865 17866######################################################################### 17867# # 17868# IEEE Aware tests # 17869# # 17870# For the IEEE aware tests, we only have to set the result based on the # 17871# floating point condition codes. The BSUN exception will not be # 17872# set for any of these tests. # 17873# # 17874######################################################################### 17875 17876# 17877# ordered greater than: 17878# _______ 17879# NANvZvN 17880# 17881fscc_ogt: 17882 fbogt.w fscc_ogt_yes # ordered greater than? 17883fscc_ogt_no: 17884 clr.b %d0 # set false 17885 bra.w fscc_done # go finish 17886fscc_ogt_yes: 17887 st %d0 # set true 17888 bra.w fscc_done # go finish 17889 17890# 17891# unordered or less or equal: 17892# _______ 17893# NANvZvN 17894# 17895fscc_ule: 17896 fbule.w fscc_ule_yes # unordered or less or equal? 17897fscc_ule_no: 17898 clr.b %d0 # set false 17899 bra.w fscc_done # go finish 17900fscc_ule_yes: 17901 st %d0 # set true 17902 bra.w fscc_done # go finish 17903 17904# 17905# ordered greater than or equal: 17906# _____ 17907# Zv(NANvN) 17908# 17909fscc_oge: 17910 fboge.w fscc_oge_yes # ordered greater than or equal? 17911fscc_oge_no: 17912 clr.b %d0 # set false 17913 bra.w fscc_done # go finish 17914fscc_oge_yes: 17915 st %d0 # set true 17916 bra.w fscc_done # go finish 17917 17918# 17919# unordered or less than: 17920# _ 17921# NANv(N^Z) 17922# 17923fscc_ult: 17924 fbult.w fscc_ult_yes # unordered or less than? 17925fscc_ult_no: 17926 clr.b %d0 # set false 17927 bra.w fscc_done # go finish 17928fscc_ult_yes: 17929 st %d0 # set true 17930 bra.w fscc_done # go finish 17931 17932# 17933# ordered less than: 17934# _____ 17935# N^(NANvZ) 17936# 17937fscc_olt: 17938 fbolt.w fscc_olt_yes # ordered less than? 17939fscc_olt_no: 17940 clr.b %d0 # set false 17941 bra.w fscc_done # go finish 17942fscc_olt_yes: 17943 st %d0 # set true 17944 bra.w fscc_done # go finish 17945 17946# 17947# unordered or greater or equal: 17948# 17949# NANvZvN 17950# 17951fscc_uge: 17952 fbuge.w fscc_uge_yes # unordered or greater than? 17953fscc_uge_no: 17954 clr.b %d0 # set false 17955 bra.w fscc_done # go finish 17956fscc_uge_yes: 17957 st %d0 # set true 17958 bra.w fscc_done # go finish 17959 17960# 17961# ordered less than or equal: 17962# ___ 17963# Zv(N^NAN) 17964# 17965fscc_ole: 17966 fbole.w fscc_ole_yes # ordered greater or less than? 17967fscc_ole_no: 17968 clr.b %d0 # set false 17969 bra.w fscc_done # go finish 17970fscc_ole_yes: 17971 st %d0 # set true 17972 bra.w fscc_done # go finish 17973 17974# 17975# unordered or greater than: 17976# ___ 17977# NANv(NvZ) 17978# 17979fscc_ugt: 17980 fbugt.w fscc_ugt_yes # unordered or greater than? 17981fscc_ugt_no: 17982 clr.b %d0 # set false 17983 bra.w fscc_done # go finish 17984fscc_ugt_yes: 17985 st %d0 # set true 17986 bra.w fscc_done # go finish 17987 17988# 17989# ordered greater or less than: 17990# _____ 17991# NANvZ 17992# 17993fscc_ogl: 17994 fbogl.w fscc_ogl_yes # ordered greater or less than? 17995fscc_ogl_no: 17996 clr.b %d0 # set false 17997 bra.w fscc_done # go finish 17998fscc_ogl_yes: 17999 st %d0 # set true 18000 bra.w fscc_done # go finish 18001 18002# 18003# unordered or equal: 18004# 18005# NANvZ 18006# 18007fscc_ueq: 18008 fbueq.w fscc_ueq_yes # unordered or equal? 18009fscc_ueq_no: 18010 clr.b %d0 # set false 18011 bra.w fscc_done # go finish 18012fscc_ueq_yes: 18013 st %d0 # set true 18014 bra.w fscc_done # go finish 18015 18016# 18017# ordered: 18018# ___ 18019# NAN 18020# 18021fscc_or: 18022 fbor.w fscc_or_yes # ordered? 18023fscc_or_no: 18024 clr.b %d0 # set false 18025 bra.w fscc_done # go finish 18026fscc_or_yes: 18027 st %d0 # set true 18028 bra.w fscc_done # go finish 18029 18030# 18031# unordered: 18032# 18033# NAN 18034# 18035fscc_un: 18036 fbun.w fscc_un_yes # unordered? 18037fscc_un_no: 18038 clr.b %d0 # set false 18039 bra.w fscc_done # go finish 18040fscc_un_yes: 18041 st %d0 # set true 18042 bra.w fscc_done # go finish 18043 18044####################################################################### 18045 18046# 18047# the bsun exception bit was set. now, check to see is BSUN 18048# is enabled. if so, don't store result and correct stack frame 18049# for a bsun exception. 18050# 18051fscc_chk_bsun: 18052 btst &bsun_bit,FPCR_ENABLE(%a6) # was BSUN set? 18053 bne.w fscc_bsun 18054 18055# 18056# the bsun exception bit was not set. 18057# the result has been selected. 18058# now, check to see if the result is to be stored in the data register 18059# file or in memory. 18060# 18061fscc_done: 18062 mov.l %d0,%a0 # save result for a moment 18063 18064 mov.b 1+EXC_OPWORD(%a6),%d1 # fetch lo opword 18065 mov.l %d1,%d0 # make a copy 18066 andi.b &0x38,%d1 # extract src mode 18067 18068 bne.b fscc_mem_op # it's a memory operation 18069 18070 mov.l %d0,%d1 18071 andi.w &0x7,%d1 # pass index in d1 18072 mov.l %a0,%d0 # pass result in d0 18073 bsr.l store_dreg_b # save result in regfile 18074 rts 18075 18076# 18077# the stacked <ea> is correct with the exception of: 18078# -> Dn : <ea> is garbage 18079# 18080# if the addressing mode is post-increment or pre-decrement, 18081# then the address registers have not been updated. 18082# 18083fscc_mem_op: 18084 cmpi.b %d1,&0x18 # is <ea> (An)+ ? 18085 beq.b fscc_mem_inc # yes 18086 cmpi.b %d1,&0x20 # is <ea> -(An) ? 18087 beq.b fscc_mem_dec # yes 18088 18089 mov.l %a0,%d0 # pass result in d0 18090 mov.l EXC_EA(%a6),%a0 # fetch <ea> 18091 bsr.l _dmem_write_byte # write result byte 18092 18093 tst.l %d1 # did dstore fail? 18094 bne.w fscc_err # yes 18095 18096 rts 18097 18098# addressing mode is post-increment. write the result byte. if the write 18099# fails then don't update the address register. if write passes then 18100# call inc_areg() to update the address register. 18101fscc_mem_inc: 18102 mov.l %a0,%d0 # pass result in d0 18103 mov.l EXC_EA(%a6),%a0 # fetch <ea> 18104 bsr.l _dmem_write_byte # write result byte 18105 18106 tst.l %d1 # did dstore fail? 18107 bne.w fscc_err # yes 18108 18109 mov.b 0x1+EXC_OPWORD(%a6),%d1 # fetch opword 18110 andi.w &0x7,%d1 # pass index in d1 18111 movq.l &0x1,%d0 # pass amt to inc by 18112 bsr.l inc_areg # increment address register 18113 18114 rts 18115 18116# addressing mode is pre-decrement. write the result byte. if the write 18117# fails then don't update the address register. if the write passes then 18118# call dec_areg() to update the address register. 18119fscc_mem_dec: 18120 mov.l %a0,%d0 # pass result in d0 18121 mov.l EXC_EA(%a6),%a0 # fetch <ea> 18122 bsr.l _dmem_write_byte # write result byte 18123 18124 tst.l %d1 # did dstore fail? 18125 bne.w fscc_err # yes 18126 18127 mov.b 0x1+EXC_OPWORD(%a6),%d1 # fetch opword 18128 andi.w &0x7,%d1 # pass index in d1 18129 movq.l &0x1,%d0 # pass amt to dec by 18130 bsr.l dec_areg # decrement address register 18131 18132 rts 18133 18134# the emulation routine set bsun and BSUN was enabled. have to 18135# fix stack and jump to the bsun handler. 18136# let the caller of this routine shift the stack frame up to 18137# eliminate the effective address field. 18138fscc_bsun: 18139 mov.b &fbsun_flg,SPCOND_FLG(%a6) 18140 rts 18141 18142# the byte write to memory has failed. pass the failing effective address 18143# and a FSLW to funimp_dacc(). 18144fscc_err: 18145 mov.w &0x00a1,EXC_VOFF(%a6) 18146 bra.l facc_finish 18147 18148######################################################################### 18149# XDEF **************************************************************** # 18150# fmovm_dynamic(): emulate "fmovm" dynamic instruction # 18151# # 18152# XREF **************************************************************** # 18153# fetch_dreg() - fetch data register # 18154# {i,d,}mem_read() - fetch data from memory # 18155# _mem_write() - write data to memory # 18156# iea_iacc() - instruction memory access error occurred # 18157# iea_dacc() - data memory access error occurred # 18158# restore() - restore An index regs if access error occurred # 18159# # 18160# INPUT *************************************************************** # 18161# None # 18162# # 18163# OUTPUT ************************************************************** # 18164# If instr is "fmovm Dn,-(A7)" from supervisor mode, # 18165# d0 = size of dump # 18166# d1 = Dn # 18167# Else if instruction access error, # 18168# d0 = FSLW # 18169# Else if data access error, # 18170# d0 = FSLW # 18171# a0 = address of fault # 18172# Else # 18173# none. # 18174# # 18175# ALGORITHM *********************************************************** # 18176# The effective address must be calculated since this is entered # 18177# from an "Unimplemented Effective Address" exception handler. So, we # 18178# have our own fcalc_ea() routine here. If an access error is flagged # 18179# by a _{i,d,}mem_read() call, we must exit through the special # 18180# handler. # 18181# The data register is determined and its value loaded to get the # 18182# string of FP registers affected. This value is used as an index into # 18183# a lookup table such that we can determine the number of bytes # 18184# involved. # 18185# If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used # 18186# to read in all FP values. Again, _mem_read() may fail and require a # 18187# special exit. # 18188# If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used # 18189# to write all FP values. _mem_write() may also fail. # 18190# If the instruction is "fmovm.x DN,-(a7)" from supervisor mode, # 18191# then we return the size of the dump and the string to the caller # 18192# so that the move can occur outside of this routine. This special # 18193# case is required so that moves to the system stack are handled # 18194# correctly. # 18195# # 18196# DYNAMIC: # 18197# fmovm.x dn, <ea> # 18198# fmovm.x <ea>, dn # 18199# # 18200# <WORD 1> <WORD2> # 18201# 1111 0010 00 |<ea>| 11@& 1000 0$$$ 0000 # 18202# # 18203# & = (0): predecrement addressing mode # 18204# (1): postincrement or control addressing mode # 18205# @ = (0): move listed regs from memory to the FPU # 18206# (1): move listed regs from the FPU to memory # 18207# $$$ : index of data register holding reg select mask # 18208# # 18209# NOTES: # 18210# If the data register holds a zero, then the # 18211# instruction is a nop. # 18212# # 18213######################################################################### 18214 18215 global fmovm_dynamic 18216fmovm_dynamic: 18217 18218# extract the data register in which the bit string resides... 18219 mov.b 1+EXC_EXTWORD(%a6),%d1 # fetch extword 18220 andi.w &0x70,%d1 # extract reg bits 18221 lsr.b &0x4,%d1 # shift into lo bits 18222 18223# fetch the bit string into d0... 18224 bsr.l fetch_dreg # fetch reg string 18225 18226 andi.l &0x000000ff,%d0 # keep only lo byte 18227 18228 mov.l %d0,-(%sp) # save strg 18229 mov.b (tbl_fmovm_size.w,%pc,%d0),%d0 18230 mov.l %d0,-(%sp) # save size 18231 bsr.l fmovm_calc_ea # calculate <ea> 18232 mov.l (%sp)+,%d0 # restore size 18233 mov.l (%sp)+,%d1 # restore strg 18234 18235# if the bit string is a zero, then the operation is a no-op 18236# but, make sure that we've calculated ea and advanced the opword pointer 18237 beq.w fmovm_data_done 18238 18239# separate move ins from move outs... 18240 btst &0x5,EXC_EXTWORD(%a6) # is it a move in or out? 18241 beq.w fmovm_data_in # it's a move out 18242 18243############# 18244# MOVE OUT: # 18245############# 18246fmovm_data_out: 18247 btst &0x4,EXC_EXTWORD(%a6) # control or predecrement? 18248 bne.w fmovm_out_ctrl # control 18249 18250############################ 18251fmovm_out_predec: 18252# for predecrement mode, the bit string is the opposite of both control 18253# operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0) 18254# here, we convert it to be just like the others... 18255 mov.b (tbl_fmovm_convert.w,%pc,%d1.w*1),%d1 18256 18257 btst &0x5,EXC_SR(%a6) # user or supervisor mode? 18258 beq.b fmovm_out_ctrl # user 18259 18260fmovm_out_predec_s: 18261 cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)? 18262 bne.b fmovm_out_ctrl 18263 18264# the operation was unfortunately an: fmovm.x dn,-(sp) 18265# called from supervisor mode. 18266# we're also passing "size" and "strg" back to the calling routine 18267 rts 18268 18269############################ 18270fmovm_out_ctrl: 18271 mov.l %a0,%a1 # move <ea> to a1 18272 18273 sub.l %d0,%sp # subtract size of dump 18274 lea (%sp),%a0 18275 18276 tst.b %d1 # should FP0 be moved? 18277 bpl.b fmovm_out_ctrl_fp1 # no 18278 18279 mov.l 0x0+EXC_FP0(%a6),(%a0)+ # yes 18280 mov.l 0x4+EXC_FP0(%a6),(%a0)+ 18281 mov.l 0x8+EXC_FP0(%a6),(%a0)+ 18282 18283fmovm_out_ctrl_fp1: 18284 lsl.b &0x1,%d1 # should FP1 be moved? 18285 bpl.b fmovm_out_ctrl_fp2 # no 18286 18287 mov.l 0x0+EXC_FP1(%a6),(%a0)+ # yes 18288 mov.l 0x4+EXC_FP1(%a6),(%a0)+ 18289 mov.l 0x8+EXC_FP1(%a6),(%a0)+ 18290 18291fmovm_out_ctrl_fp2: 18292 lsl.b &0x1,%d1 # should FP2 be moved? 18293 bpl.b fmovm_out_ctrl_fp3 # no 18294 18295 fmovm.x &0x20,(%a0) # yes 18296 add.l &0xc,%a0 18297 18298fmovm_out_ctrl_fp3: 18299 lsl.b &0x1,%d1 # should FP3 be moved? 18300 bpl.b fmovm_out_ctrl_fp4 # no 18301 18302 fmovm.x &0x10,(%a0) # yes 18303 add.l &0xc,%a0 18304 18305fmovm_out_ctrl_fp4: 18306 lsl.b &0x1,%d1 # should FP4 be moved? 18307 bpl.b fmovm_out_ctrl_fp5 # no 18308 18309 fmovm.x &0x08,(%a0) # yes 18310 add.l &0xc,%a0 18311 18312fmovm_out_ctrl_fp5: 18313 lsl.b &0x1,%d1 # should FP5 be moved? 18314 bpl.b fmovm_out_ctrl_fp6 # no 18315 18316 fmovm.x &0x04,(%a0) # yes 18317 add.l &0xc,%a0 18318 18319fmovm_out_ctrl_fp6: 18320 lsl.b &0x1,%d1 # should FP6 be moved? 18321 bpl.b fmovm_out_ctrl_fp7 # no 18322 18323 fmovm.x &0x02,(%a0) # yes 18324 add.l &0xc,%a0 18325 18326fmovm_out_ctrl_fp7: 18327 lsl.b &0x1,%d1 # should FP7 be moved? 18328 bpl.b fmovm_out_ctrl_done # no 18329 18330 fmovm.x &0x01,(%a0) # yes 18331 add.l &0xc,%a0 18332 18333fmovm_out_ctrl_done: 18334 mov.l %a1,L_SCR1(%a6) 18335 18336 lea (%sp),%a0 # pass: supervisor src 18337 mov.l %d0,-(%sp) # save size 18338 bsr.l _dmem_write # copy data to user mem 18339 18340 mov.l (%sp)+,%d0 18341 add.l %d0,%sp # clear fpreg data from stack 18342 18343 tst.l %d1 # did dstore err? 18344 bne.w fmovm_out_err # yes 18345 18346 rts 18347 18348############ 18349# MOVE IN: # 18350############ 18351fmovm_data_in: 18352 mov.l %a0,L_SCR1(%a6) 18353 18354 sub.l %d0,%sp # make room for fpregs 18355 lea (%sp),%a1 18356 18357 mov.l %d1,-(%sp) # save bit string for later 18358 mov.l %d0,-(%sp) # save # of bytes 18359 18360 bsr.l _dmem_read # copy data from user mem 18361 18362 mov.l (%sp)+,%d0 # retrieve # of bytes 18363 18364 tst.l %d1 # did dfetch fail? 18365 bne.w fmovm_in_err # yes 18366 18367 mov.l (%sp)+,%d1 # load bit string 18368 18369 lea (%sp),%a0 # addr of stack 18370 18371 tst.b %d1 # should FP0 be moved? 18372 bpl.b fmovm_data_in_fp1 # no 18373 18374 mov.l (%a0)+,0x0+EXC_FP0(%a6) # yes 18375 mov.l (%a0)+,0x4+EXC_FP0(%a6) 18376 mov.l (%a0)+,0x8+EXC_FP0(%a6) 18377 18378fmovm_data_in_fp1: 18379 lsl.b &0x1,%d1 # should FP1 be moved? 18380 bpl.b fmovm_data_in_fp2 # no 18381 18382 mov.l (%a0)+,0x0+EXC_FP1(%a6) # yes 18383 mov.l (%a0)+,0x4+EXC_FP1(%a6) 18384 mov.l (%a0)+,0x8+EXC_FP1(%a6) 18385 18386fmovm_data_in_fp2: 18387 lsl.b &0x1,%d1 # should FP2 be moved? 18388 bpl.b fmovm_data_in_fp3 # no 18389 18390 fmovm.x (%a0)+,&0x20 # yes 18391 18392fmovm_data_in_fp3: 18393 lsl.b &0x1,%d1 # should FP3 be moved? 18394 bpl.b fmovm_data_in_fp4 # no 18395 18396 fmovm.x (%a0)+,&0x10 # yes 18397 18398fmovm_data_in_fp4: 18399 lsl.b &0x1,%d1 # should FP4 be moved? 18400 bpl.b fmovm_data_in_fp5 # no 18401 18402 fmovm.x (%a0)+,&0x08 # yes 18403 18404fmovm_data_in_fp5: 18405 lsl.b &0x1,%d1 # should FP5 be moved? 18406 bpl.b fmovm_data_in_fp6 # no 18407 18408 fmovm.x (%a0)+,&0x04 # yes 18409 18410fmovm_data_in_fp6: 18411 lsl.b &0x1,%d1 # should FP6 be moved? 18412 bpl.b fmovm_data_in_fp7 # no 18413 18414 fmovm.x (%a0)+,&0x02 # yes 18415 18416fmovm_data_in_fp7: 18417 lsl.b &0x1,%d1 # should FP7 be moved? 18418 bpl.b fmovm_data_in_done # no 18419 18420 fmovm.x (%a0)+,&0x01 # yes 18421 18422fmovm_data_in_done: 18423 add.l %d0,%sp # remove fpregs from stack 18424 rts 18425 18426##################################### 18427 18428fmovm_data_done: 18429 rts 18430 18431############################################################################## 18432 18433# 18434# table indexed by the operation's bit string that gives the number 18435# of bytes that will be moved. 18436# 18437# number of bytes = (# of 1's in bit string) * 12(bytes/fpreg) 18438# 18439tbl_fmovm_size: 18440 byte 0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24 18441 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 18442 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 18443 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18444 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 18445 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18446 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18447 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18448 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 18449 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18450 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18451 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18452 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18453 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18454 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18455 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 18456 byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 18457 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18458 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18459 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18460 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18461 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18462 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18463 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 18464 byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 18465 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18466 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18467 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 18468 byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 18469 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 18470 byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 18471 byte 0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60 18472 18473# 18474# table to convert a pre-decrement bit string into a post-increment 18475# or control bit string. 18476# ex: 0x00 ==> 0x00 18477# 0x01 ==> 0x80 18478# 0x02 ==> 0x40 18479# . 18480# . 18481# 0xfd ==> 0xbf 18482# 0xfe ==> 0x7f 18483# 0xff ==> 0xff 18484# 18485tbl_fmovm_convert: 18486 byte 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0 18487 byte 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0 18488 byte 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8 18489 byte 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8 18490 byte 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4 18491 byte 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4 18492 byte 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec 18493 byte 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc 18494 byte 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2 18495 byte 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2 18496 byte 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea 18497 byte 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa 18498 byte 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6 18499 byte 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6 18500 byte 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee 18501 byte 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe 18502 byte 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1 18503 byte 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1 18504 byte 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9 18505 byte 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9 18506 byte 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5 18507 byte 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5 18508 byte 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed 18509 byte 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd 18510 byte 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3 18511 byte 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3 18512 byte 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb 18513 byte 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb 18514 byte 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7 18515 byte 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7 18516 byte 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef 18517 byte 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff 18518 18519 global fmovm_calc_ea 18520############################################### 18521# _fmovm_calc_ea: calculate effective address # 18522############################################### 18523fmovm_calc_ea: 18524 mov.l %d0,%a0 # move # bytes to a0 18525 18526# currently, MODE and REG are taken from the EXC_OPWORD. this could be 18527# easily changed if they were inputs passed in registers. 18528 mov.w EXC_OPWORD(%a6),%d0 # fetch opcode word 18529 mov.w %d0,%d1 # make a copy 18530 18531 andi.w &0x3f,%d0 # extract mode field 18532 andi.l &0x7,%d1 # extract reg field 18533 18534# jump to the corresponding function for each {MODE,REG} pair. 18535 mov.w (tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance 18536 jmp (tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode 18537 18538 swbeg &64 18539tbl_fea_mode: 18540 short tbl_fea_mode - tbl_fea_mode 18541 short tbl_fea_mode - tbl_fea_mode 18542 short tbl_fea_mode - tbl_fea_mode 18543 short tbl_fea_mode - tbl_fea_mode 18544 short tbl_fea_mode - tbl_fea_mode 18545 short tbl_fea_mode - tbl_fea_mode 18546 short tbl_fea_mode - tbl_fea_mode 18547 short tbl_fea_mode - tbl_fea_mode 18548 18549 short tbl_fea_mode - tbl_fea_mode 18550 short tbl_fea_mode - tbl_fea_mode 18551 short tbl_fea_mode - tbl_fea_mode 18552 short tbl_fea_mode - tbl_fea_mode 18553 short tbl_fea_mode - tbl_fea_mode 18554 short tbl_fea_mode - tbl_fea_mode 18555 short tbl_fea_mode - tbl_fea_mode 18556 short tbl_fea_mode - tbl_fea_mode 18557 18558 short faddr_ind_a0 - tbl_fea_mode 18559 short faddr_ind_a1 - tbl_fea_mode 18560 short faddr_ind_a2 - tbl_fea_mode 18561 short faddr_ind_a3 - tbl_fea_mode 18562 short faddr_ind_a4 - tbl_fea_mode 18563 short faddr_ind_a5 - tbl_fea_mode 18564 short faddr_ind_a6 - tbl_fea_mode 18565 short faddr_ind_a7 - tbl_fea_mode 18566 18567 short faddr_ind_p_a0 - tbl_fea_mode 18568 short faddr_ind_p_a1 - tbl_fea_mode 18569 short faddr_ind_p_a2 - tbl_fea_mode 18570 short faddr_ind_p_a3 - tbl_fea_mode 18571 short faddr_ind_p_a4 - tbl_fea_mode 18572 short faddr_ind_p_a5 - tbl_fea_mode 18573 short faddr_ind_p_a6 - tbl_fea_mode 18574 short faddr_ind_p_a7 - tbl_fea_mode 18575 18576 short faddr_ind_m_a0 - tbl_fea_mode 18577 short faddr_ind_m_a1 - tbl_fea_mode 18578 short faddr_ind_m_a2 - tbl_fea_mode 18579 short faddr_ind_m_a3 - tbl_fea_mode 18580 short faddr_ind_m_a4 - tbl_fea_mode 18581 short faddr_ind_m_a5 - tbl_fea_mode 18582 short faddr_ind_m_a6 - tbl_fea_mode 18583 short faddr_ind_m_a7 - tbl_fea_mode 18584 18585 short faddr_ind_disp_a0 - tbl_fea_mode 18586 short faddr_ind_disp_a1 - tbl_fea_mode 18587 short faddr_ind_disp_a2 - tbl_fea_mode 18588 short faddr_ind_disp_a3 - tbl_fea_mode 18589 short faddr_ind_disp_a4 - tbl_fea_mode 18590 short faddr_ind_disp_a5 - tbl_fea_mode 18591 short faddr_ind_disp_a6 - tbl_fea_mode 18592 short faddr_ind_disp_a7 - tbl_fea_mode 18593 18594 short faddr_ind_ext - tbl_fea_mode 18595 short faddr_ind_ext - tbl_fea_mode 18596 short faddr_ind_ext - tbl_fea_mode 18597 short faddr_ind_ext - tbl_fea_mode 18598 short faddr_ind_ext - tbl_fea_mode 18599 short faddr_ind_ext - tbl_fea_mode 18600 short faddr_ind_ext - tbl_fea_mode 18601 short faddr_ind_ext - tbl_fea_mode 18602 18603 short fabs_short - tbl_fea_mode 18604 short fabs_long - tbl_fea_mode 18605 short fpc_ind - tbl_fea_mode 18606 short fpc_ind_ext - tbl_fea_mode 18607 short tbl_fea_mode - tbl_fea_mode 18608 short tbl_fea_mode - tbl_fea_mode 18609 short tbl_fea_mode - tbl_fea_mode 18610 short tbl_fea_mode - tbl_fea_mode 18611 18612################################### 18613# Address register indirect: (An) # 18614################################### 18615faddr_ind_a0: 18616 mov.l EXC_DREGS+0x8(%a6),%a0 # Get current a0 18617 rts 18618 18619faddr_ind_a1: 18620 mov.l EXC_DREGS+0xc(%a6),%a0 # Get current a1 18621 rts 18622 18623faddr_ind_a2: 18624 mov.l %a2,%a0 # Get current a2 18625 rts 18626 18627faddr_ind_a3: 18628 mov.l %a3,%a0 # Get current a3 18629 rts 18630 18631faddr_ind_a4: 18632 mov.l %a4,%a0 # Get current a4 18633 rts 18634 18635faddr_ind_a5: 18636 mov.l %a5,%a0 # Get current a5 18637 rts 18638 18639faddr_ind_a6: 18640 mov.l (%a6),%a0 # Get current a6 18641 rts 18642 18643faddr_ind_a7: 18644 mov.l EXC_A7(%a6),%a0 # Get current a7 18645 rts 18646 18647##################################################### 18648# Address register indirect w/ postincrement: (An)+ # 18649##################################################### 18650faddr_ind_p_a0: 18651 mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0 18652 mov.l %d0,%d1 18653 add.l %a0,%d1 # Increment 18654 mov.l %d1,EXC_DREGS+0x8(%a6) # Save incr value 18655 mov.l %d0,%a0 18656 rts 18657 18658faddr_ind_p_a1: 18659 mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1 18660 mov.l %d0,%d1 18661 add.l %a0,%d1 # Increment 18662 mov.l %d1,EXC_DREGS+0xc(%a6) # Save incr value 18663 mov.l %d0,%a0 18664 rts 18665 18666faddr_ind_p_a2: 18667 mov.l %a2,%d0 # Get current a2 18668 mov.l %d0,%d1 18669 add.l %a0,%d1 # Increment 18670 mov.l %d1,%a2 # Save incr value 18671 mov.l %d0,%a0 18672 rts 18673 18674faddr_ind_p_a3: 18675 mov.l %a3,%d0 # Get current a3 18676 mov.l %d0,%d1 18677 add.l %a0,%d1 # Increment 18678 mov.l %d1,%a3 # Save incr value 18679 mov.l %d0,%a0 18680 rts 18681 18682faddr_ind_p_a4: 18683 mov.l %a4,%d0 # Get current a4 18684 mov.l %d0,%d1 18685 add.l %a0,%d1 # Increment 18686 mov.l %d1,%a4 # Save incr value 18687 mov.l %d0,%a0 18688 rts 18689 18690faddr_ind_p_a5: 18691 mov.l %a5,%d0 # Get current a5 18692 mov.l %d0,%d1 18693 add.l %a0,%d1 # Increment 18694 mov.l %d1,%a5 # Save incr value 18695 mov.l %d0,%a0 18696 rts 18697 18698faddr_ind_p_a6: 18699 mov.l (%a6),%d0 # Get current a6 18700 mov.l %d0,%d1 18701 add.l %a0,%d1 # Increment 18702 mov.l %d1,(%a6) # Save incr value 18703 mov.l %d0,%a0 18704 rts 18705 18706faddr_ind_p_a7: 18707 mov.b &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag 18708 18709 mov.l EXC_A7(%a6),%d0 # Get current a7 18710 mov.l %d0,%d1 18711 add.l %a0,%d1 # Increment 18712 mov.l %d1,EXC_A7(%a6) # Save incr value 18713 mov.l %d0,%a0 18714 rts 18715 18716#################################################### 18717# Address register indirect w/ predecrement: -(An) # 18718#################################################### 18719faddr_ind_m_a0: 18720 mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0 18721 sub.l %a0,%d0 # Decrement 18722 mov.l %d0,EXC_DREGS+0x8(%a6) # Save decr value 18723 mov.l %d0,%a0 18724 rts 18725 18726faddr_ind_m_a1: 18727 mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1 18728 sub.l %a0,%d0 # Decrement 18729 mov.l %d0,EXC_DREGS+0xc(%a6) # Save decr value 18730 mov.l %d0,%a0 18731 rts 18732 18733faddr_ind_m_a2: 18734 mov.l %a2,%d0 # Get current a2 18735 sub.l %a0,%d0 # Decrement 18736 mov.l %d0,%a2 # Save decr value 18737 mov.l %d0,%a0 18738 rts 18739 18740faddr_ind_m_a3: 18741 mov.l %a3,%d0 # Get current a3 18742 sub.l %a0,%d0 # Decrement 18743 mov.l %d0,%a3 # Save decr value 18744 mov.l %d0,%a0 18745 rts 18746 18747faddr_ind_m_a4: 18748 mov.l %a4,%d0 # Get current a4 18749 sub.l %a0,%d0 # Decrement 18750 mov.l %d0,%a4 # Save decr value 18751 mov.l %d0,%a0 18752 rts 18753 18754faddr_ind_m_a5: 18755 mov.l %a5,%d0 # Get current a5 18756 sub.l %a0,%d0 # Decrement 18757 mov.l %d0,%a5 # Save decr value 18758 mov.l %d0,%a0 18759 rts 18760 18761faddr_ind_m_a6: 18762 mov.l (%a6),%d0 # Get current a6 18763 sub.l %a0,%d0 # Decrement 18764 mov.l %d0,(%a6) # Save decr value 18765 mov.l %d0,%a0 18766 rts 18767 18768faddr_ind_m_a7: 18769 mov.b &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag 18770 18771 mov.l EXC_A7(%a6),%d0 # Get current a7 18772 sub.l %a0,%d0 # Decrement 18773 mov.l %d0,EXC_A7(%a6) # Save decr value 18774 mov.l %d0,%a0 18775 rts 18776 18777######################################################## 18778# Address register indirect w/ displacement: (d16, An) # 18779######################################################## 18780faddr_ind_disp_a0: 18781 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18782 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18783 bsr.l _imem_read_word 18784 18785 tst.l %d1 # did ifetch fail? 18786 bne.l iea_iacc # yes 18787 18788 mov.w %d0,%a0 # sign extend displacement 18789 18790 add.l EXC_DREGS+0x8(%a6),%a0 # a0 + d16 18791 rts 18792 18793faddr_ind_disp_a1: 18794 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18795 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18796 bsr.l _imem_read_word 18797 18798 tst.l %d1 # did ifetch fail? 18799 bne.l iea_iacc # yes 18800 18801 mov.w %d0,%a0 # sign extend displacement 18802 18803 add.l EXC_DREGS+0xc(%a6),%a0 # a1 + d16 18804 rts 18805 18806faddr_ind_disp_a2: 18807 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18808 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18809 bsr.l _imem_read_word 18810 18811 tst.l %d1 # did ifetch fail? 18812 bne.l iea_iacc # yes 18813 18814 mov.w %d0,%a0 # sign extend displacement 18815 18816 add.l %a2,%a0 # a2 + d16 18817 rts 18818 18819faddr_ind_disp_a3: 18820 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18821 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18822 bsr.l _imem_read_word 18823 18824 tst.l %d1 # did ifetch fail? 18825 bne.l iea_iacc # yes 18826 18827 mov.w %d0,%a0 # sign extend displacement 18828 18829 add.l %a3,%a0 # a3 + d16 18830 rts 18831 18832faddr_ind_disp_a4: 18833 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18834 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18835 bsr.l _imem_read_word 18836 18837 tst.l %d1 # did ifetch fail? 18838 bne.l iea_iacc # yes 18839 18840 mov.w %d0,%a0 # sign extend displacement 18841 18842 add.l %a4,%a0 # a4 + d16 18843 rts 18844 18845faddr_ind_disp_a5: 18846 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18847 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18848 bsr.l _imem_read_word 18849 18850 tst.l %d1 # did ifetch fail? 18851 bne.l iea_iacc # yes 18852 18853 mov.w %d0,%a0 # sign extend displacement 18854 18855 add.l %a5,%a0 # a5 + d16 18856 rts 18857 18858faddr_ind_disp_a6: 18859 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18860 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18861 bsr.l _imem_read_word 18862 18863 tst.l %d1 # did ifetch fail? 18864 bne.l iea_iacc # yes 18865 18866 mov.w %d0,%a0 # sign extend displacement 18867 18868 add.l (%a6),%a0 # a6 + d16 18869 rts 18870 18871faddr_ind_disp_a7: 18872 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18873 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18874 bsr.l _imem_read_word 18875 18876 tst.l %d1 # did ifetch fail? 18877 bne.l iea_iacc # yes 18878 18879 mov.w %d0,%a0 # sign extend displacement 18880 18881 add.l EXC_A7(%a6),%a0 # a7 + d16 18882 rts 18883 18884######################################################################## 18885# Address register indirect w/ index(8-bit displacement): (d8, An, Xn) # 18886# " " " w/ " (base displacement): (bd, An, Xn) # 18887# Memory indirect postindexed: ([bd, An], Xn, od) # 18888# Memory indirect preindexed: ([bd, An, Xn], od) # 18889######################################################################## 18890faddr_ind_ext: 18891 addq.l &0x8,%d1 18892 bsr.l fetch_dreg # fetch base areg 18893 mov.l %d0,-(%sp) 18894 18895 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18896 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18897 bsr.l _imem_read_word # fetch extword in d0 18898 18899 tst.l %d1 # did ifetch fail? 18900 bne.l iea_iacc # yes 18901 18902 mov.l (%sp)+,%a0 18903 18904 btst &0x8,%d0 18905 bne.w fcalc_mem_ind 18906 18907 mov.l %d0,L_SCR1(%a6) # hold opword 18908 18909 mov.l %d0,%d1 18910 rol.w &0x4,%d1 18911 andi.w &0xf,%d1 # extract index regno 18912 18913# count on fetch_dreg() not to alter a0... 18914 bsr.l fetch_dreg # fetch index 18915 18916 mov.l %d2,-(%sp) # save d2 18917 mov.l L_SCR1(%a6),%d2 # fetch opword 18918 18919 btst &0xb,%d2 # is it word or long? 18920 bne.b faii8_long 18921 ext.l %d0 # sign extend word index 18922faii8_long: 18923 mov.l %d2,%d1 18924 rol.w &0x7,%d1 18925 andi.l &0x3,%d1 # extract scale value 18926 18927 lsl.l %d1,%d0 # shift index by scale 18928 18929 extb.l %d2 # sign extend displacement 18930 add.l %d2,%d0 # index + disp 18931 add.l %d0,%a0 # An + (index + disp) 18932 18933 mov.l (%sp)+,%d2 # restore old d2 18934 rts 18935 18936########################### 18937# Absolute short: (XXX).W # 18938########################### 18939fabs_short: 18940 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18941 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18942 bsr.l _imem_read_word # fetch short address 18943 18944 tst.l %d1 # did ifetch fail? 18945 bne.l iea_iacc # yes 18946 18947 mov.w %d0,%a0 # return <ea> in a0 18948 rts 18949 18950########################## 18951# Absolute long: (XXX).L # 18952########################## 18953fabs_long: 18954 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18955 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 18956 bsr.l _imem_read_long # fetch long address 18957 18958 tst.l %d1 # did ifetch fail? 18959 bne.l iea_iacc # yes 18960 18961 mov.l %d0,%a0 # return <ea> in a0 18962 rts 18963 18964####################################################### 18965# Program counter indirect w/ displacement: (d16, PC) # 18966####################################################### 18967fpc_ind: 18968 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18969 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18970 bsr.l _imem_read_word # fetch word displacement 18971 18972 tst.l %d1 # did ifetch fail? 18973 bne.l iea_iacc # yes 18974 18975 mov.w %d0,%a0 # sign extend displacement 18976 18977 add.l EXC_EXTWPTR(%a6),%a0 # pc + d16 18978 18979# _imem_read_word() increased the extwptr by 2. need to adjust here. 18980 subq.l &0x2,%a0 # adjust <ea> 18981 rts 18982 18983########################################################## 18984# PC indirect w/ index(8-bit displacement): (d8, PC, An) # 18985# " " w/ " (base displacement): (bd, PC, An) # 18986# PC memory indirect postindexed: ([bd, PC], Xn, od) # 18987# PC memory indirect preindexed: ([bd, PC, Xn], od) # 18988########################################################## 18989fpc_ind_ext: 18990 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 18991 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 18992 bsr.l _imem_read_word # fetch ext word 18993 18994 tst.l %d1 # did ifetch fail? 18995 bne.l iea_iacc # yes 18996 18997 mov.l EXC_EXTWPTR(%a6),%a0 # put base in a0 18998 subq.l &0x2,%a0 # adjust base 18999 19000 btst &0x8,%d0 # is disp only 8 bits? 19001 bne.w fcalc_mem_ind # calc memory indirect 19002 19003 mov.l %d0,L_SCR1(%a6) # store opword 19004 19005 mov.l %d0,%d1 # make extword copy 19006 rol.w &0x4,%d1 # rotate reg num into place 19007 andi.w &0xf,%d1 # extract register number 19008 19009# count on fetch_dreg() not to alter a0... 19010 bsr.l fetch_dreg # fetch index 19011 19012 mov.l %d2,-(%sp) # save d2 19013 mov.l L_SCR1(%a6),%d2 # fetch opword 19014 19015 btst &0xb,%d2 # is index word or long? 19016 bne.b fpii8_long # long 19017 ext.l %d0 # sign extend word index 19018fpii8_long: 19019 mov.l %d2,%d1 19020 rol.w &0x7,%d1 # rotate scale value into place 19021 andi.l &0x3,%d1 # extract scale value 19022 19023 lsl.l %d1,%d0 # shift index by scale 19024 19025 extb.l %d2 # sign extend displacement 19026 add.l %d2,%d0 # disp + index 19027 add.l %d0,%a0 # An + (index + disp) 19028 19029 mov.l (%sp)+,%d2 # restore temp register 19030 rts 19031 19032# d2 = index 19033# d3 = base 19034# d4 = od 19035# d5 = extword 19036fcalc_mem_ind: 19037 btst &0x6,%d0 # is the index suppressed? 19038 beq.b fcalc_index 19039 19040 movm.l &0x3c00,-(%sp) # save d2-d5 19041 19042 mov.l %d0,%d5 # put extword in d5 19043 mov.l %a0,%d3 # put base in d3 19044 19045 clr.l %d2 # yes, so index = 0 19046 bra.b fbase_supp_ck 19047 19048# index: 19049fcalc_index: 19050 mov.l %d0,L_SCR1(%a6) # save d0 (opword) 19051 bfextu %d0{&16:&4},%d1 # fetch dreg index 19052 bsr.l fetch_dreg 19053 19054 movm.l &0x3c00,-(%sp) # save d2-d5 19055 mov.l %d0,%d2 # put index in d2 19056 mov.l L_SCR1(%a6),%d5 19057 mov.l %a0,%d3 19058 19059 btst &0xb,%d5 # is index word or long? 19060 bne.b fno_ext 19061 ext.l %d2 19062 19063fno_ext: 19064 bfextu %d5{&21:&2},%d0 19065 lsl.l %d0,%d2 19066 19067# base address (passed as parameter in d3): 19068# we clear the value here if it should actually be suppressed. 19069fbase_supp_ck: 19070 btst &0x7,%d5 # is the bd suppressed? 19071 beq.b fno_base_sup 19072 clr.l %d3 19073 19074# base displacement: 19075fno_base_sup: 19076 bfextu %d5{&26:&2},%d0 # get bd size 19077# beq.l fmovm_error # if (size == 0) it's reserved 19078 19079 cmpi.b %d0,&0x2 19080 blt.b fno_bd 19081 beq.b fget_word_bd 19082 19083 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19084 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19085 bsr.l _imem_read_long 19086 19087 tst.l %d1 # did ifetch fail? 19088 bne.l fcea_iacc # yes 19089 19090 bra.b fchk_ind 19091 19092fget_word_bd: 19093 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19094 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 19095 bsr.l _imem_read_word 19096 19097 tst.l %d1 # did ifetch fail? 19098 bne.l fcea_iacc # yes 19099 19100 ext.l %d0 # sign extend bd 19101 19102fchk_ind: 19103 add.l %d0,%d3 # base += bd 19104 19105# outer displacement: 19106fno_bd: 19107 bfextu %d5{&30:&2},%d0 # is od suppressed? 19108 beq.w faii_bd 19109 19110 cmpi.b %d0,&0x2 19111 blt.b fnull_od 19112 beq.b fword_od 19113 19114 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19115 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19116 bsr.l _imem_read_long 19117 19118 tst.l %d1 # did ifetch fail? 19119 bne.l fcea_iacc # yes 19120 19121 bra.b fadd_them 19122 19123fword_od: 19124 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19125 addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 19126 bsr.l _imem_read_word 19127 19128 tst.l %d1 # did ifetch fail? 19129 bne.l fcea_iacc # yes 19130 19131 ext.l %d0 # sign extend od 19132 bra.b fadd_them 19133 19134fnull_od: 19135 clr.l %d0 19136 19137fadd_them: 19138 mov.l %d0,%d4 19139 19140 btst &0x2,%d5 # pre or post indexing? 19141 beq.b fpre_indexed 19142 19143 mov.l %d3,%a0 19144 bsr.l _dmem_read_long 19145 19146 tst.l %d1 # did dfetch fail? 19147 bne.w fcea_err # yes 19148 19149 add.l %d2,%d0 # <ea> += index 19150 add.l %d4,%d0 # <ea> += od 19151 bra.b fdone_ea 19152 19153fpre_indexed: 19154 add.l %d2,%d3 # preindexing 19155 mov.l %d3,%a0 19156 bsr.l _dmem_read_long 19157 19158 tst.l %d1 # did dfetch fail? 19159 bne.w fcea_err # yes 19160 19161 add.l %d4,%d0 # ea += od 19162 bra.b fdone_ea 19163 19164faii_bd: 19165 add.l %d2,%d3 # ea = (base + bd) + index 19166 mov.l %d3,%d0 19167fdone_ea: 19168 mov.l %d0,%a0 19169 19170 movm.l (%sp)+,&0x003c # restore d2-d5 19171 rts 19172 19173######################################################### 19174fcea_err: 19175 mov.l %d3,%a0 19176 19177 movm.l (%sp)+,&0x003c # restore d2-d5 19178 mov.w &0x0101,%d0 19179 bra.l iea_dacc 19180 19181fcea_iacc: 19182 movm.l (%sp)+,&0x003c # restore d2-d5 19183 bra.l iea_iacc 19184 19185fmovm_out_err: 19186 bsr.l restore 19187 mov.w &0x00e1,%d0 19188 bra.b fmovm_err 19189 19190fmovm_in_err: 19191 bsr.l restore 19192 mov.w &0x0161,%d0 19193 19194fmovm_err: 19195 mov.l L_SCR1(%a6),%a0 19196 bra.l iea_dacc 19197 19198######################################################################### 19199# XDEF **************************************************************** # 19200# fmovm_ctrl(): emulate fmovm.l of control registers instr # 19201# # 19202# XREF **************************************************************** # 19203# _imem_read_long() - read longword from memory # 19204# iea_iacc() - _imem_read_long() failed; error recovery # 19205# # 19206# INPUT *************************************************************** # 19207# None # 19208# # 19209# OUTPUT ************************************************************** # 19210# If _imem_read_long() doesn't fail: # 19211# USER_FPCR(a6) = new FPCR value # 19212# USER_FPSR(a6) = new FPSR value # 19213# USER_FPIAR(a6) = new FPIAR value # 19214# # 19215# ALGORITHM *********************************************************** # 19216# Decode the instruction type by looking at the extension word # 19217# in order to see how many control registers to fetch from memory. # 19218# Fetch them using _imem_read_long(). If this fetch fails, exit through # 19219# the special access error exit handler iea_iacc(). # 19220# # 19221# Instruction word decoding: # 19222# # 19223# fmovem.l #<data>, {FPIAR&|FPCR&|FPSR} # 19224# # 19225# WORD1 WORD2 # 19226# 1111 0010 00 111100 100$ $$00 0000 0000 # 19227# # 19228# $$$ (100): FPCR # 19229# (010): FPSR # 19230# (001): FPIAR # 19231# (000): FPIAR # 19232# # 19233######################################################################### 19234 19235 global fmovm_ctrl 19236fmovm_ctrl: 19237 mov.b EXC_EXTWORD(%a6),%d0 # fetch reg select bits 19238 cmpi.b %d0,&0x9c # fpcr & fpsr & fpiar ? 19239 beq.w fctrl_in_7 # yes 19240 cmpi.b %d0,&0x98 # fpcr & fpsr ? 19241 beq.w fctrl_in_6 # yes 19242 cmpi.b %d0,&0x94 # fpcr & fpiar ? 19243 beq.b fctrl_in_5 # yes 19244 19245# fmovem.l #<data>, fpsr/fpiar 19246fctrl_in_3: 19247 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19248 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19249 bsr.l _imem_read_long # fetch FPSR from mem 19250 19251 tst.l %d1 # did ifetch fail? 19252 bne.l iea_iacc # yes 19253 19254 mov.l %d0,USER_FPSR(%a6) # store new FPSR to stack 19255 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19256 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19257 bsr.l _imem_read_long # fetch FPIAR from mem 19258 19259 tst.l %d1 # did ifetch fail? 19260 bne.l iea_iacc # yes 19261 19262 mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack 19263 rts 19264 19265# fmovem.l #<data>, fpcr/fpiar 19266fctrl_in_5: 19267 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19268 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19269 bsr.l _imem_read_long # fetch FPCR from mem 19270 19271 tst.l %d1 # did ifetch fail? 19272 bne.l iea_iacc # yes 19273 19274 mov.l %d0,USER_FPCR(%a6) # store new FPCR to stack 19275 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19276 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19277 bsr.l _imem_read_long # fetch FPIAR from mem 19278 19279 tst.l %d1 # did ifetch fail? 19280 bne.l iea_iacc # yes 19281 19282 mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack 19283 rts 19284 19285# fmovem.l #<data>, fpcr/fpsr 19286fctrl_in_6: 19287 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19288 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19289 bsr.l _imem_read_long # fetch FPCR from mem 19290 19291 tst.l %d1 # did ifetch fail? 19292 bne.l iea_iacc # yes 19293 19294 mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem 19295 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19296 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19297 bsr.l _imem_read_long # fetch FPSR from mem 19298 19299 tst.l %d1 # did ifetch fail? 19300 bne.l iea_iacc # yes 19301 19302 mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem 19303 rts 19304 19305# fmovem.l #<data>, fpcr/fpsr/fpiar 19306fctrl_in_7: 19307 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19308 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19309 bsr.l _imem_read_long # fetch FPCR from mem 19310 19311 tst.l %d1 # did ifetch fail? 19312 bne.l iea_iacc # yes 19313 19314 mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem 19315 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19316 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19317 bsr.l _imem_read_long # fetch FPSR from mem 19318 19319 tst.l %d1 # did ifetch fail? 19320 bne.l iea_iacc # yes 19321 19322 mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem 19323 mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 19324 addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 19325 bsr.l _imem_read_long # fetch FPIAR from mem 19326 19327 tst.l %d1 # did ifetch fail? 19328 bne.l iea_iacc # yes 19329 19330 mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to mem 19331 rts 19332 19333######################################################################### 19334# XDEF **************************************************************** # 19335# _dcalc_ea(): calc correct <ea> from <ea> stacked on exception # 19336# # 19337# XREF **************************************************************** # 19338# inc_areg() - increment an address register # 19339# dec_areg() - decrement an address register # 19340# # 19341# INPUT *************************************************************** # 19342# d0 = number of bytes to adjust <ea> by # 19343# # 19344# OUTPUT ************************************************************** # 19345# None # 19346# # 19347# ALGORITHM *********************************************************** # 19348# "Dummy" CALCulate Effective Address: # 19349# The stacked <ea> for FP unimplemented instructions and opclass # 19350# two packed instructions is correct with the exception of... # 19351# # 19352# 1) -(An) : The register is not updated regardless of size. # 19353# Also, for extended precision and packed, the # 19354# stacked <ea> value is 8 bytes too big # 19355# 2) (An)+ : The register is not updated. # 19356# 3) #<data> : The upper longword of the immediate operand is # 19357# stacked b,w,l and s sizes are completely stacked. # 19358# d,x, and p are not. # 19359# # 19360######################################################################### 19361 19362 global _dcalc_ea 19363_dcalc_ea: 19364 mov.l %d0, %a0 # move # bytes to %a0 19365 19366 mov.b 1+EXC_OPWORD(%a6), %d0 # fetch opcode word 19367 mov.l %d0, %d1 # make a copy 19368 19369 andi.w &0x38, %d0 # extract mode field 19370 andi.l &0x7, %d1 # extract reg field 19371 19372 cmpi.b %d0,&0x18 # is mode (An)+ ? 19373 beq.b dcea_pi # yes 19374 19375 cmpi.b %d0,&0x20 # is mode -(An) ? 19376 beq.b dcea_pd # yes 19377 19378 or.w %d1,%d0 # concat mode,reg 19379 cmpi.b %d0,&0x3c # is mode #<data>? 19380 19381 beq.b dcea_imm # yes 19382 19383 mov.l EXC_EA(%a6),%a0 # return <ea> 19384 rts 19385 19386# need to set immediate data flag here since we'll need to do 19387# an imem_read to fetch this later. 19388dcea_imm: 19389 mov.b &immed_flg,SPCOND_FLG(%a6) 19390 lea ([USER_FPIAR,%a6],0x4),%a0 # no; return <ea> 19391 rts 19392 19393# here, the <ea> is stacked correctly. however, we must update the 19394# address register... 19395dcea_pi: 19396 mov.l %a0,%d0 # pass amt to inc by 19397 bsr.l inc_areg # inc addr register 19398 19399 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 19400 rts 19401 19402# the <ea> is stacked correctly for all but extended and packed which 19403# the <ea>s are 8 bytes too large. 19404# it would make no sense to have a pre-decrement to a7 in supervisor 19405# mode so we don't even worry about this tricky case here : ) 19406dcea_pd: 19407 mov.l %a0,%d0 # pass amt to dec by 19408 bsr.l dec_areg # dec addr register 19409 19410 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 19411 19412 cmpi.b %d0,&0xc # is opsize ext or packed? 19413 beq.b dcea_pd2 # yes 19414 rts 19415dcea_pd2: 19416 sub.l &0x8,%a0 # correct <ea> 19417 mov.l %a0,EXC_EA(%a6) # put correct <ea> on stack 19418 rts 19419 19420######################################################################### 19421# XDEF **************************************************************** # 19422# _calc_ea_fout(): calculate correct stacked <ea> for extended # 19423# and packed data opclass 3 operations. # 19424# # 19425# XREF **************************************************************** # 19426# None # 19427# # 19428# INPUT *************************************************************** # 19429# None # 19430# # 19431# OUTPUT ************************************************************** # 19432# a0 = return correct effective address # 19433# # 19434# ALGORITHM *********************************************************** # 19435# For opclass 3 extended and packed data operations, the <ea> # 19436# stacked for the exception is incorrect for -(an) and (an)+ addressing # 19437# modes. Also, while we're at it, the index register itself must get # 19438# updated. # 19439# So, for -(an), we must subtract 8 off of the stacked <ea> value # 19440# and return that value as the correct <ea> and store that value in An. # 19441# For (an)+, the stacked <ea> is correct but we must adjust An by +12. # 19442# # 19443######################################################################### 19444 19445# This calc_ea is currently used to retrieve the correct <ea> 19446# for fmove outs of type extended and packed. 19447 global _calc_ea_fout 19448_calc_ea_fout: 19449 mov.b 1+EXC_OPWORD(%a6),%d0 # fetch opcode word 19450 mov.l %d0,%d1 # make a copy 19451 19452 andi.w &0x38,%d0 # extract mode field 19453 andi.l &0x7,%d1 # extract reg field 19454 19455 cmpi.b %d0,&0x18 # is mode (An)+ ? 19456 beq.b ceaf_pi # yes 19457 19458 cmpi.b %d0,&0x20 # is mode -(An) ? 19459 beq.w ceaf_pd # yes 19460 19461 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 19462 rts 19463 19464# (An)+ : extended and packed fmove out 19465# : stacked <ea> is correct 19466# : "An" not updated 19467ceaf_pi: 19468 mov.w (tbl_ceaf_pi.b,%pc,%d1.w*2),%d1 19469 mov.l EXC_EA(%a6),%a0 19470 jmp (tbl_ceaf_pi.b,%pc,%d1.w*1) 19471 19472 swbeg &0x8 19473tbl_ceaf_pi: 19474 short ceaf_pi0 - tbl_ceaf_pi 19475 short ceaf_pi1 - tbl_ceaf_pi 19476 short ceaf_pi2 - tbl_ceaf_pi 19477 short ceaf_pi3 - tbl_ceaf_pi 19478 short ceaf_pi4 - tbl_ceaf_pi 19479 short ceaf_pi5 - tbl_ceaf_pi 19480 short ceaf_pi6 - tbl_ceaf_pi 19481 short ceaf_pi7 - tbl_ceaf_pi 19482 19483ceaf_pi0: 19484 addi.l &0xc,EXC_DREGS+0x8(%a6) 19485 rts 19486ceaf_pi1: 19487 addi.l &0xc,EXC_DREGS+0xc(%a6) 19488 rts 19489ceaf_pi2: 19490 add.l &0xc,%a2 19491 rts 19492ceaf_pi3: 19493 add.l &0xc,%a3 19494 rts 19495ceaf_pi4: 19496 add.l &0xc,%a4 19497 rts 19498ceaf_pi5: 19499 add.l &0xc,%a5 19500 rts 19501ceaf_pi6: 19502 addi.l &0xc,EXC_A6(%a6) 19503 rts 19504ceaf_pi7: 19505 mov.b &mia7_flg,SPCOND_FLG(%a6) 19506 addi.l &0xc,EXC_A7(%a6) 19507 rts 19508 19509# -(An) : extended and packed fmove out 19510# : stacked <ea> = actual <ea> + 8 19511# : "An" not updated 19512ceaf_pd: 19513 mov.w (tbl_ceaf_pd.b,%pc,%d1.w*2),%d1 19514 mov.l EXC_EA(%a6),%a0 19515 sub.l &0x8,%a0 19516 sub.l &0x8,EXC_EA(%a6) 19517 jmp (tbl_ceaf_pd.b,%pc,%d1.w*1) 19518 19519 swbeg &0x8 19520tbl_ceaf_pd: 19521 short ceaf_pd0 - tbl_ceaf_pd 19522 short ceaf_pd1 - tbl_ceaf_pd 19523 short ceaf_pd2 - tbl_ceaf_pd 19524 short ceaf_pd3 - tbl_ceaf_pd 19525 short ceaf_pd4 - tbl_ceaf_pd 19526 short ceaf_pd5 - tbl_ceaf_pd 19527 short ceaf_pd6 - tbl_ceaf_pd 19528 short ceaf_pd7 - tbl_ceaf_pd 19529 19530ceaf_pd0: 19531 mov.l %a0,EXC_DREGS+0x8(%a6) 19532 rts 19533ceaf_pd1: 19534 mov.l %a0,EXC_DREGS+0xc(%a6) 19535 rts 19536ceaf_pd2: 19537 mov.l %a0,%a2 19538 rts 19539ceaf_pd3: 19540 mov.l %a0,%a3 19541 rts 19542ceaf_pd4: 19543 mov.l %a0,%a4 19544 rts 19545ceaf_pd5: 19546 mov.l %a0,%a5 19547 rts 19548ceaf_pd6: 19549 mov.l %a0,EXC_A6(%a6) 19550 rts 19551ceaf_pd7: 19552 mov.l %a0,EXC_A7(%a6) 19553 mov.b &mda7_flg,SPCOND_FLG(%a6) 19554 rts 19555 19556######################################################################### 19557# XDEF **************************************************************** # 19558# _load_fop(): load operand for unimplemented FP exception # 19559# # 19560# XREF **************************************************************** # 19561# set_tag_x() - determine ext prec optype tag # 19562# set_tag_s() - determine sgl prec optype tag # 19563# set_tag_d() - determine dbl prec optype tag # 19564# unnorm_fix() - convert normalized number to denorm or zero # 19565# norm() - normalize a denormalized number # 19566# get_packed() - fetch a packed operand from memory # 19567# _dcalc_ea() - calculate <ea>, fixing An in process # 19568# # 19569# _imem_read_{word,long}() - read from instruction memory # 19570# _dmem_read() - read from data memory # 19571# _dmem_read_{byte,word,long}() - read from data memory # 19572# # 19573# facc_in_{b,w,l,d,x}() - mem read failed; special exit point # 19574# # 19575# INPUT *************************************************************** # 19576# None # 19577# # 19578# OUTPUT ************************************************************** # 19579# If memory access doesn't fail: # 19580# FP_SRC(a6) = source operand in extended precision # 19581# FP_DST(a6) = destination operand in extended precision # 19582# # 19583# ALGORITHM *********************************************************** # 19584# This is called from the Unimplemented FP exception handler in # 19585# order to load the source and maybe destination operand into # 19586# FP_SRC(a6) and FP_DST(a6). If the instruction was opclass zero, load # 19587# the source and destination from the FP register file. Set the optype # 19588# tags for both if dyadic, one for monadic. If a number is an UNNORM, # 19589# convert it to a DENORM or a ZERO. # 19590# If the instruction is opclass two (memory->reg), then fetch # 19591# the destination from the register file and the source operand from # 19592# memory. Tag and fix both as above w/ opclass zero instructions. # 19593# If the source operand is byte,word,long, or single, it may be # 19594# in the data register file. If it's actually out in memory, use one of # 19595# the mem_read() routines to fetch it. If the mem_read() access returns # 19596# a failing value, exit through the special facc_in() routine which # 19597# will create an access error exception frame from the current exception # 19598# frame. # 19599# Immediate data and regular data accesses are separated because # 19600# if an immediate data access fails, the resulting fault status # 19601# longword stacked for the access error exception must have the # 19602# instruction bit set. # 19603# # 19604######################################################################### 19605 19606 global _load_fop 19607_load_fop: 19608 19609# 15 13 12 10 9 7 6 0 19610# / \ / \ / \ / \ 19611# --------------------------------- 19612# | opclass | RX | RY | EXTENSION | (2nd word of general FP instruction) 19613# --------------------------------- 19614# 19615 19616# bfextu EXC_CMDREG(%a6){&0:&3}, %d0 # extract opclass 19617# cmpi.b %d0, &0x2 # which class is it? ('000,'010,'011) 19618# beq.w op010 # handle <ea> -> fpn 19619# bgt.w op011 # handle fpn -> <ea> 19620 19621# we're not using op011 for now... 19622 btst &0x6,EXC_CMDREG(%a6) 19623 bne.b op010 19624 19625############################ 19626# OPCLASS '000: reg -> reg # 19627############################ 19628op000: 19629 mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension word lo 19630 btst &0x5,%d0 # testing extension bits 19631 beq.b op000_src # (bit 5 == 0) => monadic 19632 btst &0x4,%d0 # (bit 5 == 1) 19633 beq.b op000_dst # (bit 4 == 0) => dyadic 19634 and.w &0x007f,%d0 # extract extension bits {6:0} 19635 cmpi.w %d0,&0x0038 # is it an fcmp (dyadic) ? 19636 bne.b op000_src # it's an fcmp 19637 19638op000_dst: 19639 bfextu EXC_CMDREG(%a6){&6:&3}, %d0 # extract dst field 19640 bsr.l load_fpn2 # fetch dst fpreg into FP_DST 19641 19642 bsr.l set_tag_x # get dst optype tag 19643 19644 cmpi.b %d0, &UNNORM # is dst fpreg an UNNORM? 19645 beq.b op000_dst_unnorm # yes 19646op000_dst_cont: 19647 mov.b %d0, DTAG(%a6) # store the dst optype tag 19648 19649op000_src: 19650 bfextu EXC_CMDREG(%a6){&3:&3}, %d0 # extract src field 19651 bsr.l load_fpn1 # fetch src fpreg into FP_SRC 19652 19653 bsr.l set_tag_x # get src optype tag 19654 19655 cmpi.b %d0, &UNNORM # is src fpreg an UNNORM? 19656 beq.b op000_src_unnorm # yes 19657op000_src_cont: 19658 mov.b %d0, STAG(%a6) # store the src optype tag 19659 rts 19660 19661op000_dst_unnorm: 19662 bsr.l unnorm_fix # fix the dst UNNORM 19663 bra.b op000_dst_cont 19664op000_src_unnorm: 19665 bsr.l unnorm_fix # fix the src UNNORM 19666 bra.b op000_src_cont 19667 19668############################# 19669# OPCLASS '010: <ea> -> reg # 19670############################# 19671op010: 19672 mov.w EXC_CMDREG(%a6),%d0 # fetch extension word 19673 btst &0x5,%d0 # testing extension bits 19674 beq.b op010_src # (bit 5 == 0) => monadic 19675 btst &0x4,%d0 # (bit 5 == 1) 19676 beq.b op010_dst # (bit 4 == 0) => dyadic 19677 and.w &0x007f,%d0 # extract extension bits {6:0} 19678 cmpi.w %d0,&0x0038 # is it an fcmp (dyadic) ? 19679 bne.b op010_src # it's an fcmp 19680 19681op010_dst: 19682 bfextu EXC_CMDREG(%a6){&6:&3}, %d0 # extract dst field 19683 bsr.l load_fpn2 # fetch dst fpreg ptr 19684 19685 bsr.l set_tag_x # get dst type tag 19686 19687 cmpi.b %d0, &UNNORM # is dst fpreg an UNNORM? 19688 beq.b op010_dst_unnorm # yes 19689op010_dst_cont: 19690 mov.b %d0, DTAG(%a6) # store the dst optype tag 19691 19692op010_src: 19693 bfextu EXC_CMDREG(%a6){&3:&3}, %d0 # extract src type field 19694 19695 bfextu EXC_OPWORD(%a6){&10:&3}, %d1 # extract <ea> mode field 19696 bne.w fetch_from_mem # src op is in memory 19697 19698op010_dreg: 19699 clr.b STAG(%a6) # either NORM or ZERO 19700 bfextu EXC_OPWORD(%a6){&13:&3}, %d1 # extract src reg field 19701 19702 mov.w (tbl_op010_dreg.b,%pc,%d0.w*2), %d0 # jmp based on optype 19703 jmp (tbl_op010_dreg.b,%pc,%d0.w*1) # fetch src from dreg 19704 19705op010_dst_unnorm: 19706 bsr.l unnorm_fix # fix the dst UNNORM 19707 bra.b op010_dst_cont 19708 19709 swbeg &0x8 19710tbl_op010_dreg: 19711 short opd_long - tbl_op010_dreg 19712 short opd_sgl - tbl_op010_dreg 19713 short tbl_op010_dreg - tbl_op010_dreg 19714 short tbl_op010_dreg - tbl_op010_dreg 19715 short opd_word - tbl_op010_dreg 19716 short tbl_op010_dreg - tbl_op010_dreg 19717 short opd_byte - tbl_op010_dreg 19718 short tbl_op010_dreg - tbl_op010_dreg 19719 19720# 19721# LONG: can be either NORM or ZERO... 19722# 19723opd_long: 19724 bsr.l fetch_dreg # fetch long in d0 19725 fmov.l %d0, %fp0 # load a long 19726 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19727 fbeq.w opd_long_zero # long is a ZERO 19728 rts 19729opd_long_zero: 19730 mov.b &ZERO, STAG(%a6) # set ZERO optype flag 19731 rts 19732 19733# 19734# WORD: can be either NORM or ZERO... 19735# 19736opd_word: 19737 bsr.l fetch_dreg # fetch word in d0 19738 fmov.w %d0, %fp0 # load a word 19739 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19740 fbeq.w opd_word_zero # WORD is a ZERO 19741 rts 19742opd_word_zero: 19743 mov.b &ZERO, STAG(%a6) # set ZERO optype flag 19744 rts 19745 19746# 19747# BYTE: can be either NORM or ZERO... 19748# 19749opd_byte: 19750 bsr.l fetch_dreg # fetch word in d0 19751 fmov.b %d0, %fp0 # load a byte 19752 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19753 fbeq.w opd_byte_zero # byte is a ZERO 19754 rts 19755opd_byte_zero: 19756 mov.b &ZERO, STAG(%a6) # set ZERO optype flag 19757 rts 19758 19759# 19760# SGL: can be either NORM, DENORM, ZERO, INF, QNAN or SNAN but not UNNORM 19761# 19762# separate SNANs and DENORMs so they can be loaded w/ special care. 19763# all others can simply be moved "in" using fmove. 19764# 19765opd_sgl: 19766 bsr.l fetch_dreg # fetch sgl in d0 19767 mov.l %d0,L_SCR1(%a6) 19768 19769 lea L_SCR1(%a6), %a0 # pass: ptr to the sgl 19770 bsr.l set_tag_s # determine sgl type 19771 mov.b %d0, STAG(%a6) # save the src tag 19772 19773 cmpi.b %d0, &SNAN # is it an SNAN? 19774 beq.w get_sgl_snan # yes 19775 19776 cmpi.b %d0, &DENORM # is it a DENORM? 19777 beq.w get_sgl_denorm # yes 19778 19779 fmov.s (%a0), %fp0 # no, so can load it regular 19780 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19781 rts 19782 19783############################################################################## 19784 19785######################################################################### 19786# fetch_from_mem(): # 19787# - src is out in memory. must: # 19788# (1) calc ea - must read AFTER you know the src type since # 19789# if the ea is -() or ()+, need to know # of bytes. # 19790# (2) read it in from either user or supervisor space # 19791# (3) if (b || w || l) then simply read in # 19792# if (s || d || x) then check for SNAN,UNNORM,DENORM # 19793# if (packed) then punt for now # 19794# INPUT: # 19795# %d0 : src type field # 19796######################################################################### 19797fetch_from_mem: 19798 clr.b STAG(%a6) # either NORM or ZERO 19799 19800 mov.w (tbl_fp_type.b,%pc,%d0.w*2), %d0 # index by src type field 19801 jmp (tbl_fp_type.b,%pc,%d0.w*1) 19802 19803 swbeg &0x8 19804tbl_fp_type: 19805 short load_long - tbl_fp_type 19806 short load_sgl - tbl_fp_type 19807 short load_ext - tbl_fp_type 19808 short load_packed - tbl_fp_type 19809 short load_word - tbl_fp_type 19810 short load_dbl - tbl_fp_type 19811 short load_byte - tbl_fp_type 19812 short tbl_fp_type - tbl_fp_type 19813 19814######################################### 19815# load a LONG into %fp0: # 19816# -number can't fault # 19817# (1) calc ea # 19818# (2) read 4 bytes into L_SCR1 # 19819# (3) fmov.l into %fp0 # 19820######################################### 19821load_long: 19822 movq.l &0x4, %d0 # pass: 4 (bytes) 19823 bsr.l _dcalc_ea # calc <ea>; <ea> in %a0 19824 19825 cmpi.b SPCOND_FLG(%a6),&immed_flg 19826 beq.b load_long_immed 19827 19828 bsr.l _dmem_read_long # fetch src operand from memory 19829 19830 tst.l %d1 # did dfetch fail? 19831 bne.l facc_in_l # yes 19832 19833load_long_cont: 19834 fmov.l %d0, %fp0 # read into %fp0;convert to xprec 19835 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19836 19837 fbeq.w load_long_zero # src op is a ZERO 19838 rts 19839load_long_zero: 19840 mov.b &ZERO, STAG(%a6) # set optype tag to ZERO 19841 rts 19842 19843load_long_immed: 19844 bsr.l _imem_read_long # fetch src operand immed data 19845 19846 tst.l %d1 # did ifetch fail? 19847 bne.l funimp_iacc # yes 19848 bra.b load_long_cont 19849 19850######################################### 19851# load a WORD into %fp0: # 19852# -number can't fault # 19853# (1) calc ea # 19854# (2) read 2 bytes into L_SCR1 # 19855# (3) fmov.w into %fp0 # 19856######################################### 19857load_word: 19858 movq.l &0x2, %d0 # pass: 2 (bytes) 19859 bsr.l _dcalc_ea # calc <ea>; <ea> in %a0 19860 19861 cmpi.b SPCOND_FLG(%a6),&immed_flg 19862 beq.b load_word_immed 19863 19864 bsr.l _dmem_read_word # fetch src operand from memory 19865 19866 tst.l %d1 # did dfetch fail? 19867 bne.l facc_in_w # yes 19868 19869load_word_cont: 19870 fmov.w %d0, %fp0 # read into %fp0;convert to xprec 19871 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19872 19873 fbeq.w load_word_zero # src op is a ZERO 19874 rts 19875load_word_zero: 19876 mov.b &ZERO, STAG(%a6) # set optype tag to ZERO 19877 rts 19878 19879load_word_immed: 19880 bsr.l _imem_read_word # fetch src operand immed data 19881 19882 tst.l %d1 # did ifetch fail? 19883 bne.l funimp_iacc # yes 19884 bra.b load_word_cont 19885 19886######################################### 19887# load a BYTE into %fp0: # 19888# -number can't fault # 19889# (1) calc ea # 19890# (2) read 1 byte into L_SCR1 # 19891# (3) fmov.b into %fp0 # 19892######################################### 19893load_byte: 19894 movq.l &0x1, %d0 # pass: 1 (byte) 19895 bsr.l _dcalc_ea # calc <ea>; <ea> in %a0 19896 19897 cmpi.b SPCOND_FLG(%a6),&immed_flg 19898 beq.b load_byte_immed 19899 19900 bsr.l _dmem_read_byte # fetch src operand from memory 19901 19902 tst.l %d1 # did dfetch fail? 19903 bne.l facc_in_b # yes 19904 19905load_byte_cont: 19906 fmov.b %d0, %fp0 # read into %fp0;convert to xprec 19907 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19908 19909 fbeq.w load_byte_zero # src op is a ZERO 19910 rts 19911load_byte_zero: 19912 mov.b &ZERO, STAG(%a6) # set optype tag to ZERO 19913 rts 19914 19915load_byte_immed: 19916 bsr.l _imem_read_word # fetch src operand immed data 19917 19918 tst.l %d1 # did ifetch fail? 19919 bne.l funimp_iacc # yes 19920 bra.b load_byte_cont 19921 19922######################################### 19923# load a SGL into %fp0: # 19924# -number can't fault # 19925# (1) calc ea # 19926# (2) read 4 bytes into L_SCR1 # 19927# (3) fmov.s into %fp0 # 19928######################################### 19929load_sgl: 19930 movq.l &0x4, %d0 # pass: 4 (bytes) 19931 bsr.l _dcalc_ea # calc <ea>; <ea> in %a0 19932 19933 cmpi.b SPCOND_FLG(%a6),&immed_flg 19934 beq.b load_sgl_immed 19935 19936 bsr.l _dmem_read_long # fetch src operand from memory 19937 mov.l %d0, L_SCR1(%a6) # store src op on stack 19938 19939 tst.l %d1 # did dfetch fail? 19940 bne.l facc_in_l # yes 19941 19942load_sgl_cont: 19943 lea L_SCR1(%a6), %a0 # pass: ptr to sgl src op 19944 bsr.l set_tag_s # determine src type tag 19945 mov.b %d0, STAG(%a6) # save src optype tag on stack 19946 19947 cmpi.b %d0, &DENORM # is it a sgl DENORM? 19948 beq.w get_sgl_denorm # yes 19949 19950 cmpi.b %d0, &SNAN # is it a sgl SNAN? 19951 beq.w get_sgl_snan # yes 19952 19953 fmov.s L_SCR1(%a6), %fp0 # read into %fp0;convert to xprec 19954 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 19955 rts 19956 19957load_sgl_immed: 19958 bsr.l _imem_read_long # fetch src operand immed data 19959 19960 tst.l %d1 # did ifetch fail? 19961 bne.l funimp_iacc # yes 19962 bra.b load_sgl_cont 19963 19964# must convert sgl denorm format to an Xprec denorm fmt suitable for 19965# normalization... 19966# %a0 : points to sgl denorm 19967get_sgl_denorm: 19968 clr.w FP_SRC_EX(%a6) 19969 bfextu (%a0){&9:&23}, %d0 # fetch sgl hi(_mantissa) 19970 lsl.l &0x8, %d0 19971 mov.l %d0, FP_SRC_HI(%a6) # set ext hi(_mantissa) 19972 clr.l FP_SRC_LO(%a6) # set ext lo(_mantissa) 19973 19974 clr.w FP_SRC_EX(%a6) 19975 btst &0x7, (%a0) # is sgn bit set? 19976 beq.b sgl_dnrm_norm 19977 bset &0x7, FP_SRC_EX(%a6) # set sgn of xprec value 19978 19979sgl_dnrm_norm: 19980 lea FP_SRC(%a6), %a0 19981 bsr.l norm # normalize number 19982 mov.w &0x3f81, %d1 # xprec exp = 0x3f81 19983 sub.w %d0, %d1 # exp = 0x3f81 - shft amt. 19984 or.w %d1, FP_SRC_EX(%a6) # {sgn,exp} 19985 19986 mov.b &NORM, STAG(%a6) # fix src type tag 19987 rts 19988 19989# convert sgl to ext SNAN 19990# %a0 : points to sgl SNAN 19991get_sgl_snan: 19992 mov.w &0x7fff, FP_SRC_EX(%a6) # set exp of SNAN 19993 bfextu (%a0){&9:&23}, %d0 19994 lsl.l &0x8, %d0 # extract and insert hi(man) 19995 mov.l %d0, FP_SRC_HI(%a6) 19996 clr.l FP_SRC_LO(%a6) 19997 19998 btst &0x7, (%a0) # see if sign of SNAN is set 19999 beq.b no_sgl_snan_sgn 20000 bset &0x7, FP_SRC_EX(%a6) 20001no_sgl_snan_sgn: 20002 rts 20003 20004######################################### 20005# load a DBL into %fp0: # 20006# -number can't fault # 20007# (1) calc ea # 20008# (2) read 8 bytes into L_SCR(1,2)# 20009# (3) fmov.d into %fp0 # 20010######################################### 20011load_dbl: 20012 movq.l &0x8, %d0 # pass: 8 (bytes) 20013 bsr.l _dcalc_ea # calc <ea>; <ea> in %a0 20014 20015 cmpi.b SPCOND_FLG(%a6),&immed_flg 20016 beq.b load_dbl_immed 20017 20018 lea L_SCR1(%a6), %a1 # pass: ptr to input dbl tmp space 20019 movq.l &0x8, %d0 # pass: # bytes to read 20020 bsr.l _dmem_read # fetch src operand from memory 20021 20022 tst.l %d1 # did dfetch fail? 20023 bne.l facc_in_d # yes 20024 20025load_dbl_cont: 20026 lea L_SCR1(%a6), %a0 # pass: ptr to input dbl 20027 bsr.l set_tag_d # determine src type tag 20028 mov.b %d0, STAG(%a6) # set src optype tag 20029 20030 cmpi.b %d0, &DENORM # is it a dbl DENORM? 20031 beq.w get_dbl_denorm # yes 20032 20033 cmpi.b %d0, &SNAN # is it a dbl SNAN? 20034 beq.w get_dbl_snan # yes 20035 20036 fmov.d L_SCR1(%a6), %fp0 # read into %fp0;convert to xprec 20037 fmovm.x &0x80, FP_SRC(%a6) # return src op in FP_SRC 20038 rts 20039 20040load_dbl_immed: 20041 lea L_SCR1(%a6), %a1 # pass: ptr to input dbl tmp space 20042 movq.l &0x8, %d0 # pass: # bytes to read 20043 bsr.l _imem_read # fetch src operand from memory 20044 20045 tst.l %d1 # did ifetch fail? 20046 bne.l funimp_iacc # yes 20047 bra.b load_dbl_cont 20048 20049# must convert dbl denorm format to an Xprec denorm fmt suitable for 20050# normalization... 20051# %a0 : loc. of dbl denorm 20052get_dbl_denorm: 20053 clr.w FP_SRC_EX(%a6) 20054 bfextu (%a0){&12:&31}, %d0 # fetch hi(_mantissa) 20055 mov.l %d0, FP_SRC_HI(%a6) 20056 bfextu 4(%a0){&11:&21}, %d0 # fetch lo(_mantissa) 20057 mov.l &0xb, %d1 20058 lsl.l %d1, %d0 20059 mov.l %d0, FP_SRC_LO(%a6) 20060 20061 btst &0x7, (%a0) # is sgn bit set? 20062 beq.b dbl_dnrm_norm 20063 bset &0x7, FP_SRC_EX(%a6) # set sgn of xprec value 20064 20065dbl_dnrm_norm: 20066 lea FP_SRC(%a6), %a0 20067 bsr.l norm # normalize number 20068 mov.w &0x3c01, %d1 # xprec exp = 0x3c01 20069 sub.w %d0, %d1 # exp = 0x3c01 - shft amt. 20070 or.w %d1, FP_SRC_EX(%a6) # {sgn,exp} 20071 20072 mov.b &NORM, STAG(%a6) # fix src type tag 20073 rts 20074 20075# convert dbl to ext SNAN 20076# %a0 : points to dbl SNAN 20077get_dbl_snan: 20078 mov.w &0x7fff, FP_SRC_EX(%a6) # set exp of SNAN 20079 20080 bfextu (%a0){&12:&31}, %d0 # fetch hi(_mantissa) 20081 mov.l %d0, FP_SRC_HI(%a6) 20082 bfextu 4(%a0){&11:&21}, %d0 # fetch lo(_mantissa) 20083 mov.l &0xb, %d1 20084 lsl.l %d1, %d0 20085 mov.l %d0, FP_SRC_LO(%a6) 20086 20087 btst &0x7, (%a0) # see if sign of SNAN is set 20088 beq.b no_dbl_snan_sgn 20089 bset &0x7, FP_SRC_EX(%a6) 20090no_dbl_snan_sgn: 20091 rts 20092 20093################################################# 20094# load a Xprec into %fp0: # 20095# -number can't fault # 20096# (1) calc ea # 20097# (2) read 12 bytes into L_SCR(1,2) # 20098# (3) fmov.x into %fp0 # 20099################################################# 20100load_ext: 20101 mov.l &0xc, %d0 # pass: 12 (bytes) 20102 bsr.l _dcalc_ea # calc <ea> 20103 20104 lea FP_SRC(%a6), %a1 # pass: ptr to input ext tmp space 20105 mov.l &0xc, %d0 # pass: # of bytes to read 20106 bsr.l _dmem_read # fetch src operand from memory 20107 20108 tst.l %d1 # did dfetch fail? 20109 bne.l facc_in_x # yes 20110 20111 lea FP_SRC(%a6), %a0 # pass: ptr to src op 20112 bsr.l set_tag_x # determine src type tag 20113 20114 cmpi.b %d0, &UNNORM # is the src op an UNNORM? 20115 beq.b load_ext_unnorm # yes 20116 20117 mov.b %d0, STAG(%a6) # store the src optype tag 20118 rts 20119 20120load_ext_unnorm: 20121 bsr.l unnorm_fix # fix the src UNNORM 20122 mov.b %d0, STAG(%a6) # store the src optype tag 20123 rts 20124 20125################################################# 20126# load a packed into %fp0: # 20127# -number can't fault # 20128# (1) calc ea # 20129# (2) read 12 bytes into L_SCR(1,2,3) # 20130# (3) fmov.x into %fp0 # 20131################################################# 20132load_packed: 20133 bsr.l get_packed 20134 20135 lea FP_SRC(%a6),%a0 # pass ptr to src op 20136 bsr.l set_tag_x # determine src type tag 20137 cmpi.b %d0,&UNNORM # is the src op an UNNORM ZERO? 20138 beq.b load_packed_unnorm # yes 20139 20140 mov.b %d0,STAG(%a6) # store the src optype tag 20141 rts 20142 20143load_packed_unnorm: 20144 bsr.l unnorm_fix # fix the UNNORM ZERO 20145 mov.b %d0,STAG(%a6) # store the src optype tag 20146 rts 20147 20148######################################################################### 20149# XDEF **************************************************************** # 20150# fout(): move from fp register to memory or data register # 20151# # 20152# XREF **************************************************************** # 20153# _round() - needed to create EXOP for sgl/dbl precision # 20154# norm() - needed to create EXOP for extended precision # 20155# ovf_res() - create default overflow result for sgl/dbl precision# 20156# unf_res() - create default underflow result for sgl/dbl prec. # 20157# dst_dbl() - create rounded dbl precision result. # 20158# dst_sgl() - create rounded sgl precision result. # 20159# fetch_dreg() - fetch dynamic k-factor reg for packed. # 20160# bindec() - convert FP binary number to packed number. # 20161# _mem_write() - write data to memory. # 20162# _mem_write2() - write data to memory unless supv mode -(a7) exc.# 20163# _dmem_write_{byte,word,long}() - write data to memory. # 20164# store_dreg_{b,w,l}() - store data to data register file. # 20165# facc_out_{b,w,l,d,x}() - data access error occurred. # 20166# # 20167# INPUT *************************************************************** # 20168# a0 = pointer to extended precision source operand # 20169# d0 = round prec,mode # 20170# # 20171# OUTPUT ************************************************************** # 20172# fp0 : intermediate underflow or overflow result if # 20173# OVFL/UNFL occurred for a sgl or dbl operand # 20174# # 20175# ALGORITHM *********************************************************** # 20176# This routine is accessed by many handlers that need to do an # 20177# opclass three move of an operand out to memory. # 20178# Decode an fmove out (opclass 3) instruction to determine if # 20179# it's b,w,l,s,d,x, or p in size. b,w,l can be stored to either a data # 20180# register or memory. The algorithm uses a standard "fmove" to create # 20181# the rounded result. Also, since exceptions are disabled, this also # 20182# create the correct OPERR default result if appropriate. # 20183# For sgl or dbl precision, overflow or underflow can occur. If # 20184# either occurs and is enabled, the EXOP. # 20185# For extended precision, the stacked <ea> must be fixed along # 20186# w/ the address index register as appropriate w/ _calc_ea_fout(). If # 20187# the source is a denorm and if underflow is enabled, an EXOP must be # 20188# created. # 20189# For packed, the k-factor must be fetched from the instruction # 20190# word or a data register. The <ea> must be fixed as w/ extended # 20191# precision. Then, bindec() is called to create the appropriate # 20192# packed result. # 20193# If at any time an access error is flagged by one of the move- # 20194# to-memory routines, then a special exit must be made so that the # 20195# access error can be handled properly. # 20196# # 20197######################################################################### 20198 20199 global fout 20200fout: 20201 bfextu EXC_CMDREG(%a6){&3:&3},%d1 # extract dst fmt 20202 mov.w (tbl_fout.b,%pc,%d1.w*2),%a1 # use as index 20203 jmp (tbl_fout.b,%pc,%a1) # jump to routine 20204 20205 swbeg &0x8 20206tbl_fout: 20207 short fout_long - tbl_fout 20208 short fout_sgl - tbl_fout 20209 short fout_ext - tbl_fout 20210 short fout_pack - tbl_fout 20211 short fout_word - tbl_fout 20212 short fout_dbl - tbl_fout 20213 short fout_byte - tbl_fout 20214 short fout_pack - tbl_fout 20215 20216################################################################# 20217# fmove.b out ################################################### 20218################################################################# 20219 20220# Only "Unimplemented Data Type" exceptions enter here. The operand 20221# is either a DENORM or a NORM. 20222fout_byte: 20223 tst.b STAG(%a6) # is operand normalized? 20224 bne.b fout_byte_denorm # no 20225 20226 fmovm.x SRC(%a0),&0x80 # load value 20227 20228fout_byte_norm: 20229 fmov.l %d0,%fpcr # insert rnd prec,mode 20230 20231 fmov.b %fp0,%d0 # exec move out w/ correct rnd mode 20232 20233 fmov.l &0x0,%fpcr # clear FPCR 20234 fmov.l %fpsr,%d1 # fetch FPSR 20235 or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits 20236 20237 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 20238 andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 20239 beq.b fout_byte_dn # must save to integer regfile 20240 20241 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 20242 bsr.l _dmem_write_byte # write byte 20243 20244 tst.l %d1 # did dstore fail? 20245 bne.l facc_out_b # yes 20246 20247 rts 20248 20249fout_byte_dn: 20250 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 20251 andi.w &0x7,%d1 20252 bsr.l store_dreg_b 20253 rts 20254 20255fout_byte_denorm: 20256 mov.l SRC_EX(%a0),%d1 20257 andi.l &0x80000000,%d1 # keep DENORM sign 20258 ori.l &0x00800000,%d1 # make smallest sgl 20259 fmov.s %d1,%fp0 20260 bra.b fout_byte_norm 20261 20262################################################################# 20263# fmove.w out ################################################### 20264################################################################# 20265 20266# Only "Unimplemented Data Type" exceptions enter here. The operand 20267# is either a DENORM or a NORM. 20268fout_word: 20269 tst.b STAG(%a6) # is operand normalized? 20270 bne.b fout_word_denorm # no 20271 20272 fmovm.x SRC(%a0),&0x80 # load value 20273 20274fout_word_norm: 20275 fmov.l %d0,%fpcr # insert rnd prec:mode 20276 20277 fmov.w %fp0,%d0 # exec move out w/ correct rnd mode 20278 20279 fmov.l &0x0,%fpcr # clear FPCR 20280 fmov.l %fpsr,%d1 # fetch FPSR 20281 or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits 20282 20283 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 20284 andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 20285 beq.b fout_word_dn # must save to integer regfile 20286 20287 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 20288 bsr.l _dmem_write_word # write word 20289 20290 tst.l %d1 # did dstore fail? 20291 bne.l facc_out_w # yes 20292 20293 rts 20294 20295fout_word_dn: 20296 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 20297 andi.w &0x7,%d1 20298 bsr.l store_dreg_w 20299 rts 20300 20301fout_word_denorm: 20302 mov.l SRC_EX(%a0),%d1 20303 andi.l &0x80000000,%d1 # keep DENORM sign 20304 ori.l &0x00800000,%d1 # make smallest sgl 20305 fmov.s %d1,%fp0 20306 bra.b fout_word_norm 20307 20308################################################################# 20309# fmove.l out ################################################### 20310################################################################# 20311 20312# Only "Unimplemented Data Type" exceptions enter here. The operand 20313# is either a DENORM or a NORM. 20314fout_long: 20315 tst.b STAG(%a6) # is operand normalized? 20316 bne.b fout_long_denorm # no 20317 20318 fmovm.x SRC(%a0),&0x80 # load value 20319 20320fout_long_norm: 20321 fmov.l %d0,%fpcr # insert rnd prec:mode 20322 20323 fmov.l %fp0,%d0 # exec move out w/ correct rnd mode 20324 20325 fmov.l &0x0,%fpcr # clear FPCR 20326 fmov.l %fpsr,%d1 # fetch FPSR 20327 or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits 20328 20329fout_long_write: 20330 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 20331 andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 20332 beq.b fout_long_dn # must save to integer regfile 20333 20334 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 20335 bsr.l _dmem_write_long # write long 20336 20337 tst.l %d1 # did dstore fail? 20338 bne.l facc_out_l # yes 20339 20340 rts 20341 20342fout_long_dn: 20343 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 20344 andi.w &0x7,%d1 20345 bsr.l store_dreg_l 20346 rts 20347 20348fout_long_denorm: 20349 mov.l SRC_EX(%a0),%d1 20350 andi.l &0x80000000,%d1 # keep DENORM sign 20351 ori.l &0x00800000,%d1 # make smallest sgl 20352 fmov.s %d1,%fp0 20353 bra.b fout_long_norm 20354 20355################################################################# 20356# fmove.x out ################################################### 20357################################################################# 20358 20359# Only "Unimplemented Data Type" exceptions enter here. The operand 20360# is either a DENORM or a NORM. 20361# The DENORM causes an Underflow exception. 20362fout_ext: 20363 20364# we copy the extended precision result to FP_SCR0 so that the reserved 20365# 16-bit field gets zeroed. we do this since we promise not to disturb 20366# what's at SRC(a0). 20367 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 20368 clr.w 2+FP_SCR0_EX(%a6) # clear reserved field 20369 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 20370 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 20371 20372 fmovm.x SRC(%a0),&0x80 # return result 20373 20374 bsr.l _calc_ea_fout # fix stacked <ea> 20375 20376 mov.l %a0,%a1 # pass: dst addr 20377 lea FP_SCR0(%a6),%a0 # pass: src addr 20378 mov.l &0xc,%d0 # pass: opsize is 12 bytes 20379 20380# we must not yet write the extended precision data to the stack 20381# in the pre-decrement case from supervisor mode or else we'll corrupt 20382# the stack frame. so, leave it in FP_SRC for now and deal with it later... 20383 cmpi.b SPCOND_FLG(%a6),&mda7_flg 20384 beq.b fout_ext_a7 20385 20386 bsr.l _dmem_write # write ext prec number to memory 20387 20388 tst.l %d1 # did dstore fail? 20389 bne.w fout_ext_err # yes 20390 20391 tst.b STAG(%a6) # is operand normalized? 20392 bne.b fout_ext_denorm # no 20393 rts 20394 20395# the number is a DENORM. must set the underflow exception bit 20396fout_ext_denorm: 20397 bset &unfl_bit,FPSR_EXCEPT(%a6) # set underflow exc bit 20398 20399 mov.b FPCR_ENABLE(%a6),%d0 20400 andi.b &0x0a,%d0 # is UNFL or INEX enabled? 20401 bne.b fout_ext_exc # yes 20402 rts 20403 20404# we don't want to do the write if the exception occurred in supervisor mode 20405# so _mem_write2() handles this for us. 20406fout_ext_a7: 20407 bsr.l _mem_write2 # write ext prec number to memory 20408 20409 tst.l %d1 # did dstore fail? 20410 bne.w fout_ext_err # yes 20411 20412 tst.b STAG(%a6) # is operand normalized? 20413 bne.b fout_ext_denorm # no 20414 rts 20415 20416fout_ext_exc: 20417 lea FP_SCR0(%a6),%a0 20418 bsr.l norm # normalize the mantissa 20419 neg.w %d0 # new exp = -(shft amt) 20420 andi.w &0x7fff,%d0 20421 andi.w &0x8000,FP_SCR0_EX(%a6) # keep only old sign 20422 or.w %d0,FP_SCR0_EX(%a6) # insert new exponent 20423 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 20424 rts 20425 20426fout_ext_err: 20427 mov.l EXC_A6(%a6),(%a6) # fix stacked a6 20428 bra.l facc_out_x 20429 20430######################################################################### 20431# fmove.s out ########################################################### 20432######################################################################### 20433fout_sgl: 20434 andi.b &0x30,%d0 # clear rnd prec 20435 ori.b &s_mode*0x10,%d0 # insert sgl prec 20436 mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack 20437 20438# 20439# operand is a normalized number. first, we check to see if the move out 20440# would cause either an underflow or overflow. these cases are handled 20441# separately. otherwise, set the FPCR to the proper rounding mode and 20442# execute the move. 20443# 20444 mov.w SRC_EX(%a0),%d0 # extract exponent 20445 andi.w &0x7fff,%d0 # strip sign 20446 20447 cmpi.w %d0,&SGL_HI # will operand overflow? 20448 bgt.w fout_sgl_ovfl # yes; go handle OVFL 20449 beq.w fout_sgl_may_ovfl # maybe; go handle possible OVFL 20450 cmpi.w %d0,&SGL_LO # will operand underflow? 20451 blt.w fout_sgl_unfl # yes; go handle underflow 20452 20453# 20454# NORMs(in range) can be stored out by a simple "fmov.s" 20455# Unnormalized inputs can come through this point. 20456# 20457fout_sgl_exg: 20458 fmovm.x SRC(%a0),&0x80 # fetch fop from stack 20459 20460 fmov.l L_SCR3(%a6),%fpcr # set FPCR 20461 fmov.l &0x0,%fpsr # clear FPSR 20462 20463 fmov.s %fp0,%d0 # store does convert and round 20464 20465 fmov.l &0x0,%fpcr # clear FPCR 20466 fmov.l %fpsr,%d1 # save FPSR 20467 20468 or.w %d1,2+USER_FPSR(%a6) # set possible inex2/ainex 20469 20470fout_sgl_exg_write: 20471 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 20472 andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 20473 beq.b fout_sgl_exg_write_dn # must save to integer regfile 20474 20475 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 20476 bsr.l _dmem_write_long # write long 20477 20478 tst.l %d1 # did dstore fail? 20479 bne.l facc_out_l # yes 20480 20481 rts 20482 20483fout_sgl_exg_write_dn: 20484 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 20485 andi.w &0x7,%d1 20486 bsr.l store_dreg_l 20487 rts 20488 20489# 20490# here, we know that the operand would UNFL if moved out to single prec, 20491# so, denorm and round and then use generic store single routine to 20492# write the value to memory. 20493# 20494fout_sgl_unfl: 20495 bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL 20496 20497 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 20498 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 20499 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 20500 mov.l %a0,-(%sp) 20501 20502 clr.l %d0 # pass: S.F. = 0 20503 20504 cmpi.b STAG(%a6),&DENORM # fetch src optype tag 20505 bne.b fout_sgl_unfl_cont # let DENORMs fall through 20506 20507 lea FP_SCR0(%a6),%a0 20508 bsr.l norm # normalize the DENORM 20509 20510fout_sgl_unfl_cont: 20511 lea FP_SCR0(%a6),%a0 # pass: ptr to operand 20512 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 20513 bsr.l unf_res # calc default underflow result 20514 20515 lea FP_SCR0(%a6),%a0 # pass: ptr to fop 20516 bsr.l dst_sgl # convert to single prec 20517 20518 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 20519 andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 20520 beq.b fout_sgl_unfl_dn # must save to integer regfile 20521 20522 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 20523 bsr.l _dmem_write_long # write long 20524 20525 tst.l %d1 # did dstore fail? 20526 bne.l facc_out_l # yes 20527 20528 bra.b fout_sgl_unfl_chkexc 20529 20530fout_sgl_unfl_dn: 20531 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 20532 andi.w &0x7,%d1 20533 bsr.l store_dreg_l 20534 20535fout_sgl_unfl_chkexc: 20536 mov.b FPCR_ENABLE(%a6),%d1 20537 andi.b &0x0a,%d1 # is UNFL or INEX enabled? 20538 bne.w fout_sd_exc_unfl # yes 20539 addq.l &0x4,%sp 20540 rts 20541 20542# 20543# it's definitely an overflow so call ovf_res to get the correct answer 20544# 20545fout_sgl_ovfl: 20546 tst.b 3+SRC_HI(%a0) # is result inexact? 20547 bne.b fout_sgl_ovfl_inex2 20548 tst.l SRC_LO(%a0) # is result inexact? 20549 bne.b fout_sgl_ovfl_inex2 20550 ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex 20551 bra.b fout_sgl_ovfl_cont 20552fout_sgl_ovfl_inex2: 20553 ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2 20554 20555fout_sgl_ovfl_cont: 20556 mov.l %a0,-(%sp) 20557 20558# call ovf_res() w/ sgl prec and the correct rnd mode to create the default 20559# overflow result. DON'T save the returned ccodes from ovf_res() since 20560# fmove out doesn't alter them. 20561 tst.b SRC_EX(%a0) # is operand negative? 20562 smi %d1 # set if so 20563 mov.l L_SCR3(%a6),%d0 # pass: sgl prec,rnd mode 20564 bsr.l ovf_res # calc OVFL result 20565 fmovm.x (%a0),&0x80 # load default overflow result 20566 fmov.s %fp0,%d0 # store to single 20567 20568 mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 20569 andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 20570 beq.b fout_sgl_ovfl_dn # must save to integer regfile 20571 20572 mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 20573 bsr.l _dmem_write_long # write long 20574 20575 tst.l %d1 # did dstore fail? 20576 bne.l facc_out_l # yes 20577 20578 bra.b fout_sgl_ovfl_chkexc 20579 20580fout_sgl_ovfl_dn: 20581 mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 20582 andi.w &0x7,%d1 20583 bsr.l store_dreg_l 20584 20585fout_sgl_ovfl_chkexc: 20586 mov.b FPCR_ENABLE(%a6),%d1 20587 andi.b &0x0a,%d1 # is UNFL or INEX enabled? 20588 bne.w fout_sd_exc_ovfl # yes 20589 addq.l &0x4,%sp 20590 rts 20591 20592# 20593# move out MAY overflow: 20594# (1) force the exp to 0x3fff 20595# (2) do a move w/ appropriate rnd mode 20596# (3) if exp still equals zero, then insert original exponent 20597# for the correct result. 20598# if exp now equals one, then it overflowed so call ovf_res. 20599# 20600fout_sgl_may_ovfl: 20601 mov.w SRC_EX(%a0),%d1 # fetch current sign 20602 andi.w &0x8000,%d1 # keep it,clear exp 20603 ori.w &0x3fff,%d1 # insert exp = 0 20604 mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp 20605 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man) 20606 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man) 20607 20608 fmov.l L_SCR3(%a6),%fpcr # set FPCR 20609 20610 fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded 20611 fmov.l &0x0,%fpcr # clear FPCR 20612 20613 fabs.x %fp0 # need absolute value 20614 fcmp.b %fp0,&0x2 # did exponent increase? 20615 fblt.w fout_sgl_exg # no; go finish NORM 20616 bra.w fout_sgl_ovfl # yes; go handle overflow 20617 20618################ 20619 20620fout_sd_exc_unfl: 20621 mov.l (%sp)+,%a0 20622 20623 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 20624 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 20625 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 20626 20627 cmpi.b STAG(%a6),&DENORM # was src a DENORM? 20628 bne.b fout_sd_exc_cont # no 20629 20630 lea FP_SCR0(%a6),%a0 20631 bsr.l norm 20632 neg.l %d0 20633 andi.w &0x7fff,%d0 20634 bfins %d0,FP_SCR0_EX(%a6){&1:&15} 20635 bra.b fout_sd_exc_cont 20636 20637fout_sd_exc: 20638fout_sd_exc_ovfl: 20639 mov.l (%sp)+,%a0 # restore a0 20640 20641 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 20642 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 20643 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 20644 20645fout_sd_exc_cont: 20646 bclr &0x7,FP_SCR0_EX(%a6) # clear sign bit 20647 sne.b 2+FP_SCR0_EX(%a6) # set internal sign bit 20648 lea FP_SCR0(%a6),%a0 # pass: ptr to DENORM 20649 20650 mov.b 3+L_SCR3(%a6),%d1 20651 lsr.b &0x4,%d1 20652 andi.w &0x0c,%d1 20653 swap %d1 20654 mov.b 3+L_SCR3(%a6),%d1 20655 lsr.b &0x4,%d1 20656 andi.w &0x03,%d1 20657 clr.l %d0 # pass: zero g,r,s 20658 bsr.l _round # round the DENORM 20659 20660 tst.b 2+FP_SCR0_EX(%a6) # is EXOP negative? 20661 beq.b fout_sd_exc_done # no 20662 bset &0x7,FP_SCR0_EX(%a6) # yes 20663 20664fout_sd_exc_done: 20665 fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 20666 rts 20667 20668################################################################# 20669# fmove.d out ################################################### 20670################################################################# 20671fout_dbl: 20672 andi.b &0x30,%d0 # clear rnd prec 20673 ori.b &d_mode*0x10,%d0 # insert dbl prec 20674 mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack 20675 20676# 20677# operand is a normalized number. first, we check to see if the move out 20678# would cause either an underflow or overflow. these cases are handled 20679# separately. otherwise, set the FPCR to the proper rounding mode and 20680# execute the move. 20681# 20682 mov.w SRC_EX(%a0),%d0 # extract exponent 20683 andi.w &0x7fff,%d0 # strip sign 20684 20685 cmpi.w %d0,&DBL_HI # will operand overflow? 20686 bgt.w fout_dbl_ovfl # yes; go handle OVFL 20687 beq.w fout_dbl_may_ovfl # maybe; go handle possible OVFL 20688 cmpi.w %d0,&DBL_LO # will operand underflow? 20689 blt.w fout_dbl_unfl # yes; go handle underflow 20690 20691# 20692# NORMs(in range) can be stored out by a simple "fmov.d" 20693# Unnormalized inputs can come through this point. 20694# 20695fout_dbl_exg: 20696 fmovm.x SRC(%a0),&0x80 # fetch fop from stack 20697 20698 fmov.l L_SCR3(%a6),%fpcr # set FPCR 20699 fmov.l &0x0,%fpsr # clear FPSR 20700 20701 fmov.d %fp0,L_SCR1(%a6) # store does convert and round 20702 20703 fmov.l &0x0,%fpcr # clear FPCR 20704 fmov.l %fpsr,%d0 # save FPSR 20705 20706 or.w %d0,2+USER_FPSR(%a6) # set possible inex2/ainex 20707 20708 mov.l EXC_EA(%a6),%a1 # pass: dst addr 20709 lea L_SCR1(%a6),%a0 # pass: src addr 20710 movq.l &0x8,%d0 # pass: opsize is 8 bytes 20711 bsr.l _dmem_write # store dbl fop to memory 20712 20713 tst.l %d1 # did dstore fail? 20714 bne.l facc_out_d # yes 20715 20716 rts # no; so we're finished 20717 20718# 20719# here, we know that the operand would UNFL if moved out to double prec, 20720# so, denorm and round and then use generic store double routine to 20721# write the value to memory. 20722# 20723fout_dbl_unfl: 20724 bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL 20725 20726 mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 20727 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 20728 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 20729 mov.l %a0,-(%sp) 20730 20731 clr.l %d0 # pass: S.F. = 0 20732 20733 cmpi.b STAG(%a6),&DENORM # fetch src optype tag 20734 bne.b fout_dbl_unfl_cont # let DENORMs fall through 20735 20736 lea FP_SCR0(%a6),%a0 20737 bsr.l norm # normalize the DENORM 20738 20739fout_dbl_unfl_cont: 20740 lea FP_SCR0(%a6),%a0 # pass: ptr to operand 20741 mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 20742 bsr.l unf_res # calc default underflow result 20743 20744 lea FP_SCR0(%a6),%a0 # pass: ptr to fop 20745 bsr.l dst_dbl # convert to single prec 20746 mov.l %d0,L_SCR1(%a6) 20747 mov.l %d1,L_SCR2(%a6) 20748 20749 mov.l EXC_EA(%a6),%a1 # pass: dst addr 20750 lea L_SCR1(%a6),%a0 # pass: src addr 20751 movq.l &0x8,%d0 # pass: opsize is 8 bytes 20752 bsr.l _dmem_write # store dbl fop to memory 20753 20754 tst.l %d1 # did dstore fail? 20755 bne.l facc_out_d # yes 20756 20757 mov.b FPCR_ENABLE(%a6),%d1 20758 andi.b &0x0a,%d1 # is UNFL or INEX enabled? 20759 bne.w fout_sd_exc_unfl # yes 20760 addq.l &0x4,%sp 20761 rts 20762 20763# 20764# it's definitely an overflow so call ovf_res to get the correct answer 20765# 20766fout_dbl_ovfl: 20767 mov.w 2+SRC_LO(%a0),%d0 20768 andi.w &0x7ff,%d0 20769 bne.b fout_dbl_ovfl_inex2 20770 20771 ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex 20772 bra.b fout_dbl_ovfl_cont 20773fout_dbl_ovfl_inex2: 20774 ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2 20775 20776fout_dbl_ovfl_cont: 20777 mov.l %a0,-(%sp) 20778 20779# call ovf_res() w/ dbl prec and the correct rnd mode to create the default 20780# overflow result. DON'T save the returned ccodes from ovf_res() since 20781# fmove out doesn't alter them. 20782 tst.b SRC_EX(%a0) # is operand negative? 20783 smi %d1 # set if so 20784 mov.l L_SCR3(%a6),%d0 # pass: dbl prec,rnd mode 20785 bsr.l ovf_res # calc OVFL result 20786 fmovm.x (%a0),&0x80 # load default overflow result 20787 fmov.d %fp0,L_SCR1(%a6) # store to double 20788 20789 mov.l EXC_EA(%a6),%a1 # pass: dst addr 20790 lea L_SCR1(%a6),%a0 # pass: src addr 20791 movq.l &0x8,%d0 # pass: opsize is 8 bytes 20792 bsr.l _dmem_write # store dbl fop to memory 20793 20794 tst.l %d1 # did dstore fail? 20795 bne.l facc_out_d # yes 20796 20797 mov.b FPCR_ENABLE(%a6),%d1 20798 andi.b &0x0a,%d1 # is UNFL or INEX enabled? 20799 bne.w fout_sd_exc_ovfl # yes 20800 addq.l &0x4,%sp 20801 rts 20802 20803# 20804# move out MAY overflow: 20805# (1) force the exp to 0x3fff 20806# (2) do a move w/ appropriate rnd mode 20807# (3) if exp still equals zero, then insert original exponent 20808# for the correct result. 20809# if exp now equals one, then it overflowed so call ovf_res. 20810# 20811fout_dbl_may_ovfl: 20812 mov.w SRC_EX(%a0),%d1 # fetch current sign 20813 andi.w &0x8000,%d1 # keep it,clear exp 20814 ori.w &0x3fff,%d1 # insert exp = 0 20815 mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp 20816 mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man) 20817 mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man) 20818 20819 fmov.l L_SCR3(%a6),%fpcr # set FPCR 20820 20821 fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded 20822 fmov.l &0x0,%fpcr # clear FPCR 20823 20824 fabs.x %fp0 # need absolute value 20825 fcmp.b %fp0,&0x2 # did exponent increase? 20826 fblt.w fout_dbl_exg # no; go finish NORM 20827 bra.w fout_dbl_ovfl # yes; go handle overflow 20828 20829######################################################################### 20830# XDEF **************************************************************** # 20831# dst_dbl(): create double precision value from extended prec. # 20832# # 20833# XREF **************************************************************** # 20834# None # 20835# # 20836# INPUT *************************************************************** # 20837# a0 = pointer to source operand in extended precision # 20838# # 20839# OUTPUT ************************************************************** # 20840# d0 = hi(double precision result) # 20841# d1 = lo(double precision result) # 20842# # 20843# ALGORITHM *********************************************************** # 20844# # 20845# Changes extended precision to double precision. # 20846# Note: no attempt is made to round the extended value to double. # 20847# dbl_sign = ext_sign # 20848# dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias) # 20849# get rid of ext integer bit # 20850# dbl_mant = ext_mant{62:12} # 20851# # 20852# --------------- --------------- --------------- # 20853# extended -> |s| exp | |1| ms mant | | ls mant | # 20854# --------------- --------------- --------------- # 20855# 95 64 63 62 32 31 11 0 # 20856# | | # 20857# | | # 20858# | | # 20859# v v # 20860# --------------- --------------- # 20861# double -> |s|exp| mant | | mant | # 20862# --------------- --------------- # 20863# 63 51 32 31 0 # 20864# # 20865######################################################################### 20866 20867dst_dbl: 20868 clr.l %d0 # clear d0 20869 mov.w FTEMP_EX(%a0),%d0 # get exponent 20870 subi.w &EXT_BIAS,%d0 # subtract extended precision bias 20871 addi.w &DBL_BIAS,%d0 # add double precision bias 20872 tst.b FTEMP_HI(%a0) # is number a denorm? 20873 bmi.b dst_get_dupper # no 20874 subq.w &0x1,%d0 # yes; denorm bias = DBL_BIAS - 1 20875dst_get_dupper: 20876 swap %d0 # d0 now in upper word 20877 lsl.l &0x4,%d0 # d0 in proper place for dbl prec exp 20878 tst.b FTEMP_EX(%a0) # test sign 20879 bpl.b dst_get_dman # if positive, go process mantissa 20880 bset &0x1f,%d0 # if negative, set sign 20881dst_get_dman: 20882 mov.l FTEMP_HI(%a0),%d1 # get ms mantissa 20883 bfextu %d1{&1:&20},%d1 # get upper 20 bits of ms 20884 or.l %d1,%d0 # put these bits in ms word of double 20885 mov.l %d0,L_SCR1(%a6) # put the new exp back on the stack 20886 mov.l FTEMP_HI(%a0),%d1 # get ms mantissa 20887 mov.l &21,%d0 # load shift count 20888 lsl.l %d0,%d1 # put lower 11 bits in upper bits 20889 mov.l %d1,L_SCR2(%a6) # build lower lword in memory 20890 mov.l FTEMP_LO(%a0),%d1 # get ls mantissa 20891 bfextu %d1{&0:&21},%d0 # get ls 21 bits of double 20892 mov.l L_SCR2(%a6),%d1 20893 or.l %d0,%d1 # put them in double result 20894 mov.l L_SCR1(%a6),%d0 20895 rts 20896 20897######################################################################### 20898# XDEF **************************************************************** # 20899# dst_sgl(): create single precision value from extended prec # 20900# # 20901# XREF **************************************************************** # 20902# # 20903# INPUT *************************************************************** # 20904# a0 = pointer to source operand in extended precision # 20905# # 20906# OUTPUT ************************************************************** # 20907# d0 = single precision result # 20908# # 20909# ALGORITHM *********************************************************** # 20910# # 20911# Changes extended precision to single precision. # 20912# sgl_sign = ext_sign # 20913# sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias) # 20914# get rid of ext integer bit # 20915# sgl_mant = ext_mant{62:12} # 20916# # 20917# --------------- --------------- --------------- # 20918# extended -> |s| exp | |1| ms mant | | ls mant | # 20919# --------------- --------------- --------------- # 20920# 95 64 63 62 40 32 31 12 0 # 20921# | | # 20922# | | # 20923# | | # 20924# v v # 20925# --------------- # 20926# single -> |s|exp| mant | # 20927# --------------- # 20928# 31 22 0 # 20929# # 20930######################################################################### 20931 20932dst_sgl: 20933 clr.l %d0 20934 mov.w FTEMP_EX(%a0),%d0 # get exponent 20935 subi.w &EXT_BIAS,%d0 # subtract extended precision bias 20936 addi.w &SGL_BIAS,%d0 # add single precision bias 20937 tst.b FTEMP_HI(%a0) # is number a denorm? 20938 bmi.b dst_get_supper # no 20939 subq.w &0x1,%d0 # yes; denorm bias = SGL_BIAS - 1 20940dst_get_supper: 20941 swap %d0 # put exp in upper word of d0 20942 lsl.l &0x7,%d0 # shift it into single exp bits 20943 tst.b FTEMP_EX(%a0) # test sign 20944 bpl.b dst_get_sman # if positive, continue 20945 bset &0x1f,%d0 # if negative, put in sign first 20946dst_get_sman: 20947 mov.l FTEMP_HI(%a0),%d1 # get ms mantissa 20948 andi.l &0x7fffff00,%d1 # get upper 23 bits of ms 20949 lsr.l &0x8,%d1 # and put them flush right 20950 or.l %d1,%d0 # put these bits in ms word of single 20951 rts 20952 20953############################################################################## 20954fout_pack: 20955 bsr.l _calc_ea_fout # fetch the <ea> 20956 mov.l %a0,-(%sp) 20957 20958 mov.b STAG(%a6),%d0 # fetch input type 20959 bne.w fout_pack_not_norm # input is not NORM 20960 20961fout_pack_norm: 20962 btst &0x4,EXC_CMDREG(%a6) # static or dynamic? 20963 beq.b fout_pack_s # static 20964 20965fout_pack_d: 20966 mov.b 1+EXC_CMDREG(%a6),%d1 # fetch dynamic reg 20967 lsr.b &0x4,%d1 20968 andi.w &0x7,%d1 20969 20970 bsr.l fetch_dreg # fetch Dn w/ k-factor 20971 20972 bra.b fout_pack_type 20973fout_pack_s: 20974 mov.b 1+EXC_CMDREG(%a6),%d0 # fetch static field 20975 20976fout_pack_type: 20977 bfexts %d0{&25:&7},%d0 # extract k-factor 20978 mov.l %d0,-(%sp) 20979 20980 lea FP_SRC(%a6),%a0 # pass: ptr to input 20981 20982# bindec is currently scrambling FP_SRC for denorm inputs. 20983# we'll have to change this, but for now, tough luck!!! 20984 bsr.l bindec # convert xprec to packed 20985 20986# andi.l &0xcfff000f,FP_SCR0(%a6) # clear unused fields 20987 andi.l &0xcffff00f,FP_SCR0(%a6) # clear unused fields 20988 20989 mov.l (%sp)+,%d0 20990 20991 tst.b 3+FP_SCR0_EX(%a6) 20992 bne.b fout_pack_set 20993 tst.l FP_SCR0_HI(%a6) 20994 bne.b fout_pack_set 20995 tst.l FP_SCR0_LO(%a6) 20996 bne.b fout_pack_set 20997 20998# add the extra condition that only if the k-factor was zero, too, should 20999# we zero the exponent 21000 tst.l %d0 21001 bne.b fout_pack_set 21002# "mantissa" is all zero which means that the answer is zero. but, the '040 21003# algorithm allows the exponent to be non-zero. the 881/2 do not. Therefore, 21004# if the mantissa is zero, I will zero the exponent, too. 21005# the question now is whether the exponents sign bit is allowed to be non-zero 21006# for a zero, also... 21007 andi.w &0xf000,FP_SCR0(%a6) 21008 21009fout_pack_set: 21010 21011 lea FP_SCR0(%a6),%a0 # pass: src addr 21012 21013fout_pack_write: 21014 mov.l (%sp)+,%a1 # pass: dst addr 21015 mov.l &0xc,%d0 # pass: opsize is 12 bytes 21016 21017 cmpi.b SPCOND_FLG(%a6),&mda7_flg 21018 beq.b fout_pack_a7 21019 21020 bsr.l _dmem_write # write ext prec number to memory 21021 21022 tst.l %d1 # did dstore fail? 21023 bne.w fout_ext_err # yes 21024 21025 rts 21026 21027# we don't want to do the write if the exception occurred in supervisor mode 21028# so _mem_write2() handles this for us. 21029fout_pack_a7: 21030 bsr.l _mem_write2 # write ext prec number to memory 21031 21032 tst.l %d1 # did dstore fail? 21033 bne.w fout_ext_err # yes 21034 21035 rts 21036 21037fout_pack_not_norm: 21038 cmpi.b %d0,&DENORM # is it a DENORM? 21039 beq.w fout_pack_norm # yes 21040 lea FP_SRC(%a6),%a0 21041 clr.w 2+FP_SRC_EX(%a6) 21042 cmpi.b %d0,&SNAN # is it an SNAN? 21043 beq.b fout_pack_snan # yes 21044 bra.b fout_pack_write # no 21045 21046fout_pack_snan: 21047 ori.w &snaniop2_mask,FPSR_EXCEPT(%a6) # set SNAN/AIOP 21048 bset &0x6,FP_SRC_HI(%a6) # set snan bit 21049 bra.b fout_pack_write 21050 21051######################################################################### 21052# XDEF **************************************************************** # 21053# fetch_dreg(): fetch register according to index in d1 # 21054# # 21055# XREF **************************************************************** # 21056# None # 21057# # 21058# INPUT *************************************************************** # 21059# d1 = index of register to fetch from # 21060# # 21061# OUTPUT ************************************************************** # 21062# d0 = value of register fetched # 21063# # 21064# ALGORITHM *********************************************************** # 21065# According to the index value in d1 which can range from zero # 21066# to fifteen, load the corresponding register file value (where # 21067# address register indexes start at 8). D0/D1/A0/A1/A6/A7 are on the # 21068# stack. The rest should still be in their original places. # 21069# # 21070######################################################################### 21071 21072# this routine leaves d1 intact for subsequent store_dreg calls. 21073 global fetch_dreg 21074fetch_dreg: 21075 mov.w (tbl_fdreg.b,%pc,%d1.w*2),%d0 21076 jmp (tbl_fdreg.b,%pc,%d0.w*1) 21077 21078tbl_fdreg: 21079 short fdreg0 - tbl_fdreg 21080 short fdreg1 - tbl_fdreg 21081 short fdreg2 - tbl_fdreg 21082 short fdreg3 - tbl_fdreg 21083 short fdreg4 - tbl_fdreg 21084 short fdreg5 - tbl_fdreg 21085 short fdreg6 - tbl_fdreg 21086 short fdreg7 - tbl_fdreg 21087 short fdreg8 - tbl_fdreg 21088 short fdreg9 - tbl_fdreg 21089 short fdrega - tbl_fdreg 21090 short fdregb - tbl_fdreg 21091 short fdregc - tbl_fdreg 21092 short fdregd - tbl_fdreg 21093 short fdrege - tbl_fdreg 21094 short fdregf - tbl_fdreg 21095 21096fdreg0: 21097 mov.l EXC_DREGS+0x0(%a6),%d0 21098 rts 21099fdreg1: 21100 mov.l EXC_DREGS+0x4(%a6),%d0 21101 rts 21102fdreg2: 21103 mov.l %d2,%d0 21104 rts 21105fdreg3: 21106 mov.l %d3,%d0 21107 rts 21108fdreg4: 21109 mov.l %d4,%d0 21110 rts 21111fdreg5: 21112 mov.l %d5,%d0 21113 rts 21114fdreg6: 21115 mov.l %d6,%d0 21116 rts 21117fdreg7: 21118 mov.l %d7,%d0 21119 rts 21120fdreg8: 21121 mov.l EXC_DREGS+0x8(%a6),%d0 21122 rts 21123fdreg9: 21124 mov.l EXC_DREGS+0xc(%a6),%d0 21125 rts 21126fdrega: 21127 mov.l %a2,%d0 21128 rts 21129fdregb: 21130 mov.l %a3,%d0 21131 rts 21132fdregc: 21133 mov.l %a4,%d0 21134 rts 21135fdregd: 21136 mov.l %a5,%d0 21137 rts 21138fdrege: 21139 mov.l (%a6),%d0 21140 rts 21141fdregf: 21142 mov.l EXC_A7(%a6),%d0 21143 rts 21144 21145######################################################################### 21146# XDEF **************************************************************** # 21147# store_dreg_l(): store longword to data register specified by d1 # 21148# # 21149# XREF **************************************************************** # 21150# None # 21151# # 21152# INPUT *************************************************************** # 21153# d0 = longowrd value to store # 21154# d1 = index of register to fetch from # 21155# # 21156# OUTPUT ************************************************************** # 21157# (data register is updated) # 21158# # 21159# ALGORITHM *********************************************************** # 21160# According to the index value in d1, store the longword value # 21161# in d0 to the corresponding data register. D0/D1 are on the stack # 21162# while the rest are in their initial places. # 21163# # 21164######################################################################### 21165 21166 global store_dreg_l 21167store_dreg_l: 21168 mov.w (tbl_sdregl.b,%pc,%d1.w*2),%d1 21169 jmp (tbl_sdregl.b,%pc,%d1.w*1) 21170 21171tbl_sdregl: 21172 short sdregl0 - tbl_sdregl 21173 short sdregl1 - tbl_sdregl 21174 short sdregl2 - tbl_sdregl 21175 short sdregl3 - tbl_sdregl 21176 short sdregl4 - tbl_sdregl 21177 short sdregl5 - tbl_sdregl 21178 short sdregl6 - tbl_sdregl 21179 short sdregl7 - tbl_sdregl 21180 21181sdregl0: 21182 mov.l %d0,EXC_DREGS+0x0(%a6) 21183 rts 21184sdregl1: 21185 mov.l %d0,EXC_DREGS+0x4(%a6) 21186 rts 21187sdregl2: 21188 mov.l %d0,%d2 21189 rts 21190sdregl3: 21191 mov.l %d0,%d3 21192 rts 21193sdregl4: 21194 mov.l %d0,%d4 21195 rts 21196sdregl5: 21197 mov.l %d0,%d5 21198 rts 21199sdregl6: 21200 mov.l %d0,%d6 21201 rts 21202sdregl7: 21203 mov.l %d0,%d7 21204 rts 21205 21206######################################################################### 21207# XDEF **************************************************************** # 21208# store_dreg_w(): store word to data register specified by d1 # 21209# # 21210# XREF **************************************************************** # 21211# None # 21212# # 21213# INPUT *************************************************************** # 21214# d0 = word value to store # 21215# d1 = index of register to fetch from # 21216# # 21217# OUTPUT ************************************************************** # 21218# (data register is updated) # 21219# # 21220# ALGORITHM *********************************************************** # 21221# According to the index value in d1, store the word value # 21222# in d0 to the corresponding data register. D0/D1 are on the stack # 21223# while the rest are in their initial places. # 21224# # 21225######################################################################### 21226 21227 global store_dreg_w 21228store_dreg_w: 21229 mov.w (tbl_sdregw.b,%pc,%d1.w*2),%d1 21230 jmp (tbl_sdregw.b,%pc,%d1.w*1) 21231 21232tbl_sdregw: 21233 short sdregw0 - tbl_sdregw 21234 short sdregw1 - tbl_sdregw 21235 short sdregw2 - tbl_sdregw 21236 short sdregw3 - tbl_sdregw 21237 short sdregw4 - tbl_sdregw 21238 short sdregw5 - tbl_sdregw 21239 short sdregw6 - tbl_sdregw 21240 short sdregw7 - tbl_sdregw 21241 21242sdregw0: 21243 mov.w %d0,2+EXC_DREGS+0x0(%a6) 21244 rts 21245sdregw1: 21246 mov.w %d0,2+EXC_DREGS+0x4(%a6) 21247 rts 21248sdregw2: 21249 mov.w %d0,%d2 21250 rts 21251sdregw3: 21252 mov.w %d0,%d3 21253 rts 21254sdregw4: 21255 mov.w %d0,%d4 21256 rts 21257sdregw5: 21258 mov.w %d0,%d5 21259 rts 21260sdregw6: 21261 mov.w %d0,%d6 21262 rts 21263sdregw7: 21264 mov.w %d0,%d7 21265 rts 21266 21267######################################################################### 21268# XDEF **************************************************************** # 21269# store_dreg_b(): store byte to data register specified by d1 # 21270# # 21271# XREF **************************************************************** # 21272# None # 21273# # 21274# INPUT *************************************************************** # 21275# d0 = byte value to store # 21276# d1 = index of register to fetch from # 21277# # 21278# OUTPUT ************************************************************** # 21279# (data register is updated) # 21280# # 21281# ALGORITHM *********************************************************** # 21282# According to the index value in d1, store the byte value # 21283# in d0 to the corresponding data register. D0/D1 are on the stack # 21284# while the rest are in their initial places. # 21285# # 21286######################################################################### 21287 21288 global store_dreg_b 21289store_dreg_b: 21290 mov.w (tbl_sdregb.b,%pc,%d1.w*2),%d1 21291 jmp (tbl_sdregb.b,%pc,%d1.w*1) 21292 21293tbl_sdregb: 21294 short sdregb0 - tbl_sdregb 21295 short sdregb1 - tbl_sdregb 21296 short sdregb2 - tbl_sdregb 21297 short sdregb3 - tbl_sdregb 21298 short sdregb4 - tbl_sdregb 21299 short sdregb5 - tbl_sdregb 21300 short sdregb6 - tbl_sdregb 21301 short sdregb7 - tbl_sdregb 21302 21303sdregb0: 21304 mov.b %d0,3+EXC_DREGS+0x0(%a6) 21305 rts 21306sdregb1: 21307 mov.b %d0,3+EXC_DREGS+0x4(%a6) 21308 rts 21309sdregb2: 21310 mov.b %d0,%d2 21311 rts 21312sdregb3: 21313 mov.b %d0,%d3 21314 rts 21315sdregb4: 21316 mov.b %d0,%d4 21317 rts 21318sdregb5: 21319 mov.b %d0,%d5 21320 rts 21321sdregb6: 21322 mov.b %d0,%d6 21323 rts 21324sdregb7: 21325 mov.b %d0,%d7 21326 rts 21327 21328######################################################################### 21329# XDEF **************************************************************** # 21330# inc_areg(): increment an address register by the value in d0 # 21331# # 21332# XREF **************************************************************** # 21333# None # 21334# # 21335# INPUT *************************************************************** # 21336# d0 = amount to increment by # 21337# d1 = index of address register to increment # 21338# # 21339# OUTPUT ************************************************************** # 21340# (address register is updated) # 21341# # 21342# ALGORITHM *********************************************************** # 21343# Typically used for an instruction w/ a post-increment <ea>, # 21344# this routine adds the increment value in d0 to the address register # 21345# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside # 21346# in their original places. # 21347# For a7, if the increment amount is one, then we have to # 21348# increment by two. For any a7 update, set the mia7_flag so that if # 21349# an access error exception occurs later in emulation, this address # 21350# register update can be undone. # 21351# # 21352######################################################################### 21353 21354 global inc_areg 21355inc_areg: 21356 mov.w (tbl_iareg.b,%pc,%d1.w*2),%d1 21357 jmp (tbl_iareg.b,%pc,%d1.w*1) 21358 21359tbl_iareg: 21360 short iareg0 - tbl_iareg 21361 short iareg1 - tbl_iareg 21362 short iareg2 - tbl_iareg 21363 short iareg3 - tbl_iareg 21364 short iareg4 - tbl_iareg 21365 short iareg5 - tbl_iareg 21366 short iareg6 - tbl_iareg 21367 short iareg7 - tbl_iareg 21368 21369iareg0: add.l %d0,EXC_DREGS+0x8(%a6) 21370 rts 21371iareg1: add.l %d0,EXC_DREGS+0xc(%a6) 21372 rts 21373iareg2: add.l %d0,%a2 21374 rts 21375iareg3: add.l %d0,%a3 21376 rts 21377iareg4: add.l %d0,%a4 21378 rts 21379iareg5: add.l %d0,%a5 21380 rts 21381iareg6: add.l %d0,(%a6) 21382 rts 21383iareg7: mov.b &mia7_flg,SPCOND_FLG(%a6) 21384 cmpi.b %d0,&0x1 21385 beq.b iareg7b 21386 add.l %d0,EXC_A7(%a6) 21387 rts 21388iareg7b: 21389 addq.l &0x2,EXC_A7(%a6) 21390 rts 21391 21392######################################################################### 21393# XDEF **************************************************************** # 21394# dec_areg(): decrement an address register by the value in d0 # 21395# # 21396# XREF **************************************************************** # 21397# None # 21398# # 21399# INPUT *************************************************************** # 21400# d0 = amount to decrement by # 21401# d1 = index of address register to decrement # 21402# # 21403# OUTPUT ************************************************************** # 21404# (address register is updated) # 21405# # 21406# ALGORITHM *********************************************************** # 21407# Typically used for an instruction w/ a pre-decrement <ea>, # 21408# this routine adds the decrement value in d0 to the address register # 21409# specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside # 21410# in their original places. # 21411# For a7, if the decrement amount is one, then we have to # 21412# decrement by two. For any a7 update, set the mda7_flag so that if # 21413# an access error exception occurs later in emulation, this address # 21414# register update can be undone. # 21415# # 21416######################################################################### 21417 21418 global dec_areg 21419dec_areg: 21420 mov.w (tbl_dareg.b,%pc,%d1.w*2),%d1 21421 jmp (tbl_dareg.b,%pc,%d1.w*1) 21422 21423tbl_dareg: 21424 short dareg0 - tbl_dareg 21425 short dareg1 - tbl_dareg 21426 short dareg2 - tbl_dareg 21427 short dareg3 - tbl_dareg 21428 short dareg4 - tbl_dareg 21429 short dareg5 - tbl_dareg 21430 short dareg6 - tbl_dareg 21431 short dareg7 - tbl_dareg 21432 21433dareg0: sub.l %d0,EXC_DREGS+0x8(%a6) 21434 rts 21435dareg1: sub.l %d0,EXC_DREGS+0xc(%a6) 21436 rts 21437dareg2: sub.l %d0,%a2 21438 rts 21439dareg3: sub.l %d0,%a3 21440 rts 21441dareg4: sub.l %d0,%a4 21442 rts 21443dareg5: sub.l %d0,%a5 21444 rts 21445dareg6: sub.l %d0,(%a6) 21446 rts 21447dareg7: mov.b &mda7_flg,SPCOND_FLG(%a6) 21448 cmpi.b %d0,&0x1 21449 beq.b dareg7b 21450 sub.l %d0,EXC_A7(%a6) 21451 rts 21452dareg7b: 21453 subq.l &0x2,EXC_A7(%a6) 21454 rts 21455 21456############################################################################## 21457 21458######################################################################### 21459# XDEF **************************************************************** # 21460# load_fpn1(): load FP register value into FP_SRC(a6). # 21461# # 21462# XREF **************************************************************** # 21463# None # 21464# # 21465# INPUT *************************************************************** # 21466# d0 = index of FP register to load # 21467# # 21468# OUTPUT ************************************************************** # 21469# FP_SRC(a6) = value loaded from FP register file # 21470# # 21471# ALGORITHM *********************************************************** # 21472# Using the index in d0, load FP_SRC(a6) with a number from the # 21473# FP register file. # 21474# # 21475######################################################################### 21476 21477 global load_fpn1 21478load_fpn1: 21479 mov.w (tbl_load_fpn1.b,%pc,%d0.w*2), %d0 21480 jmp (tbl_load_fpn1.b,%pc,%d0.w*1) 21481 21482tbl_load_fpn1: 21483 short load_fpn1_0 - tbl_load_fpn1 21484 short load_fpn1_1 - tbl_load_fpn1 21485 short load_fpn1_2 - tbl_load_fpn1 21486 short load_fpn1_3 - tbl_load_fpn1 21487 short load_fpn1_4 - tbl_load_fpn1 21488 short load_fpn1_5 - tbl_load_fpn1 21489 short load_fpn1_6 - tbl_load_fpn1 21490 short load_fpn1_7 - tbl_load_fpn1 21491 21492load_fpn1_0: 21493 mov.l 0+EXC_FP0(%a6), 0+FP_SRC(%a6) 21494 mov.l 4+EXC_FP0(%a6), 4+FP_SRC(%a6) 21495 mov.l 8+EXC_FP0(%a6), 8+FP_SRC(%a6) 21496 lea FP_SRC(%a6), %a0 21497 rts 21498load_fpn1_1: 21499 mov.l 0+EXC_FP1(%a6), 0+FP_SRC(%a6) 21500 mov.l 4+EXC_FP1(%a6), 4+FP_SRC(%a6) 21501 mov.l 8+EXC_FP1(%a6), 8+FP_SRC(%a6) 21502 lea FP_SRC(%a6), %a0 21503 rts 21504load_fpn1_2: 21505 fmovm.x &0x20, FP_SRC(%a6) 21506 lea FP_SRC(%a6), %a0 21507 rts 21508load_fpn1_3: 21509 fmovm.x &0x10, FP_SRC(%a6) 21510 lea FP_SRC(%a6), %a0 21511 rts 21512load_fpn1_4: 21513 fmovm.x &0x08, FP_SRC(%a6) 21514 lea FP_SRC(%a6), %a0 21515 rts 21516load_fpn1_5: 21517 fmovm.x &0x04, FP_SRC(%a6) 21518 lea FP_SRC(%a6), %a0 21519 rts 21520load_fpn1_6: 21521 fmovm.x &0x02, FP_SRC(%a6) 21522 lea FP_SRC(%a6), %a0 21523 rts 21524load_fpn1_7: 21525 fmovm.x &0x01, FP_SRC(%a6) 21526 lea FP_SRC(%a6), %a0 21527 rts 21528 21529############################################################################# 21530 21531######################################################################### 21532# XDEF **************************************************************** # 21533# load_fpn2(): load FP register value into FP_DST(a6). # 21534# # 21535# XREF **************************************************************** # 21536# None # 21537# # 21538# INPUT *************************************************************** # 21539# d0 = index of FP register to load # 21540# # 21541# OUTPUT ************************************************************** # 21542# FP_DST(a6) = value loaded from FP register file # 21543# # 21544# ALGORITHM *********************************************************** # 21545# Using the index in d0, load FP_DST(a6) with a number from the # 21546# FP register file. # 21547# # 21548######################################################################### 21549 21550 global load_fpn2 21551load_fpn2: 21552 mov.w (tbl_load_fpn2.b,%pc,%d0.w*2), %d0 21553 jmp (tbl_load_fpn2.b,%pc,%d0.w*1) 21554 21555tbl_load_fpn2: 21556 short load_fpn2_0 - tbl_load_fpn2 21557 short load_fpn2_1 - tbl_load_fpn2 21558 short load_fpn2_2 - tbl_load_fpn2 21559 short load_fpn2_3 - tbl_load_fpn2 21560 short load_fpn2_4 - tbl_load_fpn2 21561 short load_fpn2_5 - tbl_load_fpn2 21562 short load_fpn2_6 - tbl_load_fpn2 21563 short load_fpn2_7 - tbl_load_fpn2 21564 21565load_fpn2_0: 21566 mov.l 0+EXC_FP0(%a6), 0+FP_DST(%a6) 21567 mov.l 4+EXC_FP0(%a6), 4+FP_DST(%a6) 21568 mov.l 8+EXC_FP0(%a6), 8+FP_DST(%a6) 21569 lea FP_DST(%a6), %a0 21570 rts 21571load_fpn2_1: 21572 mov.l 0+EXC_FP1(%a6), 0+FP_DST(%a6) 21573 mov.l 4+EXC_FP1(%a6), 4+FP_DST(%a6) 21574 mov.l 8+EXC_FP1(%a6), 8+FP_DST(%a6) 21575 lea FP_DST(%a6), %a0 21576 rts 21577load_fpn2_2: 21578 fmovm.x &0x20, FP_DST(%a6) 21579 lea FP_DST(%a6), %a0 21580 rts 21581load_fpn2_3: 21582 fmovm.x &0x10, FP_DST(%a6) 21583 lea FP_DST(%a6), %a0 21584 rts 21585load_fpn2_4: 21586 fmovm.x &0x08, FP_DST(%a6) 21587 lea FP_DST(%a6), %a0 21588 rts 21589load_fpn2_5: 21590 fmovm.x &0x04, FP_DST(%a6) 21591 lea FP_DST(%a6), %a0 21592 rts 21593load_fpn2_6: 21594 fmovm.x &0x02, FP_DST(%a6) 21595 lea FP_DST(%a6), %a0 21596 rts 21597load_fpn2_7: 21598 fmovm.x &0x01, FP_DST(%a6) 21599 lea FP_DST(%a6), %a0 21600 rts 21601 21602############################################################################# 21603 21604######################################################################### 21605# XDEF **************************************************************** # 21606# store_fpreg(): store an fp value to the fpreg designated d0. # 21607# # 21608# XREF **************************************************************** # 21609# None # 21610# # 21611# INPUT *************************************************************** # 21612# fp0 = extended precision value to store # 21613# d0 = index of floating-point register # 21614# # 21615# OUTPUT ************************************************************** # 21616# None # 21617# # 21618# ALGORITHM *********************************************************** # 21619# Store the value in fp0 to the FP register designated by the # 21620# value in d0. The FP number can be DENORM or SNAN so we have to be # 21621# careful that we don't take an exception here. # 21622# # 21623######################################################################### 21624 21625 global store_fpreg 21626store_fpreg: 21627 mov.w (tbl_store_fpreg.b,%pc,%d0.w*2), %d0 21628 jmp (tbl_store_fpreg.b,%pc,%d0.w*1) 21629 21630tbl_store_fpreg: 21631 short store_fpreg_0 - tbl_store_fpreg 21632 short store_fpreg_1 - tbl_store_fpreg 21633 short store_fpreg_2 - tbl_store_fpreg 21634 short store_fpreg_3 - tbl_store_fpreg 21635 short store_fpreg_4 - tbl_store_fpreg 21636 short store_fpreg_5 - tbl_store_fpreg 21637 short store_fpreg_6 - tbl_store_fpreg 21638 short store_fpreg_7 - tbl_store_fpreg 21639 21640store_fpreg_0: 21641 fmovm.x &0x80, EXC_FP0(%a6) 21642 rts 21643store_fpreg_1: 21644 fmovm.x &0x80, EXC_FP1(%a6) 21645 rts 21646store_fpreg_2: 21647 fmovm.x &0x01, -(%sp) 21648 fmovm.x (%sp)+, &0x20 21649 rts 21650store_fpreg_3: 21651 fmovm.x &0x01, -(%sp) 21652 fmovm.x (%sp)+, &0x10 21653 rts 21654store_fpreg_4: 21655 fmovm.x &0x01, -(%sp) 21656 fmovm.x (%sp)+, &0x08 21657 rts 21658store_fpreg_5: 21659 fmovm.x &0x01, -(%sp) 21660 fmovm.x (%sp)+, &0x04 21661 rts 21662store_fpreg_6: 21663 fmovm.x &0x01, -(%sp) 21664 fmovm.x (%sp)+, &0x02 21665 rts 21666store_fpreg_7: 21667 fmovm.x &0x01, -(%sp) 21668 fmovm.x (%sp)+, &0x01 21669 rts 21670 21671######################################################################### 21672# XDEF **************************************************************** # 21673# _denorm(): denormalize an intermediate result # 21674# # 21675# XREF **************************************************************** # 21676# None # 21677# # 21678# INPUT *************************************************************** # 21679# a0 = points to the operand to be denormalized # 21680# (in the internal extended format) # 21681# # 21682# d0 = rounding precision # 21683# # 21684# OUTPUT ************************************************************** # 21685# a0 = pointer to the denormalized result # 21686# (in the internal extended format) # 21687# # 21688# d0 = guard,round,sticky # 21689# # 21690# ALGORITHM *********************************************************** # 21691# According to the exponent underflow threshold for the given # 21692# precision, shift the mantissa bits to the right in order raise the # 21693# exponent of the operand to the threshold value. While shifting the # 21694# mantissa bits right, maintain the value of the guard, round, and # 21695# sticky bits. # 21696# other notes: # 21697# (1) _denorm() is called by the underflow routines # 21698# (2) _denorm() does NOT affect the status register # 21699# # 21700######################################################################### 21701 21702# 21703# table of exponent threshold values for each precision 21704# 21705tbl_thresh: 21706 short 0x0 21707 short sgl_thresh 21708 short dbl_thresh 21709 21710 global _denorm 21711_denorm: 21712# 21713# Load the exponent threshold for the precision selected and check 21714# to see if (threshold - exponent) is > 65 in which case we can 21715# simply calculate the sticky bit and zero the mantissa. otherwise 21716# we have to call the denormalization routine. 21717# 21718 lsr.b &0x2, %d0 # shift prec to lo bits 21719 mov.w (tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold 21720 mov.w %d1, %d0 # copy d1 into d0 21721 sub.w FTEMP_EX(%a0), %d0 # diff = threshold - exp 21722 cmpi.w %d0, &66 # is diff > 65? (mant + g,r bits) 21723 bpl.b denorm_set_stky # yes; just calc sticky 21724 21725 clr.l %d0 # clear g,r,s 21726 btst &inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set? 21727 beq.b denorm_call # no; don't change anything 21728 bset &29, %d0 # yes; set sticky bit 21729 21730denorm_call: 21731 bsr.l dnrm_lp # denormalize the number 21732 rts 21733 21734# 21735# all bit would have been shifted off during the denorm so simply 21736# calculate if the sticky should be set and clear the entire mantissa. 21737# 21738denorm_set_stky: 21739 mov.l &0x20000000, %d0 # set sticky bit in return value 21740 mov.w %d1, FTEMP_EX(%a0) # load exp with threshold 21741 clr.l FTEMP_HI(%a0) # set d1 = 0 (ms mantissa) 21742 clr.l FTEMP_LO(%a0) # set d2 = 0 (ms mantissa) 21743 rts 21744 21745# # 21746# dnrm_lp(): normalize exponent/mantissa to specified threshold # 21747# # 21748# INPUT: # 21749# %a0 : points to the operand to be denormalized # 21750# %d0{31:29} : initial guard,round,sticky # 21751# %d1{15:0} : denormalization threshold # 21752# OUTPUT: # 21753# %a0 : points to the denormalized operand # 21754# %d0{31:29} : final guard,round,sticky # 21755# # 21756 21757# *** Local Equates *** # 21758set GRS, L_SCR2 # g,r,s temp storage 21759set FTEMP_LO2, L_SCR1 # FTEMP_LO copy 21760 21761 global dnrm_lp 21762dnrm_lp: 21763 21764# 21765# make a copy of FTEMP_LO and place the g,r,s bits directly after it 21766# in memory so as to make the bitfield extraction for denormalization easier. 21767# 21768 mov.l FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy 21769 mov.l %d0, GRS(%a6) # place g,r,s after it 21770 21771# 21772# check to see how much less than the underflow threshold the operand 21773# exponent is. 21774# 21775 mov.l %d1, %d0 # copy the denorm threshold 21776 sub.w FTEMP_EX(%a0), %d1 # d1 = threshold - uns exponent 21777 ble.b dnrm_no_lp # d1 <= 0 21778 cmpi.w %d1, &0x20 # is ( 0 <= d1 < 32) ? 21779 blt.b case_1 # yes 21780 cmpi.w %d1, &0x40 # is (32 <= d1 < 64) ? 21781 blt.b case_2 # yes 21782 bra.w case_3 # (d1 >= 64) 21783 21784# 21785# No normalization necessary 21786# 21787dnrm_no_lp: 21788 mov.l GRS(%a6), %d0 # restore original g,r,s 21789 rts 21790 21791# 21792# case (0<d1<32) 21793# 21794# %d0 = denorm threshold 21795# %d1 = "n" = amt to shift 21796# 21797# --------------------------------------------------------- 21798# | FTEMP_HI | FTEMP_LO |grs000.........000| 21799# --------------------------------------------------------- 21800# <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)-> 21801# \ \ \ \ 21802# \ \ \ \ 21803# \ \ \ \ 21804# \ \ \ \ 21805# \ \ \ \ 21806# \ \ \ \ 21807# \ \ \ \ 21808# \ \ \ \ 21809# <-(n)-><-(32 - n)-><------(32)-------><------(32)-------> 21810# --------------------------------------------------------- 21811# |0.....0| NEW_HI | NEW_FTEMP_LO |grs | 21812# --------------------------------------------------------- 21813# 21814case_1: 21815 mov.l %d2, -(%sp) # create temp storage 21816 21817 mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold 21818 mov.l &32, %d0 21819 sub.w %d1, %d0 # %d0 = 32 - %d1 21820 21821 cmpi.w %d1, &29 # is shft amt >= 29 21822 blt.b case1_extract # no; no fix needed 21823 mov.b GRS(%a6), %d2 21824 or.b %d2, 3+FTEMP_LO2(%a6) 21825 21826case1_extract: 21827 bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI 21828 bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO 21829 bfextu FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S 21830 21831 mov.l %d2, FTEMP_HI(%a0) # store new FTEMP_HI 21832 mov.l %d1, FTEMP_LO(%a0) # store new FTEMP_LO 21833 21834 bftst %d0{&2:&30} # were bits shifted off? 21835 beq.b case1_sticky_clear # no; go finish 21836 bset &rnd_stky_bit, %d0 # yes; set sticky bit 21837 21838case1_sticky_clear: 21839 and.l &0xe0000000, %d0 # clear all but G,R,S 21840 mov.l (%sp)+, %d2 # restore temp register 21841 rts 21842 21843# 21844# case (32<=d1<64) 21845# 21846# %d0 = denorm threshold 21847# %d1 = "n" = amt to shift 21848# 21849# --------------------------------------------------------- 21850# | FTEMP_HI | FTEMP_LO |grs000.........000| 21851# --------------------------------------------------------- 21852# <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)-> 21853# \ \ \ 21854# \ \ \ 21855# \ \ ------------------- 21856# \ -------------------- \ 21857# ------------------- \ \ 21858# \ \ \ 21859# \ \ \ 21860# \ \ \ 21861# <-------(32)------><-(n)-><-(32 - n)-><------(32)-------> 21862# --------------------------------------------------------- 21863# |0...............0|0....0| NEW_LO |grs | 21864# --------------------------------------------------------- 21865# 21866case_2: 21867 mov.l %d2, -(%sp) # create temp storage 21868 21869 mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold 21870 subi.w &0x20, %d1 # %d1 now between 0 and 32 21871 mov.l &0x20, %d0 21872 sub.w %d1, %d0 # %d0 = 32 - %d1 21873 21874# subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize 21875# the number of bits to check for the sticky detect. 21876# it only plays a role in shift amounts of 61-63. 21877 mov.b GRS(%a6), %d2 21878 or.b %d2, 3+FTEMP_LO2(%a6) 21879 21880 bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO 21881 bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S 21882 21883 bftst %d1{&2:&30} # were any bits shifted off? 21884 bne.b case2_set_sticky # yes; set sticky bit 21885 bftst FTEMP_LO2(%a6){%d0:&31} # were any bits shifted off? 21886 bne.b case2_set_sticky # yes; set sticky bit 21887 21888 mov.l %d1, %d0 # move new G,R,S to %d0 21889 bra.b case2_end 21890 21891case2_set_sticky: 21892 mov.l %d1, %d0 # move new G,R,S to %d0 21893 bset &rnd_stky_bit, %d0 # set sticky bit 21894 21895case2_end: 21896 clr.l FTEMP_HI(%a0) # store FTEMP_HI = 0 21897 mov.l %d2, FTEMP_LO(%a0) # store FTEMP_LO 21898 and.l &0xe0000000, %d0 # clear all but G,R,S 21899 21900 mov.l (%sp)+,%d2 # restore temp register 21901 rts 21902 21903# 21904# case (d1>=64) 21905# 21906# %d0 = denorm threshold 21907# %d1 = amt to shift 21908# 21909case_3: 21910 mov.w %d0, FTEMP_EX(%a0) # insert denorm threshold 21911 21912 cmpi.w %d1, &65 # is shift amt > 65? 21913 blt.b case3_64 # no; it's == 64 21914 beq.b case3_65 # no; it's == 65 21915 21916# 21917# case (d1>65) 21918# 21919# Shift value is > 65 and out of range. All bits are shifted off. 21920# Return a zero mantissa with the sticky bit set 21921# 21922 clr.l FTEMP_HI(%a0) # clear hi(mantissa) 21923 clr.l FTEMP_LO(%a0) # clear lo(mantissa) 21924 mov.l &0x20000000, %d0 # set sticky bit 21925 rts 21926 21927# 21928# case (d1 == 64) 21929# 21930# --------------------------------------------------------- 21931# | FTEMP_HI | FTEMP_LO |grs000.........000| 21932# --------------------------------------------------------- 21933# <-------(32)------> 21934# \ \ 21935# \ \ 21936# \ \ 21937# \ ------------------------------ 21938# ------------------------------- \ 21939# \ \ 21940# \ \ 21941# \ \ 21942# <-------(32)------> 21943# --------------------------------------------------------- 21944# |0...............0|0................0|grs | 21945# --------------------------------------------------------- 21946# 21947case3_64: 21948 mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa) 21949 mov.l %d0, %d1 # make a copy 21950 and.l &0xc0000000, %d0 # extract G,R 21951 and.l &0x3fffffff, %d1 # extract other bits 21952 21953 bra.b case3_complete 21954 21955# 21956# case (d1 == 65) 21957# 21958# --------------------------------------------------------- 21959# | FTEMP_HI | FTEMP_LO |grs000.........000| 21960# --------------------------------------------------------- 21961# <-------(32)------> 21962# \ \ 21963# \ \ 21964# \ \ 21965# \ ------------------------------ 21966# -------------------------------- \ 21967# \ \ 21968# \ \ 21969# \ \ 21970# <-------(31)-----> 21971# --------------------------------------------------------- 21972# |0...............0|0................0|0rs | 21973# --------------------------------------------------------- 21974# 21975case3_65: 21976 mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa) 21977 and.l &0x80000000, %d0 # extract R bit 21978 lsr.l &0x1, %d0 # shift high bit into R bit 21979 and.l &0x7fffffff, %d1 # extract other bits 21980 21981case3_complete: 21982# last operation done was an "and" of the bits shifted off so the condition 21983# codes are already set so branch accordingly. 21984 bne.b case3_set_sticky # yes; go set new sticky 21985 tst.l FTEMP_LO(%a0) # were any bits shifted off? 21986 bne.b case3_set_sticky # yes; go set new sticky 21987 tst.b GRS(%a6) # were any bits shifted off? 21988 bne.b case3_set_sticky # yes; go set new sticky 21989 21990# 21991# no bits were shifted off so don't set the sticky bit. 21992# the guard and 21993# the entire mantissa is zero. 21994# 21995 clr.l FTEMP_HI(%a0) # clear hi(mantissa) 21996 clr.l FTEMP_LO(%a0) # clear lo(mantissa) 21997 rts 21998 21999# 22000# some bits were shifted off so set the sticky bit. 22001# the entire mantissa is zero. 22002# 22003case3_set_sticky: 22004 bset &rnd_stky_bit,%d0 # set new sticky bit 22005 clr.l FTEMP_HI(%a0) # clear hi(mantissa) 22006 clr.l FTEMP_LO(%a0) # clear lo(mantissa) 22007 rts 22008 22009######################################################################### 22010# XDEF **************************************************************** # 22011# _round(): round result according to precision/mode # 22012# # 22013# XREF **************************************************************** # 22014# None # 22015# # 22016# INPUT *************************************************************** # 22017# a0 = ptr to input operand in internal extended format # 22018# d1(hi) = contains rounding precision: # 22019# ext = $0000xxxx # 22020# sgl = $0004xxxx # 22021# dbl = $0008xxxx # 22022# d1(lo) = contains rounding mode: # 22023# RN = $xxxx0000 # 22024# RZ = $xxxx0001 # 22025# RM = $xxxx0002 # 22026# RP = $xxxx0003 # 22027# d0{31:29} = contains the g,r,s bits (extended) # 22028# # 22029# OUTPUT ************************************************************** # 22030# a0 = pointer to rounded result # 22031# # 22032# ALGORITHM *********************************************************** # 22033# On return the value pointed to by a0 is correctly rounded, # 22034# a0 is preserved and the g-r-s bits in d0 are cleared. # 22035# The result is not typed - the tag field is invalid. The # 22036# result is still in the internal extended format. # 22037# # 22038# The INEX bit of USER_FPSR will be set if the rounded result was # 22039# inexact (i.e. if any of the g-r-s bits were set). # 22040# # 22041######################################################################### 22042 22043 global _round 22044_round: 22045# 22046# ext_grs() looks at the rounding precision and sets the appropriate 22047# G,R,S bits. 22048# If (G,R,S == 0) then result is exact and round is done, else set 22049# the inex flag in status reg and continue. 22050# 22051 bsr.l ext_grs # extract G,R,S 22052 22053 tst.l %d0 # are G,R,S zero? 22054 beq.w truncate # yes; round is complete 22055 22056 or.w &inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex 22057 22058# 22059# Use rounding mode as an index into a jump table for these modes. 22060# All of the following assumes grs != 0. 22061# 22062 mov.w (tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset 22063 jmp (tbl_mode.b,%pc,%a1) # jmp to rnd mode handler 22064 22065tbl_mode: 22066 short rnd_near - tbl_mode 22067 short truncate - tbl_mode # RZ always truncates 22068 short rnd_mnus - tbl_mode 22069 short rnd_plus - tbl_mode 22070 22071################################################################# 22072# ROUND PLUS INFINITY # 22073# # 22074# If sign of fp number = 0 (positive), then add 1 to l. # 22075################################################################# 22076rnd_plus: 22077 tst.b FTEMP_SGN(%a0) # check for sign 22078 bmi.w truncate # if positive then truncate 22079 22080 mov.l &0xffffffff, %d0 # force g,r,s to be all f's 22081 swap %d1 # set up d1 for round prec. 22082 22083 cmpi.b %d1, &s_mode # is prec = sgl? 22084 beq.w add_sgl # yes 22085 bgt.w add_dbl # no; it's dbl 22086 bra.w add_ext # no; it's ext 22087 22088################################################################# 22089# ROUND MINUS INFINITY # 22090# # 22091# If sign of fp number = 1 (negative), then add 1 to l. # 22092################################################################# 22093rnd_mnus: 22094 tst.b FTEMP_SGN(%a0) # check for sign 22095 bpl.w truncate # if negative then truncate 22096 22097 mov.l &0xffffffff, %d0 # force g,r,s to be all f's 22098 swap %d1 # set up d1 for round prec. 22099 22100 cmpi.b %d1, &s_mode # is prec = sgl? 22101 beq.w add_sgl # yes 22102 bgt.w add_dbl # no; it's dbl 22103 bra.w add_ext # no; it's ext 22104 22105################################################################# 22106# ROUND NEAREST # 22107# # 22108# If (g=1), then add 1 to l and if (r=s=0), then clear l # 22109# Note that this will round to even in case of a tie. # 22110################################################################# 22111rnd_near: 22112 asl.l &0x1, %d0 # shift g-bit to c-bit 22113 bcc.w truncate # if (g=1) then 22114 22115 swap %d1 # set up d1 for round prec. 22116 22117 cmpi.b %d1, &s_mode # is prec = sgl? 22118 beq.w add_sgl # yes 22119 bgt.w add_dbl # no; it's dbl 22120 bra.w add_ext # no; it's ext 22121 22122# *** LOCAL EQUATES *** 22123set ad_1_sgl, 0x00000100 # constant to add 1 to l-bit in sgl prec 22124set ad_1_dbl, 0x00000800 # constant to add 1 to l-bit in dbl prec 22125 22126######################### 22127# ADD SINGLE # 22128######################### 22129add_sgl: 22130 add.l &ad_1_sgl, FTEMP_HI(%a0) 22131 bcc.b scc_clr # no mantissa overflow 22132 roxr.w FTEMP_HI(%a0) # shift v-bit back in 22133 roxr.w FTEMP_HI+2(%a0) # shift v-bit back in 22134 add.w &0x1, FTEMP_EX(%a0) # and incr exponent 22135scc_clr: 22136 tst.l %d0 # test for rs = 0 22137 bne.b sgl_done 22138 and.w &0xfe00, FTEMP_HI+2(%a0) # clear the l-bit 22139sgl_done: 22140 and.l &0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit 22141 clr.l FTEMP_LO(%a0) # clear d2 22142 rts 22143 22144######################### 22145# ADD EXTENDED # 22146######################### 22147add_ext: 22148 addq.l &1,FTEMP_LO(%a0) # add 1 to l-bit 22149 bcc.b xcc_clr # test for carry out 22150 addq.l &1,FTEMP_HI(%a0) # propagate carry 22151 bcc.b xcc_clr 22152 roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit 22153 roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit 22154 roxr.w FTEMP_LO(%a0) 22155 roxr.w FTEMP_LO+2(%a0) 22156 add.w &0x1,FTEMP_EX(%a0) # and inc exp 22157xcc_clr: 22158 tst.l %d0 # test rs = 0 22159 bne.b add_ext_done 22160 and.b &0xfe,FTEMP_LO+3(%a0) # clear the l bit 22161add_ext_done: 22162 rts 22163 22164######################### 22165# ADD DOUBLE # 22166######################### 22167add_dbl: 22168 add.l &ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb 22169 bcc.b dcc_clr # no carry 22170 addq.l &0x1, FTEMP_HI(%a0) # propagate carry 22171 bcc.b dcc_clr # no carry 22172 22173 roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit 22174 roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit 22175 roxr.w FTEMP_LO(%a0) 22176 roxr.w FTEMP_LO+2(%a0) 22177 addq.w &0x1, FTEMP_EX(%a0) # incr exponent 22178dcc_clr: 22179 tst.l %d0 # test for rs = 0 22180 bne.b dbl_done 22181 and.w &0xf000, FTEMP_LO+2(%a0) # clear the l-bit 22182 22183dbl_done: 22184 and.l &0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit 22185 rts 22186 22187########################### 22188# Truncate all other bits # 22189########################### 22190truncate: 22191 swap %d1 # select rnd prec 22192 22193 cmpi.b %d1, &s_mode # is prec sgl? 22194 beq.w sgl_done # yes 22195 bgt.b dbl_done # no; it's dbl 22196 rts # no; it's ext 22197 22198 22199# 22200# ext_grs(): extract guard, round and sticky bits according to 22201# rounding precision. 22202# 22203# INPUT 22204# d0 = extended precision g,r,s (in d0{31:29}) 22205# d1 = {PREC,ROUND} 22206# OUTPUT 22207# d0{31:29} = guard, round, sticky 22208# 22209# The ext_grs extract the guard/round/sticky bits according to the 22210# selected rounding precision. It is called by the round subroutine 22211# only. All registers except d0 are kept intact. d0 becomes an 22212# updated guard,round,sticky in d0{31:29} 22213# 22214# Notes: the ext_grs uses the round PREC, and therefore has to swap d1 22215# prior to usage, and needs to restore d1 to original. this 22216# routine is tightly tied to the round routine and not meant to 22217# uphold standard subroutine calling practices. 22218# 22219 22220ext_grs: 22221 swap %d1 # have d1.w point to round precision 22222 tst.b %d1 # is rnd prec = extended? 22223 bne.b ext_grs_not_ext # no; go handle sgl or dbl 22224 22225# 22226# %d0 actually already hold g,r,s since _round() had it before calling 22227# this function. so, as long as we don't disturb it, we are "returning" it. 22228# 22229ext_grs_ext: 22230 swap %d1 # yes; return to correct positions 22231 rts 22232 22233ext_grs_not_ext: 22234 movm.l &0x3000, -(%sp) # make some temp registers {d2/d3} 22235 22236 cmpi.b %d1, &s_mode # is rnd prec = sgl? 22237 bne.b ext_grs_dbl # no; go handle dbl 22238 22239# 22240# sgl: 22241# 96 64 40 32 0 22242# ----------------------------------------------------- 22243# | EXP |XXXXXXX| |xx | |grs| 22244# ----------------------------------------------------- 22245# <--(24)--->nn\ / 22246# ee --------------------- 22247# ww | 22248# v 22249# gr new sticky 22250# 22251ext_grs_sgl: 22252 bfextu FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right 22253 mov.l &30, %d2 # of the sgl prec. limits 22254 lsl.l %d2, %d3 # shift g-r bits to MSB of d3 22255 mov.l FTEMP_HI(%a0), %d2 # get word 2 for s-bit test 22256 and.l &0x0000003f, %d2 # s bit is the or of all other 22257 bne.b ext_grs_st_stky # bits to the right of g-r 22258 tst.l FTEMP_LO(%a0) # test lower mantissa 22259 bne.b ext_grs_st_stky # if any are set, set sticky 22260 tst.l %d0 # test original g,r,s 22261 bne.b ext_grs_st_stky # if any are set, set sticky 22262 bra.b ext_grs_end_sd # if words 3 and 4 are clr, exit 22263 22264# 22265# dbl: 22266# 96 64 32 11 0 22267# ----------------------------------------------------- 22268# | EXP |XXXXXXX| | |xx |grs| 22269# ----------------------------------------------------- 22270# nn\ / 22271# ee ------- 22272# ww | 22273# v 22274# gr new sticky 22275# 22276ext_grs_dbl: 22277 bfextu FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right 22278 mov.l &30, %d2 # of the dbl prec. limits 22279 lsl.l %d2, %d3 # shift g-r bits to the MSB of d3 22280 mov.l FTEMP_LO(%a0), %d2 # get lower mantissa for s-bit test 22281 and.l &0x000001ff, %d2 # s bit is the or-ing of all 22282 bne.b ext_grs_st_stky # other bits to the right of g-r 22283 tst.l %d0 # test word original g,r,s 22284 bne.b ext_grs_st_stky # if any are set, set sticky 22285 bra.b ext_grs_end_sd # if clear, exit 22286 22287ext_grs_st_stky: 22288 bset &rnd_stky_bit, %d3 # set sticky bit 22289ext_grs_end_sd: 22290 mov.l %d3, %d0 # return grs to d0 22291 22292 movm.l (%sp)+, &0xc # restore scratch registers {d2/d3} 22293 22294 swap %d1 # restore d1 to original 22295 rts 22296 22297######################################################################### 22298# norm(): normalize the mantissa of an extended precision input. the # 22299# input operand should not be normalized already. # 22300# # 22301# XDEF **************************************************************** # 22302# norm() # 22303# # 22304# XREF **************************************************************** # 22305# none # 22306# # 22307# INPUT *************************************************************** # 22308# a0 = pointer fp extended precision operand to normalize # 22309# # 22310# OUTPUT ************************************************************** # 22311# d0 = number of bit positions the mantissa was shifted # 22312# a0 = the input operand's mantissa is normalized; the exponent # 22313# is unchanged. # 22314# # 22315######################################################################### 22316 global norm 22317norm: 22318 mov.l %d2, -(%sp) # create some temp regs 22319 mov.l %d3, -(%sp) 22320 22321 mov.l FTEMP_HI(%a0), %d0 # load hi(mantissa) 22322 mov.l FTEMP_LO(%a0), %d1 # load lo(mantissa) 22323 22324 bfffo %d0{&0:&32}, %d2 # how many places to shift? 22325 beq.b norm_lo # hi(man) is all zeroes! 22326 22327norm_hi: 22328 lsl.l %d2, %d0 # left shift hi(man) 22329 bfextu %d1{&0:%d2}, %d3 # extract lo bits 22330 22331 or.l %d3, %d0 # create hi(man) 22332 lsl.l %d2, %d1 # create lo(man) 22333 22334 mov.l %d0, FTEMP_HI(%a0) # store new hi(man) 22335 mov.l %d1, FTEMP_LO(%a0) # store new lo(man) 22336 22337 mov.l %d2, %d0 # return shift amount 22338 22339 mov.l (%sp)+, %d3 # restore temp regs 22340 mov.l (%sp)+, %d2 22341 22342 rts 22343 22344norm_lo: 22345 bfffo %d1{&0:&32}, %d2 # how many places to shift? 22346 lsl.l %d2, %d1 # shift lo(man) 22347 add.l &32, %d2 # add 32 to shft amount 22348 22349 mov.l %d1, FTEMP_HI(%a0) # store hi(man) 22350 clr.l FTEMP_LO(%a0) # lo(man) is now zero 22351 22352 mov.l %d2, %d0 # return shift amount 22353 22354 mov.l (%sp)+, %d3 # restore temp regs 22355 mov.l (%sp)+, %d2 22356 22357 rts 22358 22359######################################################################### 22360# unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO # 22361# - returns corresponding optype tag # 22362# # 22363# XDEF **************************************************************** # 22364# unnorm_fix() # 22365# # 22366# XREF **************************************************************** # 22367# norm() - normalize the mantissa # 22368# # 22369# INPUT *************************************************************** # 22370# a0 = pointer to unnormalized extended precision number # 22371# # 22372# OUTPUT ************************************************************** # 22373# d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO # 22374# a0 = input operand has been converted to a norm, denorm, or # 22375# zero; both the exponent and mantissa are changed. # 22376# # 22377######################################################################### 22378 22379 global unnorm_fix 22380unnorm_fix: 22381 bfffo FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed? 22382 bne.b unnorm_shift # hi(man) is not all zeroes 22383 22384# 22385# hi(man) is all zeroes so see if any bits in lo(man) are set 22386# 22387unnorm_chk_lo: 22388 bfffo FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero? 22389 beq.w unnorm_zero # yes 22390 22391 add.w &32, %d0 # no; fix shift distance 22392 22393# 22394# d0 = # shifts needed for complete normalization 22395# 22396unnorm_shift: 22397 clr.l %d1 # clear top word 22398 mov.w FTEMP_EX(%a0), %d1 # extract exponent 22399 and.w &0x7fff, %d1 # strip off sgn 22400 22401 cmp.w %d0, %d1 # will denorm push exp < 0? 22402 bgt.b unnorm_nrm_zero # yes; denorm only until exp = 0 22403 22404# 22405# exponent would not go < 0. Therefore, number stays normalized 22406# 22407 sub.w %d0, %d1 # shift exponent value 22408 mov.w FTEMP_EX(%a0), %d0 # load old exponent 22409 and.w &0x8000, %d0 # save old sign 22410 or.w %d0, %d1 # {sgn,new exp} 22411 mov.w %d1, FTEMP_EX(%a0) # insert new exponent 22412 22413 bsr.l norm # normalize UNNORM 22414 22415 mov.b &NORM, %d0 # return new optype tag 22416 rts 22417 22418# 22419# exponent would go < 0, so only denormalize until exp = 0 22420# 22421unnorm_nrm_zero: 22422 cmp.b %d1, &32 # is exp <= 32? 22423 bgt.b unnorm_nrm_zero_lrg # no; go handle large exponent 22424 22425 bfextu FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man) 22426 mov.l %d0, FTEMP_HI(%a0) # save new hi(man) 22427 22428 mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man) 22429 lsl.l %d1, %d0 # extract new lo(man) 22430 mov.l %d0, FTEMP_LO(%a0) # save new lo(man) 22431 22432 and.w &0x8000, FTEMP_EX(%a0) # set exp = 0 22433 22434 mov.b &DENORM, %d0 # return new optype tag 22435 rts 22436 22437# 22438# only mantissa bits set are in lo(man) 22439# 22440unnorm_nrm_zero_lrg: 22441 sub.w &32, %d1 # adjust shft amt by 32 22442 22443 mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man) 22444 lsl.l %d1, %d0 # left shift lo(man) 22445 22446 mov.l %d0, FTEMP_HI(%a0) # store new hi(man) 22447 clr.l FTEMP_LO(%a0) # lo(man) = 0 22448 22449 and.w &0x8000, FTEMP_EX(%a0) # set exp = 0 22450 22451 mov.b &DENORM, %d0 # return new optype tag 22452 rts 22453 22454# 22455# whole mantissa is zero so this UNNORM is actually a zero 22456# 22457unnorm_zero: 22458 and.w &0x8000, FTEMP_EX(%a0) # force exponent to zero 22459 22460 mov.b &ZERO, %d0 # fix optype tag 22461 rts 22462 22463######################################################################### 22464# XDEF **************************************************************** # 22465# set_tag_x(): return the optype of the input ext fp number # 22466# # 22467# XREF **************************************************************** # 22468# None # 22469# # 22470# INPUT *************************************************************** # 22471# a0 = pointer to extended precision operand # 22472# # 22473# OUTPUT ************************************************************** # 22474# d0 = value of type tag # 22475# one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO # 22476# # 22477# ALGORITHM *********************************************************** # 22478# Simply test the exponent, j-bit, and mantissa values to # 22479# determine the type of operand. # 22480# If it's an unnormalized zero, alter the operand and force it # 22481# to be a normal zero. # 22482# # 22483######################################################################### 22484 22485 global set_tag_x 22486set_tag_x: 22487 mov.w FTEMP_EX(%a0), %d0 # extract exponent 22488 andi.w &0x7fff, %d0 # strip off sign 22489 cmpi.w %d0, &0x7fff # is (EXP == MAX)? 22490 beq.b inf_or_nan_x 22491not_inf_or_nan_x: 22492 btst &0x7,FTEMP_HI(%a0) 22493 beq.b not_norm_x 22494is_norm_x: 22495 mov.b &NORM, %d0 22496 rts 22497not_norm_x: 22498 tst.w %d0 # is exponent = 0? 22499 bne.b is_unnorm_x 22500not_unnorm_x: 22501 tst.l FTEMP_HI(%a0) 22502 bne.b is_denorm_x 22503 tst.l FTEMP_LO(%a0) 22504 bne.b is_denorm_x 22505is_zero_x: 22506 mov.b &ZERO, %d0 22507 rts 22508is_denorm_x: 22509 mov.b &DENORM, %d0 22510 rts 22511# must distinguish now "Unnormalized zeroes" which we 22512# must convert to zero. 22513is_unnorm_x: 22514 tst.l FTEMP_HI(%a0) 22515 bne.b is_unnorm_reg_x 22516 tst.l FTEMP_LO(%a0) 22517 bne.b is_unnorm_reg_x 22518# it's an "unnormalized zero". let's convert it to an actual zero... 22519 andi.w &0x8000,FTEMP_EX(%a0) # clear exponent 22520 mov.b &ZERO, %d0 22521 rts 22522is_unnorm_reg_x: 22523 mov.b &UNNORM, %d0 22524 rts 22525inf_or_nan_x: 22526 tst.l FTEMP_LO(%a0) 22527 bne.b is_nan_x 22528 mov.l FTEMP_HI(%a0), %d0 22529 and.l &0x7fffffff, %d0 # msb is a don't care! 22530 bne.b is_nan_x 22531is_inf_x: 22532 mov.b &INF, %d0 22533 rts 22534is_nan_x: 22535 btst &0x6, FTEMP_HI(%a0) 22536 beq.b is_snan_x 22537 mov.b &QNAN, %d0 22538 rts 22539is_snan_x: 22540 mov.b &SNAN, %d0 22541 rts 22542 22543######################################################################### 22544# XDEF **************************************************************** # 22545# set_tag_d(): return the optype of the input dbl fp number # 22546# # 22547# XREF **************************************************************** # 22548# None # 22549# # 22550# INPUT *************************************************************** # 22551# a0 = points to double precision operand # 22552# # 22553# OUTPUT ************************************************************** # 22554# d0 = value of type tag # 22555# one of: NORM, INF, QNAN, SNAN, DENORM, ZERO # 22556# # 22557# ALGORITHM *********************************************************** # 22558# Simply test the exponent, j-bit, and mantissa values to # 22559# determine the type of operand. # 22560# # 22561######################################################################### 22562 22563 global set_tag_d 22564set_tag_d: 22565 mov.l FTEMP(%a0), %d0 22566 mov.l %d0, %d1 22567 22568 andi.l &0x7ff00000, %d0 22569 beq.b zero_or_denorm_d 22570 22571 cmpi.l %d0, &0x7ff00000 22572 beq.b inf_or_nan_d 22573 22574is_norm_d: 22575 mov.b &NORM, %d0 22576 rts 22577zero_or_denorm_d: 22578 and.l &0x000fffff, %d1 22579 bne is_denorm_d 22580 tst.l 4+FTEMP(%a0) 22581 bne is_denorm_d 22582is_zero_d: 22583 mov.b &ZERO, %d0 22584 rts 22585is_denorm_d: 22586 mov.b &DENORM, %d0 22587 rts 22588inf_or_nan_d: 22589 and.l &0x000fffff, %d1 22590 bne is_nan_d 22591 tst.l 4+FTEMP(%a0) 22592 bne is_nan_d 22593is_inf_d: 22594 mov.b &INF, %d0 22595 rts 22596is_nan_d: 22597 btst &19, %d1 22598 bne is_qnan_d 22599is_snan_d: 22600 mov.b &SNAN, %d0 22601 rts 22602is_qnan_d: 22603 mov.b &QNAN, %d0 22604 rts 22605 22606######################################################################### 22607# XDEF **************************************************************** # 22608# set_tag_s(): return the optype of the input sgl fp number # 22609# # 22610# XREF **************************************************************** # 22611# None # 22612# # 22613# INPUT *************************************************************** # 22614# a0 = pointer to single precision operand # 22615# # 22616# OUTPUT ************************************************************** # 22617# d0 = value of type tag # 22618# one of: NORM, INF, QNAN, SNAN, DENORM, ZERO # 22619# # 22620# ALGORITHM *********************************************************** # 22621# Simply test the exponent, j-bit, and mantissa values to # 22622# determine the type of operand. # 22623# # 22624######################################################################### 22625 22626 global set_tag_s 22627set_tag_s: 22628 mov.l FTEMP(%a0), %d0 22629 mov.l %d0, %d1 22630 22631 andi.l &0x7f800000, %d0 22632 beq.b zero_or_denorm_s 22633 22634 cmpi.l %d0, &0x7f800000 22635 beq.b inf_or_nan_s 22636 22637is_norm_s: 22638 mov.b &NORM, %d0 22639 rts 22640zero_or_denorm_s: 22641 and.l &0x007fffff, %d1 22642 bne is_denorm_s 22643is_zero_s: 22644 mov.b &ZERO, %d0 22645 rts 22646is_denorm_s: 22647 mov.b &DENORM, %d0 22648 rts 22649inf_or_nan_s: 22650 and.l &0x007fffff, %d1 22651 bne is_nan_s 22652is_inf_s: 22653 mov.b &INF, %d0 22654 rts 22655is_nan_s: 22656 btst &22, %d1 22657 bne is_qnan_s 22658is_snan_s: 22659 mov.b &SNAN, %d0 22660 rts 22661is_qnan_s: 22662 mov.b &QNAN, %d0 22663 rts 22664 22665######################################################################### 22666# XDEF **************************************************************** # 22667# unf_res(): routine to produce default underflow result of a # 22668# scaled extended precision number; this is used by # 22669# fadd/fdiv/fmul/etc. emulation routines. # 22670# unf_res4(): same as above but for fsglmul/fsgldiv which use # 22671# single round prec and extended prec mode. # 22672# # 22673# XREF **************************************************************** # 22674# _denorm() - denormalize according to scale factor # 22675# _round() - round denormalized number according to rnd prec # 22676# # 22677# INPUT *************************************************************** # 22678# a0 = pointer to extended precison operand # 22679# d0 = scale factor # 22680# d1 = rounding precision/mode # 22681# # 22682# OUTPUT ************************************************************** # 22683# a0 = pointer to default underflow result in extended precision # 22684# d0.b = result FPSR_cc which caller may or may not want to save # 22685# # 22686# ALGORITHM *********************************************************** # 22687# Convert the input operand to "internal format" which means the # 22688# exponent is extended to 16 bits and the sign is stored in the unused # 22689# portion of the extended precison operand. Denormalize the number # 22690# according to the scale factor passed in d0. Then, round the # 22691# denormalized result. # 22692# Set the FPSR_exc bits as appropriate but return the cc bits in # 22693# d0 in case the caller doesn't want to save them (as is the case for # 22694# fmove out). # 22695# unf_res4() for fsglmul/fsgldiv forces the denorm to extended # 22696# precision and the rounding mode to single. # 22697# # 22698######################################################################### 22699 global unf_res 22700unf_res: 22701 mov.l %d1, -(%sp) # save rnd prec,mode on stack 22702 22703 btst &0x7, FTEMP_EX(%a0) # make "internal" format 22704 sne FTEMP_SGN(%a0) 22705 22706 mov.w FTEMP_EX(%a0), %d1 # extract exponent 22707 and.w &0x7fff, %d1 22708 sub.w %d0, %d1 22709 mov.w %d1, FTEMP_EX(%a0) # insert 16 bit exponent 22710 22711 mov.l %a0, -(%sp) # save operand ptr during calls 22712 22713 mov.l 0x4(%sp),%d0 # pass rnd prec. 22714 andi.w &0x00c0,%d0 22715 lsr.w &0x4,%d0 22716 bsr.l _denorm # denorm result 22717 22718 mov.l (%sp),%a0 22719 mov.w 0x6(%sp),%d1 # load prec:mode into %d1 22720 andi.w &0xc0,%d1 # extract rnd prec 22721 lsr.w &0x4,%d1 22722 swap %d1 22723 mov.w 0x6(%sp),%d1 22724 andi.w &0x30,%d1 22725 lsr.w &0x4,%d1 22726 bsr.l _round # round the denorm 22727 22728 mov.l (%sp)+, %a0 22729 22730# result is now rounded properly. convert back to normal format 22731 bclr &0x7, FTEMP_EX(%a0) # clear sgn first; may have residue 22732 tst.b FTEMP_SGN(%a0) # is "internal result" sign set? 22733 beq.b unf_res_chkifzero # no; result is positive 22734 bset &0x7, FTEMP_EX(%a0) # set result sgn 22735 clr.b FTEMP_SGN(%a0) # clear temp sign 22736 22737# the number may have become zero after rounding. set ccodes accordingly. 22738unf_res_chkifzero: 22739 clr.l %d0 22740 tst.l FTEMP_HI(%a0) # is value now a zero? 22741 bne.b unf_res_cont # no 22742 tst.l FTEMP_LO(%a0) 22743 bne.b unf_res_cont # no 22744# bset &z_bit, FPSR_CC(%a6) # yes; set zero ccode bit 22745 bset &z_bit, %d0 # yes; set zero ccode bit 22746 22747unf_res_cont: 22748 22749# 22750# can inex1 also be set along with unfl and inex2??? 22751# 22752# we know that underflow has occurred. aunfl should be set if INEX2 is also set. 22753# 22754 btst &inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set? 22755 beq.b unf_res_end # no 22756 bset &aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl 22757 22758unf_res_end: 22759 add.l &0x4, %sp # clear stack 22760 rts 22761 22762# unf_res() for fsglmul() and fsgldiv(). 22763 global unf_res4 22764unf_res4: 22765 mov.l %d1,-(%sp) # save rnd prec,mode on stack 22766 22767 btst &0x7,FTEMP_EX(%a0) # make "internal" format 22768 sne FTEMP_SGN(%a0) 22769 22770 mov.w FTEMP_EX(%a0),%d1 # extract exponent 22771 and.w &0x7fff,%d1 22772 sub.w %d0,%d1 22773 mov.w %d1,FTEMP_EX(%a0) # insert 16 bit exponent 22774 22775 mov.l %a0,-(%sp) # save operand ptr during calls 22776 22777 clr.l %d0 # force rnd prec = ext 22778 bsr.l _denorm # denorm result 22779 22780 mov.l (%sp),%a0 22781 mov.w &s_mode,%d1 # force rnd prec = sgl 22782 swap %d1 22783 mov.w 0x6(%sp),%d1 # load rnd mode 22784 andi.w &0x30,%d1 # extract rnd prec 22785 lsr.w &0x4,%d1 22786 bsr.l _round # round the denorm 22787 22788 mov.l (%sp)+,%a0 22789 22790# result is now rounded properly. convert back to normal format 22791 bclr &0x7,FTEMP_EX(%a0) # clear sgn first; may have residue 22792 tst.b FTEMP_SGN(%a0) # is "internal result" sign set? 22793 beq.b unf_res4_chkifzero # no; result is positive 22794 bset &0x7,FTEMP_EX(%a0) # set result sgn 22795 clr.b FTEMP_SGN(%a0) # clear temp sign 22796 22797# the number may have become zero after rounding. set ccodes accordingly. 22798unf_res4_chkifzero: 22799 clr.l %d0 22800 tst.l FTEMP_HI(%a0) # is value now a zero? 22801 bne.b unf_res4_cont # no 22802 tst.l FTEMP_LO(%a0) 22803 bne.b unf_res4_cont # no 22804# bset &z_bit,FPSR_CC(%a6) # yes; set zero ccode bit 22805 bset &z_bit,%d0 # yes; set zero ccode bit 22806 22807unf_res4_cont: 22808 22809# 22810# can inex1 also be set along with unfl and inex2??? 22811# 22812# we know that underflow has occurred. aunfl should be set if INEX2 is also set. 22813# 22814 btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set? 22815 beq.b unf_res4_end # no 22816 bset &aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl 22817 22818unf_res4_end: 22819 add.l &0x4,%sp # clear stack 22820 rts 22821 22822######################################################################### 22823# XDEF **************************************************************** # 22824# ovf_res(): routine to produce the default overflow result of # 22825# an overflowing number. # 22826# ovf_res2(): same as above but the rnd mode/prec are passed # 22827# differently. # 22828# # 22829# XREF **************************************************************** # 22830# none # 22831# # 22832# INPUT *************************************************************** # 22833# d1.b = '-1' => (-); '0' => (+) # 22834# ovf_res(): # 22835# d0 = rnd mode/prec # 22836# ovf_res2(): # 22837# hi(d0) = rnd prec # 22838# lo(d0) = rnd mode # 22839# # 22840# OUTPUT ************************************************************** # 22841# a0 = points to extended precision result # 22842# d0.b = condition code bits # 22843# # 22844# ALGORITHM *********************************************************** # 22845# The default overflow result can be determined by the sign of # 22846# the result and the rounding mode/prec in effect. These bits are # 22847# concatenated together to create an index into the default result # 22848# table. A pointer to the correct result is returned in a0. The # 22849# resulting condition codes are returned in d0 in case the caller # 22850# doesn't want FPSR_cc altered (as is the case for fmove out). # 22851# # 22852######################################################################### 22853 22854 global ovf_res 22855ovf_res: 22856 andi.w &0x10,%d1 # keep result sign 22857 lsr.b &0x4,%d0 # shift prec/mode 22858 or.b %d0,%d1 # concat the two 22859 mov.w %d1,%d0 # make a copy 22860 lsl.b &0x1,%d1 # multiply d1 by 2 22861 bra.b ovf_res_load 22862 22863 global ovf_res2 22864ovf_res2: 22865 and.w &0x10, %d1 # keep result sign 22866 or.b %d0, %d1 # insert rnd mode 22867 swap %d0 22868 or.b %d0, %d1 # insert rnd prec 22869 mov.w %d1, %d0 # make a copy 22870 lsl.b &0x1, %d1 # shift left by 1 22871 22872# 22873# use the rounding mode, precision, and result sign as in index into the 22874# two tables below to fetch the default result and the result ccodes. 22875# 22876ovf_res_load: 22877 mov.b (tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes 22878 lea (tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr 22879 22880 rts 22881 22882tbl_ovfl_cc: 22883 byte 0x2, 0x0, 0x0, 0x2 22884 byte 0x2, 0x0, 0x0, 0x2 22885 byte 0x2, 0x0, 0x0, 0x2 22886 byte 0x0, 0x0, 0x0, 0x0 22887 byte 0x2+0x8, 0x8, 0x2+0x8, 0x8 22888 byte 0x2+0x8, 0x8, 0x2+0x8, 0x8 22889 byte 0x2+0x8, 0x8, 0x2+0x8, 0x8 22890 22891tbl_ovfl_result: 22892 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN 22893 long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ 22894 long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM 22895 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP 22896 22897 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN 22898 long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ 22899 long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM 22900 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP 22901 22902 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN 22903 long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ 22904 long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM 22905 long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP 22906 22907 long 0x00000000,0x00000000,0x00000000,0x00000000 22908 long 0x00000000,0x00000000,0x00000000,0x00000000 22909 long 0x00000000,0x00000000,0x00000000,0x00000000 22910 long 0x00000000,0x00000000,0x00000000,0x00000000 22911 22912 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN 22913 long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ 22914 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM 22915 long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP 22916 22917 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN 22918 long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ 22919 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM 22920 long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP 22921 22922 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN 22923 long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ 22924 long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM 22925 long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP 22926 22927######################################################################### 22928# XDEF **************************************************************** # 22929# get_packed(): fetch a packed operand from memory and then # 22930# convert it to a floating-point binary number. # 22931# # 22932# XREF **************************************************************** # 22933# _dcalc_ea() - calculate the correct <ea> # 22934# _mem_read() - fetch the packed operand from memory # 22935# facc_in_x() - the fetch failed so jump to special exit code # 22936# decbin() - convert packed to binary extended precision # 22937# # 22938# INPUT *************************************************************** # 22939# None # 22940# # 22941# OUTPUT ************************************************************** # 22942# If no failure on _mem_read(): # 22943# FP_SRC(a6) = packed operand now as a binary FP number # 22944# # 22945# ALGORITHM *********************************************************** # 22946# Get the correct <ea> which is the value on the exception stack # 22947# frame w/ maybe a correction factor if the <ea> is -(an) or (an)+. # 22948# Then, fetch the operand from memory. If the fetch fails, exit # 22949# through facc_in_x(). # 22950# If the packed operand is a ZERO,NAN, or INF, convert it to # 22951# its binary representation here. Else, call decbin() which will # 22952# convert the packed value to an extended precision binary value. # 22953# # 22954######################################################################### 22955 22956# the stacked <ea> for packed is correct except for -(An). 22957# the base reg must be updated for both -(An) and (An)+. 22958 global get_packed 22959get_packed: 22960 mov.l &0xc,%d0 # packed is 12 bytes 22961 bsr.l _dcalc_ea # fetch <ea>; correct An 22962 22963 lea FP_SRC(%a6),%a1 # pass: ptr to super dst 22964 mov.l &0xc,%d0 # pass: 12 bytes 22965 bsr.l _dmem_read # read packed operand 22966 22967 tst.l %d1 # did dfetch fail? 22968 bne.l facc_in_x # yes 22969 22970# The packed operand is an INF or a NAN if the exponent field is all ones. 22971 bfextu FP_SRC(%a6){&1:&15},%d0 # get exp 22972 cmpi.w %d0,&0x7fff # INF or NAN? 22973 bne.b gp_try_zero # no 22974 rts # operand is an INF or NAN 22975 22976# The packed operand is a zero if the mantissa is all zero, else it's 22977# a normal packed op. 22978gp_try_zero: 22979 mov.b 3+FP_SRC(%a6),%d0 # get byte 4 22980 andi.b &0x0f,%d0 # clear all but last nybble 22981 bne.b gp_not_spec # not a zero 22982 tst.l FP_SRC_HI(%a6) # is lw 2 zero? 22983 bne.b gp_not_spec # not a zero 22984 tst.l FP_SRC_LO(%a6) # is lw 3 zero? 22985 bne.b gp_not_spec # not a zero 22986 rts # operand is a ZERO 22987gp_not_spec: 22988 lea FP_SRC(%a6),%a0 # pass: ptr to packed op 22989 bsr.l decbin # convert to extended 22990 fmovm.x &0x80,FP_SRC(%a6) # make this the srcop 22991 rts 22992 22993######################################################################### 22994# decbin(): Converts normalized packed bcd value pointed to by register # 22995# a0 to extended-precision value in fp0. # 22996# # 22997# INPUT *************************************************************** # 22998# a0 = pointer to normalized packed bcd value # 22999# # 23000# OUTPUT ************************************************************** # 23001# fp0 = exact fp representation of the packed bcd value. # 23002# # 23003# ALGORITHM *********************************************************** # 23004# Expected is a normal bcd (i.e. non-exceptional; all inf, zero, # 23005# and NaN operands are dispatched without entering this routine) # 23006# value in 68881/882 format at location (a0). # 23007# # 23008# A1. Convert the bcd exponent to binary by successive adds and # 23009# muls. Set the sign according to SE. Subtract 16 to compensate # 23010# for the mantissa which is to be interpreted as 17 integer # 23011# digits, rather than 1 integer and 16 fraction digits. # 23012# Note: this operation can never overflow. # 23013# # 23014# A2. Convert the bcd mantissa to binary by successive # 23015# adds and muls in FP0. Set the sign according to SM. # 23016# The mantissa digits will be converted with the decimal point # 23017# assumed following the least-significant digit. # 23018# Note: this operation can never overflow. # 23019# # 23020# A3. Count the number of leading/trailing zeros in the # 23021# bcd string. If SE is positive, count the leading zeros; # 23022# if negative, count the trailing zeros. Set the adjusted # 23023# exponent equal to the exponent from A1 and the zero count # 23024# added if SM = 1 and subtracted if SM = 0. Scale the # 23025# mantissa the equivalent of forcing in the bcd value: # 23026# # 23027# SM = 0 a non-zero digit in the integer position # 23028# SM = 1 a non-zero digit in Mant0, lsd of the fraction # 23029# # 23030# this will insure that any value, regardless of its # 23031# representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted # 23032# consistently. # 23033# # 23034# A4. Calculate the factor 10^exp in FP1 using a table of # 23035# 10^(2^n) values. To reduce the error in forming factors # 23036# greater than 10^27, a directed rounding scheme is used with # 23037# tables rounded to RN, RM, and RP, according to the table # 23038# in the comments of the pwrten section. # 23039# # 23040# A5. Form the final binary number by scaling the mantissa by # 23041# the exponent factor. This is done by multiplying the # 23042# mantissa in FP0 by the factor in FP1 if the adjusted # 23043# exponent sign is positive, and dividing FP0 by FP1 if # 23044# it is negative. # 23045# # 23046# Clean up and return. Check if the final mul or div was inexact. # 23047# If so, set INEX1 in USER_FPSR. # 23048# # 23049######################################################################### 23050 23051# 23052# PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded 23053# to nearest, minus, and plus, respectively. The tables include 23054# 10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}. No rounding 23055# is required until the power is greater than 27, however, all 23056# tables include the first 5 for ease of indexing. 23057# 23058RTABLE: 23059 byte 0,0,0,0 23060 byte 2,3,2,3 23061 byte 2,3,3,2 23062 byte 3,2,2,3 23063 23064 set FNIBS,7 23065 set FSTRT,0 23066 23067 set ESTRT,4 23068 set EDIGITS,2 23069 23070 global decbin 23071decbin: 23072 mov.l 0x0(%a0),FP_SCR0_EX(%a6) # make a copy of input 23073 mov.l 0x4(%a0),FP_SCR0_HI(%a6) # so we don't alter it 23074 mov.l 0x8(%a0),FP_SCR0_LO(%a6) 23075 23076 lea FP_SCR0(%a6),%a0 23077 23078 movm.l &0x3c00,-(%sp) # save d2-d5 23079 fmovm.x &0x1,-(%sp) # save fp1 23080# 23081# Calculate exponent: 23082# 1. Copy bcd value in memory for use as a working copy. 23083# 2. Calculate absolute value of exponent in d1 by mul and add. 23084# 3. Correct for exponent sign. 23085# 4. Subtract 16 to compensate for interpreting the mant as all integer digits. 23086# (i.e., all digits assumed left of the decimal point.) 23087# 23088# Register usage: 23089# 23090# calc_e: 23091# (*) d0: temp digit storage 23092# (*) d1: accumulator for binary exponent 23093# (*) d2: digit count 23094# (*) d3: offset pointer 23095# ( ) d4: first word of bcd 23096# ( ) a0: pointer to working bcd value 23097# ( ) a6: pointer to original bcd value 23098# (*) FP_SCR1: working copy of original bcd value 23099# (*) L_SCR1: copy of original exponent word 23100# 23101calc_e: 23102 mov.l &EDIGITS,%d2 # # of nibbles (digits) in fraction part 23103 mov.l &ESTRT,%d3 # counter to pick up digits 23104 mov.l (%a0),%d4 # get first word of bcd 23105 clr.l %d1 # zero d1 for accumulator 23106e_gd: 23107 mulu.l &0xa,%d1 # mul partial product by one digit place 23108 bfextu %d4{%d3:&4},%d0 # get the digit and zero extend into d0 23109 add.l %d0,%d1 # d1 = d1 + d0 23110 addq.b &4,%d3 # advance d3 to the next digit 23111 dbf.w %d2,e_gd # if we have used all 3 digits, exit loop 23112 btst &30,%d4 # get SE 23113 beq.b e_pos # don't negate if pos 23114 neg.l %d1 # negate before subtracting 23115e_pos: 23116 sub.l &16,%d1 # sub to compensate for shift of mant 23117 bge.b e_save # if still pos, do not neg 23118 neg.l %d1 # now negative, make pos and set SE 23119 or.l &0x40000000,%d4 # set SE in d4, 23120 or.l &0x40000000,(%a0) # and in working bcd 23121e_save: 23122 mov.l %d1,-(%sp) # save exp on stack 23123# 23124# 23125# Calculate mantissa: 23126# 1. Calculate absolute value of mantissa in fp0 by mul and add. 23127# 2. Correct for mantissa sign. 23128# (i.e., all digits assumed left of the decimal point.) 23129# 23130# Register usage: 23131# 23132# calc_m: 23133# (*) d0: temp digit storage 23134# (*) d1: lword counter 23135# (*) d2: digit count 23136# (*) d3: offset pointer 23137# ( ) d4: words 2 and 3 of bcd 23138# ( ) a0: pointer to working bcd value 23139# ( ) a6: pointer to original bcd value 23140# (*) fp0: mantissa accumulator 23141# ( ) FP_SCR1: working copy of original bcd value 23142# ( ) L_SCR1: copy of original exponent word 23143# 23144calc_m: 23145 mov.l &1,%d1 # word counter, init to 1 23146 fmov.s &0x00000000,%fp0 # accumulator 23147# 23148# 23149# Since the packed number has a long word between the first & second parts, 23150# get the integer digit then skip down & get the rest of the 23151# mantissa. We will unroll the loop once. 23152# 23153 bfextu (%a0){&28:&4},%d0 # integer part is ls digit in long word 23154 fadd.b %d0,%fp0 # add digit to sum in fp0 23155# 23156# 23157# Get the rest of the mantissa. 23158# 23159loadlw: 23160 mov.l (%a0,%d1.L*4),%d4 # load mantissa lonqword into d4 23161 mov.l &FSTRT,%d3 # counter to pick up digits 23162 mov.l &FNIBS,%d2 # reset number of digits per a0 ptr 23163md2b: 23164 fmul.s &0x41200000,%fp0 # fp0 = fp0 * 10 23165 bfextu %d4{%d3:&4},%d0 # get the digit and zero extend 23166 fadd.b %d0,%fp0 # fp0 = fp0 + digit 23167# 23168# 23169# If all the digits (8) in that long word have been converted (d2=0), 23170# then inc d1 (=2) to point to the next long word and reset d3 to 0 23171# to initialize the digit offset, and set d2 to 7 for the digit count; 23172# else continue with this long word. 23173# 23174 addq.b &4,%d3 # advance d3 to the next digit 23175 dbf.w %d2,md2b # check for last digit in this lw 23176nextlw: 23177 addq.l &1,%d1 # inc lw pointer in mantissa 23178 cmp.l %d1,&2 # test for last lw 23179 ble.b loadlw # if not, get last one 23180# 23181# Check the sign of the mant and make the value in fp0 the same sign. 23182# 23183m_sign: 23184 btst &31,(%a0) # test sign of the mantissa 23185 beq.b ap_st_z # if clear, go to append/strip zeros 23186 fneg.x %fp0 # if set, negate fp0 23187# 23188# Append/strip zeros: 23189# 23190# For adjusted exponents which have an absolute value greater than 27*, 23191# this routine calculates the amount needed to normalize the mantissa 23192# for the adjusted exponent. That number is subtracted from the exp 23193# if the exp was positive, and added if it was negative. The purpose 23194# of this is to reduce the value of the exponent and the possibility 23195# of error in calculation of pwrten. 23196# 23197# 1. Branch on the sign of the adjusted exponent. 23198# 2p.(positive exp) 23199# 2. Check M16 and the digits in lwords 2 and 3 in descending order. 23200# 3. Add one for each zero encountered until a non-zero digit. 23201# 4. Subtract the count from the exp. 23202# 5. Check if the exp has crossed zero in #3 above; make the exp abs 23203# and set SE. 23204# 6. Multiply the mantissa by 10**count. 23205# 2n.(negative exp) 23206# 2. Check the digits in lwords 3 and 2 in descending order. 23207# 3. Add one for each zero encountered until a non-zero digit. 23208# 4. Add the count to the exp. 23209# 5. Check if the exp has crossed zero in #3 above; clear SE. 23210# 6. Divide the mantissa by 10**count. 23211# 23212# *Why 27? If the adjusted exponent is within -28 < expA < 28, than 23213# any adjustment due to append/strip zeros will drive the resultane 23214# exponent towards zero. Since all pwrten constants with a power 23215# of 27 or less are exact, there is no need to use this routine to 23216# attempt to lessen the resultant exponent. 23217# 23218# Register usage: 23219# 23220# ap_st_z: 23221# (*) d0: temp digit storage 23222# (*) d1: zero count 23223# (*) d2: digit count 23224# (*) d3: offset pointer 23225# ( ) d4: first word of bcd 23226# (*) d5: lword counter 23227# ( ) a0: pointer to working bcd value 23228# ( ) FP_SCR1: working copy of original bcd value 23229# ( ) L_SCR1: copy of original exponent word 23230# 23231# 23232# First check the absolute value of the exponent to see if this 23233# routine is necessary. If so, then check the sign of the exponent 23234# and do append (+) or strip (-) zeros accordingly. 23235# This section handles a positive adjusted exponent. 23236# 23237ap_st_z: 23238 mov.l (%sp),%d1 # load expA for range test 23239 cmp.l %d1,&27 # test is with 27 23240 ble.w pwrten # if abs(expA) <28, skip ap/st zeros 23241 btst &30,(%a0) # check sign of exp 23242 bne.b ap_st_n # if neg, go to neg side 23243 clr.l %d1 # zero count reg 23244 mov.l (%a0),%d4 # load lword 1 to d4 23245 bfextu %d4{&28:&4},%d0 # get M16 in d0 23246 bne.b ap_p_fx # if M16 is non-zero, go fix exp 23247 addq.l &1,%d1 # inc zero count 23248 mov.l &1,%d5 # init lword counter 23249 mov.l (%a0,%d5.L*4),%d4 # get lword 2 to d4 23250 bne.b ap_p_cl # if lw 2 is zero, skip it 23251 addq.l &8,%d1 # and inc count by 8 23252 addq.l &1,%d5 # inc lword counter 23253 mov.l (%a0,%d5.L*4),%d4 # get lword 3 to d4 23254ap_p_cl: 23255 clr.l %d3 # init offset reg 23256 mov.l &7,%d2 # init digit counter 23257ap_p_gd: 23258 bfextu %d4{%d3:&4},%d0 # get digit 23259 bne.b ap_p_fx # if non-zero, go to fix exp 23260 addq.l &4,%d3 # point to next digit 23261 addq.l &1,%d1 # inc digit counter 23262 dbf.w %d2,ap_p_gd # get next digit 23263ap_p_fx: 23264 mov.l %d1,%d0 # copy counter to d2 23265 mov.l (%sp),%d1 # get adjusted exp from memory 23266 sub.l %d0,%d1 # subtract count from exp 23267 bge.b ap_p_fm # if still pos, go to pwrten 23268 neg.l %d1 # now its neg; get abs 23269 mov.l (%a0),%d4 # load lword 1 to d4 23270 or.l &0x40000000,%d4 # and set SE in d4 23271 or.l &0x40000000,(%a0) # and in memory 23272# 23273# Calculate the mantissa multiplier to compensate for the striping of 23274# zeros from the mantissa. 23275# 23276ap_p_fm: 23277 lea.l PTENRN(%pc),%a1 # get address of power-of-ten table 23278 clr.l %d3 # init table index 23279 fmov.s &0x3f800000,%fp1 # init fp1 to 1 23280 mov.l &3,%d2 # init d2 to count bits in counter 23281ap_p_el: 23282 asr.l &1,%d0 # shift lsb into carry 23283 bcc.b ap_p_en # if 1, mul fp1 by pwrten factor 23284 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 23285ap_p_en: 23286 add.l &12,%d3 # inc d3 to next rtable entry 23287 tst.l %d0 # check if d0 is zero 23288 bne.b ap_p_el # if not, get next bit 23289 fmul.x %fp1,%fp0 # mul mantissa by 10**(no_bits_shifted) 23290 bra.b pwrten # go calc pwrten 23291# 23292# This section handles a negative adjusted exponent. 23293# 23294ap_st_n: 23295 clr.l %d1 # clr counter 23296 mov.l &2,%d5 # set up d5 to point to lword 3 23297 mov.l (%a0,%d5.L*4),%d4 # get lword 3 23298 bne.b ap_n_cl # if not zero, check digits 23299 sub.l &1,%d5 # dec d5 to point to lword 2 23300 addq.l &8,%d1 # inc counter by 8 23301 mov.l (%a0,%d5.L*4),%d4 # get lword 2 23302ap_n_cl: 23303 mov.l &28,%d3 # point to last digit 23304 mov.l &7,%d2 # init digit counter 23305ap_n_gd: 23306 bfextu %d4{%d3:&4},%d0 # get digit 23307 bne.b ap_n_fx # if non-zero, go to exp fix 23308 subq.l &4,%d3 # point to previous digit 23309 addq.l &1,%d1 # inc digit counter 23310 dbf.w %d2,ap_n_gd # get next digit 23311ap_n_fx: 23312 mov.l %d1,%d0 # copy counter to d0 23313 mov.l (%sp),%d1 # get adjusted exp from memory 23314 sub.l %d0,%d1 # subtract count from exp 23315 bgt.b ap_n_fm # if still pos, go fix mantissa 23316 neg.l %d1 # take abs of exp and clr SE 23317 mov.l (%a0),%d4 # load lword 1 to d4 23318 and.l &0xbfffffff,%d4 # and clr SE in d4 23319 and.l &0xbfffffff,(%a0) # and in memory 23320# 23321# Calculate the mantissa multiplier to compensate for the appending of 23322# zeros to the mantissa. 23323# 23324ap_n_fm: 23325 lea.l PTENRN(%pc),%a1 # get address of power-of-ten table 23326 clr.l %d3 # init table index 23327 fmov.s &0x3f800000,%fp1 # init fp1 to 1 23328 mov.l &3,%d2 # init d2 to count bits in counter 23329ap_n_el: 23330 asr.l &1,%d0 # shift lsb into carry 23331 bcc.b ap_n_en # if 1, mul fp1 by pwrten factor 23332 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 23333ap_n_en: 23334 add.l &12,%d3 # inc d3 to next rtable entry 23335 tst.l %d0 # check if d0 is zero 23336 bne.b ap_n_el # if not, get next bit 23337 fdiv.x %fp1,%fp0 # div mantissa by 10**(no_bits_shifted) 23338# 23339# 23340# Calculate power-of-ten factor from adjusted and shifted exponent. 23341# 23342# Register usage: 23343# 23344# pwrten: 23345# (*) d0: temp 23346# ( ) d1: exponent 23347# (*) d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp 23348# (*) d3: FPCR work copy 23349# ( ) d4: first word of bcd 23350# (*) a1: RTABLE pointer 23351# calc_p: 23352# (*) d0: temp 23353# ( ) d1: exponent 23354# (*) d3: PWRTxx table index 23355# ( ) a0: pointer to working copy of bcd 23356# (*) a1: PWRTxx pointer 23357# (*) fp1: power-of-ten accumulator 23358# 23359# Pwrten calculates the exponent factor in the selected rounding mode 23360# according to the following table: 23361# 23362# Sign of Mant Sign of Exp Rounding Mode PWRTEN Rounding Mode 23363# 23364# ANY ANY RN RN 23365# 23366# + + RP RP 23367# - + RP RM 23368# + - RP RM 23369# - - RP RP 23370# 23371# + + RM RM 23372# - + RM RP 23373# + - RM RP 23374# - - RM RM 23375# 23376# + + RZ RM 23377# - + RZ RM 23378# + - RZ RP 23379# - - RZ RP 23380# 23381# 23382pwrten: 23383 mov.l USER_FPCR(%a6),%d3 # get user's FPCR 23384 bfextu %d3{&26:&2},%d2 # isolate rounding mode bits 23385 mov.l (%a0),%d4 # reload 1st bcd word to d4 23386 asl.l &2,%d2 # format d2 to be 23387 bfextu %d4{&0:&2},%d0 # {FPCR[6],FPCR[5],SM,SE} 23388 add.l %d0,%d2 # in d2 as index into RTABLE 23389 lea.l RTABLE(%pc),%a1 # load rtable base 23390 mov.b (%a1,%d2),%d0 # load new rounding bits from table 23391 clr.l %d3 # clear d3 to force no exc and extended 23392 bfins %d0,%d3{&26:&2} # stuff new rounding bits in FPCR 23393 fmov.l %d3,%fpcr # write new FPCR 23394 asr.l &1,%d0 # write correct PTENxx table 23395 bcc.b not_rp # to a1 23396 lea.l PTENRP(%pc),%a1 # it is RP 23397 bra.b calc_p # go to init section 23398not_rp: 23399 asr.l &1,%d0 # keep checking 23400 bcc.b not_rm 23401 lea.l PTENRM(%pc),%a1 # it is RM 23402 bra.b calc_p # go to init section 23403not_rm: 23404 lea.l PTENRN(%pc),%a1 # it is RN 23405calc_p: 23406 mov.l %d1,%d0 # copy exp to d0;use d0 23407 bpl.b no_neg # if exp is negative, 23408 neg.l %d0 # invert it 23409 or.l &0x40000000,(%a0) # and set SE bit 23410no_neg: 23411 clr.l %d3 # table index 23412 fmov.s &0x3f800000,%fp1 # init fp1 to 1 23413e_loop: 23414 asr.l &1,%d0 # shift next bit into carry 23415 bcc.b e_next # if zero, skip the mul 23416 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 23417e_next: 23418 add.l &12,%d3 # inc d3 to next rtable entry 23419 tst.l %d0 # check if d0 is zero 23420 bne.b e_loop # not zero, continue shifting 23421# 23422# 23423# Check the sign of the adjusted exp and make the value in fp0 the 23424# same sign. If the exp was pos then multiply fp1*fp0; 23425# else divide fp0/fp1. 23426# 23427# Register Usage: 23428# norm: 23429# ( ) a0: pointer to working bcd value 23430# (*) fp0: mantissa accumulator 23431# ( ) fp1: scaling factor - 10**(abs(exp)) 23432# 23433pnorm: 23434 btst &30,(%a0) # test the sign of the exponent 23435 beq.b mul # if clear, go to multiply 23436div: 23437 fdiv.x %fp1,%fp0 # exp is negative, so divide mant by exp 23438 bra.b end_dec 23439mul: 23440 fmul.x %fp1,%fp0 # exp is positive, so multiply by exp 23441# 23442# 23443# Clean up and return with result in fp0. 23444# 23445# If the final mul/div in decbin incurred an inex exception, 23446# it will be inex2, but will be reported as inex1 by get_op. 23447# 23448end_dec: 23449 fmov.l %fpsr,%d0 # get status register 23450 bclr &inex2_bit+8,%d0 # test for inex2 and clear it 23451 beq.b no_exc # skip this if no exc 23452 ori.w &inx1a_mask,2+USER_FPSR(%a6) # set INEX1/AINEX 23453no_exc: 23454 add.l &0x4,%sp # clear 1 lw param 23455 fmovm.x (%sp)+,&0x40 # restore fp1 23456 movm.l (%sp)+,&0x3c # restore d2-d5 23457 fmov.l &0x0,%fpcr 23458 fmov.l &0x0,%fpsr 23459 rts 23460 23461######################################################################### 23462# bindec(): Converts an input in extended precision format to bcd format# 23463# # 23464# INPUT *************************************************************** # 23465# a0 = pointer to the input extended precision value in memory. # 23466# the input may be either normalized, unnormalized, or # 23467# denormalized. # 23468# d0 = contains the k-factor sign-extended to 32-bits. # 23469# # 23470# OUTPUT ************************************************************** # 23471# FP_SCR0(a6) = bcd format result on the stack. # 23472# # 23473# ALGORITHM *********************************************************** # 23474# # 23475# A1. Set RM and size ext; Set SIGMA = sign of input. # 23476# The k-factor is saved for use in d7. Clear the # 23477# BINDEC_FLG for separating normalized/denormalized # 23478# input. If input is unnormalized or denormalized, # 23479# normalize it. # 23480# # 23481# A2. Set X = abs(input). # 23482# # 23483# A3. Compute ILOG. # 23484# ILOG is the log base 10 of the input value. It is # 23485# approximated by adding e + 0.f when the original # 23486# value is viewed as 2^^e * 1.f in extended precision. # 23487# This value is stored in d6. # 23488# # 23489# A4. Clr INEX bit. # 23490# The operation in A3 above may have set INEX2. # 23491# # 23492# A5. Set ICTR = 0; # 23493# ICTR is a flag used in A13. It must be set before the # 23494# loop entry A6. # 23495# # 23496# A6. Calculate LEN. # 23497# LEN is the number of digits to be displayed. The # 23498# k-factor can dictate either the total number of digits, # 23499# if it is a positive number, or the number of digits # 23500# after the decimal point which are to be included as # 23501# significant. See the 68882 manual for examples. # 23502# If LEN is computed to be greater than 17, set OPERR in # 23503# USER_FPSR. LEN is stored in d4. # 23504# # 23505# A7. Calculate SCALE. # 23506# SCALE is equal to 10^ISCALE, where ISCALE is the number # 23507# of decimal places needed to insure LEN integer digits # 23508# in the output before conversion to bcd. LAMBDA is the # 23509# sign of ISCALE, used in A9. Fp1 contains # 23510# 10^^(abs(ISCALE)) using a rounding mode which is a # 23511# function of the original rounding mode and the signs # 23512# of ISCALE and X. A table is given in the code. # 23513# # 23514# A8. Clr INEX; Force RZ. # 23515# The operation in A3 above may have set INEX2. # 23516# RZ mode is forced for the scaling operation to insure # 23517# only one rounding error. The grs bits are collected in # 23518# the INEX flag for use in A10. # 23519# # 23520# A9. Scale X -> Y. # 23521# The mantissa is scaled to the desired number of # 23522# significant digits. The excess digits are collected # 23523# in INEX2. # 23524# # 23525# A10. Or in INEX. # 23526# If INEX is set, round error occurred. This is # 23527# compensated for by 'or-ing' in the INEX2 flag to # 23528# the lsb of Y. # 23529# # 23530# A11. Restore original FPCR; set size ext. # 23531# Perform FINT operation in the user's rounding mode. # 23532# Keep the size to extended. # 23533# # 23534# A12. Calculate YINT = FINT(Y) according to user's rounding # 23535# mode. The FPSP routine sintd0 is used. The output # 23536# is in fp0. # 23537# # 23538# A13. Check for LEN digits. # 23539# If the int operation results in more than LEN digits, # 23540# or less than LEN -1 digits, adjust ILOG and repeat from # 23541# A6. This test occurs only on the first pass. If the # 23542# result is exactly 10^LEN, decrement ILOG and divide # 23543# the mantissa by 10. # 23544# # 23545# A14. Convert the mantissa to bcd. # 23546# The binstr routine is used to convert the LEN digit # 23547# mantissa to bcd in memory. The input to binstr is # 23548# to be a fraction; i.e. (mantissa)/10^LEN and adjusted # 23549# such that the decimal point is to the left of bit 63. # 23550# The bcd digits are stored in the correct position in # 23551# the final string area in memory. # 23552# # 23553# A15. Convert the exponent to bcd. # 23554# As in A14 above, the exp is converted to bcd and the # 23555# digits are stored in the final string. # 23556# Test the length of the final exponent string. If the # 23557# length is 4, set operr. # 23558# # 23559# A16. Write sign bits to final string. # 23560# # 23561######################################################################### 23562 23563set BINDEC_FLG, EXC_TEMP # DENORM flag 23564 23565# Constants in extended precision 23566PLOG2: 23567 long 0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000 23568PLOG2UP1: 23569 long 0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000 23570 23571# Constants in single precision 23572FONE: 23573 long 0x3F800000,0x00000000,0x00000000,0x00000000 23574FTWO: 23575 long 0x40000000,0x00000000,0x00000000,0x00000000 23576FTEN: 23577 long 0x41200000,0x00000000,0x00000000,0x00000000 23578F4933: 23579 long 0x459A2800,0x00000000,0x00000000,0x00000000 23580 23581RBDTBL: 23582 byte 0,0,0,0 23583 byte 3,3,2,2 23584 byte 3,2,2,3 23585 byte 2,3,3,2 23586 23587# Implementation Notes: 23588# 23589# The registers are used as follows: 23590# 23591# d0: scratch; LEN input to binstr 23592# d1: scratch 23593# d2: upper 32-bits of mantissa for binstr 23594# d3: scratch;lower 32-bits of mantissa for binstr 23595# d4: LEN 23596# d5: LAMBDA/ICTR 23597# d6: ILOG 23598# d7: k-factor 23599# a0: ptr for original operand/final result 23600# a1: scratch pointer 23601# a2: pointer to FP_X; abs(original value) in ext 23602# fp0: scratch 23603# fp1: scratch 23604# fp2: scratch 23605# F_SCR1: 23606# F_SCR2: 23607# L_SCR1: 23608# L_SCR2: 23609 23610 global bindec 23611bindec: 23612 movm.l &0x3f20,-(%sp) # {%d2-%d7/%a2} 23613 fmovm.x &0x7,-(%sp) # {%fp0-%fp2} 23614 23615# A1. Set RM and size ext. Set SIGMA = sign input; 23616# The k-factor is saved for use in d7. Clear BINDEC_FLG for 23617# separating normalized/denormalized input. If the input 23618# is a denormalized number, set the BINDEC_FLG memory word 23619# to signal denorm. If the input is unnormalized, normalize 23620# the input and test for denormalized result. 23621# 23622 fmov.l &rm_mode*0x10,%fpcr # set RM and ext 23623 mov.l (%a0),L_SCR2(%a6) # save exponent for sign check 23624 mov.l %d0,%d7 # move k-factor to d7 23625 23626 clr.b BINDEC_FLG(%a6) # clr norm/denorm flag 23627 cmpi.b STAG(%a6),&DENORM # is input a DENORM? 23628 bne.w A2_str # no; input is a NORM 23629 23630# 23631# Normalize the denorm 23632# 23633un_de_norm: 23634 mov.w (%a0),%d0 23635 and.w &0x7fff,%d0 # strip sign of normalized exp 23636 mov.l 4(%a0),%d1 23637 mov.l 8(%a0),%d2 23638norm_loop: 23639 sub.w &1,%d0 23640 lsl.l &1,%d2 23641 roxl.l &1,%d1 23642 tst.l %d1 23643 bge.b norm_loop 23644# 23645# Test if the normalized input is denormalized 23646# 23647 tst.w %d0 23648 bgt.b pos_exp # if greater than zero, it is a norm 23649 st BINDEC_FLG(%a6) # set flag for denorm 23650pos_exp: 23651 and.w &0x7fff,%d0 # strip sign of normalized exp 23652 mov.w %d0,(%a0) 23653 mov.l %d1,4(%a0) 23654 mov.l %d2,8(%a0) 23655 23656# A2. Set X = abs(input). 23657# 23658A2_str: 23659 mov.l (%a0),FP_SCR1(%a6) # move input to work space 23660 mov.l 4(%a0),FP_SCR1+4(%a6) # move input to work space 23661 mov.l 8(%a0),FP_SCR1+8(%a6) # move input to work space 23662 and.l &0x7fffffff,FP_SCR1(%a6) # create abs(X) 23663 23664# A3. Compute ILOG. 23665# ILOG is the log base 10 of the input value. It is approx- 23666# imated by adding e + 0.f when the original value is viewed 23667# as 2^^e * 1.f in extended precision. This value is stored 23668# in d6. 23669# 23670# Register usage: 23671# Input/Output 23672# d0: k-factor/exponent 23673# d2: x/x 23674# d3: x/x 23675# d4: x/x 23676# d5: x/x 23677# d6: x/ILOG 23678# d7: k-factor/Unchanged 23679# a0: ptr for original operand/final result 23680# a1: x/x 23681# a2: x/x 23682# fp0: x/float(ILOG) 23683# fp1: x/x 23684# fp2: x/x 23685# F_SCR1:x/x 23686# F_SCR2:Abs(X)/Abs(X) with $3fff exponent 23687# L_SCR1:x/x 23688# L_SCR2:first word of X packed/Unchanged 23689 23690 tst.b BINDEC_FLG(%a6) # check for denorm 23691 beq.b A3_cont # if clr, continue with norm 23692 mov.l &-4933,%d6 # force ILOG = -4933 23693 bra.b A4_str 23694A3_cont: 23695 mov.w FP_SCR1(%a6),%d0 # move exp to d0 23696 mov.w &0x3fff,FP_SCR1(%a6) # replace exponent with 0x3fff 23697 fmov.x FP_SCR1(%a6),%fp0 # now fp0 has 1.f 23698 sub.w &0x3fff,%d0 # strip off bias 23699 fadd.w %d0,%fp0 # add in exp 23700 fsub.s FONE(%pc),%fp0 # subtract off 1.0 23701 fbge.w pos_res # if pos, branch 23702 fmul.x PLOG2UP1(%pc),%fp0 # if neg, mul by LOG2UP1 23703 fmov.l %fp0,%d6 # put ILOG in d6 as a lword 23704 bra.b A4_str # go move out ILOG 23705pos_res: 23706 fmul.x PLOG2(%pc),%fp0 # if pos, mul by LOG2 23707 fmov.l %fp0,%d6 # put ILOG in d6 as a lword 23708 23709 23710# A4. Clr INEX bit. 23711# The operation in A3 above may have set INEX2. 23712 23713A4_str: 23714 fmov.l &0,%fpsr # zero all of fpsr - nothing needed 23715 23716 23717# A5. Set ICTR = 0; 23718# ICTR is a flag used in A13. It must be set before the 23719# loop entry A6. The lower word of d5 is used for ICTR. 23720 23721 clr.w %d5 # clear ICTR 23722 23723# A6. Calculate LEN. 23724# LEN is the number of digits to be displayed. The k-factor 23725# can dictate either the total number of digits, if it is 23726# a positive number, or the number of digits after the 23727# original decimal point which are to be included as 23728# significant. See the 68882 manual for examples. 23729# If LEN is computed to be greater than 17, set OPERR in 23730# USER_FPSR. LEN is stored in d4. 23731# 23732# Register usage: 23733# Input/Output 23734# d0: exponent/Unchanged 23735# d2: x/x/scratch 23736# d3: x/x 23737# d4: exc picture/LEN 23738# d5: ICTR/Unchanged 23739# d6: ILOG/Unchanged 23740# d7: k-factor/Unchanged 23741# a0: ptr for original operand/final result 23742# a1: x/x 23743# a2: x/x 23744# fp0: float(ILOG)/Unchanged 23745# fp1: x/x 23746# fp2: x/x 23747# F_SCR1:x/x 23748# F_SCR2:Abs(X) with $3fff exponent/Unchanged 23749# L_SCR1:x/x 23750# L_SCR2:first word of X packed/Unchanged 23751 23752A6_str: 23753 tst.l %d7 # branch on sign of k 23754 ble.b k_neg # if k <= 0, LEN = ILOG + 1 - k 23755 mov.l %d7,%d4 # if k > 0, LEN = k 23756 bra.b len_ck # skip to LEN check 23757k_neg: 23758 mov.l %d6,%d4 # first load ILOG to d4 23759 sub.l %d7,%d4 # subtract off k 23760 addq.l &1,%d4 # add in the 1 23761len_ck: 23762 tst.l %d4 # LEN check: branch on sign of LEN 23763 ble.b LEN_ng # if neg, set LEN = 1 23764 cmp.l %d4,&17 # test if LEN > 17 23765 ble.b A7_str # if not, forget it 23766 mov.l &17,%d4 # set max LEN = 17 23767 tst.l %d7 # if negative, never set OPERR 23768 ble.b A7_str # if positive, continue 23769 or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR 23770 bra.b A7_str # finished here 23771LEN_ng: 23772 mov.l &1,%d4 # min LEN is 1 23773 23774 23775# A7. Calculate SCALE. 23776# SCALE is equal to 10^ISCALE, where ISCALE is the number 23777# of decimal places needed to insure LEN integer digits 23778# in the output before conversion to bcd. LAMBDA is the sign 23779# of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using 23780# the rounding mode as given in the following table (see 23781# Coonen, p. 7.23 as ref.; however, the SCALE variable is 23782# of opposite sign in bindec.sa from Coonen). 23783# 23784# Initial USE 23785# FPCR[6:5] LAMBDA SIGN(X) FPCR[6:5] 23786# ---------------------------------------------- 23787# RN 00 0 0 00/0 RN 23788# RN 00 0 1 00/0 RN 23789# RN 00 1 0 00/0 RN 23790# RN 00 1 1 00/0 RN 23791# RZ 01 0 0 11/3 RP 23792# RZ 01 0 1 11/3 RP 23793# RZ 01 1 0 10/2 RM 23794# RZ 01 1 1 10/2 RM 23795# RM 10 0 0 11/3 RP 23796# RM 10 0 1 10/2 RM 23797# RM 10 1 0 10/2 RM 23798# RM 10 1 1 11/3 RP 23799# RP 11 0 0 10/2 RM 23800# RP 11 0 1 11/3 RP 23801# RP 11 1 0 11/3 RP 23802# RP 11 1 1 10/2 RM 23803# 23804# Register usage: 23805# Input/Output 23806# d0: exponent/scratch - final is 0 23807# d2: x/0 or 24 for A9 23808# d3: x/scratch - offset ptr into PTENRM array 23809# d4: LEN/Unchanged 23810# d5: 0/ICTR:LAMBDA 23811# d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k)) 23812# d7: k-factor/Unchanged 23813# a0: ptr for original operand/final result 23814# a1: x/ptr to PTENRM array 23815# a2: x/x 23816# fp0: float(ILOG)/Unchanged 23817# fp1: x/10^ISCALE 23818# fp2: x/x 23819# F_SCR1:x/x 23820# F_SCR2:Abs(X) with $3fff exponent/Unchanged 23821# L_SCR1:x/x 23822# L_SCR2:first word of X packed/Unchanged 23823 23824A7_str: 23825 tst.l %d7 # test sign of k 23826 bgt.b k_pos # if pos and > 0, skip this 23827 cmp.l %d7,%d6 # test k - ILOG 23828 blt.b k_pos # if ILOG >= k, skip this 23829 mov.l %d7,%d6 # if ((k<0) & (ILOG < k)) ILOG = k 23830k_pos: 23831 mov.l %d6,%d0 # calc ILOG + 1 - LEN in d0 23832 addq.l &1,%d0 # add the 1 23833 sub.l %d4,%d0 # sub off LEN 23834 swap %d5 # use upper word of d5 for LAMBDA 23835 clr.w %d5 # set it zero initially 23836 clr.w %d2 # set up d2 for very small case 23837 tst.l %d0 # test sign of ISCALE 23838 bge.b iscale # if pos, skip next inst 23839 addq.w &1,%d5 # if neg, set LAMBDA true 23840 cmp.l %d0,&0xffffecd4 # test iscale <= -4908 23841 bgt.b no_inf # if false, skip rest 23842 add.l &24,%d0 # add in 24 to iscale 23843 mov.l &24,%d2 # put 24 in d2 for A9 23844no_inf: 23845 neg.l %d0 # and take abs of ISCALE 23846iscale: 23847 fmov.s FONE(%pc),%fp1 # init fp1 to 1 23848 bfextu USER_FPCR(%a6){&26:&2},%d1 # get initial rmode bits 23849 lsl.w &1,%d1 # put them in bits 2:1 23850 add.w %d5,%d1 # add in LAMBDA 23851 lsl.w &1,%d1 # put them in bits 3:1 23852 tst.l L_SCR2(%a6) # test sign of original x 23853 bge.b x_pos # if pos, don't set bit 0 23854 addq.l &1,%d1 # if neg, set bit 0 23855x_pos: 23856 lea.l RBDTBL(%pc),%a2 # load rbdtbl base 23857 mov.b (%a2,%d1),%d3 # load d3 with new rmode 23858 lsl.l &4,%d3 # put bits in proper position 23859 fmov.l %d3,%fpcr # load bits into fpu 23860 lsr.l &4,%d3 # put bits in proper position 23861 tst.b %d3 # decode new rmode for pten table 23862 bne.b not_rn # if zero, it is RN 23863 lea.l PTENRN(%pc),%a1 # load a1 with RN table base 23864 bra.b rmode # exit decode 23865not_rn: 23866 lsr.b &1,%d3 # get lsb in carry 23867 bcc.b not_rp2 # if carry clear, it is RM 23868 lea.l PTENRP(%pc),%a1 # load a1 with RP table base 23869 bra.b rmode # exit decode 23870not_rp2: 23871 lea.l PTENRM(%pc),%a1 # load a1 with RM table base 23872rmode: 23873 clr.l %d3 # clr table index 23874e_loop2: 23875 lsr.l &1,%d0 # shift next bit into carry 23876 bcc.b e_next2 # if zero, skip the mul 23877 fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 23878e_next2: 23879 add.l &12,%d3 # inc d3 to next pwrten table entry 23880 tst.l %d0 # test if ISCALE is zero 23881 bne.b e_loop2 # if not, loop 23882 23883# A8. Clr INEX; Force RZ. 23884# The operation in A3 above may have set INEX2. 23885# RZ mode is forced for the scaling operation to insure 23886# only one rounding error. The grs bits are collected in 23887# the INEX flag for use in A10. 23888# 23889# Register usage: 23890# Input/Output 23891 23892 fmov.l &0,%fpsr # clr INEX 23893 fmov.l &rz_mode*0x10,%fpcr # set RZ rounding mode 23894 23895# A9. Scale X -> Y. 23896# The mantissa is scaled to the desired number of significant 23897# digits. The excess digits are collected in INEX2. If mul, 23898# Check d2 for excess 10 exponential value. If not zero, 23899# the iscale value would have caused the pwrten calculation 23900# to overflow. Only a negative iscale can cause this, so 23901# multiply by 10^(d2), which is now only allowed to be 24, 23902# with a multiply by 10^8 and 10^16, which is exact since 23903# 10^24 is exact. If the input was denormalized, we must 23904# create a busy stack frame with the mul command and the 23905# two operands, and allow the fpu to complete the multiply. 23906# 23907# Register usage: 23908# Input/Output 23909# d0: FPCR with RZ mode/Unchanged 23910# d2: 0 or 24/unchanged 23911# d3: x/x 23912# d4: LEN/Unchanged 23913# d5: ICTR:LAMBDA 23914# d6: ILOG/Unchanged 23915# d7: k-factor/Unchanged 23916# a0: ptr for original operand/final result 23917# a1: ptr to PTENRM array/Unchanged 23918# a2: x/x 23919# fp0: float(ILOG)/X adjusted for SCALE (Y) 23920# fp1: 10^ISCALE/Unchanged 23921# fp2: x/x 23922# F_SCR1:x/x 23923# F_SCR2:Abs(X) with $3fff exponent/Unchanged 23924# L_SCR1:x/x 23925# L_SCR2:first word of X packed/Unchanged 23926 23927A9_str: 23928 fmov.x (%a0),%fp0 # load X from memory 23929 fabs.x %fp0 # use abs(X) 23930 tst.w %d5 # LAMBDA is in lower word of d5 23931 bne.b sc_mul # if neg (LAMBDA = 1), scale by mul 23932 fdiv.x %fp1,%fp0 # calculate X / SCALE -> Y to fp0 23933 bra.w A10_st # branch to A10 23934 23935sc_mul: 23936 tst.b BINDEC_FLG(%a6) # check for denorm 23937 beq.w A9_norm # if norm, continue with mul 23938 23939# for DENORM, we must calculate: 23940# fp0 = input_op * 10^ISCALE * 10^24 23941# since the input operand is a DENORM, we can't multiply it directly. 23942# so, we do the multiplication of the exponents and mantissas separately. 23943# in this way, we avoid underflow on intermediate stages of the 23944# multiplication and guarantee a result without exception. 23945 fmovm.x &0x2,-(%sp) # save 10^ISCALE to stack 23946 23947 mov.w (%sp),%d3 # grab exponent 23948 andi.w &0x7fff,%d3 # clear sign 23949 ori.w &0x8000,(%a0) # make DENORM exp negative 23950 add.w (%a0),%d3 # add DENORM exp to 10^ISCALE exp 23951 subi.w &0x3fff,%d3 # subtract BIAS 23952 add.w 36(%a1),%d3 23953 subi.w &0x3fff,%d3 # subtract BIAS 23954 add.w 48(%a1),%d3 23955 subi.w &0x3fff,%d3 # subtract BIAS 23956 23957 bmi.w sc_mul_err # is result is DENORM, punt!!! 23958 23959 andi.w &0x8000,(%sp) # keep sign 23960 or.w %d3,(%sp) # insert new exponent 23961 andi.w &0x7fff,(%a0) # clear sign bit on DENORM again 23962 mov.l 0x8(%a0),-(%sp) # put input op mantissa on stk 23963 mov.l 0x4(%a0),-(%sp) 23964 mov.l &0x3fff0000,-(%sp) # force exp to zero 23965 fmovm.x (%sp)+,&0x80 # load normalized DENORM into fp0 23966 fmul.x (%sp)+,%fp0 23967 23968# fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8 23969# fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16 23970 mov.l 36+8(%a1),-(%sp) # get 10^8 mantissa 23971 mov.l 36+4(%a1),-(%sp) 23972 mov.l &0x3fff0000,-(%sp) # force exp to zero 23973 mov.l 48+8(%a1),-(%sp) # get 10^16 mantissa 23974 mov.l 48+4(%a1),-(%sp) 23975 mov.l &0x3fff0000,-(%sp)# force exp to zero 23976 fmul.x (%sp)+,%fp0 # multiply fp0 by 10^8 23977 fmul.x (%sp)+,%fp0 # multiply fp0 by 10^16 23978 bra.b A10_st 23979 23980sc_mul_err: 23981 bra.b sc_mul_err 23982 23983A9_norm: 23984 tst.w %d2 # test for small exp case 23985 beq.b A9_con # if zero, continue as normal 23986 fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8 23987 fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16 23988A9_con: 23989 fmul.x %fp1,%fp0 # calculate X * SCALE -> Y to fp0 23990 23991# A10. Or in INEX. 23992# If INEX is set, round error occurred. This is compensated 23993# for by 'or-ing' in the INEX2 flag to the lsb of Y. 23994# 23995# Register usage: 23996# Input/Output 23997# d0: FPCR with RZ mode/FPSR with INEX2 isolated 23998# d2: x/x 23999# d3: x/x 24000# d4: LEN/Unchanged 24001# d5: ICTR:LAMBDA 24002# d6: ILOG/Unchanged 24003# d7: k-factor/Unchanged 24004# a0: ptr for original operand/final result 24005# a1: ptr to PTENxx array/Unchanged 24006# a2: x/ptr to FP_SCR1(a6) 24007# fp0: Y/Y with lsb adjusted 24008# fp1: 10^ISCALE/Unchanged 24009# fp2: x/x 24010 24011A10_st: 24012 fmov.l %fpsr,%d0 # get FPSR 24013 fmov.x %fp0,FP_SCR1(%a6) # move Y to memory 24014 lea.l FP_SCR1(%a6),%a2 # load a2 with ptr to FP_SCR1 24015 btst &9,%d0 # check if INEX2 set 24016 beq.b A11_st # if clear, skip rest 24017 or.l &1,8(%a2) # or in 1 to lsb of mantissa 24018 fmov.x FP_SCR1(%a6),%fp0 # write adjusted Y back to fpu 24019 24020 24021# A11. Restore original FPCR; set size ext. 24022# Perform FINT operation in the user's rounding mode. Keep 24023# the size to extended. The sintdo entry point in the sint 24024# routine expects the FPCR value to be in USER_FPCR for 24025# mode and precision. The original FPCR is saved in L_SCR1. 24026 24027A11_st: 24028 mov.l USER_FPCR(%a6),L_SCR1(%a6) # save it for later 24029 and.l &0x00000030,USER_FPCR(%a6) # set size to ext, 24030# ;block exceptions 24031 24032 24033# A12. Calculate YINT = FINT(Y) according to user's rounding mode. 24034# The FPSP routine sintd0 is used. The output is in fp0. 24035# 24036# Register usage: 24037# Input/Output 24038# d0: FPSR with AINEX cleared/FPCR with size set to ext 24039# d2: x/x/scratch 24040# d3: x/x 24041# d4: LEN/Unchanged 24042# d5: ICTR:LAMBDA/Unchanged 24043# d6: ILOG/Unchanged 24044# d7: k-factor/Unchanged 24045# a0: ptr for original operand/src ptr for sintdo 24046# a1: ptr to PTENxx array/Unchanged 24047# a2: ptr to FP_SCR1(a6)/Unchanged 24048# a6: temp pointer to FP_SCR1(a6) - orig value saved and restored 24049# fp0: Y/YINT 24050# fp1: 10^ISCALE/Unchanged 24051# fp2: x/x 24052# F_SCR1:x/x 24053# F_SCR2:Y adjusted for inex/Y with original exponent 24054# L_SCR1:x/original USER_FPCR 24055# L_SCR2:first word of X packed/Unchanged 24056 24057A12_st: 24058 movm.l &0xc0c0,-(%sp) # save regs used by sintd0 {%d0-%d1/%a0-%a1} 24059 mov.l L_SCR1(%a6),-(%sp) 24060 mov.l L_SCR2(%a6),-(%sp) 24061 24062 lea.l FP_SCR1(%a6),%a0 # a0 is ptr to FP_SCR1(a6) 24063 fmov.x %fp0,(%a0) # move Y to memory at FP_SCR1(a6) 24064 tst.l L_SCR2(%a6) # test sign of original operand 24065 bge.b do_fint12 # if pos, use Y 24066 or.l &0x80000000,(%a0) # if neg, use -Y 24067do_fint12: 24068 mov.l USER_FPSR(%a6),-(%sp) 24069# bsr sintdo # sint routine returns int in fp0 24070 24071 fmov.l USER_FPCR(%a6),%fpcr 24072 fmov.l &0x0,%fpsr # clear the AEXC bits!!! 24073## mov.l USER_FPCR(%a6),%d0 # ext prec/keep rnd mode 24074## andi.l &0x00000030,%d0 24075## fmov.l %d0,%fpcr 24076 fint.x FP_SCR1(%a6),%fp0 # do fint() 24077 fmov.l %fpsr,%d0 24078 or.w %d0,FPSR_EXCEPT(%a6) 24079## fmov.l &0x0,%fpcr 24080## fmov.l %fpsr,%d0 # don't keep ccodes 24081## or.w %d0,FPSR_EXCEPT(%a6) 24082 24083 mov.b (%sp),USER_FPSR(%a6) 24084 add.l &4,%sp 24085 24086 mov.l (%sp)+,L_SCR2(%a6) 24087 mov.l (%sp)+,L_SCR1(%a6) 24088 movm.l (%sp)+,&0x303 # restore regs used by sint {%d0-%d1/%a0-%a1} 24089 24090 mov.l L_SCR2(%a6),FP_SCR1(%a6) # restore original exponent 24091 mov.l L_SCR1(%a6),USER_FPCR(%a6) # restore user's FPCR 24092 24093# A13. Check for LEN digits. 24094# If the int operation results in more than LEN digits, 24095# or less than LEN -1 digits, adjust ILOG and repeat from 24096# A6. This test occurs only on the first pass. If the 24097# result is exactly 10^LEN, decrement ILOG and divide 24098# the mantissa by 10. The calculation of 10^LEN cannot 24099# be inexact, since all powers of ten up to 10^27 are exact 24100# in extended precision, so the use of a previous power-of-ten 24101# table will introduce no error. 24102# 24103# 24104# Register usage: 24105# Input/Output 24106# d0: FPCR with size set to ext/scratch final = 0 24107# d2: x/x 24108# d3: x/scratch final = x 24109# d4: LEN/LEN adjusted 24110# d5: ICTR:LAMBDA/LAMBDA:ICTR 24111# d6: ILOG/ILOG adjusted 24112# d7: k-factor/Unchanged 24113# a0: pointer into memory for packed bcd string formation 24114# a1: ptr to PTENxx array/Unchanged 24115# a2: ptr to FP_SCR1(a6)/Unchanged 24116# fp0: int portion of Y/abs(YINT) adjusted 24117# fp1: 10^ISCALE/Unchanged 24118# fp2: x/10^LEN 24119# F_SCR1:x/x 24120# F_SCR2:Y with original exponent/Unchanged 24121# L_SCR1:original USER_FPCR/Unchanged 24122# L_SCR2:first word of X packed/Unchanged 24123 24124A13_st: 24125 swap %d5 # put ICTR in lower word of d5 24126 tst.w %d5 # check if ICTR = 0 24127 bne not_zr # if non-zero, go to second test 24128# 24129# Compute 10^(LEN-1) 24130# 24131 fmov.s FONE(%pc),%fp2 # init fp2 to 1.0 24132 mov.l %d4,%d0 # put LEN in d0 24133 subq.l &1,%d0 # d0 = LEN -1 24134 clr.l %d3 # clr table index 24135l_loop: 24136 lsr.l &1,%d0 # shift next bit into carry 24137 bcc.b l_next # if zero, skip the mul 24138 fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no) 24139l_next: 24140 add.l &12,%d3 # inc d3 to next pwrten table entry 24141 tst.l %d0 # test if LEN is zero 24142 bne.b l_loop # if not, loop 24143# 24144# 10^LEN-1 is computed for this test and A14. If the input was 24145# denormalized, check only the case in which YINT > 10^LEN. 24146# 24147 tst.b BINDEC_FLG(%a6) # check if input was norm 24148 beq.b A13_con # if norm, continue with checking 24149 fabs.x %fp0 # take abs of YINT 24150 bra test_2 24151# 24152# Compare abs(YINT) to 10^(LEN-1) and 10^LEN 24153# 24154A13_con: 24155 fabs.x %fp0 # take abs of YINT 24156 fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^(LEN-1) 24157 fbge.w test_2 # if greater, do next test 24158 subq.l &1,%d6 # subtract 1 from ILOG 24159 mov.w &1,%d5 # set ICTR 24160 fmov.l &rm_mode*0x10,%fpcr # set rmode to RM 24161 fmul.s FTEN(%pc),%fp2 # compute 10^LEN 24162 bra.w A6_str # return to A6 and recompute YINT 24163test_2: 24164 fmul.s FTEN(%pc),%fp2 # compute 10^LEN 24165 fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^LEN 24166 fblt.w A14_st # if less, all is ok, go to A14 24167 fbgt.w fix_ex # if greater, fix and redo 24168 fdiv.s FTEN(%pc),%fp0 # if equal, divide by 10 24169 addq.l &1,%d6 # and inc ILOG 24170 bra.b A14_st # and continue elsewhere 24171fix_ex: 24172 addq.l &1,%d6 # increment ILOG by 1 24173 mov.w &1,%d5 # set ICTR 24174 fmov.l &rm_mode*0x10,%fpcr # set rmode to RM 24175 bra.w A6_str # return to A6 and recompute YINT 24176# 24177# Since ICTR <> 0, we have already been through one adjustment, 24178# and shouldn't have another; this is to check if abs(YINT) = 10^LEN 24179# 10^LEN is again computed using whatever table is in a1 since the 24180# value calculated cannot be inexact. 24181# 24182not_zr: 24183 fmov.s FONE(%pc),%fp2 # init fp2 to 1.0 24184 mov.l %d4,%d0 # put LEN in d0 24185 clr.l %d3 # clr table index 24186z_loop: 24187 lsr.l &1,%d0 # shift next bit into carry 24188 bcc.b z_next # if zero, skip the mul 24189 fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no) 24190z_next: 24191 add.l &12,%d3 # inc d3 to next pwrten table entry 24192 tst.l %d0 # test if LEN is zero 24193 bne.b z_loop # if not, loop 24194 fabs.x %fp0 # get abs(YINT) 24195 fcmp.x %fp0,%fp2 # check if abs(YINT) = 10^LEN 24196 fbneq.w A14_st # if not, skip this 24197 fdiv.s FTEN(%pc),%fp0 # divide abs(YINT) by 10 24198 addq.l &1,%d6 # and inc ILOG by 1 24199 addq.l &1,%d4 # and inc LEN 24200 fmul.s FTEN(%pc),%fp2 # if LEN++, the get 10^^LEN 24201 24202# A14. Convert the mantissa to bcd. 24203# The binstr routine is used to convert the LEN digit 24204# mantissa to bcd in memory. The input to binstr is 24205# to be a fraction; i.e. (mantissa)/10^LEN and adjusted 24206# such that the decimal point is to the left of bit 63. 24207# The bcd digits are stored in the correct position in 24208# the final string area in memory. 24209# 24210# 24211# Register usage: 24212# Input/Output 24213# d0: x/LEN call to binstr - final is 0 24214# d1: x/0 24215# d2: x/ms 32-bits of mant of abs(YINT) 24216# d3: x/ls 32-bits of mant of abs(YINT) 24217# d4: LEN/Unchanged 24218# d5: ICTR:LAMBDA/LAMBDA:ICTR 24219# d6: ILOG 24220# d7: k-factor/Unchanged 24221# a0: pointer into memory for packed bcd string formation 24222# /ptr to first mantissa byte in result string 24223# a1: ptr to PTENxx array/Unchanged 24224# a2: ptr to FP_SCR1(a6)/Unchanged 24225# fp0: int portion of Y/abs(YINT) adjusted 24226# fp1: 10^ISCALE/Unchanged 24227# fp2: 10^LEN/Unchanged 24228# F_SCR1:x/Work area for final result 24229# F_SCR2:Y with original exponent/Unchanged 24230# L_SCR1:original USER_FPCR/Unchanged 24231# L_SCR2:first word of X packed/Unchanged 24232 24233A14_st: 24234 fmov.l &rz_mode*0x10,%fpcr # force rz for conversion 24235 fdiv.x %fp2,%fp0 # divide abs(YINT) by 10^LEN 24236 lea.l FP_SCR0(%a6),%a0 24237 fmov.x %fp0,(%a0) # move abs(YINT)/10^LEN to memory 24238 mov.l 4(%a0),%d2 # move 2nd word of FP_RES to d2 24239 mov.l 8(%a0),%d3 # move 3rd word of FP_RES to d3 24240 clr.l 4(%a0) # zero word 2 of FP_RES 24241 clr.l 8(%a0) # zero word 3 of FP_RES 24242 mov.l (%a0),%d0 # move exponent to d0 24243 swap %d0 # put exponent in lower word 24244 beq.b no_sft # if zero, don't shift 24245 sub.l &0x3ffd,%d0 # sub bias less 2 to make fract 24246 tst.l %d0 # check if > 1 24247 bgt.b no_sft # if so, don't shift 24248 neg.l %d0 # make exp positive 24249m_loop: 24250 lsr.l &1,%d2 # shift d2:d3 right, add 0s 24251 roxr.l &1,%d3 # the number of places 24252 dbf.w %d0,m_loop # given in d0 24253no_sft: 24254 tst.l %d2 # check for mantissa of zero 24255 bne.b no_zr # if not, go on 24256 tst.l %d3 # continue zero check 24257 beq.b zer_m # if zero, go directly to binstr 24258no_zr: 24259 clr.l %d1 # put zero in d1 for addx 24260 add.l &0x00000080,%d3 # inc at bit 7 24261 addx.l %d1,%d2 # continue inc 24262 and.l &0xffffff80,%d3 # strip off lsb not used by 882 24263zer_m: 24264 mov.l %d4,%d0 # put LEN in d0 for binstr call 24265 addq.l &3,%a0 # a0 points to M16 byte in result 24266 bsr binstr # call binstr to convert mant 24267 24268 24269# A15. Convert the exponent to bcd. 24270# As in A14 above, the exp is converted to bcd and the 24271# digits are stored in the final string. 24272# 24273# Digits are stored in L_SCR1(a6) on return from BINDEC as: 24274# 24275# 32 16 15 0 24276# ----------------------------------------- 24277# | 0 | e3 | e2 | e1 | e4 | X | X | X | 24278# ----------------------------------------- 24279# 24280# And are moved into their proper places in FP_SCR0. If digit e4 24281# is non-zero, OPERR is signaled. In all cases, all 4 digits are 24282# written as specified in the 881/882 manual for packed decimal. 24283# 24284# Register usage: 24285# Input/Output 24286# d0: x/LEN call to binstr - final is 0 24287# d1: x/scratch (0);shift count for final exponent packing 24288# d2: x/ms 32-bits of exp fraction/scratch 24289# d3: x/ls 32-bits of exp fraction 24290# d4: LEN/Unchanged 24291# d5: ICTR:LAMBDA/LAMBDA:ICTR 24292# d6: ILOG 24293# d7: k-factor/Unchanged 24294# a0: ptr to result string/ptr to L_SCR1(a6) 24295# a1: ptr to PTENxx array/Unchanged 24296# a2: ptr to FP_SCR1(a6)/Unchanged 24297# fp0: abs(YINT) adjusted/float(ILOG) 24298# fp1: 10^ISCALE/Unchanged 24299# fp2: 10^LEN/Unchanged 24300# F_SCR1:Work area for final result/BCD result 24301# F_SCR2:Y with original exponent/ILOG/10^4 24302# L_SCR1:original USER_FPCR/Exponent digits on return from binstr 24303# L_SCR2:first word of X packed/Unchanged 24304 24305A15_st: 24306 tst.b BINDEC_FLG(%a6) # check for denorm 24307 beq.b not_denorm 24308 ftest.x %fp0 # test for zero 24309 fbeq.w den_zero # if zero, use k-factor or 4933 24310 fmov.l %d6,%fp0 # float ILOG 24311 fabs.x %fp0 # get abs of ILOG 24312 bra.b convrt 24313den_zero: 24314 tst.l %d7 # check sign of the k-factor 24315 blt.b use_ilog # if negative, use ILOG 24316 fmov.s F4933(%pc),%fp0 # force exponent to 4933 24317 bra.b convrt # do it 24318use_ilog: 24319 fmov.l %d6,%fp0 # float ILOG 24320 fabs.x %fp0 # get abs of ILOG 24321 bra.b convrt 24322not_denorm: 24323 ftest.x %fp0 # test for zero 24324 fbneq.w not_zero # if zero, force exponent 24325 fmov.s FONE(%pc),%fp0 # force exponent to 1 24326 bra.b convrt # do it 24327not_zero: 24328 fmov.l %d6,%fp0 # float ILOG 24329 fabs.x %fp0 # get abs of ILOG 24330convrt: 24331 fdiv.x 24(%a1),%fp0 # compute ILOG/10^4 24332 fmov.x %fp0,FP_SCR1(%a6) # store fp0 in memory 24333 mov.l 4(%a2),%d2 # move word 2 to d2 24334 mov.l 8(%a2),%d3 # move word 3 to d3 24335 mov.w (%a2),%d0 # move exp to d0 24336 beq.b x_loop_fin # if zero, skip the shift 24337 sub.w &0x3ffd,%d0 # subtract off bias 24338 neg.w %d0 # make exp positive 24339x_loop: 24340 lsr.l &1,%d2 # shift d2:d3 right 24341 roxr.l &1,%d3 # the number of places 24342 dbf.w %d0,x_loop # given in d0 24343x_loop_fin: 24344 clr.l %d1 # put zero in d1 for addx 24345 add.l &0x00000080,%d3 # inc at bit 6 24346 addx.l %d1,%d2 # continue inc 24347 and.l &0xffffff80,%d3 # strip off lsb not used by 882 24348 mov.l &4,%d0 # put 4 in d0 for binstr call 24349 lea.l L_SCR1(%a6),%a0 # a0 is ptr to L_SCR1 for exp digits 24350 bsr binstr # call binstr to convert exp 24351 mov.l L_SCR1(%a6),%d0 # load L_SCR1 lword to d0 24352 mov.l &12,%d1 # use d1 for shift count 24353 lsr.l %d1,%d0 # shift d0 right by 12 24354 bfins %d0,FP_SCR0(%a6){&4:&12} # put e3:e2:e1 in FP_SCR0 24355 lsr.l %d1,%d0 # shift d0 right by 12 24356 bfins %d0,FP_SCR0(%a6){&16:&4} # put e4 in FP_SCR0 24357 tst.b %d0 # check if e4 is zero 24358 beq.b A16_st # if zero, skip rest 24359 or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR 24360 24361 24362# A16. Write sign bits to final string. 24363# Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG). 24364# 24365# Register usage: 24366# Input/Output 24367# d0: x/scratch - final is x 24368# d2: x/x 24369# d3: x/x 24370# d4: LEN/Unchanged 24371# d5: ICTR:LAMBDA/LAMBDA:ICTR 24372# d6: ILOG/ILOG adjusted 24373# d7: k-factor/Unchanged 24374# a0: ptr to L_SCR1(a6)/Unchanged 24375# a1: ptr to PTENxx array/Unchanged 24376# a2: ptr to FP_SCR1(a6)/Unchanged 24377# fp0: float(ILOG)/Unchanged 24378# fp1: 10^ISCALE/Unchanged 24379# fp2: 10^LEN/Unchanged 24380# F_SCR1:BCD result with correct signs 24381# F_SCR2:ILOG/10^4 24382# L_SCR1:Exponent digits on return from binstr 24383# L_SCR2:first word of X packed/Unchanged 24384 24385A16_st: 24386 clr.l %d0 # clr d0 for collection of signs 24387 and.b &0x0f,FP_SCR0(%a6) # clear first nibble of FP_SCR0 24388 tst.l L_SCR2(%a6) # check sign of original mantissa 24389 bge.b mant_p # if pos, don't set SM 24390 mov.l &2,%d0 # move 2 in to d0 for SM 24391mant_p: 24392 tst.l %d6 # check sign of ILOG 24393 bge.b wr_sgn # if pos, don't set SE 24394 addq.l &1,%d0 # set bit 0 in d0 for SE 24395wr_sgn: 24396 bfins %d0,FP_SCR0(%a6){&0:&2} # insert SM and SE into FP_SCR0 24397 24398# Clean up and restore all registers used. 24399 24400 fmov.l &0,%fpsr # clear possible inex2/ainex bits 24401 fmovm.x (%sp)+,&0xe0 # {%fp0-%fp2} 24402 movm.l (%sp)+,&0x4fc # {%d2-%d7/%a2} 24403 rts 24404 24405 global PTENRN 24406PTENRN: 24407 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 24408 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 24409 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 24410 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 24411 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 24412 long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32 24413 long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64 24414 long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128 24415 long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256 24416 long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512 24417 long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024 24418 long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048 24419 long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096 24420 24421 global PTENRP 24422PTENRP: 24423 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 24424 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 24425 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 24426 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 24427 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 24428 long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32 24429 long 0x40D30000,0xC2781F49,0xFFCFA6D6 # 10 ^ 64 24430 long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128 24431 long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256 24432 long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512 24433 long 0x4D480000,0xC9767586,0x81750C18 # 10 ^ 1024 24434 long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048 24435 long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096 24436 24437 global PTENRM 24438PTENRM: 24439 long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 24440 long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 24441 long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 24442 long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 24443 long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 24444 long 0x40690000,0x9DC5ADA8,0x2B70B59D # 10 ^ 32 24445 long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64 24446 long 0x41A80000,0x93BA47C9,0x80E98CDF # 10 ^ 128 24447 long 0x43510000,0xAA7EEBFB,0x9DF9DE8D # 10 ^ 256 24448 long 0x46A30000,0xE319A0AE,0xA60E91C6 # 10 ^ 512 24449 long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024 24450 long 0x5A920000,0x9E8B3B5D,0xC53D5DE4 # 10 ^ 2048 24451 long 0x75250000,0xC4605202,0x8A20979A # 10 ^ 4096 24452 24453######################################################################### 24454# binstr(): Converts a 64-bit binary integer to bcd. # 24455# # 24456# INPUT *************************************************************** # 24457# d2:d3 = 64-bit binary integer # 24458# d0 = desired length (LEN) # 24459# a0 = pointer to start in memory for bcd characters # 24460# (This pointer must point to byte 4 of the first # 24461# lword of the packed decimal memory string.) # 24462# # 24463# OUTPUT ************************************************************** # 24464# a0 = pointer to LEN bcd digits representing the 64-bit integer. # 24465# # 24466# ALGORITHM *********************************************************** # 24467# The 64-bit binary is assumed to have a decimal point before # 24468# bit 63. The fraction is multiplied by 10 using a mul by 2 # 24469# shift and a mul by 8 shift. The bits shifted out of the # 24470# msb form a decimal digit. This process is iterated until # 24471# LEN digits are formed. # 24472# # 24473# A1. Init d7 to 1. D7 is the byte digit counter, and if 1, the # 24474# digit formed will be assumed the least significant. This is # 24475# to force the first byte formed to have a 0 in the upper 4 bits. # 24476# # 24477# A2. Beginning of the loop: # 24478# Copy the fraction in d2:d3 to d4:d5. # 24479# # 24480# A3. Multiply the fraction in d2:d3 by 8 using bit-field # 24481# extracts and shifts. The three msbs from d2 will go into d1. # 24482# # 24483# A4. Multiply the fraction in d4:d5 by 2 using shifts. The msb # 24484# will be collected by the carry. # 24485# # 24486# A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5 # 24487# into d2:d3. D1 will contain the bcd digit formed. # 24488# # 24489# A6. Test d7. If zero, the digit formed is the ms digit. If non- # 24490# zero, it is the ls digit. Put the digit in its place in the # 24491# upper word of d0. If it is the ls digit, write the word # 24492# from d0 to memory. # 24493# # 24494# A7. Decrement d6 (LEN counter) and repeat the loop until zero. # 24495# # 24496######################################################################### 24497 24498# Implementation Notes: 24499# 24500# The registers are used as follows: 24501# 24502# d0: LEN counter 24503# d1: temp used to form the digit 24504# d2: upper 32-bits of fraction for mul by 8 24505# d3: lower 32-bits of fraction for mul by 8 24506# d4: upper 32-bits of fraction for mul by 2 24507# d5: lower 32-bits of fraction for mul by 2 24508# d6: temp for bit-field extracts 24509# d7: byte digit formation word;digit count {0,1} 24510# a0: pointer into memory for packed bcd string formation 24511# 24512 24513 global binstr 24514binstr: 24515 movm.l &0xff00,-(%sp) # {%d0-%d7} 24516 24517# 24518# A1: Init d7 24519# 24520 mov.l &1,%d7 # init d7 for second digit 24521 subq.l &1,%d0 # for dbf d0 would have LEN+1 passes 24522# 24523# A2. Copy d2:d3 to d4:d5. Start loop. 24524# 24525loop: 24526 mov.l %d2,%d4 # copy the fraction before muls 24527 mov.l %d3,%d5 # to d4:d5 24528# 24529# A3. Multiply d2:d3 by 8; extract msbs into d1. 24530# 24531 bfextu %d2{&0:&3},%d1 # copy 3 msbs of d2 into d1 24532 asl.l &3,%d2 # shift d2 left by 3 places 24533 bfextu %d3{&0:&3},%d6 # copy 3 msbs of d3 into d6 24534 asl.l &3,%d3 # shift d3 left by 3 places 24535 or.l %d6,%d2 # or in msbs from d3 into d2 24536# 24537# A4. Multiply d4:d5 by 2; add carry out to d1. 24538# 24539 asl.l &1,%d5 # mul d5 by 2 24540 roxl.l &1,%d4 # mul d4 by 2 24541 swap %d6 # put 0 in d6 lower word 24542 addx.w %d6,%d1 # add in extend from mul by 2 24543# 24544# A5. Add mul by 8 to mul by 2. D1 contains the digit formed. 24545# 24546 add.l %d5,%d3 # add lower 32 bits 24547 nop # ERRATA FIX #13 (Rev. 1.2 6/6/90) 24548 addx.l %d4,%d2 # add with extend upper 32 bits 24549 nop # ERRATA FIX #13 (Rev. 1.2 6/6/90) 24550 addx.w %d6,%d1 # add in extend from add to d1 24551 swap %d6 # with d6 = 0; put 0 in upper word 24552# 24553# A6. Test d7 and branch. 24554# 24555 tst.w %d7 # if zero, store digit & to loop 24556 beq.b first_d # if non-zero, form byte & write 24557sec_d: 24558 swap %d7 # bring first digit to word d7b 24559 asl.w &4,%d7 # first digit in upper 4 bits d7b 24560 add.w %d1,%d7 # add in ls digit to d7b 24561 mov.b %d7,(%a0)+ # store d7b byte in memory 24562 swap %d7 # put LEN counter in word d7a 24563 clr.w %d7 # set d7a to signal no digits done 24564 dbf.w %d0,loop # do loop some more! 24565 bra.b end_bstr # finished, so exit 24566first_d: 24567 swap %d7 # put digit word in d7b 24568 mov.w %d1,%d7 # put new digit in d7b 24569 swap %d7 # put LEN counter in word d7a 24570 addq.w &1,%d7 # set d7a to signal first digit done 24571 dbf.w %d0,loop # do loop some more! 24572 swap %d7 # put last digit in string 24573 lsl.w &4,%d7 # move it to upper 4 bits 24574 mov.b %d7,(%a0)+ # store it in memory string 24575# 24576# Clean up and return with result in fp0. 24577# 24578end_bstr: 24579 movm.l (%sp)+,&0xff # {%d0-%d7} 24580 rts 24581 24582######################################################################### 24583# XDEF **************************************************************** # 24584# facc_in_b(): dmem_read_byte failed # 24585# facc_in_w(): dmem_read_word failed # 24586# facc_in_l(): dmem_read_long failed # 24587# facc_in_d(): dmem_read of dbl prec failed # 24588# facc_in_x(): dmem_read of ext prec failed # 24589# # 24590# facc_out_b(): dmem_write_byte failed # 24591# facc_out_w(): dmem_write_word failed # 24592# facc_out_l(): dmem_write_long failed # 24593# facc_out_d(): dmem_write of dbl prec failed # 24594# facc_out_x(): dmem_write of ext prec failed # 24595# # 24596# XREF **************************************************************** # 24597# _real_access() - exit through access error handler # 24598# # 24599# INPUT *************************************************************** # 24600# None # 24601# # 24602# OUTPUT ************************************************************** # 24603# None # 24604# # 24605# ALGORITHM *********************************************************** # 24606# Flow jumps here when an FP data fetch call gets an error # 24607# result. This means the operating system wants an access error frame # 24608# made out of the current exception stack frame. # 24609# So, we first call restore() which makes sure that any updated # 24610# -(an)+ register gets returned to its pre-exception value and then # 24611# we change the stack to an access error stack frame. # 24612# # 24613######################################################################### 24614 24615facc_in_b: 24616 movq.l &0x1,%d0 # one byte 24617 bsr.w restore # fix An 24618 24619 mov.w &0x0121,EXC_VOFF(%a6) # set FSLW 24620 bra.w facc_finish 24621 24622facc_in_w: 24623 movq.l &0x2,%d0 # two bytes 24624 bsr.w restore # fix An 24625 24626 mov.w &0x0141,EXC_VOFF(%a6) # set FSLW 24627 bra.b facc_finish 24628 24629facc_in_l: 24630 movq.l &0x4,%d0 # four bytes 24631 bsr.w restore # fix An 24632 24633 mov.w &0x0101,EXC_VOFF(%a6) # set FSLW 24634 bra.b facc_finish 24635 24636facc_in_d: 24637 movq.l &0x8,%d0 # eight bytes 24638 bsr.w restore # fix An 24639 24640 mov.w &0x0161,EXC_VOFF(%a6) # set FSLW 24641 bra.b facc_finish 24642 24643facc_in_x: 24644 movq.l &0xc,%d0 # twelve bytes 24645 bsr.w restore # fix An 24646 24647 mov.w &0x0161,EXC_VOFF(%a6) # set FSLW 24648 bra.b facc_finish 24649 24650################################################################ 24651 24652facc_out_b: 24653 movq.l &0x1,%d0 # one byte 24654 bsr.w restore # restore An 24655 24656 mov.w &0x00a1,EXC_VOFF(%a6) # set FSLW 24657 bra.b facc_finish 24658 24659facc_out_w: 24660 movq.l &0x2,%d0 # two bytes 24661 bsr.w restore # restore An 24662 24663 mov.w &0x00c1,EXC_VOFF(%a6) # set FSLW 24664 bra.b facc_finish 24665 24666facc_out_l: 24667 movq.l &0x4,%d0 # four bytes 24668 bsr.w restore # restore An 24669 24670 mov.w &0x0081,EXC_VOFF(%a6) # set FSLW 24671 bra.b facc_finish 24672 24673facc_out_d: 24674 movq.l &0x8,%d0 # eight bytes 24675 bsr.w restore # restore An 24676 24677 mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW 24678 bra.b facc_finish 24679 24680facc_out_x: 24681 mov.l &0xc,%d0 # twelve bytes 24682 bsr.w restore # restore An 24683 24684 mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW 24685 24686# here's where we actually create the access error frame from the 24687# current exception stack frame. 24688facc_finish: 24689 mov.l USER_FPIAR(%a6),EXC_PC(%a6) # store current PC 24690 24691 fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 24692 fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 24693 movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 24694 24695 unlk %a6 24696 24697 mov.l (%sp),-(%sp) # store SR, hi(PC) 24698 mov.l 0x8(%sp),0x4(%sp) # store lo(PC) 24699 mov.l 0xc(%sp),0x8(%sp) # store EA 24700 mov.l &0x00000001,0xc(%sp) # store FSLW 24701 mov.w 0x6(%sp),0xc(%sp) # fix FSLW (size) 24702 mov.w &0x4008,0x6(%sp) # store voff 24703 24704 btst &0x5,(%sp) # supervisor or user mode? 24705 beq.b facc_out2 # user 24706 bset &0x2,0xd(%sp) # set supervisor TM bit 24707 24708facc_out2: 24709 bra.l _real_access 24710 24711################################################################## 24712 24713# if the effective addressing mode was predecrement or postincrement, 24714# the emulation has already changed its value to the correct post- 24715# instruction value. but since we're exiting to the access error 24716# handler, then AN must be returned to its pre-instruction value. 24717# we do that here. 24718restore: 24719 mov.b EXC_OPWORD+0x1(%a6),%d1 24720 andi.b &0x38,%d1 # extract opmode 24721 cmpi.b %d1,&0x18 # postinc? 24722 beq.w rest_inc 24723 cmpi.b %d1,&0x20 # predec? 24724 beq.w rest_dec 24725 rts 24726 24727rest_inc: 24728 mov.b EXC_OPWORD+0x1(%a6),%d1 24729 andi.w &0x0007,%d1 # fetch An 24730 24731 mov.w (tbl_rest_inc.b,%pc,%d1.w*2),%d1 24732 jmp (tbl_rest_inc.b,%pc,%d1.w*1) 24733 24734tbl_rest_inc: 24735 short ri_a0 - tbl_rest_inc 24736 short ri_a1 - tbl_rest_inc 24737 short ri_a2 - tbl_rest_inc 24738 short ri_a3 - tbl_rest_inc 24739 short ri_a4 - tbl_rest_inc 24740 short ri_a5 - tbl_rest_inc 24741 short ri_a6 - tbl_rest_inc 24742 short ri_a7 - tbl_rest_inc 24743 24744ri_a0: 24745 sub.l %d0,EXC_DREGS+0x8(%a6) # fix stacked a0 24746 rts 24747ri_a1: 24748 sub.l %d0,EXC_DREGS+0xc(%a6) # fix stacked a1 24749 rts 24750ri_a2: 24751 sub.l %d0,%a2 # fix a2 24752 rts 24753ri_a3: 24754 sub.l %d0,%a3 # fix a3 24755 rts 24756ri_a4: 24757 sub.l %d0,%a4 # fix a4 24758 rts 24759ri_a5: 24760 sub.l %d0,%a5 # fix a5 24761 rts 24762ri_a6: 24763 sub.l %d0,(%a6) # fix stacked a6 24764 rts 24765# if it's a fmove out instruction, we don't have to fix a7 24766# because we hadn't changed it yet. if it's an opclass two 24767# instruction (data moved in) and the exception was in supervisor 24768# mode, then also also wasn't updated. if it was user mode, then 24769# restore the correct a7 which is in the USP currently. 24770ri_a7: 24771 cmpi.b EXC_VOFF(%a6),&0x30 # move in or out? 24772 bne.b ri_a7_done # out 24773 24774 btst &0x5,EXC_SR(%a6) # user or supervisor? 24775 bne.b ri_a7_done # supervisor 24776 movc %usp,%a0 # restore USP 24777 sub.l %d0,%a0 24778 movc %a0,%usp 24779ri_a7_done: 24780 rts 24781 24782# need to invert adjustment value if the <ea> was predec 24783rest_dec: 24784 neg.l %d0 24785 bra.b rest_inc 24786