1 1.1 is # 2 1.4 christos # $NetBSD: pfpsp.s,v 1.4 2005/12/11 12:17:52 christos Exp $ 3 1.1 is # 4 1.1 is 5 1.1 is #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 1.1 is # MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP 7 1.1 is # M68000 Hi-Performance Microprocessor Division 8 1.1 is # M68060 Software Package Production Release 9 1.1 is # 10 1.1 is # M68060 Software Package Copyright (C) 1993, 1994, 1995, 1996 Motorola Inc. 11 1.1 is # All rights reserved. 12 1.1 is # 13 1.1 is # THE SOFTWARE is provided on an "AS IS" basis and without warranty. 14 1.1 is # To the maximum extent permitted by applicable law, 15 1.1 is # MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, 16 1.1 is # INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS 17 1.1 is # FOR A PARTICULAR PURPOSE and any warranty against infringement with 18 1.1 is # regard to the SOFTWARE (INCLUDING ANY MODIFIED VERSIONS THEREOF) 19 1.1 is # and any accompanying written materials. 20 1.1 is # 21 1.1 is # To the maximum extent permitted by applicable law, 22 1.1 is # IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER 23 1.1 is # (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, 24 1.1 is # BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS) 25 1.1 is # ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE. 26 1.1 is # 27 1.1 is # Motorola assumes no responsibility for the maintenance and support 28 1.1 is # of the SOFTWARE. 29 1.1 is # 30 1.1 is # You are hereby granted a copyright license to use, modify, and distribute the 31 1.1 is # SOFTWARE so long as this entire notice is retained without alteration 32 1.1 is # in any modified and/or redistributed versions, and that such modified 33 1.1 is # versions are clearly identified as such. 34 1.1 is # No licenses are granted by implication, estoppel or otherwise under any 35 1.1 is # patents or trademarks of Motorola, Inc. 36 1.1 is #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 37 1.1 is 38 1.1 is # 39 1.1 is # freal.s: 40 1.1 is # This file is appended to the top of the 060FPSP package 41 1.1 is # and contains the entry points into the package. The user, in 42 1.1 is # effect, branches to one of the branch table entries located 43 1.1 is # after _060FPSP_TABLE. 44 1.1 is # Also, subroutine stubs exist in this file (_fpsp_done for 45 1.1 is # example) that are referenced by the FPSP package itself in order 46 1.1 is # to call a given routine. The stub routine actually performs the 47 1.1 is # callout. The FPSP code does a "bsr" to the stub routine. This 48 1.1 is # extra layer of hierarchy adds a slight performance penalty but 49 1.1 is # it makes the FPSP code easier to read and more mainatinable. 50 1.1 is # 51 1.1 is 52 1.1 is set _off_bsun, 0x00 53 1.1 is set _off_snan, 0x04 54 1.1 is set _off_operr, 0x08 55 1.1 is set _off_ovfl, 0x0c 56 1.1 is set _off_unfl, 0x10 57 1.1 is set _off_dz, 0x14 58 1.1 is set _off_inex, 0x18 59 1.1 is set _off_fline, 0x1c 60 1.1 is set _off_fpu_dis, 0x20 61 1.1 is set _off_trap, 0x24 62 1.1 is set _off_trace, 0x28 63 1.1 is set _off_access, 0x2c 64 1.1 is set _off_done, 0x30 65 1.1 is 66 1.1 is set _off_imr, 0x40 67 1.1 is set _off_dmr, 0x44 68 1.1 is set _off_dmw, 0x48 69 1.1 is set _off_irw, 0x4c 70 1.1 is set _off_irl, 0x50 71 1.1 is set _off_drb, 0x54 72 1.1 is set _off_drw, 0x58 73 1.1 is set _off_drl, 0x5c 74 1.1 is set _off_dwb, 0x60 75 1.1 is set _off_dww, 0x64 76 1.1 is set _off_dwl, 0x68 77 1.1 is 78 1.1 is _060FPSP_TABLE: 79 1.1 is 80 1.1 is ############################################################### 81 1.1 is 82 1.1 is # Here's the table of ENTRY POINTS for those linking the package. 83 1.1 is bra.l _fpsp_snan 84 1.1 is short 0x0000 85 1.1 is bra.l _fpsp_operr 86 1.1 is short 0x0000 87 1.1 is bra.l _fpsp_ovfl 88 1.1 is short 0x0000 89 1.1 is bra.l _fpsp_unfl 90 1.1 is short 0x0000 91 1.1 is bra.l _fpsp_dz 92 1.1 is short 0x0000 93 1.1 is bra.l _fpsp_inex 94 1.1 is short 0x0000 95 1.1 is bra.l _fpsp_fline 96 1.1 is short 0x0000 97 1.1 is bra.l _fpsp_unsupp 98 1.1 is short 0x0000 99 1.1 is bra.l _fpsp_effadd 100 1.1 is short 0x0000 101 1.1 is 102 1.1 is space 56 103 1.1 is 104 1.1 is ############################################################### 105 1.1 is global _fpsp_done 106 1.1 is _fpsp_done: 107 1.1 is mov.l %d0,-(%sp) 108 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_done,%pc),%d0 109 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 110 1.1 is mov.l 0x4(%sp),%d0 111 1.1 is rtd &0x4 112 1.1 is 113 1.1 is global _real_ovfl 114 1.1 is _real_ovfl: 115 1.1 is mov.l %d0,-(%sp) 116 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_ovfl,%pc),%d0 117 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 118 1.1 is mov.l 0x4(%sp),%d0 119 1.1 is rtd &0x4 120 1.1 is 121 1.1 is global _real_unfl 122 1.1 is _real_unfl: 123 1.1 is mov.l %d0,-(%sp) 124 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_unfl,%pc),%d0 125 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 126 1.1 is mov.l 0x4(%sp),%d0 127 1.1 is rtd &0x4 128 1.1 is 129 1.1 is global _real_inex 130 1.1 is _real_inex: 131 1.1 is mov.l %d0,-(%sp) 132 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_inex,%pc),%d0 133 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 134 1.1 is mov.l 0x4(%sp),%d0 135 1.1 is rtd &0x4 136 1.1 is 137 1.1 is global _real_bsun 138 1.1 is _real_bsun: 139 1.1 is mov.l %d0,-(%sp) 140 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_bsun,%pc),%d0 141 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 142 1.1 is mov.l 0x4(%sp),%d0 143 1.1 is rtd &0x4 144 1.1 is 145 1.1 is global _real_operr 146 1.1 is _real_operr: 147 1.1 is mov.l %d0,-(%sp) 148 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_operr,%pc),%d0 149 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 150 1.1 is mov.l 0x4(%sp),%d0 151 1.1 is rtd &0x4 152 1.1 is 153 1.1 is global _real_snan 154 1.1 is _real_snan: 155 1.1 is mov.l %d0,-(%sp) 156 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_snan,%pc),%d0 157 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 158 1.1 is mov.l 0x4(%sp),%d0 159 1.1 is rtd &0x4 160 1.1 is 161 1.1 is global _real_dz 162 1.1 is _real_dz: 163 1.1 is mov.l %d0,-(%sp) 164 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dz,%pc),%d0 165 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 166 1.1 is mov.l 0x4(%sp),%d0 167 1.1 is rtd &0x4 168 1.1 is 169 1.1 is global _real_fline 170 1.1 is _real_fline: 171 1.1 is mov.l %d0,-(%sp) 172 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_fline,%pc),%d0 173 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 174 1.1 is mov.l 0x4(%sp),%d0 175 1.1 is rtd &0x4 176 1.1 is 177 1.1 is global _real_fpu_disabled 178 1.1 is _real_fpu_disabled: 179 1.1 is mov.l %d0,-(%sp) 180 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_fpu_dis,%pc),%d0 181 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 182 1.1 is mov.l 0x4(%sp),%d0 183 1.1 is rtd &0x4 184 1.1 is 185 1.1 is global _real_trap 186 1.1 is _real_trap: 187 1.1 is mov.l %d0,-(%sp) 188 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_trap,%pc),%d0 189 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 190 1.1 is mov.l 0x4(%sp),%d0 191 1.1 is rtd &0x4 192 1.1 is 193 1.1 is global _real_trace 194 1.1 is _real_trace: 195 1.1 is mov.l %d0,-(%sp) 196 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_trace,%pc),%d0 197 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 198 1.1 is mov.l 0x4(%sp),%d0 199 1.1 is rtd &0x4 200 1.1 is 201 1.1 is global _real_access 202 1.1 is _real_access: 203 1.1 is mov.l %d0,-(%sp) 204 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_access,%pc),%d0 205 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 206 1.1 is mov.l 0x4(%sp),%d0 207 1.1 is rtd &0x4 208 1.1 is 209 1.1 is ####################################### 210 1.1 is 211 1.1 is global _imem_read 212 1.1 is _imem_read: 213 1.1 is mov.l %d0,-(%sp) 214 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_imr,%pc),%d0 215 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 216 1.1 is mov.l 0x4(%sp),%d0 217 1.1 is rtd &0x4 218 1.1 is 219 1.1 is global _dmem_read 220 1.1 is _dmem_read: 221 1.1 is mov.l %d0,-(%sp) 222 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dmr,%pc),%d0 223 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 224 1.1 is mov.l 0x4(%sp),%d0 225 1.1 is rtd &0x4 226 1.1 is 227 1.1 is global _dmem_write 228 1.1 is _dmem_write: 229 1.1 is mov.l %d0,-(%sp) 230 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dmw,%pc),%d0 231 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 232 1.1 is mov.l 0x4(%sp),%d0 233 1.1 is rtd &0x4 234 1.1 is 235 1.1 is global _imem_read_word 236 1.1 is _imem_read_word: 237 1.1 is mov.l %d0,-(%sp) 238 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_irw,%pc),%d0 239 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 240 1.1 is mov.l 0x4(%sp),%d0 241 1.1 is rtd &0x4 242 1.1 is 243 1.1 is global _imem_read_long 244 1.1 is _imem_read_long: 245 1.1 is mov.l %d0,-(%sp) 246 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_irl,%pc),%d0 247 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 248 1.1 is mov.l 0x4(%sp),%d0 249 1.1 is rtd &0x4 250 1.1 is 251 1.1 is global _dmem_read_byte 252 1.1 is _dmem_read_byte: 253 1.1 is mov.l %d0,-(%sp) 254 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_drb,%pc),%d0 255 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 256 1.1 is mov.l 0x4(%sp),%d0 257 1.1 is rtd &0x4 258 1.1 is 259 1.1 is global _dmem_read_word 260 1.1 is _dmem_read_word: 261 1.1 is mov.l %d0,-(%sp) 262 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_drw,%pc),%d0 263 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 264 1.1 is mov.l 0x4(%sp),%d0 265 1.1 is rtd &0x4 266 1.1 is 267 1.1 is global _dmem_read_long 268 1.1 is _dmem_read_long: 269 1.1 is mov.l %d0,-(%sp) 270 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_drl,%pc),%d0 271 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 272 1.1 is mov.l 0x4(%sp),%d0 273 1.1 is rtd &0x4 274 1.1 is 275 1.1 is global _dmem_write_byte 276 1.1 is _dmem_write_byte: 277 1.1 is mov.l %d0,-(%sp) 278 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dwb,%pc),%d0 279 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 280 1.1 is mov.l 0x4(%sp),%d0 281 1.1 is rtd &0x4 282 1.1 is 283 1.1 is global _dmem_write_word 284 1.1 is _dmem_write_word: 285 1.1 is mov.l %d0,-(%sp) 286 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dww,%pc),%d0 287 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 288 1.1 is mov.l 0x4(%sp),%d0 289 1.1 is rtd &0x4 290 1.1 is 291 1.1 is global _dmem_write_long 292 1.1 is _dmem_write_long: 293 1.1 is mov.l %d0,-(%sp) 294 1.1 is mov.l (_060FPSP_TABLE-0x80+_off_dwl,%pc),%d0 295 1.1 is pea.l (_060FPSP_TABLE-0x80,%pc,%d0) 296 1.1 is mov.l 0x4(%sp),%d0 297 1.1 is rtd &0x4 298 1.1 is 299 1.1 is # 300 1.1 is # This file contains a set of define statements for constants 301 1.1 is # in order to promote readability within the corecode itself. 302 1.1 is # 303 1.1 is 304 1.1 is set LOCAL_SIZE, 192 # stack frame size(bytes) 305 1.1 is set LV, -LOCAL_SIZE # stack offset 306 1.1 is 307 1.1 is set EXC_SR, 0x4 # stack status register 308 1.1 is set EXC_PC, 0x6 # stack pc 309 1.1 is set EXC_VOFF, 0xa # stacked vector offset 310 1.1 is set EXC_EA, 0xc # stacked <ea> 311 1.1 is 312 1.1 is set EXC_FP, 0x0 # frame pointer 313 1.1 is 314 1.1 is set EXC_AREGS, -68 # offset of all address regs 315 1.1 is set EXC_DREGS, -100 # offset of all data regs 316 1.1 is set EXC_FPREGS, -36 # offset of all fp regs 317 1.1 is 318 1.1 is set EXC_A7, EXC_AREGS+(7*4) # offset of saved a7 319 1.1 is set OLD_A7, EXC_AREGS+(6*4) # extra copy of saved a7 320 1.1 is set EXC_A6, EXC_AREGS+(6*4) # offset of saved a6 321 1.1 is set EXC_A5, EXC_AREGS+(5*4) 322 1.1 is set EXC_A4, EXC_AREGS+(4*4) 323 1.1 is set EXC_A3, EXC_AREGS+(3*4) 324 1.1 is set EXC_A2, EXC_AREGS+(2*4) 325 1.1 is set EXC_A1, EXC_AREGS+(1*4) 326 1.1 is set EXC_A0, EXC_AREGS+(0*4) 327 1.1 is set EXC_D7, EXC_DREGS+(7*4) 328 1.1 is set EXC_D6, EXC_DREGS+(6*4) 329 1.1 is set EXC_D5, EXC_DREGS+(5*4) 330 1.1 is set EXC_D4, EXC_DREGS+(4*4) 331 1.1 is set EXC_D3, EXC_DREGS+(3*4) 332 1.1 is set EXC_D2, EXC_DREGS+(2*4) 333 1.1 is set EXC_D1, EXC_DREGS+(1*4) 334 1.1 is set EXC_D0, EXC_DREGS+(0*4) 335 1.1 is 336 1.1 is set EXC_FP0, EXC_FPREGS+(0*12) # offset of saved fp0 337 1.1 is set EXC_FP1, EXC_FPREGS+(1*12) # offset of saved fp1 338 1.1 is set EXC_FP2, EXC_FPREGS+(2*12) # offset of saved fp2 (not used) 339 1.1 is 340 1.1 is set FP_SCR1, LV+80 # fp scratch 1 341 1.1 is set FP_SCR1_EX, FP_SCR1+0 342 1.1 is set FP_SCR1_SGN, FP_SCR1+2 343 1.1 is set FP_SCR1_HI, FP_SCR1+4 344 1.1 is set FP_SCR1_LO, FP_SCR1+8 345 1.1 is 346 1.1 is set FP_SCR0, LV+68 # fp scratch 0 347 1.1 is set FP_SCR0_EX, FP_SCR0+0 348 1.1 is set FP_SCR0_SGN, FP_SCR0+2 349 1.1 is set FP_SCR0_HI, FP_SCR0+4 350 1.1 is set FP_SCR0_LO, FP_SCR0+8 351 1.1 is 352 1.1 is set FP_DST, LV+56 # fp destination operand 353 1.1 is set FP_DST_EX, FP_DST+0 354 1.1 is set FP_DST_SGN, FP_DST+2 355 1.1 is set FP_DST_HI, FP_DST+4 356 1.1 is set FP_DST_LO, FP_DST+8 357 1.1 is 358 1.1 is set FP_SRC, LV+44 # fp source operand 359 1.1 is set FP_SRC_EX, FP_SRC+0 360 1.1 is set FP_SRC_SGN, FP_SRC+2 361 1.1 is set FP_SRC_HI, FP_SRC+4 362 1.1 is set FP_SRC_LO, FP_SRC+8 363 1.1 is 364 1.1 is set USER_FPIAR, LV+40 # FP instr address register 365 1.1 is 366 1.1 is set USER_FPSR, LV+36 # FP status register 367 1.1 is set FPSR_CC, USER_FPSR+0 # FPSR condition codes 368 1.1 is set FPSR_QBYTE, USER_FPSR+1 # FPSR qoutient byte 369 1.1 is set FPSR_EXCEPT, USER_FPSR+2 # FPSR exception status byte 370 1.1 is set FPSR_AEXCEPT, USER_FPSR+3 # FPSR accrued exception byte 371 1.1 is 372 1.1 is set USER_FPCR, LV+32 # FP control register 373 1.1 is set FPCR_ENABLE, USER_FPCR+2 # FPCR exception enable 374 1.1 is set FPCR_MODE, USER_FPCR+3 # FPCR rounding mode control 375 1.1 is 376 1.1 is set L_SCR3, LV+28 # integer scratch 3 377 1.1 is set L_SCR2, LV+24 # integer scratch 2 378 1.1 is set L_SCR1, LV+20 # integer scratch 1 379 1.1 is 380 1.1 is set STORE_FLG, LV+19 # flag: operand store (ie. not fcmp/ftst) 381 1.1 is 382 1.1 is set EXC_TEMP2, LV+24 # temporary space 383 1.1 is set EXC_TEMP, LV+16 # temporary space 384 1.1 is 385 1.1 is set DTAG, LV+15 # destination operand type 386 1.1 is set STAG, LV+14 # source operand type 387 1.1 is 388 1.1 is set SPCOND_FLG, LV+10 # flag: special case (see below) 389 1.1 is 390 1.1 is set EXC_CC, LV+8 # saved condition codes 391 1.1 is set EXC_EXTWPTR, LV+4 # saved current PC (active) 392 1.1 is set EXC_EXTWORD, LV+2 # saved extension word 393 1.1 is set EXC_CMDREG, LV+2 # saved extension word 394 1.1 is set EXC_OPWORD, LV+0 # saved operation word 395 1.1 is 396 1.1 is ################################ 397 1.1 is 398 1.1 is # Helpful macros 399 1.1 is 400 1.1 is set FTEMP, 0 # offsets within an 401 1.1 is set FTEMP_EX, 0 # extended precision 402 1.1 is set FTEMP_SGN, 2 # value saved in memory. 403 1.1 is set FTEMP_HI, 4 404 1.1 is set FTEMP_LO, 8 405 1.1 is set FTEMP_GRS, 12 406 1.1 is 407 1.1 is set LOCAL, 0 # offsets within an 408 1.1 is set LOCAL_EX, 0 # extended precision 409 1.1 is set LOCAL_SGN, 2 # value saved in memory. 410 1.1 is set LOCAL_HI, 4 411 1.1 is set LOCAL_LO, 8 412 1.1 is set LOCAL_GRS, 12 413 1.1 is 414 1.1 is set DST, 0 # offsets within an 415 1.1 is set DST_EX, 0 # extended precision 416 1.1 is set DST_HI, 4 # value saved in memory. 417 1.1 is set DST_LO, 8 418 1.1 is 419 1.1 is set SRC, 0 # offsets within an 420 1.1 is set SRC_EX, 0 # extended precision 421 1.1 is set SRC_HI, 4 # value saved in memory. 422 1.1 is set SRC_LO, 8 423 1.1 is 424 1.1 is set SGL_LO, 0x3f81 # min sgl prec exponent 425 1.1 is set SGL_HI, 0x407e # max sgl prec exponent 426 1.1 is set DBL_LO, 0x3c01 # min dbl prec exponent 427 1.1 is set DBL_HI, 0x43fe # max dbl prec exponent 428 1.1 is set EXT_LO, 0x0 # min ext prec exponent 429 1.1 is set EXT_HI, 0x7ffe # max ext prec exponent 430 1.1 is 431 1.1 is set EXT_BIAS, 0x3fff # extended precision bias 432 1.1 is set SGL_BIAS, 0x007f # single precision bias 433 1.1 is set DBL_BIAS, 0x03ff # double precision bias 434 1.1 is 435 1.1 is set NORM, 0x00 # operand type for STAG/DTAG 436 1.1 is set ZERO, 0x01 # operand type for STAG/DTAG 437 1.1 is set INF, 0x02 # operand type for STAG/DTAG 438 1.1 is set QNAN, 0x03 # operand type for STAG/DTAG 439 1.1 is set DENORM, 0x04 # operand type for STAG/DTAG 440 1.1 is set SNAN, 0x05 # operand type for STAG/DTAG 441 1.1 is set UNNORM, 0x06 # operand type for STAG/DTAG 442 1.1 is 443 1.1 is ################## 444 1.1 is # FPSR/FPCR bits # 445 1.1 is ################## 446 1.1 is set neg_bit, 0x3 # negative result 447 1.1 is set z_bit, 0x2 # zero result 448 1.1 is set inf_bit, 0x1 # infinite result 449 1.1 is set nan_bit, 0x0 # NAN result 450 1.1 is 451 1.1 is set q_sn_bit, 0x7 # sign bit of quotient byte 452 1.1 is 453 1.1 is set bsun_bit, 7 # branch on unordered 454 1.1 is set snan_bit, 6 # signalling NAN 455 1.1 is set operr_bit, 5 # operand error 456 1.1 is set ovfl_bit, 4 # overflow 457 1.1 is set unfl_bit, 3 # underflow 458 1.1 is set dz_bit, 2 # divide by zero 459 1.1 is set inex2_bit, 1 # inexact result 2 460 1.1 is set inex1_bit, 0 # inexact result 1 461 1.1 is 462 1.1 is set aiop_bit, 7 # accrued inexact operation bit 463 1.1 is set aovfl_bit, 6 # accrued overflow bit 464 1.1 is set aunfl_bit, 5 # accrued underflow bit 465 1.1 is set adz_bit, 4 # accrued dz bit 466 1.1 is set ainex_bit, 3 # accrued inexact bit 467 1.1 is 468 1.1 is ############################# 469 1.1 is # FPSR individual bit masks # 470 1.1 is ############################# 471 1.1 is set neg_mask, 0x08000000 # negative bit mask (lw) 472 1.1 is set inf_mask, 0x02000000 # infinity bit mask (lw) 473 1.1 is set z_mask, 0x04000000 # zero bit mask (lw) 474 1.1 is set nan_mask, 0x01000000 # nan bit mask (lw) 475 1.1 is 476 1.1 is set neg_bmask, 0x08 # negative bit mask (byte) 477 1.1 is set inf_bmask, 0x02 # infinity bit mask (byte) 478 1.1 is set z_bmask, 0x04 # zero bit mask (byte) 479 1.1 is set nan_bmask, 0x01 # nan bit mask (byte) 480 1.1 is 481 1.1 is set bsun_mask, 0x00008000 # bsun exception mask 482 1.1 is set snan_mask, 0x00004000 # snan exception mask 483 1.1 is set operr_mask, 0x00002000 # operr exception mask 484 1.1 is set ovfl_mask, 0x00001000 # overflow exception mask 485 1.1 is set unfl_mask, 0x00000800 # underflow exception mask 486 1.1 is set dz_mask, 0x00000400 # dz exception mask 487 1.1 is set inex2_mask, 0x00000200 # inex2 exception mask 488 1.1 is set inex1_mask, 0x00000100 # inex1 exception mask 489 1.1 is 490 1.1 is set aiop_mask, 0x00000080 # accrued illegal operation 491 1.1 is set aovfl_mask, 0x00000040 # accrued overflow 492 1.1 is set aunfl_mask, 0x00000020 # accrued underflow 493 1.1 is set adz_mask, 0x00000010 # accrued divide by zero 494 1.1 is set ainex_mask, 0x00000008 # accrued inexact 495 1.1 is 496 1.1 is ###################################### 497 1.1 is # FPSR combinations used in the FPSP # 498 1.1 is ###################################### 499 1.1 is set dzinf_mask, inf_mask+dz_mask+adz_mask 500 1.1 is set opnan_mask, nan_mask+operr_mask+aiop_mask 501 1.1 is set nzi_mask, 0x01ffffff #clears N, Z, and I 502 1.1 is set unfinx_mask, unfl_mask+inex2_mask+aunfl_mask+ainex_mask 503 1.1 is set unf2inx_mask, unfl_mask+inex2_mask+ainex_mask 504 1.1 is set ovfinx_mask, ovfl_mask+inex2_mask+aovfl_mask+ainex_mask 505 1.1 is set inx1a_mask, inex1_mask+ainex_mask 506 1.1 is set inx2a_mask, inex2_mask+ainex_mask 507 1.1 is set snaniop_mask, nan_mask+snan_mask+aiop_mask 508 1.1 is set snaniop2_mask, snan_mask+aiop_mask 509 1.1 is set naniop_mask, nan_mask+aiop_mask 510 1.1 is set neginf_mask, neg_mask+inf_mask 511 1.1 is set infaiop_mask, inf_mask+aiop_mask 512 1.1 is set negz_mask, neg_mask+z_mask 513 1.1 is set opaop_mask, operr_mask+aiop_mask 514 1.1 is set unfl_inx_mask, unfl_mask+aunfl_mask+ainex_mask 515 1.1 is set ovfl_inx_mask, ovfl_mask+aovfl_mask+ainex_mask 516 1.1 is 517 1.1 is ######### 518 1.1 is # misc. # 519 1.1 is ######### 520 1.1 is set rnd_stky_bit, 29 # stky bit pos in longword 521 1.1 is 522 1.1 is set sign_bit, 0x7 # sign bit 523 1.1 is set signan_bit, 0x6 # signalling nan bit 524 1.1 is 525 1.1 is set sgl_thresh, 0x3f81 # minimum sgl exponent 526 1.1 is set dbl_thresh, 0x3c01 # minimum dbl exponent 527 1.1 is 528 1.1 is set x_mode, 0x0 # extended precision 529 1.1 is set s_mode, 0x4 # single precision 530 1.1 is set d_mode, 0x8 # double precision 531 1.1 is 532 1.1 is set rn_mode, 0x0 # round-to-nearest 533 1.1 is set rz_mode, 0x1 # round-to-zero 534 1.1 is set rm_mode, 0x2 # round-tp-minus-infinity 535 1.1 is set rp_mode, 0x3 # round-to-plus-infinity 536 1.1 is 537 1.1 is set mantissalen, 64 # length of mantissa in bits 538 1.1 is 539 1.1 is set BYTE, 1 # len(byte) == 1 byte 540 1.1 is set WORD, 2 # len(word) == 2 bytes 541 1.1 is set LONG, 4 # len(longword) == 2 bytes 542 1.1 is 543 1.1 is set BSUN_VEC, 0xc0 # bsun vector offset 544 1.1 is set INEX_VEC, 0xc4 # inexact vector offset 545 1.1 is set DZ_VEC, 0xc8 # dz vector offset 546 1.1 is set UNFL_VEC, 0xcc # unfl vector offset 547 1.1 is set OPERR_VEC, 0xd0 # operr vector offset 548 1.1 is set OVFL_VEC, 0xd4 # ovfl vector offset 549 1.1 is set SNAN_VEC, 0xd8 # snan vector offset 550 1.1 is 551 1.1 is ########################### 552 1.1 is # SPecial CONDition FLaGs # 553 1.1 is ########################### 554 1.1 is set ftrapcc_flg, 0x01 # flag bit: ftrapcc exception 555 1.1 is set fbsun_flg, 0x02 # flag bit: bsun exception 556 1.1 is set mia7_flg, 0x04 # flag bit: (a7)+ <ea> 557 1.1 is set mda7_flg, 0x08 # flag bit: -(a7) <ea> 558 1.1 is set fmovm_flg, 0x40 # flag bit: fmovm instruction 559 1.1 is set immed_flg, 0x80 # flag bit: &<data> <ea> 560 1.1 is 561 1.1 is set ftrapcc_bit, 0x0 562 1.1 is set fbsun_bit, 0x1 563 1.1 is set mia7_bit, 0x2 564 1.1 is set mda7_bit, 0x3 565 1.1 is set immed_bit, 0x7 566 1.1 is 567 1.1 is ################################## 568 1.1 is # TRANSCENDENTAL "LAST-OP" FLAGS # 569 1.1 is ################################## 570 1.1 is set FMUL_OP, 0x0 # fmul instr performed last 571 1.1 is set FDIV_OP, 0x1 # fdiv performed last 572 1.1 is set FADD_OP, 0x2 # fadd performed last 573 1.1 is set FMOV_OP, 0x3 # fmov performed last 574 1.1 is 575 1.1 is ############# 576 1.1 is # CONSTANTS # 577 1.1 is ############# 578 1.1 is T1: long 0x40C62D38,0xD3D64634 # 16381 LOG2 LEAD 579 1.1 is T2: long 0x3D6F90AE,0xB1E75CC7 # 16381 LOG2 TRAIL 580 1.1 is 581 1.1 is PI: long 0x40000000,0xC90FDAA2,0x2168C235,0x00000000 582 1.1 is PIBY2: long 0x3FFF0000,0xC90FDAA2,0x2168C235,0x00000000 583 1.1 is 584 1.1 is TWOBYPI: 585 1.1 is long 0x3FE45F30,0x6DC9C883 586 1.1 is 587 1.1 is ######################################################################### 588 1.1 is # XDEF **************************************************************** # 589 1.1 is # _fpsp_ovfl(): 060FPSP entry point for FP Overflow exception. # 590 1.1 is # # 591 1.1 is # This handler should be the first code executed upon taking the # 592 1.1 is # FP Overflow exception in an operating system. # 593 1.1 is # # 594 1.1 is # XREF **************************************************************** # 595 1.1 is # _imem_read_long() - read instruction longword # 596 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame # 597 1.1 is # set_tag_x() - determine optype of src/dst operands # 598 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile # 599 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO # 600 1.1 is # load_fpn2() - load dst operand from FP regfile # 601 1.1 is # fout() - emulate an opclass 3 instruction # 602 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 # 603 1.1 is # _fpsp_done() - "callout" for 060FPSP exit (all work done!) # 604 1.1 is # _real_ovfl() - "callout" for Overflow exception enabled code # 605 1.1 is # _real_inex() - "callout" for Inexact exception enabled code # 606 1.1 is # _real_trace() - "callout" for Trace exception code # 607 1.1 is # # 608 1.1 is # INPUT *************************************************************** # 609 1.1 is # - The system stack contains the FP Ovfl exception stack frame # 610 1.1 is # - The fsave frame contains the source operand # 611 1.1 is # # 612 1.1 is # OUTPUT ************************************************************** # 613 1.1 is # Overflow Exception enabled: # 614 1.1 is # - The system stack is unchanged # 615 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 # 616 1.1 is # Overflow Exception disabled: # 617 1.1 is # - The system stack is unchanged # 618 1.1 is # - The "exception present" flag in the fsave frame is cleared # 619 1.1 is # # 620 1.1 is # ALGORITHM *********************************************************** # 621 1.1 is # On the 060, if an FP overflow is present as the result of any # 622 1.1 is # instruction, the 060 will take an overflow exception whether the # 623 1.1 is # exception is enabled or disabled in the FPCR. For the disabled case, # 624 1.1 is # This handler emulates the instruction to determine what the correct # 625 1.1 is # default result should be for the operation. This default result is # 626 1.1 is # then stored in either the FP regfile, data regfile, or memory. # 627 1.1 is # Finally, the handler exits through the "callout" _fpsp_done() # 628 1.1 is # denoting that no exceptional conditions exist within the machine. # 629 1.1 is # If the exception is enabled, then this handler must create the # 630 1.1 is # exceptional operand and plave it in the fsave state frame, and store # 631 1.1 is # the default result (only if the instruction is opclass 3). For # 632 1.1 is # exceptions enabled, this handler must exit through the "callout" # 633 1.1 is # _real_ovfl() so that the operating system enabled overflow handler # 634 1.1 is # can handle this case. # 635 1.1 is # Two other conditions exist. First, if overflow was disabled # 636 1.1 is # but the inexact exception was enabled, this handler must exit # 637 1.1 is # through the "callout" _real_inex() regardless of whether the result # 638 1.1 is # was inexact. # 639 1.1 is # Also, in the case of an opclass three instruction where # 640 1.1 is # overflow was disabled and the trace exception was enabled, this # 641 1.1 is # handler must exit through the "callout" _real_trace(). # 642 1.1 is # # 643 1.1 is ######################################################################### 644 1.1 is 645 1.1 is global _fpsp_ovfl 646 1.1 is _fpsp_ovfl: 647 1.1 is 648 1.1 is #$# sub.l &24,%sp # make room for src/dst 649 1.1 is 650 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame 651 1.1 is 652 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame 653 1.1 is 654 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 655 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 656 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 657 1.1 is 658 1.1 is # the FPIAR holds the "current PC" of the faulting instruction 659 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 660 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 661 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 662 1.1 is bsr.l _imem_read_long # fetch the instruction words 663 1.1 is mov.l %d0,EXC_OPWORD(%a6) 664 1.1 is 665 1.1 is ############################################################################## 666 1.1 is 667 1.1 is btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out? 668 1.1 is bne.w fovfl_out 669 1.1 is 670 1.1 is 671 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 672 1.1 is bsr.l fix_skewed_ops # fix src op 673 1.1 is 674 1.1 is # since, I believe, only NORMs and DENORMs can come through here, 675 1.1 is # maybe we can avoid the subroutine call. 676 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 677 1.1 is bsr.l set_tag_x # tag the operand type 678 1.1 is mov.b %d0,STAG(%a6) # maybe NORM,DENORM 679 1.1 is 680 1.1 is # bit five of the fp extension word separates the monadic and dyadic operations 681 1.1 is # that can pass through fpsp_ovfl(). remember that fcmp, ftst, and fsincos 682 1.1 is # will never take this exception. 683 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 684 1.1 is beq.b fovfl_extract # monadic 685 1.1 is 686 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 687 1.1 is bsr.l load_fpn2 # load dst into FP_DST 688 1.1 is 689 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op 690 1.1 is bsr.l set_tag_x # tag the operand type 691 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 692 1.1 is bne.b fovfl_op2_done # no 693 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 694 1.1 is fovfl_op2_done: 695 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag 696 1.1 is 697 1.1 is fovfl_extract: 698 1.1 is 699 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 700 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 701 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 702 1.1 is #$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6) 703 1.1 is #$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6) 704 1.1 is #$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6) 705 1.1 is 706 1.1 is clr.l %d0 707 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 708 1.1 is 709 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1 710 1.1 is andi.w &0x007f,%d1 # extract extension 711 1.1 is 712 1.1 is andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field 713 1.1 is 714 1.1 is fmov.l &0x0,%fpcr # zero current control regs 715 1.1 is fmov.l &0x0,%fpsr 716 1.1 is 717 1.1 is lea FP_SRC(%a6),%a0 718 1.1 is lea FP_DST(%a6),%a1 719 1.1 is 720 1.1 is # maybe we can make these entry points ONLY the OVFL entry points of each routine. 721 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 722 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1) 723 1.1 is 724 1.1 is # the operation has been emulated. the result is in fp0. 725 1.1 is # the EXOP, if an exception occurred, is in fp1. 726 1.1 is # we must save the default result regardless of whether 727 1.1 is # traps are enabled or disabled. 728 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 729 1.1 is bsr.l store_fpreg 730 1.1 is 731 1.1 is # the exceptional possibilities we have left ourselves with are ONLY overflow 732 1.1 is # and inexact. and, the inexact is such that overflow occurred and was disabled 733 1.1 is # but inexact was enabled. 734 1.1 is btst &ovfl_bit,FPCR_ENABLE(%a6) 735 1.1 is bne.b fovfl_ovfl_on 736 1.1 is 737 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) 738 1.1 is bne.b fovfl_inex_on 739 1.1 is 740 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 741 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 742 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 743 1.1 is 744 1.1 is unlk %a6 745 1.1 is #$# add.l &24,%sp 746 1.1 is bra.l _fpsp_done 747 1.1 is 748 1.1 is # overflow is enabled AND overflow, of course, occurred. so, we have the EXOP 749 1.1 is # in fp1. now, simply jump to _real_ovfl()! 750 1.1 is fovfl_ovfl_on: 751 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack 752 1.1 is 753 1.1 is mov.w &0xe005,2+FP_SRC(%a6) # save exc status 754 1.1 is 755 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 756 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 757 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 758 1.1 is 759 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 760 1.1 is 761 1.1 is unlk %a6 762 1.1 is 763 1.1 is bra.l _real_ovfl 764 1.1 is 765 1.1 is # overflow occurred but is disabled. meanwhile, inexact is enabled. therefore, 766 1.1 is # we must jump to real_inex(). 767 1.1 is fovfl_inex_on: 768 1.1 is 769 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack 770 1.1 is 771 1.1 is mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4 772 1.1 is mov.w &0xe001,2+FP_SRC(%a6) # save exc status 773 1.1 is 774 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 775 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 776 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 777 1.1 is 778 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 779 1.1 is 780 1.1 is unlk %a6 781 1.1 is 782 1.1 is bra.l _real_inex 783 1.1 is 784 1.1 is ######################################################################## 785 1.1 is fovfl_out: 786 1.1 is 787 1.1 is 788 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 789 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 790 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 791 1.1 is 792 1.1 is # the src operand is definitely a NORM(!), so tag it as such 793 1.1 is mov.b &NORM,STAG(%a6) # set src optype tag 794 1.1 is 795 1.1 is clr.l %d0 796 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 797 1.1 is 798 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field 799 1.1 is 800 1.1 is fmov.l &0x0,%fpcr # zero current control regs 801 1.1 is fmov.l &0x0,%fpsr 802 1.1 is 803 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand 804 1.1 is 805 1.1 is bsr.l fout 806 1.1 is 807 1.1 is btst &ovfl_bit,FPCR_ENABLE(%a6) 808 1.1 is bne.w fovfl_ovfl_on 809 1.1 is 810 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) 811 1.1 is bne.w fovfl_inex_on 812 1.1 is 813 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 814 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 815 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 816 1.1 is 817 1.1 is unlk %a6 818 1.1 is #$# add.l &24,%sp 819 1.1 is 820 1.1 is btst &0x7,(%sp) # is trace on? 821 1.1 is beq.l _fpsp_done # no 822 1.1 is 823 1.1 is fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR 824 1.1 is mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 825 1.1 is bra.l _real_trace 826 1.1 is 827 1.1 is ######################################################################### 828 1.1 is # XDEF **************************************************************** # 829 1.1 is # _fpsp_unfl(): 060FPSP entry point for FP Underflow exception. # 830 1.1 is # # 831 1.1 is # This handler should be the first code executed upon taking the # 832 1.1 is # FP Underflow exception in an operating system. # 833 1.1 is # # 834 1.1 is # XREF **************************************************************** # 835 1.1 is # _imem_read_long() - read instruction longword # 836 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame # 837 1.1 is # set_tag_x() - determine optype of src/dst operands # 838 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile # 839 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO # 840 1.1 is # load_fpn2() - load dst operand from FP regfile # 841 1.1 is # fout() - emulate an opclass 3 instruction # 842 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 # 843 1.1 is # _fpsp_done() - "callout" for 060FPSP exit (all work done!) # 844 1.1 is # _real_ovfl() - "callout" for Overflow exception enabled code # 845 1.1 is # _real_inex() - "callout" for Inexact exception enabled code # 846 1.1 is # _real_trace() - "callout" for Trace exception code # 847 1.1 is # # 848 1.1 is # INPUT *************************************************************** # 849 1.1 is # - The system stack contains the FP Unfl exception stack frame # 850 1.1 is # - The fsave frame contains the source operand # 851 1.1 is # # 852 1.1 is # OUTPUT ************************************************************** # 853 1.1 is # Underflow Exception enabled: # 854 1.1 is # - The system stack is unchanged # 855 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 # 856 1.1 is # Underflow Exception disabled: # 857 1.1 is # - The system stack is unchanged # 858 1.1 is # - The "exception present" flag in the fsave frame is cleared # 859 1.1 is # # 860 1.1 is # ALGORITHM *********************************************************** # 861 1.1 is # On the 060, if an FP underflow is present as the result of any # 862 1.1 is # instruction, the 060 will take an underflow exception whether the # 863 1.1 is # exception is enabled or disabled in the FPCR. For the disabled case, # 864 1.1 is # This handler emulates the instruction to determine what the correct # 865 1.1 is # default result should be for the operation. This default result is # 866 1.1 is # then stored in either the FP regfile, data regfile, or memory. # 867 1.1 is # Finally, the handler exits through the "callout" _fpsp_done() # 868 1.1 is # denoting that no exceptional conditions exist within the machine. # 869 1.1 is # If the exception is enabled, then this handler must create the # 870 1.1 is # exceptional operand and plave it in the fsave state frame, and store # 871 1.1 is # the default result (only if the instruction is opclass 3). For # 872 1.1 is # exceptions enabled, this handler must exit through the "callout" # 873 1.1 is # _real_unfl() so that the operating system enabled overflow handler # 874 1.1 is # can handle this case. # 875 1.1 is # Two other conditions exist. First, if underflow was disabled # 876 1.1 is # but the inexact exception was enabled and the result was inexact, # 877 1.1 is # this handler must exit through the "callout" _real_inex(). # 878 1.1 is # was inexact. # 879 1.1 is # Also, in the case of an opclass three instruction where # 880 1.1 is # underflow was disabled and the trace exception was enabled, this # 881 1.1 is # handler must exit through the "callout" _real_trace(). # 882 1.1 is # # 883 1.1 is ######################################################################### 884 1.1 is 885 1.1 is global _fpsp_unfl 886 1.1 is _fpsp_unfl: 887 1.1 is 888 1.1 is #$# sub.l &24,%sp # make room for src/dst 889 1.1 is 890 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame 891 1.1 is 892 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame 893 1.1 is 894 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 895 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 896 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 897 1.1 is 898 1.1 is # the FPIAR holds the "current PC" of the faulting instruction 899 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 900 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 901 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 902 1.1 is bsr.l _imem_read_long # fetch the instruction words 903 1.1 is mov.l %d0,EXC_OPWORD(%a6) 904 1.1 is 905 1.1 is ############################################################################## 906 1.1 is 907 1.1 is btst &0x5,EXC_CMDREG(%a6) # is instr an fmove out? 908 1.1 is bne.w funfl_out 909 1.1 is 910 1.1 is 911 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 912 1.1 is bsr.l fix_skewed_ops # fix src op 913 1.1 is 914 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 915 1.1 is bsr.l set_tag_x # tag the operand type 916 1.1 is mov.b %d0,STAG(%a6) # maybe NORM,DENORM 917 1.1 is 918 1.1 is # bit five of the fp ext word separates the monadic and dyadic operations 919 1.1 is # that can pass through fpsp_unfl(). remember that fcmp, and ftst 920 1.1 is # will never take this exception. 921 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is op monadic or dyadic? 922 1.1 is beq.b funfl_extract # monadic 923 1.1 is 924 1.1 is # now, what's left that's not dyadic is fsincos. we can distinguish it 925 1.1 is # from all dyadics by the '0110xxx pattern 926 1.1 is btst &0x4,1+EXC_CMDREG(%a6) # is op an fsincos? 927 1.1 is bne.b funfl_extract # yes 928 1.1 is 929 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 930 1.1 is bsr.l load_fpn2 # load dst into FP_DST 931 1.1 is 932 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op 933 1.1 is bsr.l set_tag_x # tag the operand type 934 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 935 1.1 is bne.b funfl_op2_done # no 936 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 937 1.1 is funfl_op2_done: 938 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag 939 1.1 is 940 1.1 is funfl_extract: 941 1.1 is 942 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 943 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 944 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 945 1.1 is #$# mov.l FP_DST_EX(%a6),TRAP_DSTOP_EX(%a6) 946 1.1 is #$# mov.l FP_DST_HI(%a6),TRAP_DSTOP_HI(%a6) 947 1.1 is #$# mov.l FP_DST_LO(%a6),TRAP_DSTOP_LO(%a6) 948 1.1 is 949 1.1 is clr.l %d0 950 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 951 1.1 is 952 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1 953 1.1 is andi.w &0x007f,%d1 # extract extension 954 1.1 is 955 1.1 is andi.l &0x00ff01ff,USER_FPSR(%a6) 956 1.1 is 957 1.1 is fmov.l &0x0,%fpcr # zero current control regs 958 1.1 is fmov.l &0x0,%fpsr 959 1.1 is 960 1.1 is lea FP_SRC(%a6),%a0 961 1.1 is lea FP_DST(%a6),%a1 962 1.1 is 963 1.1 is # maybe we can make these entry points ONLY the OVFL entry points of each routine. 964 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 965 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1) 966 1.1 is 967 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 968 1.1 is bsr.l store_fpreg 969 1.1 is 970 1.1 is # The `060 FPU multiplier hardware is such that if the result of a 971 1.1 is # multiply operation is the smallest possible normalized number 972 1.1 is # (0x00000000_80000000_00000000), then the machine will take an 973 1.1 is # underflow exception. Since this is incorrect, we need to check 974 1.1 is # if our emulation, after re-doing the operation, decided that 975 1.1 is # no underflow was called for. We do these checks only in 976 1.1 is # funfl_{unfl,inex}_on() because w/ both exceptions disabled, this 977 1.1 is # special case will simply exit gracefully with the correct result. 978 1.1 is 979 1.1 is # the exceptional possibilities we have left ourselves with are ONLY overflow 980 1.1 is # and inexact. and, the inexact is such that overflow occurred and was disabled 981 1.1 is # but inexact was enabled. 982 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) 983 1.1 is bne.b funfl_unfl_on 984 1.1 is 985 1.1 is funfl_chkinex: 986 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) 987 1.1 is bne.b funfl_inex_on 988 1.1 is 989 1.1 is funfl_exit: 990 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 991 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 992 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 993 1.1 is 994 1.1 is unlk %a6 995 1.1 is #$# add.l &24,%sp 996 1.1 is bra.l _fpsp_done 997 1.1 is 998 1.1 is # overflow is enabled AND overflow, of course, occurred. so, we have the EXOP 999 1.1 is # in fp1 (don't forget to save fp0). what to do now? 1000 1.1 is # well, we simply have to get to go to _real_unfl()! 1001 1.1 is funfl_unfl_on: 1002 1.1 is 1003 1.1 is # The `060 FPU multiplier hardware is such that if the result of a 1004 1.1 is # multiply operation is the smallest possible normalized number 1005 1.1 is # (0x00000000_80000000_00000000), then the machine will take an 1006 1.1 is # underflow exception. Since this is incorrect, we check here to see 1007 1.1 is # if our emulation, after re-doing the operation, decided that 1008 1.1 is # no underflow was called for. 1009 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6) 1010 1.1 is beq.w funfl_chkinex 1011 1.1 is 1012 1.1 is funfl_unfl_on2: 1013 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP (fp1) to stack 1014 1.1 is 1015 1.1 is mov.w &0xe003,2+FP_SRC(%a6) # save exc status 1016 1.1 is 1017 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 1018 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1019 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1020 1.1 is 1021 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 1022 1.1 is 1023 1.1 is unlk %a6 1024 1.1 is 1025 1.1 is bra.l _real_unfl 1026 1.1 is 1027 1.1 is # undeflow occurred but is disabled. meanwhile, inexact is enabled. therefore, 1028 1.1 is # we must jump to real_inex(). 1029 1.1 is funfl_inex_on: 1030 1.1 is 1031 1.1 is # The `060 FPU multiplier hardware is such that if the result of a 1032 1.1 is # multiply operation is the smallest possible normalized number 1033 1.1 is # (0x00000000_80000000_00000000), then the machine will take an 1034 1.1 is # underflow exception. 1035 1.1 is # But, whether bogus or not, if inexact is enabled AND it occurred, 1036 1.1 is # then we have to branch to real_inex. 1037 1.1 is 1038 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6) 1039 1.1 is beq.w funfl_exit 1040 1.1 is 1041 1.1 is funfl_inex_on2: 1042 1.1 is 1043 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to stack 1044 1.1 is 1045 1.1 is mov.b &0xc4,1+EXC_VOFF(%a6) # vector offset = 0xc4 1046 1.1 is mov.w &0xe001,2+FP_SRC(%a6) # save exc status 1047 1.1 is 1048 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 1049 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1050 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1051 1.1 is 1052 1.1 is frestore FP_SRC(%a6) # do this after fmovm,other f<op>s! 1053 1.1 is 1054 1.1 is unlk %a6 1055 1.1 is 1056 1.1 is bra.l _real_inex 1057 1.1 is 1058 1.1 is ####################################################################### 1059 1.1 is funfl_out: 1060 1.1 is 1061 1.1 is 1062 1.1 is #$# mov.l FP_SRC_EX(%a6),TRAP_SRCOP_EX(%a6) 1063 1.1 is #$# mov.l FP_SRC_HI(%a6),TRAP_SRCOP_HI(%a6) 1064 1.1 is #$# mov.l FP_SRC_LO(%a6),TRAP_SRCOP_LO(%a6) 1065 1.1 is 1066 1.1 is # the src operand is definitely a NORM(!), so tag it as such 1067 1.1 is mov.b &NORM,STAG(%a6) # set src optype tag 1068 1.1 is 1069 1.1 is clr.l %d0 1070 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 1071 1.1 is 1072 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero all but accured field 1073 1.1 is 1074 1.1 is fmov.l &0x0,%fpcr # zero current control regs 1075 1.1 is fmov.l &0x0,%fpsr 1076 1.1 is 1077 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand 1078 1.1 is 1079 1.1 is bsr.l fout 1080 1.1 is 1081 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) 1082 1.1 is bne.w funfl_unfl_on2 1083 1.1 is 1084 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) 1085 1.1 is bne.w funfl_inex_on2 1086 1.1 is 1087 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 1088 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1089 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1090 1.1 is 1091 1.1 is unlk %a6 1092 1.1 is #$# add.l &24,%sp 1093 1.1 is 1094 1.1 is btst &0x7,(%sp) # is trace on? 1095 1.1 is beq.l _fpsp_done # no 1096 1.1 is 1097 1.1 is fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR 1098 1.1 is mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 1099 1.1 is bra.l _real_trace 1100 1.1 is 1101 1.1 is ######################################################################### 1102 1.1 is # XDEF **************************************************************** # 1103 1.1 is # _fpsp_unsupp(): 060FPSP entry point for FP "Unimplemented # 1104 1.1 is # Data Type" exception. # 1105 1.1 is # # 1106 1.1 is # This handler should be the first code executed upon taking the # 1107 1.1 is # FP Unimplemented Data Type exception in an operating system. # 1108 1.1 is # # 1109 1.1 is # XREF **************************************************************** # 1110 1.1 is # _imem_read_{word,long}() - read instruction word/longword # 1111 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame # 1112 1.1 is # set_tag_x() - determine optype of src/dst operands # 1113 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile # 1114 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO # 1115 1.1 is # load_fpn2() - load dst operand from FP regfile # 1116 1.1 is # load_fpn1() - load src operand from FP regfile # 1117 1.1 is # fout() - emulate an opclass 3 instruction # 1118 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 # 1119 1.1 is # _real_inex() - "callout" to operating system inexact handler # 1120 1.1 is # _fpsp_done() - "callout" for exit; work all done # 1121 1.1 is # _real_trace() - "callout" for Trace enabled exception # 1122 1.1 is # funimp_skew() - adjust fsave src ops to "incorrect" value # 1123 1.1 is # _real_snan() - "callout" for SNAN exception # 1124 1.1 is # _real_operr() - "callout" for OPERR exception # 1125 1.1 is # _real_ovfl() - "callout" for OVFL exception # 1126 1.1 is # _real_unfl() - "callout" for UNFL exception # 1127 1.1 is # get_packed() - fetch packed operand from memory # 1128 1.1 is # # 1129 1.1 is # INPUT *************************************************************** # 1130 1.1 is # - The system stack contains the "Unimp Data Type" stk frame # 1131 1.1 is # - The fsave frame contains the ssrc op (for UNNORM/DENORM) # 1132 1.1 is # # 1133 1.1 is # OUTPUT ************************************************************** # 1134 1.1 is # If Inexact exception (opclass 3): # 1135 1.1 is # - The system stack is changed to an Inexact exception stk frame # 1136 1.1 is # If SNAN exception (opclass 3): # 1137 1.1 is # - The system stack is changed to an SNAN exception stk frame # 1138 1.1 is # If OPERR exception (opclass 3): # 1139 1.1 is # - The system stack is changed to an OPERR exception stk frame # 1140 1.1 is # If OVFL exception (opclass 3): # 1141 1.1 is # - The system stack is changed to an OVFL exception stk frame # 1142 1.1 is # If UNFL exception (opclass 3): # 1143 1.1 is # - The system stack is changed to an UNFL exception stack frame # 1144 1.1 is # If Trace exception enabled: # 1145 1.1 is # - The system stack is changed to a Trace exception stack frame # 1146 1.1 is # Else: (normal case) # 1147 1.1 is # - Correct result has been stored as appropriate # 1148 1.1 is # # 1149 1.1 is # ALGORITHM *********************************************************** # 1150 1.1 is # Two main instruction types can enter here: (1) DENORM or UNNORM # 1151 1.1 is # unimplemented data types. These can be either opclass 0,2 or 3 # 1152 1.1 is # instructions, and (2) PACKED unimplemented data format instructions # 1153 1.1 is # also of opclasses 0,2, or 3. # 1154 1.1 is # For UNNORM/DENORM opclass 0 and 2, the handler fetches the src # 1155 1.1 is # operand from the fsave state frame and the dst operand (if dyadic) # 1156 1.1 is # from the FP register file. The instruction is then emulated by # 1157 1.1 is # choosing an emulation routine from a table of routines indexed by # 1158 1.1 is # instruction type. Once the instruction has been emulated and result # 1159 1.1 is # saved, then we check to see if any enabled exceptions resulted from # 1160 1.1 is # instruction emulation. If none, then we exit through the "callout" # 1161 1.1 is # _fpsp_done(). If there is an enabled FP exception, then we insert # 1162 1.1 is # this exception into the FPU in the fsave state frame and then exit # 1163 1.1 is # through _fpsp_done(). # 1164 1.1 is # PACKED opclass 0 and 2 is similar in how the instruction is # 1165 1.1 is # emulated and exceptions handled. The differences occur in how the # 1166 1.1 is # handler loads the packed op (by calling get_packed() routine) and # 1167 1.1 is # by the fact that a Trace exception could be pending for PACKED ops. # 1168 1.1 is # If a Trace exception is pending, then the current exception stack # 1169 1.1 is # frame is changed to a Trace exception stack frame and an exit is # 1170 1.1 is # made through _real_trace(). # 1171 1.1 is # For UNNORM/DENORM opclass 3, the actual move out to memory is # 1172 1.1 is # performed by calling the routine fout(). If no exception should occur # 1173 1.1 is # as the result of emulation, then an exit either occurs through # 1174 1.1 is # _fpsp_done() or through _real_trace() if a Trace exception is pending # 1175 1.1 is # (a Trace stack frame must be created here, too). If an FP exception # 1176 1.1 is # should occur, then we must create an exception stack frame of that # 1177 1.1 is # type and jump to either _real_snan(), _real_operr(), _real_inex(), # 1178 1.1 is # _real_unfl(), or _real_ovfl() as appropriate. PACKED opclass 3 # 1179 1.1 is # emulation is performed in a similar manner. # 1180 1.1 is # # 1181 1.1 is ######################################################################### 1182 1.1 is 1183 1.1 is # 1184 1.1 is # (1) DENORM and UNNORM (unimplemented) data types: 1185 1.1 is # 1186 1.1 is # post-instruction 1187 1.1 is # ***************** 1188 1.1 is # * EA * 1189 1.1 is # pre-instruction * * 1190 1.1 is # ***************** ***************** 1191 1.1 is # * 0x0 * 0x0dc * * 0x3 * 0x0dc * 1192 1.1 is # ***************** ***************** 1193 1.1 is # * Next * * Next * 1194 1.1 is # * PC * * PC * 1195 1.1 is # ***************** ***************** 1196 1.1 is # * SR * * SR * 1197 1.1 is # ***************** ***************** 1198 1.1 is # 1199 1.1 is # (2) PACKED format (unsupported) opclasses two and three: 1200 1.1 is # ***************** 1201 1.1 is # * EA * 1202 1.1 is # * * 1203 1.1 is # ***************** 1204 1.1 is # * 0x2 * 0x0dc * 1205 1.1 is # ***************** 1206 1.1 is # * Next * 1207 1.1 is # * PC * 1208 1.1 is # ***************** 1209 1.1 is # * SR * 1210 1.1 is # ***************** 1211 1.1 is # 1212 1.1 is global _fpsp_unsupp 1213 1.1 is _fpsp_unsupp: 1214 1.1 is 1215 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame 1216 1.1 is 1217 1.1 is fsave FP_SRC(%a6) # save fp state 1218 1.1 is 1219 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 1220 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 1221 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 1222 1.1 is 1223 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor mode? 1224 1.1 is bne.b fu_s 1225 1.1 is fu_u: 1226 1.1 is mov.l %usp,%a0 # fetch user stack pointer 1227 1.1 is mov.l %a0,EXC_A7(%a6) # save on stack 1228 1.1 is bra.b fu_cont 1229 1.1 is # if the exception is an opclass zero or two unimplemented data type 1230 1.1 is # exception, then the a7' calculated here is wrong since it doesn't 1231 1.1 is # stack an ea. however, we don't need an a7' for this case anyways. 1232 1.1 is fu_s: 1233 1.1 is lea 0x4+EXC_EA(%a6),%a0 # load old a7' 1234 1.1 is mov.l %a0,EXC_A7(%a6) # save on stack 1235 1.1 is 1236 1.1 is fu_cont: 1237 1.1 is 1238 1.1 is # the FPIAR holds the "current PC" of the faulting instruction 1239 1.1 is # the FPIAR should be set correctly for ALL exceptions passing through 1240 1.1 is # this point. 1241 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 1242 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 1243 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 1244 1.1 is bsr.l _imem_read_long # fetch the instruction words 1245 1.1 is mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD 1246 1.1 is 1247 1.1 is ############################ 1248 1.1 is 1249 1.1 is clr.b SPCOND_FLG(%a6) # clear special condition flag 1250 1.1 is 1251 1.1 is # Separate opclass three (fpn-to-mem) ops since they have a different 1252 1.1 is # stack frame and protocol. 1253 1.1 is btst &0x5,EXC_CMDREG(%a6) # is it an fmove out? 1254 1.1 is bne.w fu_out # yes 1255 1.1 is 1256 1.1 is # Separate packed opclass two instructions. 1257 1.1 is bfextu EXC_CMDREG(%a6){&0:&6},%d0 1258 1.1 is cmpi.b %d0,&0x13 1259 1.1 is beq.w fu_in_pack 1260 1.1 is 1261 1.1 is 1262 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction. 1263 1.1 is # so, since the emulation routines re-create them anyways, zero exception field 1264 1.1 is andi.l &0x00ff00ff,USER_FPSR(%a6) # zero exception field 1265 1.1 is 1266 1.1 is fmov.l &0x0,%fpcr # zero current control regs 1267 1.1 is fmov.l &0x0,%fpsr 1268 1.1 is 1269 1.1 is # Opclass two w/ memory-to-fpn operation will have an incorrect extended 1270 1.1 is # precision format if the src format was single or double and the 1271 1.1 is # source data type was an INF, NAN, DENORM, or UNNORM 1272 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to input 1273 1.1 is bsr.l fix_skewed_ops 1274 1.1 is 1275 1.1 is # we don't know whether the src operand or the dst operand (or both) is the 1276 1.1 is # UNNORM or DENORM. call the function that tags the operand type. if the 1277 1.1 is # input is an UNNORM, then convert it to a NORM, DENORM, or ZERO. 1278 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 1279 1.1 is bsr.l set_tag_x # tag the operand type 1280 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 1281 1.1 is bne.b fu_op2 # no 1282 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 1283 1.1 is 1284 1.1 is fu_op2: 1285 1.1 is mov.b %d0,STAG(%a6) # save src optype tag 1286 1.1 is 1287 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1288 1.1 is 1289 1.1 is # bit five of the fp extension word separates the monadic and dyadic operations 1290 1.1 is # at this point 1291 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 1292 1.1 is beq.b fu_extract # monadic 1293 1.1 is cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst? 1294 1.1 is beq.b fu_extract # yes, so it's monadic, too 1295 1.1 is 1296 1.1 is bsr.l load_fpn2 # load dst into FP_DST 1297 1.1 is 1298 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op 1299 1.1 is bsr.l set_tag_x # tag the operand type 1300 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 1301 1.1 is bne.b fu_op2_done # no 1302 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 1303 1.1 is fu_op2_done: 1304 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag 1305 1.1 is 1306 1.1 is fu_extract: 1307 1.1 is clr.l %d0 1308 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 1309 1.1 is 1310 1.1 is bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension 1311 1.1 is 1312 1.1 is lea FP_SRC(%a6),%a0 1313 1.1 is lea FP_DST(%a6),%a1 1314 1.1 is 1315 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr 1316 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1) 1317 1.1 is 1318 1.1 is # 1319 1.1 is # Exceptions in order of precedence: 1320 1.1 is # BSUN : none 1321 1.1 is # SNAN : all dyadic ops 1322 1.1 is # OPERR : fsqrt(-NORM) 1323 1.1 is # OVFL : all except ftst,fcmp 1324 1.1 is # UNFL : all except ftst,fcmp 1325 1.1 is # DZ : fdiv 1326 1.1 is # INEX2 : all except ftst,fcmp 1327 1.1 is # INEX1 : none (packed doesn't go through here) 1328 1.1 is # 1329 1.1 is 1330 1.1 is # we determine the highest priority exception(if any) set by the 1331 1.1 is # emulation routine that has also been enabled by the user. 1332 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions set 1333 1.1 is bne.b fu_in_ena # some are enabled 1334 1.1 is 1335 1.1 is fu_in_cont: 1336 1.1 is # fcmp and ftst do not store any result. 1337 1.1 is mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension 1338 1.1 is andi.b &0x38,%d0 # extract bits 3-5 1339 1.1 is cmpi.b %d0,&0x38 # is instr fcmp or ftst? 1340 1.1 is beq.b fu_in_exit # yes 1341 1.1 is 1342 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1343 1.1 is bsr.l store_fpreg # store the result 1344 1.1 is 1345 1.1 is fu_in_exit: 1346 1.1 is 1347 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1348 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1349 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1350 1.1 is 1351 1.1 is unlk %a6 1352 1.1 is 1353 1.1 is bra.l _fpsp_done 1354 1.1 is 1355 1.1 is fu_in_ena: 1356 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled 1357 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception 1358 1.1 is bne.b fu_in_exc # there is at least one set 1359 1.1 is 1360 1.1 is # 1361 1.1 is # No exceptions occurred that were also enabled. Now: 1362 1.1 is # 1363 1.1 is # if (OVFL && ovfl_disabled && inexact_enabled) { 1364 1.1 is # branch to _real_inex() (even if the result was exact!); 1365 1.1 is # } else { 1366 1.1 is # save the result in the proper fp reg (unless the op is fcmp or ftst); 1367 1.1 is # return; 1368 1.1 is # } 1369 1.1 is # 1370 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? 1371 1.1 is beq.b fu_in_cont # no 1372 1.1 is 1373 1.1 is fu_in_ovflchk: 1374 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? 1375 1.1 is beq.b fu_in_cont # no 1376 1.1 is bra.w fu_in_exc_ovfl # go insert overflow frame 1377 1.1 is 1378 1.1 is # 1379 1.1 is # An exception occurred and that exception was enabled: 1380 1.1 is # 1381 1.1 is # shift enabled exception field into lo byte of d0; 1382 1.1 is # if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) || 1383 1.1 is # ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) { 1384 1.1 is # /* 1385 1.1 is # * this is the case where we must call _real_inex() now or else 1386 1.1 is # * there will be no other way to pass it the exceptional operand 1387 1.1 is # */ 1388 1.1 is # call _real_inex(); 1389 1.1 is # } else { 1390 1.1 is # restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU; 1391 1.1 is # } 1392 1.1 is # 1393 1.1 is fu_in_exc: 1394 1.1 is subi.l &24,%d0 # fix offset to be 0-8 1395 1.1 is cmpi.b %d0,&0x6 # is exception INEX? (6) 1396 1.1 is bne.b fu_in_exc_exit # no 1397 1.1 is 1398 1.1 is # the enabled exception was inexact 1399 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur? 1400 1.1 is bne.w fu_in_exc_unfl # yes 1401 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur? 1402 1.1 is bne.w fu_in_exc_ovfl # yes 1403 1.1 is 1404 1.1 is # here, we insert the correct fsave status value into the fsave frame for the 1405 1.1 is # corresponding exception. the operand in the fsave frame should be the original 1406 1.1 is # src operand. 1407 1.1 is fu_in_exc_exit: 1408 1.1 is mov.l %d0,-(%sp) # save d0 1409 1.1 is bsr.l funimp_skew # skew sgl or dbl inputs 1410 1.1 is mov.l (%sp)+,%d0 # restore d0 1411 1.1 is 1412 1.1 is mov.w (tbl_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) # create exc status 1413 1.1 is 1414 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1415 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1416 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1417 1.1 is 1418 1.1 is frestore FP_SRC(%a6) # restore src op 1419 1.1 is 1420 1.1 is unlk %a6 1421 1.1 is 1422 1.1 is bra.l _fpsp_done 1423 1.1 is 1424 1.1 is tbl_except: 1425 1.1 is short 0xe000,0xe006,0xe004,0xe005 1426 1.1 is short 0xe003,0xe002,0xe001,0xe001 1427 1.1 is 1428 1.1 is fu_in_exc_unfl: 1429 1.1 is mov.w &0x4,%d0 1430 1.1 is bra.b fu_in_exc_exit 1431 1.1 is fu_in_exc_ovfl: 1432 1.1 is mov.w &0x03,%d0 1433 1.1 is bra.b fu_in_exc_exit 1434 1.1 is 1435 1.1 is # If the input operand to this operation was opclass two and a single 1436 1.1 is # or double precision denorm, inf, or nan, the operand needs to be 1437 1.1 is # "corrected" in order to have the proper equivalent extended precision 1438 1.1 is # number. 1439 1.1 is global fix_skewed_ops 1440 1.1 is fix_skewed_ops: 1441 1.1 is bfextu EXC_CMDREG(%a6){&0:&6},%d0 # extract opclass,src fmt 1442 1.1 is cmpi.b %d0,&0x11 # is class = 2 & fmt = sgl? 1443 1.1 is beq.b fso_sgl # yes 1444 1.1 is cmpi.b %d0,&0x15 # is class = 2 & fmt = dbl? 1445 1.1 is beq.b fso_dbl # yes 1446 1.1 is rts # no 1447 1.1 is 1448 1.1 is fso_sgl: 1449 1.1 is mov.w LOCAL_EX(%a0),%d0 # fetch src exponent 1450 1.1 is andi.w &0x7fff,%d0 # strip sign 1451 1.1 is cmpi.w %d0,&0x3f80 # is |exp| == $3f80? 1452 1.1 is beq.b fso_sgl_dnrm_zero # yes 1453 1.1 is cmpi.w %d0,&0x407f # no; is |exp| == $407f? 1454 1.1 is beq.b fso_infnan # yes 1455 1.1 is rts # no 1456 1.1 is 1457 1.1 is fso_sgl_dnrm_zero: 1458 1.1 is andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit 1459 1.1 is beq.b fso_zero # it's a skewed zero 1460 1.1 is fso_sgl_dnrm: 1461 1.1 is # here, we count on norm not to alter a0... 1462 1.1 is bsr.l norm # normalize mantissa 1463 1.1 is neg.w %d0 # -shft amt 1464 1.1 is addi.w &0x3f81,%d0 # adjust new exponent 1465 1.1 is andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent 1466 1.1 is or.w %d0,LOCAL_EX(%a0) # insert new exponent 1467 1.1 is rts 1468 1.1 is 1469 1.1 is fso_zero: 1470 1.1 is andi.w &0x8000,LOCAL_EX(%a0) # clear bogus exponent 1471 1.1 is rts 1472 1.1 is 1473 1.1 is fso_infnan: 1474 1.1 is andi.b &0x7f,LOCAL_HI(%a0) # clear j-bit 1475 1.1 is ori.w &0x7fff,LOCAL_EX(%a0) # make exponent = $7fff 1476 1.1 is rts 1477 1.1 is 1478 1.1 is fso_dbl: 1479 1.1 is mov.w LOCAL_EX(%a0),%d0 # fetch src exponent 1480 1.1 is andi.w &0x7fff,%d0 # strip sign 1481 1.1 is cmpi.w %d0,&0x3c00 # is |exp| == $3c00? 1482 1.1 is beq.b fso_dbl_dnrm_zero # yes 1483 1.1 is cmpi.w %d0,&0x43ff # no; is |exp| == $43ff? 1484 1.1 is beq.b fso_infnan # yes 1485 1.1 is rts # no 1486 1.1 is 1487 1.1 is fso_dbl_dnrm_zero: 1488 1.1 is andi.l &0x7fffffff,LOCAL_HI(%a0) # clear j-bit 1489 1.1 is bne.b fso_dbl_dnrm # it's a skewed denorm 1490 1.1 is tst.l LOCAL_LO(%a0) # is it a zero? 1491 1.1 is beq.b fso_zero # yes 1492 1.1 is fso_dbl_dnrm: 1493 1.1 is # here, we count on norm not to alter a0... 1494 1.1 is bsr.l norm # normalize mantissa 1495 1.1 is neg.w %d0 # -shft amt 1496 1.1 is addi.w &0x3c01,%d0 # adjust new exponent 1497 1.1 is andi.w &0x8000,LOCAL_EX(%a0) # clear old exponent 1498 1.1 is or.w %d0,LOCAL_EX(%a0) # insert new exponent 1499 1.1 is rts 1500 1.1 is 1501 1.1 is ################################################################# 1502 1.1 is 1503 1.1 is # fmove out took an unimplemented data type exception. 1504 1.1 is # the src operand is in FP_SRC. Call _fout() to write out the result and 1505 1.1 is # to determine which exceptions, if any, to take. 1506 1.1 is fu_out: 1507 1.1 is 1508 1.1 is # Separate packed move outs from the UNNORM and DENORM move outs. 1509 1.1 is bfextu EXC_CMDREG(%a6){&3:&3},%d0 1510 1.1 is cmpi.b %d0,&0x3 1511 1.1 is beq.w fu_out_pack 1512 1.1 is cmpi.b %d0,&0x7 1513 1.1 is beq.w fu_out_pack 1514 1.1 is 1515 1.1 is 1516 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction. 1517 1.1 is # so, since the emulation routines re-create them anyways, zero exception field. 1518 1.1 is # fmove out doesn't affect ccodes. 1519 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field 1520 1.1 is 1521 1.1 is fmov.l &0x0,%fpcr # zero current control regs 1522 1.1 is fmov.l &0x0,%fpsr 1523 1.1 is 1524 1.1 is # the src can ONLY be a DENORM or an UNNORM! so, don't make any big subroutine 1525 1.1 is # call here. just figure out what it is... 1526 1.1 is mov.w FP_SRC_EX(%a6),%d0 # get exponent 1527 1.1 is andi.w &0x7fff,%d0 # strip sign 1528 1.1 is beq.b fu_out_denorm # it's a DENORM 1529 1.1 is 1530 1.1 is lea FP_SRC(%a6),%a0 1531 1.1 is bsr.l unnorm_fix # yes; fix it 1532 1.1 is 1533 1.1 is mov.b %d0,STAG(%a6) 1534 1.1 is 1535 1.1 is bra.b fu_out_cont 1536 1.1 is fu_out_denorm: 1537 1.1 is mov.b &DENORM,STAG(%a6) 1538 1.1 is fu_out_cont: 1539 1.1 is 1540 1.1 is clr.l %d0 1541 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 1542 1.1 is 1543 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand 1544 1.1 is 1545 1.1 is mov.l (%a6),EXC_A6(%a6) # in case a6 changes 1546 1.1 is bsr.l fout # call fmove out routine 1547 1.1 is 1548 1.1 is # Exceptions in order of precedence: 1549 1.1 is # BSUN : none 1550 1.1 is # SNAN : none 1551 1.1 is # OPERR : fmove.{b,w,l} out of large UNNORM 1552 1.1 is # OVFL : fmove.{s,d} 1553 1.1 is # UNFL : fmove.{s,d,x} 1554 1.1 is # DZ : none 1555 1.1 is # INEX2 : all 1556 1.1 is # INEX1 : none (packed doesn't travel through here) 1557 1.1 is 1558 1.1 is # determine the highest priority exception(if any) set by the 1559 1.1 is # emulation routine that has also been enabled by the user. 1560 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 1561 1.1 is bne.w fu_out_ena # some are enabled 1562 1.1 is 1563 1.1 is fu_out_done: 1564 1.1 is 1565 1.1 is mov.l EXC_A6(%a6),(%a6) # in case a6 changed 1566 1.1 is 1567 1.1 is # on extended precision opclass three instructions using pre-decrement or 1568 1.1 is # post-increment addressing mode, the address register is not updated. is the 1569 1.1 is # address register was the stack pointer used from user mode, then let's update 1570 1.1 is # it here. if it was used from supervisor mode, then we have to handle this 1571 1.1 is # as a special case. 1572 1.1 is btst &0x5,EXC_SR(%a6) 1573 1.1 is bne.b fu_out_done_s 1574 1.1 is 1575 1.1 is mov.l EXC_A7(%a6),%a0 # restore a7 1576 1.1 is mov.l %a0,%usp 1577 1.1 is 1578 1.1 is fu_out_done_cont: 1579 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1580 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1581 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1582 1.1 is 1583 1.1 is unlk %a6 1584 1.1 is 1585 1.1 is btst &0x7,(%sp) # is trace on? 1586 1.1 is bne.b fu_out_trace # yes 1587 1.1 is 1588 1.1 is bra.l _fpsp_done 1589 1.1 is 1590 1.1 is # is the ea mode pre-decrement of the stack pointer from supervisor mode? 1591 1.1 is # ("fmov.x fpm,-(a7)") if so, 1592 1.1 is fu_out_done_s: 1593 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg 1594 1.1 is bne.b fu_out_done_cont 1595 1.1 is 1596 1.1 is # the extended precision result is still in fp0. but, we need to save it 1597 1.1 is # somewhere on the stack until we can copy it to its final resting place. 1598 1.1 is # here, we're counting on the top of the stack to be the old place-holders 1599 1.1 is # for fp0/fp1 which have already been restored. that way, we can write 1600 1.1 is # over those destinations with the shifted stack frame. 1601 1.1 is fmovm.x &0x80,FP_SRC(%a6) # put answer on stack 1602 1.1 is 1603 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1604 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1605 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1606 1.1 is 1607 1.1 is mov.l (%a6),%a6 # restore frame pointer 1608 1.1 is 1609 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 1610 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 1611 1.1 is 1612 1.1 is # now, copy the result to the proper place on the stack 1613 1.1 is mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) 1614 1.1 is mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) 1615 1.1 is mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) 1616 1.1 is 1617 1.1 is add.l &LOCAL_SIZE-0x8,%sp 1618 1.1 is 1619 1.1 is btst &0x7,(%sp) 1620 1.1 is bne.b fu_out_trace 1621 1.1 is 1622 1.1 is bra.l _fpsp_done 1623 1.1 is 1624 1.1 is fu_out_ena: 1625 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled 1626 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception 1627 1.1 is bne.b fu_out_exc # there is at least one set 1628 1.1 is 1629 1.1 is # no exceptions were set. 1630 1.1 is # if a disabled overflow occurred and inexact was enabled but the result 1631 1.1 is # was exact, then a branch to _real_inex() is made. 1632 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? 1633 1.1 is beq.w fu_out_done # no 1634 1.1 is 1635 1.1 is fu_out_ovflchk: 1636 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? 1637 1.1 is beq.w fu_out_done # no 1638 1.1 is bra.w fu_inex # yes 1639 1.1 is 1640 1.1 is # 1641 1.1 is # The fp move out that took the "Unimplemented Data Type" exception was 1642 1.1 is # being traced. Since the stack frames are similar, get the "current" PC 1643 1.1 is # from FPIAR and put it in the trace stack frame then jump to _real_trace(). 1644 1.1 is # 1645 1.1 is # UNSUPP FRAME TRACE FRAME 1646 1.1 is # ***************** ***************** 1647 1.1 is # * EA * * Current * 1648 1.1 is # * * * PC * 1649 1.1 is # ***************** ***************** 1650 1.1 is # * 0x3 * 0x0dc * * 0x2 * 0x024 * 1651 1.1 is # ***************** ***************** 1652 1.1 is # * Next * * Next * 1653 1.1 is # * PC * * PC * 1654 1.1 is # ***************** ***************** 1655 1.1 is # * SR * * SR * 1656 1.1 is # ***************** ***************** 1657 1.1 is # 1658 1.1 is fu_out_trace: 1659 1.1 is mov.w &0x2024,0x6(%sp) 1660 1.1 is fmov.l %fpiar,0x8(%sp) 1661 1.1 is bra.l _real_trace 1662 1.1 is 1663 1.1 is # an exception occurred and that exception was enabled. 1664 1.1 is fu_out_exc: 1665 1.1 is subi.l &24,%d0 # fix offset to be 0-8 1666 1.1 is 1667 1.1 is # we don't mess with the existing fsave frame. just re-insert it and 1668 1.1 is # jump to the "_real_{}()" handler... 1669 1.1 is mov.w (tbl_fu_out.b,%pc,%d0.w*2),%d0 1670 1.1 is jmp (tbl_fu_out.b,%pc,%d0.w*1) 1671 1.1 is 1672 1.1 is swbeg &0x8 1673 1.1 is tbl_fu_out: 1674 1.1 is short tbl_fu_out - tbl_fu_out # BSUN can't happen 1675 1.1 is short tbl_fu_out - tbl_fu_out # SNAN can't happen 1676 1.1 is short fu_operr - tbl_fu_out # OPERR 1677 1.1 is short fu_ovfl - tbl_fu_out # OVFL 1678 1.1 is short fu_unfl - tbl_fu_out # UNFL 1679 1.1 is short tbl_fu_out - tbl_fu_out # DZ can't happen 1680 1.1 is short fu_inex - tbl_fu_out # INEX2 1681 1.1 is short tbl_fu_out - tbl_fu_out # INEX1 won't make it here 1682 1.1 is 1683 1.1 is # for snan,operr,ovfl,unfl, src op is still in FP_SRC so just 1684 1.1 is # frestore it. 1685 1.1 is fu_snan: 1686 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1687 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1688 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1689 1.1 is 1690 1.1 is mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd8 1691 1.1 is mov.w &0xe006,2+FP_SRC(%a6) 1692 1.1 is 1693 1.1 is frestore FP_SRC(%a6) 1694 1.1 is 1695 1.1 is unlk %a6 1696 1.1 is 1697 1.1 is 1698 1.1 is bra.l _real_snan 1699 1.1 is 1700 1.1 is fu_operr: 1701 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1702 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1703 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1704 1.1 is 1705 1.1 is mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0 1706 1.1 is mov.w &0xe004,2+FP_SRC(%a6) 1707 1.1 is 1708 1.1 is frestore FP_SRC(%a6) 1709 1.1 is 1710 1.1 is unlk %a6 1711 1.1 is 1712 1.1 is 1713 1.1 is bra.l _real_operr 1714 1.1 is 1715 1.1 is fu_ovfl: 1716 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack 1717 1.1 is 1718 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1719 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1720 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1721 1.1 is 1722 1.1 is mov.w &0x30d4,EXC_VOFF(%a6) # vector offset = 0xd4 1723 1.1 is mov.w &0xe005,2+FP_SRC(%a6) 1724 1.1 is 1725 1.1 is frestore FP_SRC(%a6) # restore EXOP 1726 1.1 is 1727 1.1 is unlk %a6 1728 1.1 is 1729 1.1 is bra.l _real_ovfl 1730 1.1 is 1731 1.1 is # underflow can happen for extended precision. extended precision opclass 1732 1.1 is # three instruction exceptions don't update the stack pointer. so, if the 1733 1.1 is # exception occurred from user mode, then simply update a7 and exit normally. 1734 1.1 is # if the exception occurred from supervisor mode, check if 1735 1.1 is fu_unfl: 1736 1.1 is mov.l EXC_A6(%a6),(%a6) # restore a6 1737 1.1 is 1738 1.1 is btst &0x5,EXC_SR(%a6) 1739 1.1 is bne.w fu_unfl_s 1740 1.1 is 1741 1.1 is mov.l EXC_A7(%a6),%a0 # restore a7 whether we need 1742 1.1 is mov.l %a0,%usp # to or not... 1743 1.1 is 1744 1.1 is fu_unfl_cont: 1745 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack 1746 1.1 is 1747 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1748 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1749 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1750 1.1 is 1751 1.1 is mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc 1752 1.1 is mov.w &0xe003,2+FP_SRC(%a6) 1753 1.1 is 1754 1.1 is frestore FP_SRC(%a6) # restore EXOP 1755 1.1 is 1756 1.1 is unlk %a6 1757 1.1 is 1758 1.1 is bra.l _real_unfl 1759 1.1 is 1760 1.1 is fu_unfl_s: 1761 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg # was the <ea> mode -(sp)? 1762 1.1 is bne.b fu_unfl_cont 1763 1.1 is 1764 1.1 is # the extended precision result is still in fp0. but, we need to save it 1765 1.1 is # somewhere on the stack until we can copy it to its final resting place 1766 1.1 is # (where the exc frame is currently). make sure it's not at the top of the 1767 1.1 is # frame or it will get overwritten when the exc stack frame is shifted "down". 1768 1.1 is fmovm.x &0x80,FP_SRC(%a6) # put answer on stack 1769 1.1 is fmovm.x &0x40,FP_DST(%a6) # put EXOP on stack 1770 1.1 is 1771 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1772 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1773 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1774 1.1 is 1775 1.1 is mov.w &0x30cc,EXC_VOFF(%a6) # vector offset = 0xcc 1776 1.1 is mov.w &0xe003,2+FP_DST(%a6) 1777 1.1 is 1778 1.1 is frestore FP_DST(%a6) # restore EXOP 1779 1.1 is 1780 1.1 is mov.l (%a6),%a6 # restore frame pointer 1781 1.1 is 1782 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 1783 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 1784 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 1785 1.1 is 1786 1.1 is # now, copy the result to the proper place on the stack 1787 1.1 is mov.l LOCAL_SIZE+FP_SRC_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) 1788 1.1 is mov.l LOCAL_SIZE+FP_SRC_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) 1789 1.1 is mov.l LOCAL_SIZE+FP_SRC_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) 1790 1.1 is 1791 1.1 is add.l &LOCAL_SIZE-0x8,%sp 1792 1.1 is 1793 1.1 is bra.l _real_unfl 1794 1.1 is 1795 1.1 is # fmove in and out enter here. 1796 1.1 is fu_inex: 1797 1.1 is fmovm.x &0x40,FP_SRC(%a6) # save EXOP to the stack 1798 1.1 is 1799 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1800 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1801 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1802 1.1 is 1803 1.1 is mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4 1804 1.1 is mov.w &0xe001,2+FP_SRC(%a6) 1805 1.1 is 1806 1.1 is frestore FP_SRC(%a6) # restore EXOP 1807 1.1 is 1808 1.1 is unlk %a6 1809 1.1 is 1810 1.1 is 1811 1.1 is bra.l _real_inex 1812 1.1 is 1813 1.1 is ######################################################################### 1814 1.1 is ######################################################################### 1815 1.1 is fu_in_pack: 1816 1.1 is 1817 1.1 is 1818 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction. 1819 1.1 is # so, since the emulation routines re-create them anyways, zero exception field 1820 1.1 is andi.l &0x0ff00ff,USER_FPSR(%a6) # zero exception field 1821 1.1 is 1822 1.1 is fmov.l &0x0,%fpcr # zero current control regs 1823 1.1 is fmov.l &0x0,%fpsr 1824 1.1 is 1825 1.1 is bsr.l get_packed # fetch packed src operand 1826 1.1 is 1827 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src 1828 1.1 is bsr.l set_tag_x # set src optype tag 1829 1.1 is 1830 1.1 is mov.b %d0,STAG(%a6) # save src optype tag 1831 1.1 is 1832 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1833 1.1 is 1834 1.1 is # bit five of the fp extension word separates the monadic and dyadic operations 1835 1.1 is # at this point 1836 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 1837 1.1 is beq.b fu_extract_p # monadic 1838 1.1 is cmpi.b 1+EXC_CMDREG(%a6),&0x3a # is operation an ftst? 1839 1.1 is beq.b fu_extract_p # yes, so it's monadic, too 1840 1.1 is 1841 1.1 is bsr.l load_fpn2 # load dst into FP_DST 1842 1.1 is 1843 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op 1844 1.1 is bsr.l set_tag_x # tag the operand type 1845 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 1846 1.1 is bne.b fu_op2_done_p # no 1847 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 1848 1.1 is fu_op2_done_p: 1849 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag 1850 1.1 is 1851 1.1 is fu_extract_p: 1852 1.1 is clr.l %d0 1853 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 1854 1.1 is 1855 1.1 is bfextu 1+EXC_CMDREG(%a6){&1:&7},%d1 # extract extension 1856 1.1 is 1857 1.1 is lea FP_SRC(%a6),%a0 1858 1.1 is lea FP_DST(%a6),%a1 1859 1.1 is 1860 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.l*4),%d1 # fetch routine addr 1861 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1) 1862 1.1 is 1863 1.1 is # 1864 1.1 is # Exceptions in order of precedence: 1865 1.1 is # BSUN : none 1866 1.1 is # SNAN : all dyadic ops 1867 1.1 is # OPERR : fsqrt(-NORM) 1868 1.1 is # OVFL : all except ftst,fcmp 1869 1.1 is # UNFL : all except ftst,fcmp 1870 1.1 is # DZ : fdiv 1871 1.1 is # INEX2 : all except ftst,fcmp 1872 1.1 is # INEX1 : all 1873 1.1 is # 1874 1.1 is 1875 1.1 is # we determine the highest priority exception(if any) set by the 1876 1.1 is # emulation routine that has also been enabled by the user. 1877 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 1878 1.1 is bne.w fu_in_ena_p # some are enabled 1879 1.1 is 1880 1.1 is fu_in_cont_p: 1881 1.1 is # fcmp and ftst do not store any result. 1882 1.1 is mov.b 1+EXC_CMDREG(%a6),%d0 # fetch extension 1883 1.1 is andi.b &0x38,%d0 # extract bits 3-5 1884 1.1 is cmpi.b %d0,&0x38 # is instr fcmp or ftst? 1885 1.1 is beq.b fu_in_exit_p # yes 1886 1.1 is 1887 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 1888 1.1 is bsr.l store_fpreg # store the result 1889 1.1 is 1890 1.1 is fu_in_exit_p: 1891 1.1 is 1892 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor? 1893 1.1 is bne.w fu_in_exit_s_p # supervisor 1894 1.1 is 1895 1.1 is mov.l EXC_A7(%a6),%a0 # update user a7 1896 1.1 is mov.l %a0,%usp 1897 1.1 is 1898 1.1 is fu_in_exit_cont_p: 1899 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1900 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1901 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1902 1.1 is 1903 1.1 is unlk %a6 # unravel stack frame 1904 1.1 is 1905 1.1 is btst &0x7,(%sp) # is trace on? 1906 1.1 is bne.w fu_trace_p # yes 1907 1.1 is 1908 1.1 is bra.l _fpsp_done # exit to os 1909 1.1 is 1910 1.1 is # the exception occurred in supervisor mode. check to see if the 1911 1.1 is # addressing mode was (a7)+. if so, we'll need to shift the 1912 1.1 is # stack frame "up". 1913 1.1 is fu_in_exit_s_p: 1914 1.1 is btst &mia7_bit,SPCOND_FLG(%a6) # was ea mode (a7)+ 1915 1.1 is beq.b fu_in_exit_cont_p # no 1916 1.1 is 1917 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1918 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 1919 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 1920 1.1 is 1921 1.1 is unlk %a6 # unravel stack frame 1922 1.1 is 1923 1.1 is # shift the stack frame "up". we don't really care about the <ea> field. 1924 1.1 is mov.l 0x4(%sp),0x10(%sp) 1925 1.1 is mov.l 0x0(%sp),0xc(%sp) 1926 1.1 is add.l &0xc,%sp 1927 1.1 is 1928 1.1 is btst &0x7,(%sp) # is trace on? 1929 1.1 is bne.w fu_trace_p # yes 1930 1.1 is 1931 1.1 is bra.l _fpsp_done # exit to os 1932 1.1 is 1933 1.1 is fu_in_ena_p: 1934 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled & set 1935 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception 1936 1.1 is bne.b fu_in_exc_p # at least one was set 1937 1.1 is 1938 1.1 is # 1939 1.1 is # No exceptions occurred that were also enabled. Now: 1940 1.1 is # 1941 1.1 is # if (OVFL && ovfl_disabled && inexact_enabled) { 1942 1.1 is # branch to _real_inex() (even if the result was exact!); 1943 1.1 is # } else { 1944 1.1 is # save the result in the proper fp reg (unless the op is fcmp or ftst); 1945 1.1 is # return; 1946 1.1 is # } 1947 1.1 is # 1948 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # was overflow set? 1949 1.1 is beq.w fu_in_cont_p # no 1950 1.1 is 1951 1.1 is fu_in_ovflchk_p: 1952 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # was inexact enabled? 1953 1.1 is beq.w fu_in_cont_p # no 1954 1.1 is bra.w fu_in_exc_ovfl_p # do _real_inex() now 1955 1.1 is 1956 1.1 is # 1957 1.1 is # An exception occurred and that exception was enabled: 1958 1.1 is # 1959 1.1 is # shift enabled exception field into lo byte of d0; 1960 1.1 is # if (((INEX2 || INEX1) && inex_enabled && OVFL && ovfl_disabled) || 1961 1.1 is # ((INEX2 || INEX1) && inex_enabled && UNFL && unfl_disabled)) { 1962 1.1 is # /* 1963 1.1 is # * this is the case where we must call _real_inex() now or else 1964 1.1 is # * there will be no other way to pass it the exceptional operand 1965 1.1 is # */ 1966 1.1 is # call _real_inex(); 1967 1.1 is # } else { 1968 1.1 is # restore exc state (SNAN||OPERR||OVFL||UNFL||DZ||INEX) into the FPU; 1969 1.1 is # } 1970 1.1 is # 1971 1.1 is fu_in_exc_p: 1972 1.1 is subi.l &24,%d0 # fix offset to be 0-8 1973 1.1 is cmpi.b %d0,&0x6 # is exception INEX? (6 or 7) 1974 1.1 is blt.b fu_in_exc_exit_p # no 1975 1.1 is 1976 1.1 is # the enabled exception was inexact 1977 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6) # did disabled underflow occur? 1978 1.1 is bne.w fu_in_exc_unfl_p # yes 1979 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did disabled overflow occur? 1980 1.1 is bne.w fu_in_exc_ovfl_p # yes 1981 1.1 is 1982 1.1 is # here, we insert the correct fsave status value into the fsave frame for the 1983 1.1 is # corresponding exception. the operand in the fsave frame should be the original 1984 1.1 is # src operand. 1985 1.1 is # as a reminder for future predicted pain and agony, we are passing in fsave the 1986 1.1 is # "non-skewed" operand for cases of sgl and dbl src INFs,NANs, and DENORMs. 1987 1.1 is # this is INCORRECT for enabled SNAN which would give to the user the skewed SNAN!!! 1988 1.1 is fu_in_exc_exit_p: 1989 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor? 1990 1.1 is bne.w fu_in_exc_exit_s_p # supervisor 1991 1.1 is 1992 1.1 is mov.l EXC_A7(%a6),%a0 # update user a7 1993 1.1 is mov.l %a0,%usp 1994 1.1 is 1995 1.1 is fu_in_exc_exit_cont_p: 1996 1.1 is mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6) 1997 1.1 is 1998 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 1999 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2000 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2001 1.1 is 2002 1.1 is frestore FP_SRC(%a6) # restore src op 2003 1.1 is 2004 1.1 is unlk %a6 2005 1.1 is 2006 1.1 is btst &0x7,(%sp) # is trace enabled? 2007 1.1 is bne.w fu_trace_p # yes 2008 1.1 is 2009 1.1 is bra.l _fpsp_done 2010 1.1 is 2011 1.1 is tbl_except_p: 2012 1.1 is short 0xe000,0xe006,0xe004,0xe005 2013 1.1 is short 0xe003,0xe002,0xe001,0xe001 2014 1.1 is 2015 1.1 is fu_in_exc_ovfl_p: 2016 1.1 is mov.w &0x3,%d0 2017 1.1 is bra.w fu_in_exc_exit_p 2018 1.1 is 2019 1.1 is fu_in_exc_unfl_p: 2020 1.1 is mov.w &0x4,%d0 2021 1.1 is bra.w fu_in_exc_exit_p 2022 1.1 is 2023 1.1 is fu_in_exc_exit_s_p: 2024 1.1 is btst &mia7_bit,SPCOND_FLG(%a6) 2025 1.1 is beq.b fu_in_exc_exit_cont_p 2026 1.1 is 2027 1.1 is mov.w (tbl_except_p.b,%pc,%d0.w*2),2+FP_SRC(%a6) 2028 1.1 is 2029 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2030 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2031 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2032 1.1 is 2033 1.1 is frestore FP_SRC(%a6) # restore src op 2034 1.1 is 2035 1.1 is unlk %a6 # unravel stack frame 2036 1.1 is 2037 1.1 is # shift stack frame "up". who cares about <ea> field. 2038 1.1 is mov.l 0x4(%sp),0x10(%sp) 2039 1.1 is mov.l 0x0(%sp),0xc(%sp) 2040 1.1 is add.l &0xc,%sp 2041 1.1 is 2042 1.1 is btst &0x7,(%sp) # is trace on? 2043 1.1 is bne.b fu_trace_p # yes 2044 1.1 is 2045 1.1 is bra.l _fpsp_done # exit to os 2046 1.1 is 2047 1.1 is # 2048 1.1 is # The opclass two PACKED instruction that took an "Unimplemented Data Type" 2049 1.1 is # exception was being traced. Make the "current" PC the FPIAR and put it in the 2050 1.1 is # trace stack frame then jump to _real_trace(). 2051 1.1 is # 2052 1.1 is # UNSUPP FRAME TRACE FRAME 2053 1.1 is # ***************** ***************** 2054 1.1 is # * EA * * Current * 2055 1.1 is # * * * PC * 2056 1.1 is # ***************** ***************** 2057 1.1 is # * 0x2 * 0x0dc * * 0x2 * 0x024 * 2058 1.1 is # ***************** ***************** 2059 1.1 is # * Next * * Next * 2060 1.1 is # * PC * * PC * 2061 1.1 is # ***************** ***************** 2062 1.1 is # * SR * * SR * 2063 1.1 is # ***************** ***************** 2064 1.1 is fu_trace_p: 2065 1.1 is mov.w &0x2024,0x6(%sp) 2066 1.1 is fmov.l %fpiar,0x8(%sp) 2067 1.1 is 2068 1.1 is bra.l _real_trace 2069 1.1 is 2070 1.1 is ######################################################### 2071 1.1 is ######################################################### 2072 1.1 is fu_out_pack: 2073 1.1 is 2074 1.1 is 2075 1.1 is # I'm not sure at this point what FPSR bits are valid for this instruction. 2076 1.1 is # so, since the emulation routines re-create them anyways, zero exception field. 2077 1.1 is # fmove out doesn't affect ccodes. 2078 1.1 is and.l &0xffff00ff,USER_FPSR(%a6) # zero exception field 2079 1.1 is 2080 1.1 is fmov.l &0x0,%fpcr # zero current control regs 2081 1.1 is fmov.l &0x0,%fpsr 2082 1.1 is 2083 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 2084 1.1 is bsr.l load_fpn1 2085 1.1 is 2086 1.1 is # unlike other opclass 3, unimplemented data type exceptions, packed must be 2087 1.1 is # able to detect all operand types. 2088 1.1 is lea FP_SRC(%a6),%a0 2089 1.1 is bsr.l set_tag_x # tag the operand type 2090 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 2091 1.1 is bne.b fu_op2_p # no 2092 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 2093 1.1 is 2094 1.1 is fu_op2_p: 2095 1.1 is mov.b %d0,STAG(%a6) # save src optype tag 2096 1.1 is 2097 1.1 is clr.l %d0 2098 1.1 is mov.b FPCR_MODE(%a6),%d0 # fetch rnd mode/prec 2099 1.1 is 2100 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand 2101 1.1 is 2102 1.1 is mov.l (%a6),EXC_A6(%a6) # in case a6 changes 2103 1.1 is bsr.l fout # call fmove out routine 2104 1.1 is 2105 1.1 is # Exceptions in order of precedence: 2106 1.1 is # BSUN : no 2107 1.1 is # SNAN : yes 2108 1.1 is # OPERR : if ((k_factor > +17) || (dec. exp exceeds 3 digits)) 2109 1.1 is # OVFL : no 2110 1.1 is # UNFL : no 2111 1.1 is # DZ : no 2112 1.1 is # INEX2 : yes 2113 1.1 is # INEX1 : no 2114 1.1 is 2115 1.1 is # determine the highest priority exception(if any) set by the 2116 1.1 is # emulation routine that has also been enabled by the user. 2117 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 2118 1.1 is bne.w fu_out_ena_p # some are enabled 2119 1.1 is 2120 1.1 is fu_out_exit_p: 2121 1.1 is mov.l EXC_A6(%a6),(%a6) # restore a6 2122 1.1 is 2123 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor? 2124 1.1 is bne.b fu_out_exit_s_p # supervisor 2125 1.1 is 2126 1.1 is mov.l EXC_A7(%a6),%a0 # update user a7 2127 1.1 is mov.l %a0,%usp 2128 1.1 is 2129 1.1 is fu_out_exit_cont_p: 2130 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2131 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2132 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2133 1.1 is 2134 1.1 is unlk %a6 # unravel stack frame 2135 1.1 is 2136 1.1 is btst &0x7,(%sp) # is trace on? 2137 1.1 is bne.w fu_trace_p # yes 2138 1.1 is 2139 1.1 is bra.l _fpsp_done # exit to os 2140 1.1 is 2141 1.1 is # the exception occurred in supervisor mode. check to see if the 2142 1.1 is # addressing mode was -(a7). if so, we'll need to shift the 2143 1.1 is # stack frame "down". 2144 1.1 is fu_out_exit_s_p: 2145 1.1 is btst &mda7_bit,SPCOND_FLG(%a6) # was ea mode -(a7) 2146 1.1 is beq.b fu_out_exit_cont_p # no 2147 1.1 is 2148 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2149 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2150 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2151 1.1 is 2152 1.1 is mov.l (%a6),%a6 # restore frame pointer 2153 1.1 is 2154 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2155 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2156 1.1 is 2157 1.1 is # now, copy the result to the proper place on the stack 2158 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+EXC_SR+0x0(%sp) 2159 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+EXC_SR+0x4(%sp) 2160 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+EXC_SR+0x8(%sp) 2161 1.1 is 2162 1.1 is add.l &LOCAL_SIZE-0x8,%sp 2163 1.1 is 2164 1.1 is btst &0x7,(%sp) 2165 1.1 is bne.w fu_trace_p 2166 1.1 is 2167 1.1 is bra.l _fpsp_done 2168 1.1 is 2169 1.1 is fu_out_ena_p: 2170 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enabled 2171 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception 2172 1.1 is beq.w fu_out_exit_p 2173 1.1 is 2174 1.1 is mov.l EXC_A6(%a6),(%a6) # restore a6 2175 1.1 is 2176 1.1 is # an exception occurred and that exception was enabled. 2177 1.1 is # the only exception possible on packed move out are INEX, OPERR, and SNAN. 2178 1.1 is fu_out_exc_p: 2179 1.1 is cmpi.b %d0,&0x1a 2180 1.1 is bgt.w fu_inex_p2 2181 1.1 is beq.w fu_operr_p 2182 1.1 is 2183 1.1 is fu_snan_p: 2184 1.1 is btst &0x5,EXC_SR(%a6) 2185 1.1 is bne.b fu_snan_s_p 2186 1.1 is 2187 1.1 is mov.l EXC_A7(%a6),%a0 2188 1.1 is mov.l %a0,%usp 2189 1.1 is bra.w fu_snan 2190 1.1 is 2191 1.1 is fu_snan_s_p: 2192 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg 2193 1.1 is bne.w fu_snan 2194 1.1 is 2195 1.1 is # the instruction was "fmove.p fpn,-(a7)" from supervisor mode. 2196 1.1 is # the strategy is to move the exception frame "down" 12 bytes. then, we 2197 1.1 is # can store the default result where the exception frame was. 2198 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2199 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2200 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2201 1.1 is 2202 1.1 is mov.w &0x30d8,EXC_VOFF(%a6) # vector offset = 0xd0 2203 1.1 is mov.w &0xe006,2+FP_SRC(%a6) # set fsave status 2204 1.1 is 2205 1.1 is frestore FP_SRC(%a6) # restore src operand 2206 1.1 is 2207 1.1 is mov.l (%a6),%a6 # restore frame pointer 2208 1.1 is 2209 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2210 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2211 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 2212 1.1 is 2213 1.1 is # now, we copy the default result to it's proper location 2214 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) 2215 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) 2216 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) 2217 1.1 is 2218 1.1 is add.l &LOCAL_SIZE-0x8,%sp 2219 1.1 is 2220 1.1 is 2221 1.1 is bra.l _real_snan 2222 1.1 is 2223 1.1 is fu_operr_p: 2224 1.1 is btst &0x5,EXC_SR(%a6) 2225 1.1 is bne.w fu_operr_p_s 2226 1.1 is 2227 1.1 is mov.l EXC_A7(%a6),%a0 2228 1.1 is mov.l %a0,%usp 2229 1.1 is bra.w fu_operr 2230 1.1 is 2231 1.1 is fu_operr_p_s: 2232 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg 2233 1.1 is bne.w fu_operr 2234 1.1 is 2235 1.1 is # the instruction was "fmove.p fpn,-(a7)" from supervisor mode. 2236 1.1 is # the strategy is to move the exception frame "down" 12 bytes. then, we 2237 1.1 is # can store the default result where the exception frame was. 2238 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2239 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2240 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2241 1.1 is 2242 1.1 is mov.w &0x30d0,EXC_VOFF(%a6) # vector offset = 0xd0 2243 1.1 is mov.w &0xe004,2+FP_SRC(%a6) # set fsave status 2244 1.1 is 2245 1.1 is frestore FP_SRC(%a6) # restore src operand 2246 1.1 is 2247 1.1 is mov.l (%a6),%a6 # restore frame pointer 2248 1.1 is 2249 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2250 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2251 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 2252 1.1 is 2253 1.1 is # now, we copy the default result to it's proper location 2254 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) 2255 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) 2256 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) 2257 1.1 is 2258 1.1 is add.l &LOCAL_SIZE-0x8,%sp 2259 1.1 is 2260 1.1 is 2261 1.1 is bra.l _real_operr 2262 1.1 is 2263 1.1 is fu_inex_p2: 2264 1.1 is btst &0x5,EXC_SR(%a6) 2265 1.1 is bne.w fu_inex_s_p2 2266 1.1 is 2267 1.1 is mov.l EXC_A7(%a6),%a0 2268 1.1 is mov.l %a0,%usp 2269 1.1 is bra.w fu_inex 2270 1.1 is 2271 1.1 is fu_inex_s_p2: 2272 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg 2273 1.1 is bne.w fu_inex 2274 1.1 is 2275 1.1 is # the instruction was "fmove.p fpn,-(a7)" from supervisor mode. 2276 1.1 is # the strategy is to move the exception frame "down" 12 bytes. then, we 2277 1.1 is # can store the default result where the exception frame was. 2278 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0/fp1 2279 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2280 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2281 1.1 is 2282 1.1 is mov.w &0x30c4,EXC_VOFF(%a6) # vector offset = 0xc4 2283 1.1 is mov.w &0xe001,2+FP_SRC(%a6) # set fsave status 2284 1.1 is 2285 1.1 is frestore FP_SRC(%a6) # restore src operand 2286 1.1 is 2287 1.1 is mov.l (%a6),%a6 # restore frame pointer 2288 1.1 is 2289 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 2290 1.1 is mov.l LOCAL_SIZE+2+EXC_PC(%sp),LOCAL_SIZE+2+EXC_PC-0xc(%sp) 2291 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 2292 1.1 is 2293 1.1 is # now, we copy the default result to it's proper location 2294 1.1 is mov.l LOCAL_SIZE+FP_DST_EX(%sp),LOCAL_SIZE+0x4(%sp) 2295 1.1 is mov.l LOCAL_SIZE+FP_DST_HI(%sp),LOCAL_SIZE+0x8(%sp) 2296 1.1 is mov.l LOCAL_SIZE+FP_DST_LO(%sp),LOCAL_SIZE+0xc(%sp) 2297 1.1 is 2298 1.1 is add.l &LOCAL_SIZE-0x8,%sp 2299 1.1 is 2300 1.1 is 2301 1.1 is bra.l _real_inex 2302 1.1 is 2303 1.1 is ######################################################################### 2304 1.1 is 2305 1.1 is # 2306 1.1 is # if we're stuffing a source operand back into an fsave frame then we 2307 1.1 is # have to make sure that for single or double source operands that the 2308 1.1 is # format stuffed is as weird as the hardware usually makes it. 2309 1.1 is # 2310 1.1 is global funimp_skew 2311 1.1 is funimp_skew: 2312 1.1 is bfextu EXC_EXTWORD(%a6){&3:&3},%d0 # extract src specifier 2313 1.1 is cmpi.b %d0,&0x1 # was src sgl? 2314 1.1 is beq.b funimp_skew_sgl # yes 2315 1.1 is cmpi.b %d0,&0x5 # was src dbl? 2316 1.1 is beq.b funimp_skew_dbl # yes 2317 1.1 is rts 2318 1.1 is 2319 1.1 is funimp_skew_sgl: 2320 1.1 is mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent 2321 1.1 is andi.w &0x7fff,%d0 # strip sign 2322 1.1 is beq.b funimp_skew_sgl_not 2323 1.1 is cmpi.w %d0,&0x3f80 2324 1.1 is bgt.b funimp_skew_sgl_not 2325 1.1 is neg.w %d0 # make exponent negative 2326 1.1 is addi.w &0x3f81,%d0 # find amt to shift 2327 1.1 is mov.l FP_SRC_HI(%a6),%d1 # fetch DENORM hi(man) 2328 1.1 is lsr.l %d0,%d1 # shift it 2329 1.1 is bset &31,%d1 # set j-bit 2330 1.1 is mov.l %d1,FP_SRC_HI(%a6) # insert new hi(man) 2331 1.1 is andi.w &0x8000,FP_SRC_EX(%a6) # clear old exponent 2332 1.1 is ori.w &0x3f80,FP_SRC_EX(%a6) # insert new "skewed" exponent 2333 1.1 is funimp_skew_sgl_not: 2334 1.1 is rts 2335 1.1 is 2336 1.1 is funimp_skew_dbl: 2337 1.1 is mov.w FP_SRC_EX(%a6),%d0 # fetch DENORM exponent 2338 1.1 is andi.w &0x7fff,%d0 # strip sign 2339 1.1 is beq.b funimp_skew_dbl_not 2340 1.1 is cmpi.w %d0,&0x3c00 2341 1.1 is bgt.b funimp_skew_dbl_not 2342 1.1 is 2343 1.1 is tst.b FP_SRC_EX(%a6) # make "internal format" 2344 1.1 is smi.b 0x2+FP_SRC(%a6) 2345 1.1 is mov.w %d0,FP_SRC_EX(%a6) # insert exponent with cleared sign 2346 1.1 is clr.l %d0 # clear g,r,s 2347 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src op 2348 1.1 is mov.w &0x3c01,%d1 # pass denorm threshold 2349 1.1 is bsr.l dnrm_lp # denorm it 2350 1.1 is mov.w &0x3c00,%d0 # new exponent 2351 1.1 is tst.b 0x2+FP_SRC(%a6) # is sign set? 2352 1.1 is beq.b fss_dbl_denorm_done # no 2353 1.1 is bset &15,%d0 # set sign 2354 1.1 is fss_dbl_denorm_done: 2355 1.1 is bset &0x7,FP_SRC_HI(%a6) # set j-bit 2356 1.1 is mov.w %d0,FP_SRC_EX(%a6) # insert new exponent 2357 1.1 is funimp_skew_dbl_not: 2358 1.1 is rts 2359 1.1 is 2360 1.1 is ######################################################################### 2361 1.1 is global _mem_write2 2362 1.1 is _mem_write2: 2363 1.1 is btst &0x5,EXC_SR(%a6) 2364 1.1 is beq.l _dmem_write 2365 1.1 is mov.l 0x0(%a0),FP_DST_EX(%a6) 2366 1.1 is mov.l 0x4(%a0),FP_DST_HI(%a6) 2367 1.1 is mov.l 0x8(%a0),FP_DST_LO(%a6) 2368 1.1 is clr.l %d1 2369 1.1 is rts 2370 1.1 is 2371 1.1 is ######################################################################### 2372 1.1 is # XDEF **************************************************************** # 2373 1.1 is # _fpsp_effadd(): 060FPSP entry point for FP "Unimplemented # 2374 1.1 is # effective address" exception. # 2375 1.1 is # # 2376 1.1 is # This handler should be the first code executed upon taking the # 2377 1.1 is # FP Unimplemented Effective Address exception in an operating # 2378 1.1 is # system. # 2379 1.1 is # # 2380 1.1 is # XREF **************************************************************** # 2381 1.1 is # _imem_read_long() - read instruction longword # 2382 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame # 2383 1.1 is # set_tag_x() - determine optype of src/dst operands # 2384 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile # 2385 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO # 2386 1.1 is # load_fpn2() - load dst operand from FP regfile # 2387 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 # 2388 1.1 is # decbin() - convert packed data to FP binary data # 2389 1.1 is # _real_fpu_disabled() - "callout" for "FPU disabled" exception # 2390 1.1 is # _real_access() - "callout" for access error exception # 2391 1.1 is # _mem_read() - read extended immediate operand from memory # 2392 1.1 is # _fpsp_done() - "callout" for exit; work all done # 2393 1.1 is # _real_trace() - "callout" for Trace enabled exception # 2394 1.1 is # fmovm_dynamic() - emulate dynamic fmovm instruction # 2395 1.1 is # fmovm_ctrl() - emulate fmovm control instruction # 2396 1.1 is # # 2397 1.1 is # INPUT *************************************************************** # 2398 1.1 is # - The system stack contains the "Unimplemented <ea>" stk frame # 2399 1.1 is # # 2400 1.1 is # OUTPUT ************************************************************** # 2401 1.1 is # If access error: # 2402 1.1 is # - The system stack is changed to an access error stack frame # 2403 1.1 is # If FPU disabled: # 2404 1.1 is # - The system stack is changed to an FPU disabled stack frame # 2405 1.1 is # If Trace exception enabled: # 2406 1.1 is # - The system stack is changed to a Trace exception stack frame # 2407 1.1 is # Else: (normal case) # 2408 1.1 is # - None (correct result has been stored as appropriate) # 2409 1.1 is # # 2410 1.1 is # ALGORITHM *********************************************************** # 2411 1.1 is # This exception handles 3 types of operations: # 2412 1.1 is # (1) FP Instructions using extended precision or packed immediate # 2413 1.1 is # addressing mode. # 2414 1.1 is # (2) The "fmovm.x" instruction w/ dynamic register specification. # 2415 1.1 is # (3) The "fmovm.l" instruction w/ 2 or 3 control registers. # 2416 1.1 is # # 2417 1.1 is # For immediate data operations, the data is read in w/ a # 2418 1.1 is # _mem_read() "callout", converted to FP binary (if packed), and used # 2419 1.1 is # as the source operand to the instruction specified by the instruction # 2420 1.1 is # word. If no FP exception should be reported ads a result of the # 2421 1.1 is # emulation, then the result is stored to the destination register and # 2422 1.1 is # the handler exits through _fpsp_done(). If an enabled exc has been # 2423 1.1 is # signalled as a result of emulation, then an fsave state frame # 2424 1.1 is # corresponding to the FP exception type must be entered into the 060 # 2425 1.1 is # FPU before exiting. In either the enabled or disabled cases, we # 2426 1.1 is # must also check if a Trace exception is pending, in which case, we # 2427 1.1 is # must create a Trace exception stack frame from the current exception # 2428 1.1 is # stack frame. If no Trace is pending, we simply exit through # 2429 1.1 is # _fpsp_done(). # 2430 1.1 is # For "fmovm.x", call the routine fmovm_dynamic() which will # 2431 1.1 is # decode and emulate the instruction. No FP exceptions can be pending # 2432 1.1 is # as a result of this operation emulation. A Trace exception can be # 2433 1.1 is # pending, though, which means the current stack frame must be changed # 2434 1.1 is # to a Trace stack frame and an exit made through _real_trace(). # 2435 1.1 is # For the case of "fmovm.x Dn,-(a7)", where the offending instruction # 2436 1.1 is # was executed from supervisor mode, this handler must store the FP # 2437 1.1 is # register file values to the system stack by itself since # 2438 1.1 is # fmovm_dynamic() can't handle this. A normal exit is made through # 2439 1.1 is # fpsp_done(). # 2440 1.1 is # For "fmovm.l", fmovm_ctrl() is used to emulate the instruction. # 2441 1.1 is # Again, a Trace exception may be pending and an exit made through # 2442 1.1 is # _real_trace(). Else, a normal exit is made through _fpsp_done(). # 2443 1.1 is # # 2444 1.1 is # Before any of the above is attempted, it must be checked to # 2445 1.1 is # see if the FPU is disabled. Since the "Unimp <ea>" exception is taken # 2446 1.1 is # before the "FPU disabled" exception, but the "FPU disabled" exception # 2447 1.1 is # has higher priority, we check the disabled bit in the PCR. If set, # 2448 1.1 is # then we must create an 8 word "FPU disabled" exception stack frame # 2449 1.1 is # from the current 4 word exception stack frame. This includes # 2450 1.1 is # reproducing the effective address of the instruction to put on the # 2451 1.1 is # new stack frame. # 2452 1.1 is # # 2453 1.1 is # In the process of all emulation work, if a _mem_read() # 2454 1.1 is # "callout" returns a failing result indicating an access error, then # 2455 1.1 is # we must create an access error stack frame from the current stack # 2456 1.1 is # frame. This information includes a faulting address and a fault- # 2457 1.1 is # status-longword. These are created within this handler. # 2458 1.1 is # # 2459 1.1 is ######################################################################### 2460 1.1 is 2461 1.1 is global _fpsp_effadd 2462 1.1 is _fpsp_effadd: 2463 1.1 is 2464 1.1 is # This exception type takes priority over the "Line F Emulator" 2465 1.1 is # exception. Therefore, the FPU could be disabled when entering here. 2466 1.1 is # So, we must check to see if it's disabled and handle that case separately. 2467 1.1 is mov.l %d0,-(%sp) # save d0 2468 1.1 is movc %pcr,%d0 # load proc cr 2469 1.1 is btst &0x1,%d0 # is FPU disabled? 2470 1.1 is bne.w iea_disabled # yes 2471 1.1 is mov.l (%sp)+,%d0 # restore d0 2472 1.1 is 2473 1.1 is link %a6,&-LOCAL_SIZE # init stack frame 2474 1.1 is 2475 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 2476 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 2477 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 2478 1.1 is 2479 1.1 is # PC of instruction that took the exception is the PC in the frame 2480 1.1 is mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) 2481 1.1 is 2482 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 2483 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 2484 1.1 is bsr.l _imem_read_long # fetch the instruction words 2485 1.1 is mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD 2486 1.1 is 2487 1.1 is ######################################################################### 2488 1.1 is 2489 1.1 is tst.w %d0 # is operation fmovem? 2490 1.1 is bmi.w iea_fmovm # yes 2491 1.1 is 2492 1.1 is # 2493 1.1 is # here, we will have: 2494 1.1 is # fabs fdabs fsabs facos fmod 2495 1.1 is # fadd fdadd fsadd fasin frem 2496 1.1 is # fcmp fatan fscale 2497 1.1 is # fdiv fddiv fsdiv fatanh fsin 2498 1.1 is # fint fcos fsincos 2499 1.1 is # fintrz fcosh fsinh 2500 1.1 is # fmove fdmove fsmove fetox ftan 2501 1.1 is # fmul fdmul fsmul fetoxm1 ftanh 2502 1.1 is # fneg fdneg fsneg fgetexp ftentox 2503 1.1 is # fsgldiv fgetman ftwotox 2504 1.1 is # fsglmul flog10 2505 1.1 is # fsqrt flog2 2506 1.1 is # fsub fdsub fssub flogn 2507 1.1 is # ftst flognp1 2508 1.1 is # which can all use f<op>.{x,p} 2509 1.1 is # so, now it's immediate data extended precision AND PACKED FORMAT! 2510 1.1 is # 2511 1.1 is iea_op: 2512 1.1 is andi.l &0x00ff00ff,USER_FPSR(%a6) 2513 1.1 is 2514 1.1 is btst &0xa,%d0 # is src fmt x or p? 2515 1.1 is bne.b iea_op_pack # packed 2516 1.1 is 2517 1.1 is 2518 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data> 2519 1.1 is lea FP_SRC(%a6),%a1 # pass: ptr to super addr 2520 1.1 is mov.l &0xc,%d0 # pass: 12 bytes 2521 1.1 is bsr.l _imem_read # read extended immediate 2522 1.1 is 2523 1.1 is tst.l %d1 # did ifetch fail? 2524 1.1 is bne.w iea_iacc # yes 2525 1.1 is 2526 1.1 is bra.b iea_op_setsrc 2527 1.1 is 2528 1.1 is iea_op_pack: 2529 1.1 is 2530 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # pass: ptr to #<data> 2531 1.1 is lea FP_SRC(%a6),%a1 # pass: ptr to super dst 2532 1.1 is mov.l &0xc,%d0 # pass: 12 bytes 2533 1.1 is bsr.l _imem_read # read packed operand 2534 1.1 is 2535 1.1 is tst.l %d1 # did ifetch fail? 2536 1.1 is bne.w iea_iacc # yes 2537 1.1 is 2538 1.1 is # The packed operand is an INF or a NAN if the exponent field is all ones. 2539 1.1 is bfextu FP_SRC(%a6){&1:&15},%d0 # get exp 2540 1.1 is cmpi.w %d0,&0x7fff # INF or NAN? 2541 1.1 is beq.b iea_op_setsrc # operand is an INF or NAN 2542 1.1 is 2543 1.1 is # The packed operand is a zero if the mantissa is all zero, else it's 2544 1.1 is # a normal packed op. 2545 1.1 is mov.b 3+FP_SRC(%a6),%d0 # get byte 4 2546 1.1 is andi.b &0x0f,%d0 # clear all but last nybble 2547 1.1 is bne.b iea_op_gp_not_spec # not a zero 2548 1.1 is tst.l FP_SRC_HI(%a6) # is lw 2 zero? 2549 1.1 is bne.b iea_op_gp_not_spec # not a zero 2550 1.1 is tst.l FP_SRC_LO(%a6) # is lw 3 zero? 2551 1.1 is beq.b iea_op_setsrc # operand is a ZERO 2552 1.1 is iea_op_gp_not_spec: 2553 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to packed op 2554 1.1 is bsr.l decbin # convert to extended 2555 1.1 is fmovm.x &0x80,FP_SRC(%a6) # make this the srcop 2556 1.1 is 2557 1.1 is iea_op_setsrc: 2558 1.1 is addi.l &0xc,EXC_EXTWPTR(%a6) # update extension word pointer 2559 1.1 is 2560 1.1 is # FP_SRC now holds the src operand. 2561 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 2562 1.1 is bsr.l set_tag_x # tag the operand type 2563 1.1 is mov.b %d0,STAG(%a6) # could be ANYTHING!!! 2564 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 2565 1.1 is bne.b iea_op_getdst # no 2566 1.1 is bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO 2567 1.1 is mov.b %d0,STAG(%a6) # set new optype tag 2568 1.1 is iea_op_getdst: 2569 1.1 is clr.b STORE_FLG(%a6) # clear "store result" boolean 2570 1.1 is 2571 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 2572 1.1 is beq.b iea_op_extract # monadic 2573 1.1 is btst &0x4,1+EXC_CMDREG(%a6) # is operation fsincos,ftst,fcmp? 2574 1.1 is bne.b iea_op_spec # yes 2575 1.1 is 2576 1.1 is iea_op_loaddst: 2577 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno 2578 1.1 is bsr.l load_fpn2 # load dst operand 2579 1.1 is 2580 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op 2581 1.1 is bsr.l set_tag_x # tag the operand type 2582 1.1 is mov.b %d0,DTAG(%a6) # could be ANYTHING!!! 2583 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 2584 1.1 is bne.b iea_op_extract # no 2585 1.1 is bsr.l unnorm_fix # yes; convert to NORM/DENORM/ZERO 2586 1.1 is mov.b %d0,DTAG(%a6) # set new optype tag 2587 1.1 is bra.b iea_op_extract 2588 1.1 is 2589 1.1 is # the operation is fsincos, ftst, or fcmp. only fcmp is dyadic 2590 1.1 is iea_op_spec: 2591 1.1 is btst &0x3,1+EXC_CMDREG(%a6) # is operation fsincos? 2592 1.1 is beq.b iea_op_extract # yes 2593 1.1 is # now, we're left with ftst and fcmp. so, first let's tag them so that they don't 2594 1.1 is # store a result. then, only fcmp will branch back and pick up a dst operand. 2595 1.1 is st STORE_FLG(%a6) # don't store a final result 2596 1.1 is btst &0x1,1+EXC_CMDREG(%a6) # is operation fcmp? 2597 1.1 is beq.b iea_op_loaddst # yes 2598 1.1 is 2599 1.1 is iea_op_extract: 2600 1.1 is clr.l %d0 2601 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass: rnd mode,prec 2602 1.1 is 2603 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1 2604 1.1 is andi.w &0x007f,%d1 # extract extension 2605 1.1 is 2606 1.1 is fmov.l &0x0,%fpcr 2607 1.1 is fmov.l &0x0,%fpsr 2608 1.1 is 2609 1.1 is lea FP_SRC(%a6),%a0 2610 1.1 is lea FP_DST(%a6),%a1 2611 1.1 is 2612 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 2613 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1) 2614 1.1 is 2615 1.1 is # 2616 1.1 is # Exceptions in order of precedence: 2617 1.1 is # BSUN : none 2618 1.1 is # SNAN : all operations 2619 1.1 is # OPERR : all reg-reg or mem-reg operations that can normally operr 2620 1.1 is # OVFL : same as OPERR 2621 1.1 is # UNFL : same as OPERR 2622 1.1 is # DZ : same as OPERR 2623 1.1 is # INEX2 : same as OPERR 2624 1.1 is # INEX1 : all packed immediate operations 2625 1.1 is # 2626 1.1 is 2627 1.1 is # we determine the highest priority exception(if any) set by the 2628 1.1 is # emulation routine that has also been enabled by the user. 2629 1.1 is mov.b FPCR_ENABLE(%a6),%d0 # fetch exceptions enabled 2630 1.1 is bne.b iea_op_ena # some are enabled 2631 1.1 is 2632 1.1 is # now, we save the result, unless, of course, the operation was ftst or fcmp. 2633 1.1 is # these don't save results. 2634 1.1 is iea_op_save: 2635 1.1 is tst.b STORE_FLG(%a6) # does this op store a result? 2636 1.1 is bne.b iea_op_exit1 # exit with no frestore 2637 1.1 is 2638 1.1 is iea_op_store: 2639 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # fetch dst regno 2640 1.1 is bsr.l store_fpreg # store the result 2641 1.1 is 2642 1.1 is iea_op_exit1: 2643 1.1 is mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC" 2644 1.1 is mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame 2645 1.1 is 2646 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 2647 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2648 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2649 1.1 is 2650 1.1 is unlk %a6 # unravel the frame 2651 1.1 is 2652 1.1 is btst &0x7,(%sp) # is trace on? 2653 1.1 is bne.w iea_op_trace # yes 2654 1.1 is 2655 1.1 is bra.l _fpsp_done # exit to os 2656 1.1 is 2657 1.1 is iea_op_ena: 2658 1.1 is and.b FPSR_EXCEPT(%a6),%d0 # keep only ones enable and set 2659 1.1 is bfffo %d0{&24:&8},%d0 # find highest priority exception 2660 1.1 is bne.b iea_op_exc # at least one was set 2661 1.1 is 2662 1.1 is # no exception occurred. now, did a disabled, exact overflow occur with inexact 2663 1.1 is # enabled? if so, then we have to stuff an overflow frame into the FPU. 2664 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? 2665 1.1 is beq.b iea_op_save 2666 1.1 is 2667 1.1 is iea_op_ovfl: 2668 1.1 is btst &inex2_bit,FPCR_ENABLE(%a6) # is inexact enabled? 2669 1.1 is beq.b iea_op_store # no 2670 1.1 is bra.b iea_op_exc_ovfl # yes 2671 1.1 is 2672 1.1 is # an enabled exception occurred. we have to insert the exception type back into 2673 1.1 is # the machine. 2674 1.1 is iea_op_exc: 2675 1.1 is subi.l &24,%d0 # fix offset to be 0-8 2676 1.1 is cmpi.b %d0,&0x6 # is exception INEX? 2677 1.1 is bne.b iea_op_exc_force # no 2678 1.1 is 2679 1.1 is # the enabled exception was inexact. so, if it occurs with an overflow 2680 1.1 is # or underflow that was disabled, then we have to force an overflow or 2681 1.1 is # underflow frame. 2682 1.1 is btst &ovfl_bit,FPSR_EXCEPT(%a6) # did overflow occur? 2683 1.1 is bne.b iea_op_exc_ovfl # yes 2684 1.1 is btst &unfl_bit,FPSR_EXCEPT(%a6) # did underflow occur? 2685 1.1 is bne.b iea_op_exc_unfl # yes 2686 1.1 is 2687 1.1 is iea_op_exc_force: 2688 1.1 is mov.w (tbl_iea_except.b,%pc,%d0.w*2),2+FP_SRC(%a6) 2689 1.1 is bra.b iea_op_exit2 # exit with frestore 2690 1.1 is 2691 1.1 is tbl_iea_except: 2692 1.1 is short 0xe002, 0xe006, 0xe004, 0xe005 2693 1.1 is short 0xe003, 0xe002, 0xe001, 0xe001 2694 1.1 is 2695 1.1 is iea_op_exc_ovfl: 2696 1.1 is mov.w &0xe005,2+FP_SRC(%a6) 2697 1.1 is bra.b iea_op_exit2 2698 1.1 is 2699 1.1 is iea_op_exc_unfl: 2700 1.1 is mov.w &0xe003,2+FP_SRC(%a6) 2701 1.1 is 2702 1.1 is iea_op_exit2: 2703 1.1 is mov.l EXC_PC(%a6),USER_FPIAR(%a6) # set FPIAR to "Current PC" 2704 1.1 is mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set "Next PC" in exc frame 2705 1.1 is 2706 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 2707 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2708 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2709 1.1 is 2710 1.1 is frestore FP_SRC(%a6) # restore exceptional state 2711 1.1 is 2712 1.1 is unlk %a6 # unravel the frame 2713 1.1 is 2714 1.1 is btst &0x7,(%sp) # is trace on? 2715 1.1 is bne.b iea_op_trace # yes 2716 1.1 is 2717 1.1 is bra.l _fpsp_done # exit to os 2718 1.1 is 2719 1.1 is # 2720 1.1 is # The opclass two instruction that took an "Unimplemented Effective Address" 2721 1.1 is # exception was being traced. Make the "current" PC the FPIAR and put it in 2722 1.1 is # the trace stack frame then jump to _real_trace(). 2723 1.1 is # 2724 1.1 is # UNIMP EA FRAME TRACE FRAME 2725 1.1 is # ***************** ***************** 2726 1.1 is # * 0x0 * 0x0f0 * * Current * 2727 1.1 is # ***************** * PC * 2728 1.1 is # * Current * ***************** 2729 1.1 is # * PC * * 0x2 * 0x024 * 2730 1.1 is # ***************** ***************** 2731 1.1 is # * SR * * Next * 2732 1.1 is # ***************** * PC * 2733 1.1 is # ***************** 2734 1.1 is # * SR * 2735 1.1 is # ***************** 2736 1.1 is iea_op_trace: 2737 1.1 is mov.l (%sp),-(%sp) # shift stack frame "down" 2738 1.1 is mov.w 0x8(%sp),0x4(%sp) 2739 1.1 is mov.w &0x2024,0x6(%sp) # stk fmt = 0x2; voff = 0x024 2740 1.1 is fmov.l %fpiar,0x8(%sp) # "Current PC" is in FPIAR 2741 1.1 is 2742 1.1 is bra.l _real_trace 2743 1.1 is 2744 1.1 is ######################################################################### 2745 1.1 is iea_fmovm: 2746 1.1 is btst &14,%d0 # ctrl or data reg 2747 1.1 is beq.w iea_fmovm_ctrl 2748 1.1 is 2749 1.1 is iea_fmovm_data: 2750 1.1 is 2751 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor mode 2752 1.1 is bne.b iea_fmovm_data_s 2753 1.1 is 2754 1.1 is iea_fmovm_data_u: 2755 1.1 is mov.l %usp,%a0 2756 1.1 is mov.l %a0,EXC_A7(%a6) # store current a7 2757 1.1 is bsr.l fmovm_dynamic # do dynamic fmovm 2758 1.1 is mov.l EXC_A7(%a6),%a0 # load possibly new a7 2759 1.1 is mov.l %a0,%usp # update usp 2760 1.1 is bra.w iea_fmovm_exit 2761 1.1 is 2762 1.1 is iea_fmovm_data_s: 2763 1.1 is clr.b SPCOND_FLG(%a6) 2764 1.1 is lea 0x2+EXC_VOFF(%a6),%a0 2765 1.1 is mov.l %a0,EXC_A7(%a6) 2766 1.1 is bsr.l fmovm_dynamic # do dynamic fmovm 2767 1.1 is 2768 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg 2769 1.1 is beq.w iea_fmovm_data_predec 2770 1.1 is cmpi.b SPCOND_FLG(%a6),&mia7_flg 2771 1.1 is bne.w iea_fmovm_exit 2772 1.1 is 2773 1.1 is # right now, d0 = the size. 2774 1.1 is # the data has been fetched from the supervisor stack, but we have not 2775 1.1 is # incremented the stack pointer by the appropriate number of bytes. 2776 1.1 is # do it here. 2777 1.1 is iea_fmovm_data_postinc: 2778 1.1 is btst &0x7,EXC_SR(%a6) 2779 1.1 is bne.b iea_fmovm_data_pi_trace 2780 1.1 is 2781 1.1 is mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0) 2782 1.1 is mov.l EXC_EXTWPTR(%a6),(EXC_PC,%a6,%d0) 2783 1.1 is mov.w &0x00f0,(EXC_VOFF,%a6,%d0) 2784 1.1 is 2785 1.1 is lea (EXC_SR,%a6,%d0),%a0 2786 1.1 is mov.l %a0,EXC_SR(%a6) 2787 1.1 is 2788 1.1 is fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 2789 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2790 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2791 1.1 is 2792 1.1 is unlk %a6 2793 1.1 is mov.l (%sp)+,%sp 2794 1.1 is bra.l _fpsp_done 2795 1.1 is 2796 1.1 is iea_fmovm_data_pi_trace: 2797 1.1 is mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0) 2798 1.1 is mov.l EXC_EXTWPTR(%a6),(EXC_PC-0x4,%a6,%d0) 2799 1.1 is mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0) 2800 1.1 is mov.l EXC_PC(%a6),(EXC_VOFF+0x2-0x4,%a6,%d0) 2801 1.1 is 2802 1.1 is lea (EXC_SR-0x4,%a6,%d0),%a0 2803 1.1 is mov.l %a0,EXC_SR(%a6) 2804 1.1 is 2805 1.1 is fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 2806 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2807 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2808 1.1 is 2809 1.1 is unlk %a6 2810 1.1 is mov.l (%sp)+,%sp 2811 1.1 is bra.l _real_trace 2812 1.1 is 2813 1.1 is # right now, d1 = size and d0 = the strg. 2814 1.1 is iea_fmovm_data_predec: 2815 1.1 is mov.b %d1,EXC_VOFF(%a6) # store strg 2816 1.1 is mov.b %d0,0x1+EXC_VOFF(%a6) # store size 2817 1.1 is 2818 1.1 is fmovm.x EXC_FP0(%a6),&0xc0 # restore fp0-fp1 2819 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2820 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2821 1.1 is 2822 1.1 is mov.l (%a6),-(%sp) # make a copy of a6 2823 1.1 is mov.l %d0,-(%sp) # save d0 2824 1.1 is mov.l %d1,-(%sp) # save d1 2825 1.1 is mov.l EXC_EXTWPTR(%a6),-(%sp) # make a copy of Next PC 2826 1.1 is 2827 1.1 is clr.l %d0 2828 1.1 is mov.b 0x1+EXC_VOFF(%a6),%d0 # fetch size 2829 1.1 is neg.l %d0 # get negative of size 2830 1.1 is 2831 1.1 is btst &0x7,EXC_SR(%a6) # is trace enabled? 2832 1.1 is beq.b iea_fmovm_data_p2 2833 1.1 is 2834 1.1 is mov.w EXC_SR(%a6),(EXC_SR-0x4,%a6,%d0) 2835 1.1 is mov.l EXC_PC(%a6),(EXC_VOFF-0x2,%a6,%d0) 2836 1.1 is mov.l (%sp)+,(EXC_PC-0x4,%a6,%d0) 2837 1.1 is mov.w &0x2024,(EXC_VOFF-0x4,%a6,%d0) 2838 1.1 is 2839 1.1 is pea (%a6,%d0) # create final sp 2840 1.1 is bra.b iea_fmovm_data_p3 2841 1.1 is 2842 1.1 is iea_fmovm_data_p2: 2843 1.1 is mov.w EXC_SR(%a6),(EXC_SR,%a6,%d0) 2844 1.1 is mov.l (%sp)+,(EXC_PC,%a6,%d0) 2845 1.1 is mov.w &0x00f0,(EXC_VOFF,%a6,%d0) 2846 1.1 is 2847 1.1 is pea (0x4,%a6,%d0) # create final sp 2848 1.1 is 2849 1.1 is iea_fmovm_data_p3: 2850 1.1 is clr.l %d1 2851 1.1 is mov.b EXC_VOFF(%a6),%d1 # fetch strg 2852 1.1 is 2853 1.1 is tst.b %d1 2854 1.1 is bpl.b fm_1 2855 1.1 is fmovm.x &0x80,(0x4+0x8,%a6,%d0) 2856 1.1 is addi.l &0xc,%d0 2857 1.1 is fm_1: 2858 1.1 is lsl.b &0x1,%d1 2859 1.1 is bpl.b fm_2 2860 1.1 is fmovm.x &0x40,(0x4+0x8,%a6,%d0) 2861 1.1 is addi.l &0xc,%d0 2862 1.1 is fm_2: 2863 1.1 is lsl.b &0x1,%d1 2864 1.1 is bpl.b fm_3 2865 1.1 is fmovm.x &0x20,(0x4+0x8,%a6,%d0) 2866 1.1 is addi.l &0xc,%d0 2867 1.1 is fm_3: 2868 1.1 is lsl.b &0x1,%d1 2869 1.1 is bpl.b fm_4 2870 1.1 is fmovm.x &0x10,(0x4+0x8,%a6,%d0) 2871 1.1 is addi.l &0xc,%d0 2872 1.1 is fm_4: 2873 1.1 is lsl.b &0x1,%d1 2874 1.1 is bpl.b fm_5 2875 1.1 is fmovm.x &0x08,(0x4+0x8,%a6,%d0) 2876 1.1 is addi.l &0xc,%d0 2877 1.1 is fm_5: 2878 1.1 is lsl.b &0x1,%d1 2879 1.1 is bpl.b fm_6 2880 1.1 is fmovm.x &0x04,(0x4+0x8,%a6,%d0) 2881 1.1 is addi.l &0xc,%d0 2882 1.1 is fm_6: 2883 1.1 is lsl.b &0x1,%d1 2884 1.1 is bpl.b fm_7 2885 1.1 is fmovm.x &0x02,(0x4+0x8,%a6,%d0) 2886 1.1 is addi.l &0xc,%d0 2887 1.1 is fm_7: 2888 1.1 is lsl.b &0x1,%d1 2889 1.1 is bpl.b fm_end 2890 1.1 is fmovm.x &0x01,(0x4+0x8,%a6,%d0) 2891 1.1 is fm_end: 2892 1.1 is mov.l 0x4(%sp),%d1 2893 1.1 is mov.l 0x8(%sp),%d0 2894 1.1 is mov.l 0xc(%sp),%a6 2895 1.1 is mov.l (%sp)+,%sp 2896 1.1 is 2897 1.1 is btst &0x7,(%sp) # is trace enabled? 2898 1.1 is beq.l _fpsp_done 2899 1.1 is bra.l _real_trace 2900 1.1 is 2901 1.1 is ######################################################################### 2902 1.1 is iea_fmovm_ctrl: 2903 1.1 is 2904 1.1 is bsr.l fmovm_ctrl # load ctrl regs 2905 1.1 is 2906 1.1 is iea_fmovm_exit: 2907 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 2908 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 2909 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 2910 1.1 is 2911 1.1 is btst &0x7,EXC_SR(%a6) # is trace on? 2912 1.1 is bne.b iea_fmovm_trace # yes 2913 1.1 is 2914 1.1 is mov.l EXC_EXTWPTR(%a6),EXC_PC(%a6) # set Next PC 2915 1.1 is 2916 1.1 is unlk %a6 # unravel the frame 2917 1.1 is 2918 1.1 is bra.l _fpsp_done # exit to os 2919 1.1 is 2920 1.1 is # 2921 1.1 is # The control reg instruction that took an "Unimplemented Effective Address" 2922 1.1 is # exception was being traced. The "Current PC" for the trace frame is the 2923 1.1 is # PC stacked for Unimp EA. The "Next PC" is in EXC_EXTWPTR. 2924 1.1 is # After fixing the stack frame, jump to _real_trace(). 2925 1.1 is # 2926 1.1 is # UNIMP EA FRAME TRACE FRAME 2927 1.1 is # ***************** ***************** 2928 1.1 is # * 0x0 * 0x0f0 * * Current * 2929 1.1 is # ***************** * PC * 2930 1.1 is # * Current * ***************** 2931 1.1 is # * PC * * 0x2 * 0x024 * 2932 1.1 is # ***************** ***************** 2933 1.1 is # * SR * * Next * 2934 1.1 is # ***************** * PC * 2935 1.1 is # ***************** 2936 1.1 is # * SR * 2937 1.1 is # ***************** 2938 1.1 is # this ain't a pretty solution, but it works: 2939 1.1 is # -restore a6 (not with unlk) 2940 1.1 is # -shift stack frame down over where old a6 used to be 2941 1.1 is # -add LOCAL_SIZE to stack pointer 2942 1.1 is iea_fmovm_trace: 2943 1.1 is mov.l (%a6),%a6 # restore frame pointer 2944 1.1 is mov.w EXC_SR+LOCAL_SIZE(%sp),0x0+LOCAL_SIZE(%sp) 2945 1.1 is mov.l EXC_PC+LOCAL_SIZE(%sp),0x8+LOCAL_SIZE(%sp) 2946 1.1 is mov.l EXC_EXTWPTR+LOCAL_SIZE(%sp),0x2+LOCAL_SIZE(%sp) 2947 1.1 is mov.w &0x2024,0x6+LOCAL_SIZE(%sp) # stk fmt = 0x2; voff = 0x024 2948 1.1 is add.l &LOCAL_SIZE,%sp # clear stack frame 2949 1.1 is 2950 1.1 is bra.l _real_trace 2951 1.1 is 2952 1.1 is ######################################################################### 2953 1.1 is # The FPU is disabled and so we should really have taken the "Line 2954 1.1 is # F Emulator" exception. So, here we create an 8-word stack frame 2955 1.1 is # from our 4-word stack frame. This means we must calculate the length 2956 1.1 is # of the faulting instruction to get the "next PC". This is trivial for 2957 1.1 is # immediate operands but requires some extra work for fmovm dynamic 2958 1.1 is # which can use most addressing modes. 2959 1.1 is iea_disabled: 2960 1.1 is mov.l (%sp)+,%d0 # restore d0 2961 1.1 is 2962 1.1 is link %a6,&-LOCAL_SIZE # init stack frame 2963 1.1 is 2964 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 2965 1.1 is 2966 1.1 is # PC of instruction that took the exception is the PC in the frame 2967 1.1 is mov.l EXC_PC(%a6),EXC_EXTWPTR(%a6) 2968 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 2969 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 2970 1.1 is bsr.l _imem_read_long # fetch the instruction words 2971 1.1 is mov.l %d0,EXC_OPWORD(%a6) # store OPWORD and EXTWORD 2972 1.1 is 2973 1.1 is tst.w %d0 # is instr fmovm? 2974 1.1 is bmi.b iea_dis_fmovm # yes 2975 1.1 is # instruction is using an extended precision immediate operand. therefore, 2976 1.1 is # the total instruction length is 16 bytes. 2977 1.1 is iea_dis_immed: 2978 1.1 is mov.l &0x10,%d0 # 16 bytes of instruction 2979 1.1 is bra.b iea_dis_cont 2980 1.1 is iea_dis_fmovm: 2981 1.1 is btst &0xe,%d0 # is instr fmovm ctrl 2982 1.1 is bne.b iea_dis_fmovm_data # no 2983 1.1 is # the instruction is a fmovm.l with 2 or 3 registers. 2984 1.1 is bfextu %d0{&19:&3},%d1 2985 1.1 is mov.l &0xc,%d0 2986 1.1 is cmpi.b %d1,&0x7 # move all regs? 2987 1.1 is bne.b iea_dis_cont 2988 1.1 is addq.l &0x4,%d0 2989 1.1 is bra.b iea_dis_cont 2990 1.1 is # the instruction is an fmovm.x dynamic which can use many addressing 2991 1.1 is # modes and thus can have several different total instruction lengths. 2992 1.1 is # call fmovm_calc_ea which will go through the ea calc process and, 2993 1.1 is # as a by-product, will tell us how long the instruction is. 2994 1.1 is iea_dis_fmovm_data: 2995 1.1 is clr.l %d0 2996 1.1 is bsr.l fmovm_calc_ea 2997 1.1 is mov.l EXC_EXTWPTR(%a6),%d0 2998 1.1 is sub.l EXC_PC(%a6),%d0 2999 1.1 is iea_dis_cont: 3000 1.1 is mov.w %d0,EXC_VOFF(%a6) # store stack shift value 3001 1.1 is 3002 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3003 1.1 is 3004 1.1 is unlk %a6 3005 1.1 is 3006 1.1 is # here, we actually create the 8-word frame from the 4-word frame, 3007 1.1 is # with the "next PC" as additional info. 3008 1.1 is # the <ea> field is let as undefined. 3009 1.1 is subq.l &0x8,%sp # make room for new stack 3010 1.1 is mov.l %d0,-(%sp) # save d0 3011 1.1 is mov.w 0xc(%sp),0x4(%sp) # move SR 3012 1.1 is mov.l 0xe(%sp),0x6(%sp) # move Current PC 3013 1.1 is clr.l %d0 3014 1.1 is mov.w 0x12(%sp),%d0 3015 1.1 is mov.l 0x6(%sp),0x10(%sp) # move Current PC 3016 1.1 is add.l %d0,0x6(%sp) # make Next PC 3017 1.1 is mov.w &0x402c,0xa(%sp) # insert offset,frame format 3018 1.1 is mov.l (%sp)+,%d0 # restore d0 3019 1.1 is 3020 1.1 is bra.l _real_fpu_disabled 3021 1.1 is 3022 1.1 is ########## 3023 1.1 is 3024 1.1 is iea_iacc: 3025 1.1 is movc %pcr,%d0 3026 1.1 is btst &0x1,%d0 3027 1.1 is bne.b iea_iacc_cont 3028 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3029 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack 3030 1.1 is iea_iacc_cont: 3031 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3032 1.1 is 3033 1.1 is unlk %a6 3034 1.1 is 3035 1.1 is subq.w &0x8,%sp # make stack frame bigger 3036 1.1 is mov.l 0x8(%sp),(%sp) # store SR,hi(PC) 3037 1.1 is mov.w 0xc(%sp),0x4(%sp) # store lo(PC) 3038 1.1 is mov.w &0x4008,0x6(%sp) # store voff 3039 1.1 is mov.l 0x2(%sp),0x8(%sp) # store ea 3040 1.1 is mov.l &0x09428001,0xc(%sp) # store fslw 3041 1.1 is 3042 1.1 is iea_acc_done: 3043 1.1 is btst &0x5,(%sp) # user or supervisor mode? 3044 1.1 is beq.b iea_acc_done2 # user 3045 1.1 is bset &0x2,0xd(%sp) # set supervisor TM bit 3046 1.1 is 3047 1.1 is iea_acc_done2: 3048 1.1 is bra.l _real_access 3049 1.1 is 3050 1.1 is iea_dacc: 3051 1.1 is lea -LOCAL_SIZE(%a6),%sp 3052 1.1 is 3053 1.1 is movc %pcr,%d1 3054 1.1 is btst &0x1,%d1 3055 1.1 is bne.b iea_dacc_cont 3056 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 on stack 3057 1.1 is fmovm.l LOCAL_SIZE+USER_FPCR(%sp),%fpcr,%fpsr,%fpiar # restore ctrl regs 3058 1.1 is iea_dacc_cont: 3059 1.1 is mov.l (%a6),%a6 3060 1.1 is 3061 1.1 is mov.l 0x4+LOCAL_SIZE(%sp),-0x8+0x4+LOCAL_SIZE(%sp) 3062 1.1 is mov.w 0x8+LOCAL_SIZE(%sp),-0x8+0x8+LOCAL_SIZE(%sp) 3063 1.1 is mov.w &0x4008,-0x8+0xa+LOCAL_SIZE(%sp) 3064 1.1 is mov.l %a0,-0x8+0xc+LOCAL_SIZE(%sp) 3065 1.1 is mov.w %d0,-0x8+0x10+LOCAL_SIZE(%sp) 3066 1.1 is mov.w &0x0001,-0x8+0x12+LOCAL_SIZE(%sp) 3067 1.1 is 3068 1.1 is movm.l LOCAL_SIZE+EXC_DREGS(%sp),&0x0303 # restore d0-d1/a0-a1 3069 1.1 is add.w &LOCAL_SIZE-0x4,%sp 3070 1.1 is 3071 1.1 is bra.b iea_acc_done 3072 1.1 is 3073 1.1 is ######################################################################### 3074 1.1 is # XDEF **************************************************************** # 3075 1.1 is # _fpsp_operr(): 060FPSP entry point for FP Operr exception. # 3076 1.1 is # # 3077 1.1 is # This handler should be the first code executed upon taking the # 3078 1.1 is # FP Operand Error exception in an operating system. # 3079 1.1 is # # 3080 1.1 is # XREF **************************************************************** # 3081 1.1 is # _imem_read_long() - read instruction longword # 3082 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame # 3083 1.1 is # _real_operr() - "callout" to operating system operr handler # 3084 1.1 is # _dmem_write_{byte,word,long}() - store data to mem (opclass 3) # 3085 1.1 is # store_dreg_{b,w,l}() - store data to data regfile (opclass 3) # 3086 1.1 is # facc_out_{b,w,l}() - store to memory took access error (opcl 3) # 3087 1.1 is # # 3088 1.1 is # INPUT *************************************************************** # 3089 1.1 is # - The system stack contains the FP Operr exception frame # 3090 1.1 is # - The fsave frame contains the source operand # 3091 1.1 is # # 3092 1.1 is # OUTPUT ************************************************************** # 3093 1.1 is # No access error: # 3094 1.1 is # - The system stack is unchanged # 3095 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 # 3096 1.1 is # # 3097 1.1 is # ALGORITHM *********************************************************** # 3098 1.1 is # In a system where the FP Operr exception is enabled, the goal # 3099 1.1 is # is to get to the handler specified at _real_operr(). But, on the 060, # 3100 1.1 is # for opclass zero and two instruction taking this exception, the # 3101 1.1 is # input operand in the fsave frame may be incorrect for some cases # 3102 1.1 is # and needs to be corrected. This handler calls fix_skewed_ops() to # 3103 1.1 is # do just this and then exits through _real_operr(). # 3104 1.1 is # For opclass 3 instructions, the 060 doesn't store the default # 3105 1.1 is # operr result out to memory or data register file as it should. # 3106 1.1 is # This code must emulate the move out before finally exiting through # 3107 1.1 is # _real_inex(). The move out, if to memory, is performed using # 3108 1.1 is # _mem_write() "callout" routines that may return a failing result. # 3109 1.1 is # In this special case, the handler must exit through facc_out() # 3110 1.1 is # which creates an access error stack frame from the current operr # 3111 1.1 is # stack frame. # 3112 1.1 is # # 3113 1.1 is ######################################################################### 3114 1.1 is 3115 1.1 is global _fpsp_operr 3116 1.1 is _fpsp_operr: 3117 1.1 is 3118 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame 3119 1.1 is 3120 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame 3121 1.1 is 3122 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3123 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3124 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3125 1.1 is 3126 1.1 is # the FPIAR holds the "current PC" of the faulting instruction 3127 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3128 1.1 is 3129 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3130 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3131 1.1 is bsr.l _imem_read_long # fetch the instruction words 3132 1.1 is mov.l %d0,EXC_OPWORD(%a6) 3133 1.1 is 3134 1.1 is ############################################################################## 3135 1.1 is 3136 1.1 is btst &13,%d0 # is instr an fmove out? 3137 1.1 is bne.b foperr_out # fmove out 3138 1.1 is 3139 1.1 is 3140 1.1 is # here, we simply see if the operand in the fsave frame needs to be "unskewed". 3141 1.1 is # this would be the case for opclass two operations with a source infinity or 3142 1.1 is # denorm operand in the sgl or dbl format. NANs also become skewed, but can't 3143 1.1 is # cause an operr so we don't need to check for them here. 3144 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 3145 1.1 is bsr.l fix_skewed_ops # fix src op 3146 1.1 is 3147 1.1 is foperr_exit: 3148 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3149 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3150 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3151 1.1 is 3152 1.1 is frestore FP_SRC(%a6) 3153 1.1 is 3154 1.1 is unlk %a6 3155 1.1 is bra.l _real_operr 3156 1.1 is 3157 1.1 is ######################################################################## 3158 1.1 is 3159 1.1 is # 3160 1.1 is # the hardware does not save the default result to memory on enabled 3161 1.1 is # operand error exceptions. we do this here before passing control to 3162 1.1 is # the user operand error handler. 3163 1.1 is # 3164 1.1 is # byte, word, and long destination format operations can pass 3165 1.1 is # through here. we simply need to test the sign of the src 3166 1.1 is # operand and save the appropriate minimum or maximum integer value 3167 1.1 is # to the effective address as pointed to by the stacked effective address. 3168 1.1 is # 3169 1.1 is # although packed opclass three operations can take operand error 3170 1.1 is # exceptions, they won't pass through here since they are caught 3171 1.1 is # first by the unsupported data format exception handler. that handler 3172 1.1 is # sends them directly to _real_operr() if necessary. 3173 1.1 is # 3174 1.1 is foperr_out: 3175 1.1 is 3176 1.1 is mov.w FP_SRC_EX(%a6),%d1 # fetch exponent 3177 1.1 is andi.w &0x7fff,%d1 3178 1.1 is cmpi.w %d1,&0x7fff 3179 1.1 is bne.b foperr_out_not_qnan 3180 1.1 is # the operand is either an infinity or a QNAN. 3181 1.1 is tst.l FP_SRC_LO(%a6) 3182 1.1 is bne.b foperr_out_qnan 3183 1.1 is mov.l FP_SRC_HI(%a6),%d1 3184 1.1 is andi.l &0x7fffffff,%d1 3185 1.1 is beq.b foperr_out_not_qnan 3186 1.1 is foperr_out_qnan: 3187 1.1 is mov.l FP_SRC_HI(%a6),L_SCR1(%a6) 3188 1.1 is bra.b foperr_out_jmp 3189 1.1 is 3190 1.1 is foperr_out_not_qnan: 3191 1.1 is mov.l &0x7fffffff,%d1 3192 1.1 is tst.b FP_SRC_EX(%a6) 3193 1.1 is bpl.b foperr_out_not_qnan2 3194 1.1 is addq.l &0x1,%d1 3195 1.1 is foperr_out_not_qnan2: 3196 1.1 is mov.l %d1,L_SCR1(%a6) 3197 1.1 is 3198 1.1 is foperr_out_jmp: 3199 1.1 is bfextu %d0{&19:&3},%d0 # extract dst format field 3200 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg 3201 1.1 is mov.w (tbl_operr.b,%pc,%d0.w*2),%a0 3202 1.1 is jmp (tbl_operr.b,%pc,%a0) 3203 1.1 is 3204 1.1 is tbl_operr: 3205 1.1 is short foperr_out_l - tbl_operr # long word integer 3206 1.1 is short tbl_operr - tbl_operr # sgl prec shouldn't happen 3207 1.1 is short tbl_operr - tbl_operr # ext prec shouldn't happen 3208 1.1 is short foperr_exit - tbl_operr # packed won't enter here 3209 1.1 is short foperr_out_w - tbl_operr # word integer 3210 1.1 is short tbl_operr - tbl_operr # dbl prec shouldn't happen 3211 1.1 is short foperr_out_b - tbl_operr # byte integer 3212 1.1 is short tbl_operr - tbl_operr # packed won't enter here 3213 1.1 is 3214 1.1 is foperr_out_b: 3215 1.1 is mov.b L_SCR1(%a6),%d0 # load positive default result 3216 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3217 1.1 is ble.b foperr_out_b_save_dn # yes 3218 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3219 1.1 is bsr.l _dmem_write_byte # write the default result 3220 1.1 is 3221 1.1 is tst.l %d1 # did dstore fail? 3222 1.1 is bne.l facc_out_b # yes 3223 1.1 is 3224 1.1 is bra.w foperr_exit 3225 1.1 is foperr_out_b_save_dn: 3226 1.1 is andi.w &0x0007,%d1 3227 1.1 is bsr.l store_dreg_b # store result to regfile 3228 1.1 is bra.w foperr_exit 3229 1.1 is 3230 1.1 is foperr_out_w: 3231 1.1 is mov.w L_SCR1(%a6),%d0 # load positive default result 3232 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3233 1.1 is ble.b foperr_out_w_save_dn # yes 3234 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3235 1.1 is bsr.l _dmem_write_word # write the default result 3236 1.1 is 3237 1.1 is tst.l %d1 # did dstore fail? 3238 1.1 is bne.l facc_out_w # yes 3239 1.1 is 3240 1.1 is bra.w foperr_exit 3241 1.1 is foperr_out_w_save_dn: 3242 1.1 is andi.w &0x0007,%d1 3243 1.1 is bsr.l store_dreg_w # store result to regfile 3244 1.1 is bra.w foperr_exit 3245 1.1 is 3246 1.1 is foperr_out_l: 3247 1.1 is mov.l L_SCR1(%a6),%d0 # load positive default result 3248 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3249 1.1 is ble.b foperr_out_l_save_dn # yes 3250 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3251 1.1 is bsr.l _dmem_write_long # write the default result 3252 1.1 is 3253 1.1 is tst.l %d1 # did dstore fail? 3254 1.1 is bne.l facc_out_l # yes 3255 1.1 is 3256 1.1 is bra.w foperr_exit 3257 1.1 is foperr_out_l_save_dn: 3258 1.1 is andi.w &0x0007,%d1 3259 1.1 is bsr.l store_dreg_l # store result to regfile 3260 1.1 is bra.w foperr_exit 3261 1.1 is 3262 1.1 is ######################################################################### 3263 1.1 is # XDEF **************************************************************** # 3264 1.1 is # _fpsp_snan(): 060FPSP entry point for FP SNAN exception. # 3265 1.1 is # # 3266 1.1 is # This handler should be the first code executed upon taking the # 3267 1.1 is # FP Signalling NAN exception in an operating system. # 3268 1.1 is # # 3269 1.1 is # XREF **************************************************************** # 3270 1.1 is # _imem_read_long() - read instruction longword # 3271 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame # 3272 1.1 is # _real_snan() - "callout" to operating system SNAN handler # 3273 1.1 is # _dmem_write_{byte,word,long}() - store data to mem (opclass 3) # 3274 1.1 is # store_dreg_{b,w,l}() - store data to data regfile (opclass 3) # 3275 1.1 is # facc_out_{b,w,l,d,x}() - store to mem took acc error (opcl 3) # 3276 1.1 is # _calc_ea_fout() - fix An if <ea> is -() or ()+; also get <ea> # 3277 1.1 is # # 3278 1.1 is # INPUT *************************************************************** # 3279 1.1 is # - The system stack contains the FP SNAN exception frame # 3280 1.1 is # - The fsave frame contains the source operand # 3281 1.1 is # # 3282 1.1 is # OUTPUT ************************************************************** # 3283 1.1 is # No access error: # 3284 1.1 is # - The system stack is unchanged # 3285 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 # 3286 1.1 is # # 3287 1.1 is # ALGORITHM *********************************************************** # 3288 1.1 is # In a system where the FP SNAN exception is enabled, the goal # 3289 1.1 is # is to get to the handler specified at _real_snan(). But, on the 060, # 3290 1.1 is # for opclass zero and two instructions taking this exception, the # 3291 1.1 is # input operand in the fsave frame may be incorrect for some cases # 3292 1.1 is # and needs to be corrected. This handler calls fix_skewed_ops() to # 3293 1.1 is # do just this and then exits through _real_snan(). # 3294 1.1 is # For opclass 3 instructions, the 060 doesn't store the default # 3295 1.1 is # SNAN result out to memory or data register file as it should. # 3296 1.1 is # This code must emulate the move out before finally exiting through # 3297 1.1 is # _real_snan(). The move out, if to memory, is performed using # 3298 1.1 is # _mem_write() "callout" routines that may return a failing result. # 3299 1.1 is # In this special case, the handler must exit through facc_out() # 3300 1.1 is # which creates an access error stack frame from the current SNAN # 3301 1.1 is # stack frame. # 3302 1.1 is # For the case of an extended precision opclass 3 instruction, # 3303 1.1 is # if the effective addressing mode was -() or ()+, then the address # 3304 1.1 is # register must get updated by calling _calc_ea_fout(). If the <ea> # 3305 1.1 is # was -(a7) from supervisor mode, then the exception frame currently # 3306 1.1 is # on the system stack must be carefully moved "down" to make room # 3307 1.1 is # for the operand being moved. # 3308 1.1 is # # 3309 1.1 is ######################################################################### 3310 1.1 is 3311 1.1 is global _fpsp_snan 3312 1.1 is _fpsp_snan: 3313 1.1 is 3314 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame 3315 1.1 is 3316 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame 3317 1.1 is 3318 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3319 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3320 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3321 1.1 is 3322 1.1 is # the FPIAR holds the "current PC" of the faulting instruction 3323 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3324 1.1 is 3325 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3326 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3327 1.1 is bsr.l _imem_read_long # fetch the instruction words 3328 1.1 is mov.l %d0,EXC_OPWORD(%a6) 3329 1.1 is 3330 1.1 is ############################################################################## 3331 1.1 is 3332 1.1 is btst &13,%d0 # is instr an fmove out? 3333 1.1 is bne.w fsnan_out # fmove out 3334 1.1 is 3335 1.1 is 3336 1.1 is # here, we simply see if the operand in the fsave frame needs to be "unskewed". 3337 1.1 is # this would be the case for opclass two operations with a source infinity or 3338 1.1 is # denorm operand in the sgl or dbl format. NANs also become skewed and must be 3339 1.1 is # fixed here. 3340 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 3341 1.1 is bsr.l fix_skewed_ops # fix src op 3342 1.1 is 3343 1.1 is fsnan_exit: 3344 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3345 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3346 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3347 1.1 is 3348 1.1 is frestore FP_SRC(%a6) 3349 1.1 is 3350 1.1 is unlk %a6 3351 1.1 is bra.l _real_snan 3352 1.1 is 3353 1.1 is ######################################################################## 3354 1.1 is 3355 1.1 is # 3356 1.1 is # the hardware does not save the default result to memory on enabled 3357 1.1 is # snan exceptions. we do this here before passing control to 3358 1.1 is # the user snan handler. 3359 1.1 is # 3360 1.1 is # byte, word, long, and packed destination format operations can pass 3361 1.1 is # through here. since packed format operations already were handled by 3362 1.1 is # fpsp_unsupp(), then we need to do nothing else for them here. 3363 1.1 is # for byte, word, and long, we simply need to test the sign of the src 3364 1.1 is # operand and save the appropriate minimum or maximum integer value 3365 1.1 is # to the effective address as pointed to by the stacked effective address. 3366 1.1 is # 3367 1.1 is fsnan_out: 3368 1.1 is 3369 1.1 is bfextu %d0{&19:&3},%d0 # extract dst format field 3370 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract <ea> mode,reg 3371 1.1 is mov.w (tbl_snan.b,%pc,%d0.w*2),%a0 3372 1.1 is jmp (tbl_snan.b,%pc,%a0) 3373 1.1 is 3374 1.1 is tbl_snan: 3375 1.1 is short fsnan_out_l - tbl_snan # long word integer 3376 1.1 is short fsnan_out_s - tbl_snan # sgl prec shouldn't happen 3377 1.1 is short fsnan_out_x - tbl_snan # ext prec shouldn't happen 3378 1.1 is short tbl_snan - tbl_snan # packed needs no help 3379 1.1 is short fsnan_out_w - tbl_snan # word integer 3380 1.1 is short fsnan_out_d - tbl_snan # dbl prec shouldn't happen 3381 1.1 is short fsnan_out_b - tbl_snan # byte integer 3382 1.1 is short tbl_snan - tbl_snan # packed needs no help 3383 1.1 is 3384 1.1 is fsnan_out_b: 3385 1.1 is mov.b FP_SRC_HI(%a6),%d0 # load upper byte of SNAN 3386 1.1 is bset &6,%d0 # set SNAN bit 3387 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3388 1.1 is ble.b fsnan_out_b_dn # yes 3389 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3390 1.1 is bsr.l _dmem_write_byte # write the default result 3391 1.1 is 3392 1.1 is tst.l %d1 # did dstore fail? 3393 1.1 is bne.l facc_out_b # yes 3394 1.1 is 3395 1.1 is bra.w fsnan_exit 3396 1.1 is fsnan_out_b_dn: 3397 1.1 is andi.w &0x0007,%d1 3398 1.1 is bsr.l store_dreg_b # store result to regfile 3399 1.1 is bra.w fsnan_exit 3400 1.1 is 3401 1.1 is fsnan_out_w: 3402 1.1 is mov.w FP_SRC_HI(%a6),%d0 # load upper word of SNAN 3403 1.1 is bset &14,%d0 # set SNAN bit 3404 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3405 1.1 is ble.b fsnan_out_w_dn # yes 3406 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3407 1.1 is bsr.l _dmem_write_word # write the default result 3408 1.1 is 3409 1.1 is tst.l %d1 # did dstore fail? 3410 1.1 is bne.l facc_out_w # yes 3411 1.1 is 3412 1.1 is bra.w fsnan_exit 3413 1.1 is fsnan_out_w_dn: 3414 1.1 is andi.w &0x0007,%d1 3415 1.1 is bsr.l store_dreg_w # store result to regfile 3416 1.1 is bra.w fsnan_exit 3417 1.1 is 3418 1.1 is fsnan_out_l: 3419 1.1 is mov.l FP_SRC_HI(%a6),%d0 # load upper longword of SNAN 3420 1.1 is bset &30,%d0 # set SNAN bit 3421 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3422 1.1 is ble.b fsnan_out_l_dn # yes 3423 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3424 1.1 is bsr.l _dmem_write_long # write the default result 3425 1.1 is 3426 1.1 is tst.l %d1 # did dstore fail? 3427 1.1 is bne.l facc_out_l # yes 3428 1.1 is 3429 1.1 is bra.w fsnan_exit 3430 1.1 is fsnan_out_l_dn: 3431 1.1 is andi.w &0x0007,%d1 3432 1.1 is bsr.l store_dreg_l # store result to regfile 3433 1.1 is bra.w fsnan_exit 3434 1.1 is 3435 1.1 is fsnan_out_s: 3436 1.1 is cmpi.b %d1,&0x7 # is <ea> mode a data reg? 3437 1.1 is ble.b fsnan_out_d_dn # yes 3438 1.1 is mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign 3439 1.1 is andi.l &0x80000000,%d0 # keep sign 3440 1.1 is ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit 3441 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load mantissa 3442 1.1 is lsr.l &0x8,%d1 # shift mantissa for sgl 3443 1.1 is or.l %d1,%d0 # create sgl SNAN 3444 1.1 is mov.l EXC_EA(%a6),%a0 # pass: <ea> of default result 3445 1.1 is bsr.l _dmem_write_long # write the default result 3446 1.1 is 3447 1.1 is tst.l %d1 # did dstore fail? 3448 1.1 is bne.l facc_out_l # yes 3449 1.1 is 3450 1.1 is bra.w fsnan_exit 3451 1.1 is fsnan_out_d_dn: 3452 1.1 is mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign 3453 1.1 is andi.l &0x80000000,%d0 # keep sign 3454 1.1 is ori.l &0x7fc00000,%d0 # insert new exponent,SNAN bit 3455 1.1 is mov.l %d1,-(%sp) 3456 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load mantissa 3457 1.1 is lsr.l &0x8,%d1 # shift mantissa for sgl 3458 1.1 is or.l %d1,%d0 # create sgl SNAN 3459 1.1 is mov.l (%sp)+,%d1 3460 1.1 is andi.w &0x0007,%d1 3461 1.1 is bsr.l store_dreg_l # store result to regfile 3462 1.1 is bra.w fsnan_exit 3463 1.1 is 3464 1.1 is fsnan_out_d: 3465 1.1 is mov.l FP_SRC_EX(%a6),%d0 # fetch SNAN sign 3466 1.1 is andi.l &0x80000000,%d0 # keep sign 3467 1.1 is ori.l &0x7ff80000,%d0 # insert new exponent,SNAN bit 3468 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa 3469 1.1 is mov.l %d0,FP_SCR0_EX(%a6) # store to temp space 3470 1.1 is mov.l &11,%d0 # load shift amt 3471 1.1 is lsr.l %d0,%d1 3472 1.1 is or.l %d1,FP_SCR0_EX(%a6) # create dbl hi 3473 1.1 is mov.l FP_SRC_HI(%a6),%d1 # load hi mantissa 3474 1.1 is andi.l &0x000007ff,%d1 3475 1.1 is ror.l %d0,%d1 3476 1.1 is mov.l %d1,FP_SCR0_HI(%a6) # store to temp space 3477 1.1 is mov.l FP_SRC_LO(%a6),%d1 # load lo mantissa 3478 1.1 is lsr.l %d0,%d1 3479 1.1 is or.l %d1,FP_SCR0_HI(%a6) # create dbl lo 3480 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand 3481 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr 3482 1.1 is movq.l &0x8,%d0 # pass: size of 8 bytes 3483 1.1 is bsr.l _dmem_write # write the default result 3484 1.1 is 3485 1.1 is tst.l %d1 # did dstore fail? 3486 1.1 is bne.l facc_out_d # yes 3487 1.1 is 3488 1.1 is bra.w fsnan_exit 3489 1.1 is 3490 1.1 is # for extended precision, if the addressing mode is pre-decrement or 3491 1.1 is # post-increment, then the address register did not get updated. 3492 1.1 is # in addition, for pre-decrement, the stacked <ea> is incorrect. 3493 1.1 is fsnan_out_x: 3494 1.1 is clr.b SPCOND_FLG(%a6) # clear special case flag 3495 1.1 is 3496 1.1 is mov.w FP_SRC_EX(%a6),FP_SCR0_EX(%a6) 3497 1.1 is clr.w 2+FP_SCR0(%a6) 3498 1.1 is mov.l FP_SRC_HI(%a6),%d0 3499 1.1 is bset &30,%d0 3500 1.1 is mov.l %d0,FP_SCR0_HI(%a6) 3501 1.1 is mov.l FP_SRC_LO(%a6),FP_SCR0_LO(%a6) 3502 1.1 is 3503 1.1 is btst &0x5,EXC_SR(%a6) # supervisor mode exception? 3504 1.1 is bne.b fsnan_out_x_s # yes 3505 1.1 is 3506 1.1 is mov.l %usp,%a0 # fetch user stack pointer 3507 1.1 is mov.l %a0,EXC_A7(%a6) # save on stack for calc_ea() 3508 1.1 is mov.l (%a6),EXC_A6(%a6) 3509 1.1 is 3510 1.1 is bsr.l _calc_ea_fout # find the correct ea,update An 3511 1.1 is mov.l %a0,%a1 3512 1.1 is mov.l %a0,EXC_EA(%a6) # stack correct <ea> 3513 1.1 is 3514 1.1 is mov.l EXC_A7(%a6),%a0 3515 1.1 is mov.l %a0,%usp # restore user stack pointer 3516 1.1 is mov.l EXC_A6(%a6),(%a6) 3517 1.1 is 3518 1.1 is fsnan_out_x_save: 3519 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand 3520 1.1 is movq.l &0xc,%d0 # pass: size of extended 3521 1.1 is bsr.l _dmem_write # write the default result 3522 1.1 is 3523 1.1 is tst.l %d1 # did dstore fail? 3524 1.1 is bne.l facc_out_x # yes 3525 1.1 is 3526 1.1 is bra.w fsnan_exit 3527 1.1 is 3528 1.1 is fsnan_out_x_s: 3529 1.1 is mov.l (%a6),EXC_A6(%a6) 3530 1.1 is 3531 1.1 is bsr.l _calc_ea_fout # find the correct ea,update An 3532 1.1 is mov.l %a0,%a1 3533 1.1 is mov.l %a0,EXC_EA(%a6) # stack correct <ea> 3534 1.1 is 3535 1.1 is mov.l EXC_A6(%a6),(%a6) 3536 1.1 is 3537 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)? 3538 1.1 is bne.b fsnan_out_x_save # no 3539 1.1 is 3540 1.1 is # the operation was "fmove.x SNAN,-(a7)" from supervisor mode. 3541 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3542 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3543 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3544 1.1 is 3545 1.1 is frestore FP_SRC(%a6) 3546 1.1 is 3547 1.1 is mov.l EXC_A6(%a6),%a6 # restore frame pointer 3548 1.1 is 3549 1.1 is mov.l LOCAL_SIZE+EXC_SR(%sp),LOCAL_SIZE+EXC_SR-0xc(%sp) 3550 1.1 is mov.l LOCAL_SIZE+EXC_PC+0x2(%sp),LOCAL_SIZE+EXC_PC+0x2-0xc(%sp) 3551 1.1 is mov.l LOCAL_SIZE+EXC_EA(%sp),LOCAL_SIZE+EXC_EA-0xc(%sp) 3552 1.1 is 3553 1.1 is mov.l LOCAL_SIZE+FP_SCR0_EX(%sp),LOCAL_SIZE+EXC_SR(%sp) 3554 1.1 is mov.l LOCAL_SIZE+FP_SCR0_HI(%sp),LOCAL_SIZE+EXC_PC+0x2(%sp) 3555 1.1 is mov.l LOCAL_SIZE+FP_SCR0_LO(%sp),LOCAL_SIZE+EXC_EA(%sp) 3556 1.1 is 3557 1.1 is add.l &LOCAL_SIZE-0x8,%sp 3558 1.1 is 3559 1.1 is bra.l _real_snan 3560 1.1 is 3561 1.1 is ######################################################################### 3562 1.1 is # XDEF **************************************************************** # 3563 1.1 is # _fpsp_inex(): 060FPSP entry point for FP Inexact exception. # 3564 1.1 is # # 3565 1.1 is # This handler should be the first code executed upon taking the # 3566 1.1 is # FP Inexact exception in an operating system. # 3567 1.1 is # # 3568 1.1 is # XREF **************************************************************** # 3569 1.1 is # _imem_read_long() - read instruction longword # 3570 1.1 is # fix_skewed_ops() - adjust src operand in fsave frame # 3571 1.1 is # set_tag_x() - determine optype of src/dst operands # 3572 1.1 is # store_fpreg() - store opclass 0 or 2 result to FP regfile # 3573 1.1 is # unnorm_fix() - change UNNORM operands to NORM or ZERO # 3574 1.1 is # load_fpn2() - load dst operand from FP regfile # 3575 1.1 is # smovcr() - emulate an "fmovcr" instruction # 3576 1.1 is # fout() - emulate an opclass 3 instruction # 3577 1.1 is # tbl_unsupp - add of table of emulation routines for opclass 0,2 # 3578 1.1 is # _real_inex() - "callout" to operating system inexact handler # 3579 1.1 is # # 3580 1.1 is # INPUT *************************************************************** # 3581 1.1 is # - The system stack contains the FP Inexact exception frame # 3582 1.1 is # - The fsave frame contains the source operand # 3583 1.1 is # # 3584 1.1 is # OUTPUT ************************************************************** # 3585 1.1 is # - The system stack is unchanged # 3586 1.1 is # - The fsave frame contains the adjusted src op for opclass 0,2 # 3587 1.1 is # # 3588 1.1 is # ALGORITHM *********************************************************** # 3589 1.1 is # In a system where the FP Inexact exception is enabled, the goal # 3590 1.1 is # is to get to the handler specified at _real_inex(). But, on the 060, # 3591 1.1 is # for opclass zero and two instruction taking this exception, the # 3592 1.1 is # hardware doesn't store the correct result to the destination FP # 3593 1.1 is # register as did the '040 and '881/2. This handler must emulate the # 3594 1.1 is # instruction in order to get this value and then store it to the # 3595 1.1 is # correct register before calling _real_inex(). # 3596 1.1 is # For opclass 3 instructions, the 060 doesn't store the default # 3597 1.1 is # inexact result out to memory or data register file as it should. # 3598 1.1 is # This code must emulate the move out by calling fout() before finally # 3599 1.1 is # exiting through _real_inex(). # 3600 1.1 is # # 3601 1.1 is ######################################################################### 3602 1.1 is 3603 1.1 is global _fpsp_inex 3604 1.1 is _fpsp_inex: 3605 1.1 is 3606 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame 3607 1.1 is 3608 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame 3609 1.1 is 3610 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3611 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3612 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3613 1.1 is 3614 1.1 is # the FPIAR holds the "current PC" of the faulting instruction 3615 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3616 1.1 is 3617 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3618 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3619 1.1 is bsr.l _imem_read_long # fetch the instruction words 3620 1.1 is mov.l %d0,EXC_OPWORD(%a6) 3621 1.1 is 3622 1.1 is ############################################################################## 3623 1.1 is 3624 1.1 is btst &13,%d0 # is instr an fmove out? 3625 1.1 is bne.w finex_out # fmove out 3626 1.1 is 3627 1.1 is 3628 1.1 is # the hardware, for "fabs" and "fneg" w/ a long source format, puts the 3629 1.1 is # longword integer directly into the upper longword of the mantissa along 3630 1.1 is # w/ an exponent value of 0x401e. we convert this to extended precision here. 3631 1.1 is bfextu %d0{&19:&3},%d0 # fetch instr size 3632 1.1 is bne.b finex_cont # instr size is not long 3633 1.1 is cmpi.w FP_SRC_EX(%a6),&0x401e # is exponent 0x401e? 3634 1.1 is bne.b finex_cont # no 3635 1.1 is fmov.l &0x0,%fpcr 3636 1.1 is fmov.l FP_SRC_HI(%a6),%fp0 # load integer src 3637 1.1 is fmov.x %fp0,FP_SRC(%a6) # store integer as extended precision 3638 1.1 is mov.w &0xe001,0x2+FP_SRC(%a6) 3639 1.1 is 3640 1.1 is finex_cont: 3641 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 3642 1.1 is bsr.l fix_skewed_ops # fix src op 3643 1.1 is 3644 1.1 is # Here, we zero the ccode and exception byte field since we're going to 3645 1.1 is # emulate the whole instruction. Notice, though, that we don't kill the 3646 1.1 is # INEX1 bit. This is because a packed op has long since been converted 3647 1.1 is # to extended before arriving here. Therefore, we need to retain the 3648 1.1 is # INEX1 bit from when the operand was first converted. 3649 1.1 is andi.l &0x00ff01ff,USER_FPSR(%a6) # zero all but accured field 3650 1.1 is 3651 1.1 is fmov.l &0x0,%fpcr # zero current control regs 3652 1.1 is fmov.l &0x0,%fpsr 3653 1.1 is 3654 1.1 is bfextu EXC_EXTWORD(%a6){&0:&6},%d1 # extract upper 6 of cmdreg 3655 1.1 is cmpi.b %d1,&0x17 # is op an fmovecr? 3656 1.1 is beq.w finex_fmovcr # yes 3657 1.1 is 3658 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 3659 1.1 is bsr.l set_tag_x # tag the operand type 3660 1.1 is mov.b %d0,STAG(%a6) # maybe NORM,DENORM 3661 1.1 is 3662 1.1 is # bits four and five of the fp extension word separate the monadic and dyadic 3663 1.1 is # operations that can pass through fpsp_inex(). remember that fcmp and ftst 3664 1.1 is # will never take this exception, but fsincos will. 3665 1.1 is btst &0x5,1+EXC_CMDREG(%a6) # is operation monadic or dyadic? 3666 1.1 is beq.b finex_extract # monadic 3667 1.1 is 3668 1.1 is btst &0x4,1+EXC_CMDREG(%a6) # is operation an fsincos? 3669 1.1 is bne.b finex_extract # yes 3670 1.1 is 3671 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 # dyadic; load dst reg 3672 1.1 is bsr.l load_fpn2 # load dst into FP_DST 3673 1.1 is 3674 1.1 is lea FP_DST(%a6),%a0 # pass: ptr to dst op 3675 1.1 is bsr.l set_tag_x # tag the operand type 3676 1.1 is cmpi.b %d0,&UNNORM # is operand an UNNORM? 3677 1.1 is bne.b finex_op2_done # no 3678 1.1 is bsr.l unnorm_fix # yes; convert to NORM,DENORM,or ZERO 3679 1.1 is finex_op2_done: 3680 1.1 is mov.b %d0,DTAG(%a6) # save dst optype tag 3681 1.1 is 3682 1.1 is finex_extract: 3683 1.1 is clr.l %d0 3684 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec/mode 3685 1.1 is 3686 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1 3687 1.1 is andi.w &0x007f,%d1 # extract extension 3688 1.1 is 3689 1.1 is lea FP_SRC(%a6),%a0 3690 1.1 is lea FP_DST(%a6),%a1 3691 1.1 is 3692 1.1 is mov.l (tbl_unsupp.l,%pc,%d1.w*4),%d1 # fetch routine addr 3693 1.1 is jsr (tbl_unsupp.l,%pc,%d1.l*1) 3694 1.1 is 3695 1.1 is # the operation has been emulated. the result is in fp0. 3696 1.1 is finex_save: 3697 1.1 is bfextu EXC_CMDREG(%a6){&6:&3},%d0 3698 1.1 is bsr.l store_fpreg 3699 1.1 is 3700 1.1 is finex_exit: 3701 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3702 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3703 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3704 1.1 is 3705 1.1 is frestore FP_SRC(%a6) 3706 1.1 is 3707 1.1 is unlk %a6 3708 1.1 is bra.l _real_inex 3709 1.1 is 3710 1.1 is finex_fmovcr: 3711 1.1 is clr.l %d0 3712 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode 3713 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1 3714 1.1 is andi.l &0x0000007f,%d1 # pass rom offset 3715 1.1 is bsr.l smovcr 3716 1.1 is bra.b finex_save 3717 1.1 is 3718 1.1 is ######################################################################## 3719 1.1 is 3720 1.1 is # 3721 1.1 is # the hardware does not save the default result to memory on enabled 3722 1.1 is # inexact exceptions. we do this here before passing control to 3723 1.1 is # the user inexact handler. 3724 1.1 is # 3725 1.1 is # byte, word, and long destination format operations can pass 3726 1.1 is # through here. so can double and single precision. 3727 1.1 is # although packed opclass three operations can take inexact 3728 1.1 is # exceptions, they won't pass through here since they are caught 3729 1.1 is # first by the unsupported data format exception handler. that handler 3730 1.1 is # sends them directly to _real_inex() if necessary. 3731 1.1 is # 3732 1.1 is finex_out: 3733 1.1 is 3734 1.1 is mov.b &NORM,STAG(%a6) # src is a NORM 3735 1.1 is 3736 1.1 is clr.l %d0 3737 1.1 is mov.b FPCR_MODE(%a6),%d0 # pass rnd prec,mode 3738 1.1 is 3739 1.1 is andi.l &0xffff00ff,USER_FPSR(%a6) # zero exception field 3740 1.1 is 3741 1.1 is lea FP_SRC(%a6),%a0 # pass ptr to src operand 3742 1.1 is 3743 1.1 is bsr.l fout # store the default result 3744 1.1 is 3745 1.1 is bra.b finex_exit 3746 1.1 is 3747 1.1 is ######################################################################### 3748 1.1 is # XDEF **************************************************************** # 3749 1.1 is # _fpsp_dz(): 060FPSP entry point for FP DZ exception. # 3750 1.1 is # # 3751 1.1 is # This handler should be the first code executed upon taking # 3752 1.1 is # the FP DZ exception in an operating system. # 3753 1.1 is # # 3754 1.1 is # XREF **************************************************************** # 3755 1.1 is # _imem_read_long() - read instruction longword from memory # 3756 1.1 is # fix_skewed_ops() - adjust fsave operand # 3757 1.1 is # _real_dz() - "callout" exit point from FP DZ handler # 3758 1.1 is # # 3759 1.1 is # INPUT *************************************************************** # 3760 1.1 is # - The system stack contains the FP DZ exception stack. # 3761 1.1 is # - The fsave frame contains the source operand. # 3762 1.1 is # # 3763 1.1 is # OUTPUT ************************************************************** # 3764 1.1 is # - The system stack contains the FP DZ exception stack. # 3765 1.1 is # - The fsave frame contains the adjusted source operand. # 3766 1.1 is # # 3767 1.1 is # ALGORITHM *********************************************************** # 3768 1.1 is # In a system where the DZ exception is enabled, the goal is to # 3769 1.1 is # get to the handler specified at _real_dz(). But, on the 060, when the # 3770 1.1 is # exception is taken, the input operand in the fsave state frame may # 3771 1.1 is # be incorrect for some cases and need to be adjusted. So, this package # 3772 1.1 is # adjusts the operand using fix_skewed_ops() and then branches to # 3773 1.1 is # _real_dz(). # 3774 1.1 is # # 3775 1.1 is ######################################################################### 3776 1.1 is 3777 1.1 is global _fpsp_dz 3778 1.1 is _fpsp_dz: 3779 1.1 is 3780 1.1 is link.w %a6,&-LOCAL_SIZE # init stack frame 3781 1.1 is 3782 1.1 is fsave FP_SRC(%a6) # grab the "busy" frame 3783 1.1 is 3784 1.1 is movm.l &0x0303,EXC_DREGS(%a6) # save d0-d1/a0-a1 3785 1.1 is fmovm.l %fpcr,%fpsr,%fpiar,USER_FPCR(%a6) # save ctrl regs 3786 1.1 is fmovm.x &0xc0,EXC_FPREGS(%a6) # save fp0-fp1 on stack 3787 1.1 is 3788 1.1 is # the FPIAR holds the "current PC" of the faulting instruction 3789 1.1 is mov.l USER_FPIAR(%a6),EXC_EXTWPTR(%a6) 3790 1.1 is 3791 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 3792 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 3793 1.1 is bsr.l _imem_read_long # fetch the instruction words 3794 1.1 is mov.l %d0,EXC_OPWORD(%a6) 3795 1.1 is 3796 1.1 is ############################################################################## 3797 1.1 is 3798 1.1 is 3799 1.1 is # here, we simply see if the operand in the fsave frame needs to be "unskewed". 3800 1.1 is # this would be the case for opclass two operations with a source zero 3801 1.1 is # in the sgl or dbl format. 3802 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to src op 3803 1.1 is bsr.l fix_skewed_ops # fix src op 3804 1.1 is 3805 1.1 is fdz_exit: 3806 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 3807 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 3808 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 3809 1.1 is 3810 1.1 is frestore FP_SRC(%a6) 3811 1.1 is 3812 1.1 is unlk %a6 3813 1.1 is bra.l _real_dz 3814 1.1 is 3815 1.1 is ######################################################################### 3816 1.1 is # XDEF **************************************************************** # 3817 1.1 is # _fpsp_fline(): 060FPSP entry point for "Line F emulator" # 3818 1.1 is # exception when the "reduced" version of the # 3819 1.1 is # FPSP is implemented that does not emulate # 3820 1.1 is # FP unimplemented instructions. # 3821 1.1 is # # 3822 1.1 is # This handler should be the first code executed upon taking a # 3823 1.1 is # "Line F Emulator" exception in an operating system integrating # 3824 1.1 is # the reduced version of 060FPSP. # 3825 1.1 is # # 3826 1.1 is # XREF **************************************************************** # 3827 1.1 is # _real_fpu_disabled() - Handle "FPU disabled" exceptions # 3828 1.1 is # _real_fline() - Handle all other cases (treated equally) # 3829 1.1 is # # 3830 1.1 is # INPUT *************************************************************** # 3831 1.1 is # - The system stack contains a "Line F Emulator" exception # 3832 1.1 is # stack frame. # 3833 1.1 is # # 3834 1.1 is # OUTPUT ************************************************************** # 3835 1.1 is # - The system stack is unchanged. # 3836 1.1 is # # 3837 1.1 is # ALGORITHM *********************************************************** # 3838 1.1 is # When a "Line F Emulator" exception occurs in a system where # 3839 1.1 is # "FPU Unimplemented" instructions will not be emulated, the exception # 3840 1.1 is # can occur because then FPU is disabled or the instruction is to be # 3841 1.1 is # classifed as "Line F". This module determines which case exists and # 3842 1.1 is # calls the appropriate "callout". # 3843 1.1 is # # 3844 1.1 is ######################################################################### 3845 1.1 is 3846 1.1 is global _fpsp_fline 3847 1.1 is _fpsp_fline: 3848 1.1 is 3849 1.1 is # check to see if the FPU is disabled. if so, jump to the OS entry 3850 1.1 is # point for that condition. 3851 1.1 is cmpi.w 0x6(%sp),&0x402c 3852 1.1 is beq.l _real_fpu_disabled 3853 1.1 is 3854 1.1 is bra.l _real_fline 3855 1.1 is 3856 1.1 is ######################################################################### 3857 1.1 is # XDEF **************************************************************** # 3858 1.1 is # _dcalc_ea(): calc correct <ea> from <ea> stacked on exception # 3859 1.1 is # # 3860 1.1 is # XREF **************************************************************** # 3861 1.1 is # inc_areg() - increment an address register # 3862 1.1 is # dec_areg() - decrement an address register # 3863 1.1 is # # 3864 1.1 is # INPUT *************************************************************** # 3865 1.1 is # d0 = number of bytes to adjust <ea> by # 3866 1.1 is # # 3867 1.1 is # OUTPUT ************************************************************** # 3868 1.1 is # None # 3869 1.1 is # # 3870 1.1 is # ALGORITHM *********************************************************** # 3871 1.1 is # "Dummy" CALCulate Effective Address: # 3872 1.1 is # The stacked <ea> for FP unimplemented instructions and opclass # 3873 1.1 is # two packed instructions is correct with the exception of... # 3874 1.1 is # # 3875 1.1 is # 1) -(An) : The register is not updated regardless of size. # 3876 1.1 is # Also, for extended precision and packed, the # 3877 1.1 is # stacked <ea> value is 8 bytes too big # 3878 1.1 is # 2) (An)+ : The register is not updated. # 3879 1.1 is # 3) #<data> : The upper longword of the immediate operand is # 3880 1.1 is # stacked b,w,l and s sizes are completely stacked. # 3881 1.1 is # d,x, and p are not. # 3882 1.1 is # # 3883 1.1 is ######################################################################### 3884 1.1 is 3885 1.1 is global _dcalc_ea 3886 1.1 is _dcalc_ea: 3887 1.1 is mov.l %d0, %a0 # move # bytes to %a0 3888 1.1 is 3889 1.1 is mov.b 1+EXC_OPWORD(%a6), %d0 # fetch opcode word 3890 1.1 is mov.l %d0, %d1 # make a copy 3891 1.1 is 3892 1.1 is andi.w &0x38, %d0 # extract mode field 3893 1.1 is andi.l &0x7, %d1 # extract reg field 3894 1.1 is 3895 1.1 is cmpi.b %d0,&0x18 # is mode (An)+ ? 3896 1.1 is beq.b dcea_pi # yes 3897 1.1 is 3898 1.1 is cmpi.b %d0,&0x20 # is mode -(An) ? 3899 1.1 is beq.b dcea_pd # yes 3900 1.1 is 3901 1.1 is or.w %d1,%d0 # concat mode,reg 3902 1.1 is cmpi.b %d0,&0x3c # is mode #<data>? 3903 1.1 is 3904 1.1 is beq.b dcea_imm # yes 3905 1.1 is 3906 1.1 is mov.l EXC_EA(%a6),%a0 # return <ea> 3907 1.1 is rts 3908 1.1 is 3909 1.1 is # need to set immediate data flag here since we'll need to do 3910 1.1 is # an imem_read to fetch this later. 3911 1.1 is dcea_imm: 3912 1.1 is mov.b &immed_flg,SPCOND_FLG(%a6) 3913 1.1 is lea ([USER_FPIAR,%a6],0x4),%a0 # no; return <ea> 3914 1.1 is rts 3915 1.1 is 3916 1.1 is # here, the <ea> is stacked correctly. however, we must update the 3917 1.1 is # address register... 3918 1.1 is dcea_pi: 3919 1.1 is mov.l %a0,%d0 # pass amt to inc by 3920 1.1 is bsr.l inc_areg # inc addr register 3921 1.1 is 3922 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 3923 1.1 is rts 3924 1.1 is 3925 1.1 is # the <ea> is stacked correctly for all but extended and packed which 3926 1.1 is # the <ea>s are 8 bytes too large. 3927 1.1 is # it would make no sense to have a pre-decrement to a7 in supervisor 3928 1.1 is # mode so we don't even worry about this tricky case here : ) 3929 1.1 is dcea_pd: 3930 1.1 is mov.l %a0,%d0 # pass amt to dec by 3931 1.1 is bsr.l dec_areg # dec addr register 3932 1.1 is 3933 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 3934 1.1 is 3935 1.1 is cmpi.b %d0,&0xc # is opsize ext or packed? 3936 1.1 is beq.b dcea_pd2 # yes 3937 1.1 is rts 3938 1.1 is dcea_pd2: 3939 1.1 is sub.l &0x8,%a0 # correct <ea> 3940 1.1 is mov.l %a0,EXC_EA(%a6) # put correct <ea> on stack 3941 1.1 is rts 3942 1.1 is 3943 1.1 is ######################################################################### 3944 1.1 is # XDEF **************************************************************** # 3945 1.1 is # _calc_ea_fout(): calculate correct stacked <ea> for extended # 3946 1.1 is # and packed data opclass 3 operations. # 3947 1.1 is # # 3948 1.1 is # XREF **************************************************************** # 3949 1.1 is # None # 3950 1.1 is # # 3951 1.1 is # INPUT *************************************************************** # 3952 1.1 is # None # 3953 1.1 is # # 3954 1.1 is # OUTPUT ************************************************************** # 3955 1.1 is # a0 = return correct effective address # 3956 1.1 is # # 3957 1.1 is # ALGORITHM *********************************************************** # 3958 1.1 is # For opclass 3 extended and packed data operations, the <ea> # 3959 1.1 is # stacked for the exception is incorrect for -(an) and (an)+ addressing # 3960 1.1 is # modes. Also, while we're at it, the index register itself must get # 3961 1.1 is # updated. # 3962 1.1 is # So, for -(an), we must subtract 8 off of the stacked <ea> value # 3963 1.1 is # and return that value as the correct <ea> and store that value in An. # 3964 1.1 is # For (an)+, the stacked <ea> is correct but we must adjust An by +12. # 3965 1.1 is # # 3966 1.1 is ######################################################################### 3967 1.1 is 3968 1.1 is # This calc_ea is currently used to retrieve the correct <ea> 3969 1.1 is # for fmove outs of type extended and packed. 3970 1.1 is global _calc_ea_fout 3971 1.1 is _calc_ea_fout: 3972 1.1 is mov.b 1+EXC_OPWORD(%a6),%d0 # fetch opcode word 3973 1.1 is mov.l %d0,%d1 # make a copy 3974 1.1 is 3975 1.1 is andi.w &0x38,%d0 # extract mode field 3976 1.1 is andi.l &0x7,%d1 # extract reg field 3977 1.1 is 3978 1.1 is cmpi.b %d0,&0x18 # is mode (An)+ ? 3979 1.1 is beq.b ceaf_pi # yes 3980 1.1 is 3981 1.1 is cmpi.b %d0,&0x20 # is mode -(An) ? 3982 1.1 is beq.w ceaf_pd # yes 3983 1.1 is 3984 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 3985 1.1 is rts 3986 1.1 is 3987 1.1 is # (An)+ : extended and packed fmove out 3988 1.1 is # : stacked <ea> is correct 3989 1.1 is # : "An" not updated 3990 1.1 is ceaf_pi: 3991 1.1 is mov.w (tbl_ceaf_pi.b,%pc,%d1.w*2),%d1 3992 1.1 is mov.l EXC_EA(%a6),%a0 3993 1.1 is jmp (tbl_ceaf_pi.b,%pc,%d1.w*1) 3994 1.1 is 3995 1.1 is swbeg &0x8 3996 1.1 is tbl_ceaf_pi: 3997 1.1 is short ceaf_pi0 - tbl_ceaf_pi 3998 1.1 is short ceaf_pi1 - tbl_ceaf_pi 3999 1.1 is short ceaf_pi2 - tbl_ceaf_pi 4000 1.1 is short ceaf_pi3 - tbl_ceaf_pi 4001 1.1 is short ceaf_pi4 - tbl_ceaf_pi 4002 1.1 is short ceaf_pi5 - tbl_ceaf_pi 4003 1.1 is short ceaf_pi6 - tbl_ceaf_pi 4004 1.1 is short ceaf_pi7 - tbl_ceaf_pi 4005 1.1 is 4006 1.1 is ceaf_pi0: 4007 1.1 is addi.l &0xc,EXC_DREGS+0x8(%a6) 4008 1.1 is rts 4009 1.1 is ceaf_pi1: 4010 1.1 is addi.l &0xc,EXC_DREGS+0xc(%a6) 4011 1.1 is rts 4012 1.1 is ceaf_pi2: 4013 1.1 is add.l &0xc,%a2 4014 1.1 is rts 4015 1.1 is ceaf_pi3: 4016 1.1 is add.l &0xc,%a3 4017 1.1 is rts 4018 1.1 is ceaf_pi4: 4019 1.1 is add.l &0xc,%a4 4020 1.1 is rts 4021 1.1 is ceaf_pi5: 4022 1.1 is add.l &0xc,%a5 4023 1.1 is rts 4024 1.1 is ceaf_pi6: 4025 1.1 is addi.l &0xc,EXC_A6(%a6) 4026 1.1 is rts 4027 1.1 is ceaf_pi7: 4028 1.1 is mov.b &mia7_flg,SPCOND_FLG(%a6) 4029 1.1 is addi.l &0xc,EXC_A7(%a6) 4030 1.1 is rts 4031 1.1 is 4032 1.1 is # -(An) : extended and packed fmove out 4033 1.1 is # : stacked <ea> = actual <ea> + 8 4034 1.1 is # : "An" not updated 4035 1.1 is ceaf_pd: 4036 1.1 is mov.w (tbl_ceaf_pd.b,%pc,%d1.w*2),%d1 4037 1.1 is mov.l EXC_EA(%a6),%a0 4038 1.1 is sub.l &0x8,%a0 4039 1.1 is sub.l &0x8,EXC_EA(%a6) 4040 1.1 is jmp (tbl_ceaf_pd.b,%pc,%d1.w*1) 4041 1.1 is 4042 1.1 is swbeg &0x8 4043 1.1 is tbl_ceaf_pd: 4044 1.1 is short ceaf_pd0 - tbl_ceaf_pd 4045 1.1 is short ceaf_pd1 - tbl_ceaf_pd 4046 1.1 is short ceaf_pd2 - tbl_ceaf_pd 4047 1.1 is short ceaf_pd3 - tbl_ceaf_pd 4048 1.1 is short ceaf_pd4 - tbl_ceaf_pd 4049 1.1 is short ceaf_pd5 - tbl_ceaf_pd 4050 1.1 is short ceaf_pd6 - tbl_ceaf_pd 4051 1.1 is short ceaf_pd7 - tbl_ceaf_pd 4052 1.1 is 4053 1.1 is ceaf_pd0: 4054 1.1 is mov.l %a0,EXC_DREGS+0x8(%a6) 4055 1.1 is rts 4056 1.1 is ceaf_pd1: 4057 1.1 is mov.l %a0,EXC_DREGS+0xc(%a6) 4058 1.1 is rts 4059 1.1 is ceaf_pd2: 4060 1.1 is mov.l %a0,%a2 4061 1.1 is rts 4062 1.1 is ceaf_pd3: 4063 1.1 is mov.l %a0,%a3 4064 1.1 is rts 4065 1.1 is ceaf_pd4: 4066 1.1 is mov.l %a0,%a4 4067 1.1 is rts 4068 1.1 is ceaf_pd5: 4069 1.1 is mov.l %a0,%a5 4070 1.1 is rts 4071 1.1 is ceaf_pd6: 4072 1.1 is mov.l %a0,EXC_A6(%a6) 4073 1.1 is rts 4074 1.1 is ceaf_pd7: 4075 1.1 is mov.l %a0,EXC_A7(%a6) 4076 1.1 is mov.b &mda7_flg,SPCOND_FLG(%a6) 4077 1.1 is rts 4078 1.1 is 4079 1.1 is # 4080 1.1 is # This table holds the offsets of the emulation routines for each individual 4081 1.1 is # math operation relative to the address of this table. Included are 4082 1.1 is # routines like fadd/fmul/fabs. The transcendentals ARE NOT. This is because 4083 1.1 is # this table is for the version if the 060FPSP without transcendentals. 4084 1.1 is # The location within the table is determined by the extension bits of the 4085 1.1 is # operation longword. 4086 1.1 is # 4087 1.1 is 4088 1.1 is swbeg &109 4089 1.1 is tbl_unsupp: 4090 1.1 is long fin - tbl_unsupp # 00: fmove 4091 1.1 is long fint - tbl_unsupp # 01: fint 4092 1.1 is long tbl_unsupp - tbl_unsupp # 02: fsinh 4093 1.1 is long fintrz - tbl_unsupp # 03: fintrz 4094 1.1 is long fsqrt - tbl_unsupp # 04: fsqrt 4095 1.1 is long tbl_unsupp - tbl_unsupp 4096 1.1 is long tbl_unsupp - tbl_unsupp # 06: flognp1 4097 1.1 is long tbl_unsupp - tbl_unsupp 4098 1.1 is long tbl_unsupp - tbl_unsupp # 08: fetoxm1 4099 1.1 is long tbl_unsupp - tbl_unsupp # 09: ftanh 4100 1.1 is long tbl_unsupp - tbl_unsupp # 0a: fatan 4101 1.1 is long tbl_unsupp - tbl_unsupp 4102 1.1 is long tbl_unsupp - tbl_unsupp # 0c: fasin 4103 1.1 is long tbl_unsupp - tbl_unsupp # 0d: fatanh 4104 1.1 is long tbl_unsupp - tbl_unsupp # 0e: fsin 4105 1.1 is long tbl_unsupp - tbl_unsupp # 0f: ftan 4106 1.1 is long tbl_unsupp - tbl_unsupp # 10: fetox 4107 1.1 is long tbl_unsupp - tbl_unsupp # 11: ftwotox 4108 1.1 is long tbl_unsupp - tbl_unsupp # 12: ftentox 4109 1.1 is long tbl_unsupp - tbl_unsupp 4110 1.1 is long tbl_unsupp - tbl_unsupp # 14: flogn 4111 1.1 is long tbl_unsupp - tbl_unsupp # 15: flog10 4112 1.1 is long tbl_unsupp - tbl_unsupp # 16: flog2 4113 1.1 is long tbl_unsupp - tbl_unsupp 4114 1.1 is long fabs - tbl_unsupp # 18: fabs 4115 1.1 is long tbl_unsupp - tbl_unsupp # 19: fcosh 4116 1.1 is long fneg - tbl_unsupp # 1a: fneg 4117 1.1 is long tbl_unsupp - tbl_unsupp 4118 1.1 is long tbl_unsupp - tbl_unsupp # 1c: facos 4119 1.1 is long tbl_unsupp - tbl_unsupp # 1d: fcos 4120 1.1 is long tbl_unsupp - tbl_unsupp # 1e: fgetexp 4121 1.1 is long tbl_unsupp - tbl_unsupp # 1f: fgetman 4122 1.1 is long fdiv - tbl_unsupp # 20: fdiv 4123 1.1 is long tbl_unsupp - tbl_unsupp # 21: fmod 4124 1.1 is long fadd - tbl_unsupp # 22: fadd 4125 1.1 is long fmul - tbl_unsupp # 23: fmul 4126 1.1 is long fsgldiv - tbl_unsupp # 24: fsgldiv 4127 1.1 is long tbl_unsupp - tbl_unsupp # 25: frem 4128 1.1 is long tbl_unsupp - tbl_unsupp # 26: fscale 4129 1.1 is long fsglmul - tbl_unsupp # 27: fsglmul 4130 1.1 is long fsub - tbl_unsupp # 28: fsub 4131 1.1 is long tbl_unsupp - tbl_unsupp 4132 1.1 is long tbl_unsupp - tbl_unsupp 4133 1.1 is long tbl_unsupp - tbl_unsupp 4134 1.1 is long tbl_unsupp - tbl_unsupp 4135 1.1 is long tbl_unsupp - tbl_unsupp 4136 1.1 is long tbl_unsupp - tbl_unsupp 4137 1.1 is long tbl_unsupp - tbl_unsupp 4138 1.1 is long tbl_unsupp - tbl_unsupp # 30: fsincos 4139 1.1 is long tbl_unsupp - tbl_unsupp # 31: fsincos 4140 1.1 is long tbl_unsupp - tbl_unsupp # 32: fsincos 4141 1.1 is long tbl_unsupp - tbl_unsupp # 33: fsincos 4142 1.1 is long tbl_unsupp - tbl_unsupp # 34: fsincos 4143 1.1 is long tbl_unsupp - tbl_unsupp # 35: fsincos 4144 1.1 is long tbl_unsupp - tbl_unsupp # 36: fsincos 4145 1.1 is long tbl_unsupp - tbl_unsupp # 37: fsincos 4146 1.1 is long fcmp - tbl_unsupp # 38: fcmp 4147 1.1 is long tbl_unsupp - tbl_unsupp 4148 1.1 is long ftst - tbl_unsupp # 3a: ftst 4149 1.1 is long tbl_unsupp - tbl_unsupp 4150 1.1 is long tbl_unsupp - tbl_unsupp 4151 1.1 is long tbl_unsupp - tbl_unsupp 4152 1.1 is long tbl_unsupp - tbl_unsupp 4153 1.1 is long tbl_unsupp - tbl_unsupp 4154 1.1 is long fsin - tbl_unsupp # 40: fsmove 4155 1.1 is long fssqrt - tbl_unsupp # 41: fssqrt 4156 1.1 is long tbl_unsupp - tbl_unsupp 4157 1.1 is long tbl_unsupp - tbl_unsupp 4158 1.1 is long fdin - tbl_unsupp # 44: fdmove 4159 1.1 is long fdsqrt - tbl_unsupp # 45: fdsqrt 4160 1.1 is long tbl_unsupp - tbl_unsupp 4161 1.1 is long tbl_unsupp - tbl_unsupp 4162 1.1 is long tbl_unsupp - tbl_unsupp 4163 1.1 is long tbl_unsupp - tbl_unsupp 4164 1.1 is long tbl_unsupp - tbl_unsupp 4165 1.1 is long tbl_unsupp - tbl_unsupp 4166 1.1 is long tbl_unsupp - tbl_unsupp 4167 1.1 is long tbl_unsupp - tbl_unsupp 4168 1.1 is long tbl_unsupp - tbl_unsupp 4169 1.1 is long tbl_unsupp - tbl_unsupp 4170 1.1 is long tbl_unsupp - tbl_unsupp 4171 1.1 is long tbl_unsupp - tbl_unsupp 4172 1.1 is long tbl_unsupp - tbl_unsupp 4173 1.1 is long tbl_unsupp - tbl_unsupp 4174 1.1 is long tbl_unsupp - tbl_unsupp 4175 1.1 is long tbl_unsupp - tbl_unsupp 4176 1.1 is long tbl_unsupp - tbl_unsupp 4177 1.1 is long tbl_unsupp - tbl_unsupp 4178 1.1 is long fsabs - tbl_unsupp # 58: fsabs 4179 1.1 is long tbl_unsupp - tbl_unsupp 4180 1.1 is long fsneg - tbl_unsupp # 5a: fsneg 4181 1.1 is long tbl_unsupp - tbl_unsupp 4182 1.1 is long fdabs - tbl_unsupp # 5c: fdabs 4183 1.1 is long tbl_unsupp - tbl_unsupp 4184 1.1 is long fdneg - tbl_unsupp # 5e: fdneg 4185 1.1 is long tbl_unsupp - tbl_unsupp 4186 1.1 is long fsdiv - tbl_unsupp # 60: fsdiv 4187 1.1 is long tbl_unsupp - tbl_unsupp 4188 1.1 is long fsadd - tbl_unsupp # 62: fsadd 4189 1.1 is long fsmul - tbl_unsupp # 63: fsmul 4190 1.1 is long fddiv - tbl_unsupp # 64: fddiv 4191 1.1 is long tbl_unsupp - tbl_unsupp 4192 1.1 is long fdadd - tbl_unsupp # 66: fdadd 4193 1.1 is long fdmul - tbl_unsupp # 67: fdmul 4194 1.1 is long fssub - tbl_unsupp # 68: fssub 4195 1.1 is long tbl_unsupp - tbl_unsupp 4196 1.1 is long tbl_unsupp - tbl_unsupp 4197 1.1 is long tbl_unsupp - tbl_unsupp 4198 1.1 is long fdsub - tbl_unsupp # 6c: fdsub 4199 1.1 is 4200 1.1 is ################################################# 4201 1.1 is # Add this here so non-fp modules can compile. 4202 1.1 is # (smovcr is called from fpsp_inex.) 4203 1.1 is global smovcr 4204 1.1 is smovcr: 4205 1.1 is bra.b smovcr 4206 1.1 is 4207 1.1 is ######################################################################### 4208 1.1 is # XDEF **************************************************************** # 4209 1.1 is # fmovm_dynamic(): emulate "fmovm" dynamic instruction # 4210 1.1 is # # 4211 1.1 is # XREF **************************************************************** # 4212 1.1 is # fetch_dreg() - fetch data register # 4213 1.1 is # {i,d,}mem_read() - fetch data from memory # 4214 1.1 is # _mem_write() - write data to memory # 4215 1.1 is # iea_iacc() - instruction memory access error occurred # 4216 1.1 is # iea_dacc() - data memory access error occurred # 4217 1.1 is # restore() - restore An index regs if access error occurred # 4218 1.1 is # # 4219 1.1 is # INPUT *************************************************************** # 4220 1.1 is # None # 4221 1.1 is # # 4222 1.1 is # OUTPUT ************************************************************** # 4223 1.1 is # If instr is "fmovm Dn,-(A7)" from supervisor mode, # 4224 1.1 is # d0 = size of dump # 4225 1.1 is # d1 = Dn # 4226 1.1 is # Else if instruction access error, # 4227 1.1 is # d0 = FSLW # 4228 1.1 is # Else if data access error, # 4229 1.1 is # d0 = FSLW # 4230 1.1 is # a0 = address of fault # 4231 1.1 is # Else # 4232 1.1 is # none. # 4233 1.1 is # # 4234 1.1 is # ALGORITHM *********************************************************** # 4235 1.1 is # The effective address must be calculated since this is entered # 4236 1.1 is # from an "Unimplemented Effective Address" exception handler. So, we # 4237 1.1 is # have our own fcalc_ea() routine here. If an access error is flagged # 4238 1.1 is # by a _{i,d,}mem_read() call, we must exit through the special # 4239 1.1 is # handler. # 4240 1.1 is # The data register is determined and its value loaded to get the # 4241 1.1 is # string of FP registers affected. This value is used as an index into # 4242 1.1 is # a lookup table such that we can determine the number of bytes # 4243 1.1 is # involved. # 4244 1.1 is # If the instruction is "fmovm.x <ea>,Dn", a _mem_read() is used # 4245 1.1 is # to read in all FP values. Again, _mem_read() may fail and require a # 4246 1.1 is # special exit. # 4247 1.1 is # If the instruction is "fmovm.x DN,<ea>", a _mem_write() is used # 4248 1.1 is # to write all FP values. _mem_write() may also fail. # 4249 1.1 is # If the instruction is "fmovm.x DN,-(a7)" from supervisor mode, # 4250 1.1 is # then we return the size of the dump and the string to the caller # 4251 1.1 is # so that the move can occur outside of this routine. This special # 4252 1.1 is # case is required so that moves to the system stack are handled # 4253 1.1 is # correctly. # 4254 1.1 is # # 4255 1.1 is # DYNAMIC: # 4256 1.1 is # fmovm.x dn, <ea> # 4257 1.1 is # fmovm.x <ea>, dn # 4258 1.1 is # # 4259 1.1 is # <WORD 1> <WORD2> # 4260 1.1 is # 1111 0010 00 |<ea>| 11@& 1000 0$$$ 0000 # 4261 1.1 is # # 4262 1.1 is # & = (0): predecrement addressing mode # 4263 1.1 is # (1): postincrement or control addressing mode # 4264 1.1 is # @ = (0): move listed regs from memory to the FPU # 4265 1.1 is # (1): move listed regs from the FPU to memory # 4266 1.1 is # $$$ : index of data register holding reg select mask # 4267 1.1 is # # 4268 1.1 is # NOTES: # 4269 1.1 is # If the data register holds a zero, then the # 4270 1.1 is # instruction is a nop. # 4271 1.1 is # # 4272 1.1 is ######################################################################### 4273 1.1 is 4274 1.1 is global fmovm_dynamic 4275 1.1 is fmovm_dynamic: 4276 1.1 is 4277 1.1 is # extract the data register in which the bit string resides... 4278 1.1 is mov.b 1+EXC_EXTWORD(%a6),%d1 # fetch extword 4279 1.1 is andi.w &0x70,%d1 # extract reg bits 4280 1.1 is lsr.b &0x4,%d1 # shift into lo bits 4281 1.1 is 4282 1.1 is # fetch the bit string into d0... 4283 1.1 is bsr.l fetch_dreg # fetch reg string 4284 1.1 is 4285 1.1 is andi.l &0x000000ff,%d0 # keep only lo byte 4286 1.1 is 4287 1.1 is mov.l %d0,-(%sp) # save strg 4288 1.1 is mov.b (tbl_fmovm_size.w,%pc,%d0),%d0 4289 1.1 is mov.l %d0,-(%sp) # save size 4290 1.1 is bsr.l fmovm_calc_ea # calculate <ea> 4291 1.1 is mov.l (%sp)+,%d0 # restore size 4292 1.1 is mov.l (%sp)+,%d1 # restore strg 4293 1.1 is 4294 1.1 is # if the bit string is a zero, then the operation is a no-op 4295 1.1 is # but, make sure that we've calculated ea and advanced the opword pointer 4296 1.1 is beq.w fmovm_data_done 4297 1.1 is 4298 1.1 is # separate move ins from move outs... 4299 1.1 is btst &0x5,EXC_EXTWORD(%a6) # is it a move in or out? 4300 1.1 is beq.w fmovm_data_in # it's a move out 4301 1.1 is 4302 1.1 is ############# 4303 1.1 is # MOVE OUT: # 4304 1.1 is ############# 4305 1.1 is fmovm_data_out: 4306 1.1 is btst &0x4,EXC_EXTWORD(%a6) # control or predecrement? 4307 1.1 is bne.w fmovm_out_ctrl # control 4308 1.1 is 4309 1.1 is ############################ 4310 1.1 is fmovm_out_predec: 4311 1.1 is # for predecrement mode, the bit string is the opposite of both control 4312 1.1 is # operations and postincrement mode. (bit7 = FP7 ... bit0 = FP0) 4313 1.1 is # here, we convert it to be just like the others... 4314 1.1 is mov.b (tbl_fmovm_convert.w,%pc,%d1.w*1),%d1 4315 1.1 is 4316 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor mode? 4317 1.1 is beq.b fmovm_out_ctrl # user 4318 1.1 is 4319 1.1 is fmovm_out_predec_s: 4320 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg # is <ea> mode -(a7)? 4321 1.1 is bne.b fmovm_out_ctrl 4322 1.1 is 4323 1.1 is # the operation was unfortunately an: fmovm.x dn,-(sp) 4324 1.1 is # called from supervisor mode. 4325 1.1 is # we're also passing "size" and "strg" back to the calling routine 4326 1.1 is rts 4327 1.1 is 4328 1.1 is ############################ 4329 1.1 is fmovm_out_ctrl: 4330 1.1 is mov.l %a0,%a1 # move <ea> to a1 4331 1.1 is 4332 1.1 is sub.l %d0,%sp # subtract size of dump 4333 1.1 is lea (%sp),%a0 4334 1.1 is 4335 1.1 is tst.b %d1 # should FP0 be moved? 4336 1.1 is bpl.b fmovm_out_ctrl_fp1 # no 4337 1.1 is 4338 1.1 is mov.l 0x0+EXC_FP0(%a6),(%a0)+ # yes 4339 1.1 is mov.l 0x4+EXC_FP0(%a6),(%a0)+ 4340 1.1 is mov.l 0x8+EXC_FP0(%a6),(%a0)+ 4341 1.1 is 4342 1.1 is fmovm_out_ctrl_fp1: 4343 1.1 is lsl.b &0x1,%d1 # should FP1 be moved? 4344 1.1 is bpl.b fmovm_out_ctrl_fp2 # no 4345 1.1 is 4346 1.1 is mov.l 0x0+EXC_FP1(%a6),(%a0)+ # yes 4347 1.1 is mov.l 0x4+EXC_FP1(%a6),(%a0)+ 4348 1.1 is mov.l 0x8+EXC_FP1(%a6),(%a0)+ 4349 1.1 is 4350 1.1 is fmovm_out_ctrl_fp2: 4351 1.1 is lsl.b &0x1,%d1 # should FP2 be moved? 4352 1.1 is bpl.b fmovm_out_ctrl_fp3 # no 4353 1.1 is 4354 1.1 is fmovm.x &0x20,(%a0) # yes 4355 1.1 is add.l &0xc,%a0 4356 1.1 is 4357 1.1 is fmovm_out_ctrl_fp3: 4358 1.1 is lsl.b &0x1,%d1 # should FP3 be moved? 4359 1.1 is bpl.b fmovm_out_ctrl_fp4 # no 4360 1.1 is 4361 1.1 is fmovm.x &0x10,(%a0) # yes 4362 1.1 is add.l &0xc,%a0 4363 1.1 is 4364 1.1 is fmovm_out_ctrl_fp4: 4365 1.1 is lsl.b &0x1,%d1 # should FP4 be moved? 4366 1.1 is bpl.b fmovm_out_ctrl_fp5 # no 4367 1.1 is 4368 1.1 is fmovm.x &0x08,(%a0) # yes 4369 1.1 is add.l &0xc,%a0 4370 1.1 is 4371 1.1 is fmovm_out_ctrl_fp5: 4372 1.1 is lsl.b &0x1,%d1 # should FP5 be moved? 4373 1.1 is bpl.b fmovm_out_ctrl_fp6 # no 4374 1.1 is 4375 1.1 is fmovm.x &0x04,(%a0) # yes 4376 1.1 is add.l &0xc,%a0 4377 1.1 is 4378 1.1 is fmovm_out_ctrl_fp6: 4379 1.1 is lsl.b &0x1,%d1 # should FP6 be moved? 4380 1.1 is bpl.b fmovm_out_ctrl_fp7 # no 4381 1.1 is 4382 1.1 is fmovm.x &0x02,(%a0) # yes 4383 1.1 is add.l &0xc,%a0 4384 1.1 is 4385 1.1 is fmovm_out_ctrl_fp7: 4386 1.1 is lsl.b &0x1,%d1 # should FP7 be moved? 4387 1.1 is bpl.b fmovm_out_ctrl_done # no 4388 1.1 is 4389 1.1 is fmovm.x &0x01,(%a0) # yes 4390 1.1 is add.l &0xc,%a0 4391 1.1 is 4392 1.1 is fmovm_out_ctrl_done: 4393 1.1 is mov.l %a1,L_SCR1(%a6) 4394 1.1 is 4395 1.1 is lea (%sp),%a0 # pass: supervisor src 4396 1.1 is mov.l %d0,-(%sp) # save size 4397 1.1 is bsr.l _dmem_write # copy data to user mem 4398 1.1 is 4399 1.1 is mov.l (%sp)+,%d0 4400 1.1 is add.l %d0,%sp # clear fpreg data from stack 4401 1.1 is 4402 1.1 is tst.l %d1 # did dstore err? 4403 1.1 is bne.w fmovm_out_err # yes 4404 1.1 is 4405 1.1 is rts 4406 1.1 is 4407 1.1 is ############ 4408 1.1 is # MOVE IN: # 4409 1.1 is ############ 4410 1.1 is fmovm_data_in: 4411 1.1 is mov.l %a0,L_SCR1(%a6) 4412 1.1 is 4413 1.1 is sub.l %d0,%sp # make room for fpregs 4414 1.1 is lea (%sp),%a1 4415 1.1 is 4416 1.1 is mov.l %d1,-(%sp) # save bit string for later 4417 1.1 is mov.l %d0,-(%sp) # save # of bytes 4418 1.1 is 4419 1.1 is bsr.l _dmem_read # copy data from user mem 4420 1.1 is 4421 1.1 is mov.l (%sp)+,%d0 # retrieve # of bytes 4422 1.1 is 4423 1.1 is tst.l %d1 # did dfetch fail? 4424 1.1 is bne.w fmovm_in_err # yes 4425 1.1 is 4426 1.1 is mov.l (%sp)+,%d1 # load bit string 4427 1.1 is 4428 1.1 is lea (%sp),%a0 # addr of stack 4429 1.1 is 4430 1.1 is tst.b %d1 # should FP0 be moved? 4431 1.1 is bpl.b fmovm_data_in_fp1 # no 4432 1.1 is 4433 1.1 is mov.l (%a0)+,0x0+EXC_FP0(%a6) # yes 4434 1.1 is mov.l (%a0)+,0x4+EXC_FP0(%a6) 4435 1.1 is mov.l (%a0)+,0x8+EXC_FP0(%a6) 4436 1.1 is 4437 1.1 is fmovm_data_in_fp1: 4438 1.1 is lsl.b &0x1,%d1 # should FP1 be moved? 4439 1.1 is bpl.b fmovm_data_in_fp2 # no 4440 1.1 is 4441 1.1 is mov.l (%a0)+,0x0+EXC_FP1(%a6) # yes 4442 1.1 is mov.l (%a0)+,0x4+EXC_FP1(%a6) 4443 1.1 is mov.l (%a0)+,0x8+EXC_FP1(%a6) 4444 1.1 is 4445 1.1 is fmovm_data_in_fp2: 4446 1.1 is lsl.b &0x1,%d1 # should FP2 be moved? 4447 1.1 is bpl.b fmovm_data_in_fp3 # no 4448 1.1 is 4449 1.1 is fmovm.x (%a0)+,&0x20 # yes 4450 1.1 is 4451 1.1 is fmovm_data_in_fp3: 4452 1.1 is lsl.b &0x1,%d1 # should FP3 be moved? 4453 1.1 is bpl.b fmovm_data_in_fp4 # no 4454 1.1 is 4455 1.1 is fmovm.x (%a0)+,&0x10 # yes 4456 1.1 is 4457 1.1 is fmovm_data_in_fp4: 4458 1.1 is lsl.b &0x1,%d1 # should FP4 be moved? 4459 1.1 is bpl.b fmovm_data_in_fp5 # no 4460 1.1 is 4461 1.1 is fmovm.x (%a0)+,&0x08 # yes 4462 1.1 is 4463 1.1 is fmovm_data_in_fp5: 4464 1.1 is lsl.b &0x1,%d1 # should FP5 be moved? 4465 1.1 is bpl.b fmovm_data_in_fp6 # no 4466 1.1 is 4467 1.1 is fmovm.x (%a0)+,&0x04 # yes 4468 1.1 is 4469 1.1 is fmovm_data_in_fp6: 4470 1.1 is lsl.b &0x1,%d1 # should FP6 be moved? 4471 1.1 is bpl.b fmovm_data_in_fp7 # no 4472 1.1 is 4473 1.1 is fmovm.x (%a0)+,&0x02 # yes 4474 1.1 is 4475 1.1 is fmovm_data_in_fp7: 4476 1.1 is lsl.b &0x1,%d1 # should FP7 be moved? 4477 1.1 is bpl.b fmovm_data_in_done # no 4478 1.1 is 4479 1.1 is fmovm.x (%a0)+,&0x01 # yes 4480 1.1 is 4481 1.1 is fmovm_data_in_done: 4482 1.1 is add.l %d0,%sp # remove fpregs from stack 4483 1.1 is rts 4484 1.1 is 4485 1.1 is ##################################### 4486 1.1 is 4487 1.1 is fmovm_data_done: 4488 1.1 is rts 4489 1.1 is 4490 1.1 is ############################################################################## 4491 1.1 is 4492 1.1 is # 4493 1.1 is # table indexed by the operation's bit string that gives the number 4494 1.1 is # of bytes that will be moved. 4495 1.1 is # 4496 1.1 is # number of bytes = (# of 1's in bit string) * 12(bytes/fpreg) 4497 1.1 is # 4498 1.1 is tbl_fmovm_size: 4499 1.1 is byte 0x00,0x0c,0x0c,0x18,0x0c,0x18,0x18,0x24 4500 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 4501 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 4502 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4503 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 4504 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4505 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4506 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4507 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 4508 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4509 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4510 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4511 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4512 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4513 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4514 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 4515 1.1 is byte 0x0c,0x18,0x18,0x24,0x18,0x24,0x24,0x30 4516 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4517 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4518 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4519 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4520 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4521 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4522 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 4523 1.1 is byte 0x18,0x24,0x24,0x30,0x24,0x30,0x30,0x3c 4524 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4525 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4526 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 4527 1.1 is byte 0x24,0x30,0x30,0x3c,0x30,0x3c,0x3c,0x48 4528 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 4529 1.1 is byte 0x30,0x3c,0x3c,0x48,0x3c,0x48,0x48,0x54 4530 1.1 is byte 0x3c,0x48,0x48,0x54,0x48,0x54,0x54,0x60 4531 1.1 is 4532 1.1 is # 4533 1.1 is # table to convert a pre-decrement bit string into a post-increment 4534 1.1 is # or control bit string. 4535 1.1 is # ex: 0x00 ==> 0x00 4536 1.1 is # 0x01 ==> 0x80 4537 1.1 is # 0x02 ==> 0x40 4538 1.1 is # . 4539 1.1 is # . 4540 1.1 is # 0xfd ==> 0xbf 4541 1.1 is # 0xfe ==> 0x7f 4542 1.1 is # 0xff ==> 0xff 4543 1.1 is # 4544 1.1 is tbl_fmovm_convert: 4545 1.1 is byte 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0 4546 1.1 is byte 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0 4547 1.1 is byte 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8 4548 1.1 is byte 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8 4549 1.1 is byte 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4 4550 1.1 is byte 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4 4551 1.1 is byte 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec 4552 1.1 is byte 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc 4553 1.1 is byte 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2 4554 1.1 is byte 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2 4555 1.1 is byte 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea 4556 1.1 is byte 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa 4557 1.1 is byte 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6 4558 1.1 is byte 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6 4559 1.1 is byte 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee 4560 1.1 is byte 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe 4561 1.1 is byte 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1 4562 1.1 is byte 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1 4563 1.1 is byte 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9 4564 1.1 is byte 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9 4565 1.1 is byte 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5 4566 1.1 is byte 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5 4567 1.1 is byte 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed 4568 1.1 is byte 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd 4569 1.1 is byte 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3 4570 1.1 is byte 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3 4571 1.1 is byte 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb 4572 1.1 is byte 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb 4573 1.1 is byte 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7 4574 1.1 is byte 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7 4575 1.1 is byte 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef 4576 1.1 is byte 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff 4577 1.1 is 4578 1.1 is global fmovm_calc_ea 4579 1.1 is ############################################### 4580 1.1 is # _fmovm_calc_ea: calculate effective address # 4581 1.1 is ############################################### 4582 1.1 is fmovm_calc_ea: 4583 1.1 is mov.l %d0,%a0 # move # bytes to a0 4584 1.1 is 4585 1.1 is # currently, MODE and REG are taken from the EXC_OPWORD. this could be 4586 1.1 is # easily changed if they were inputs passed in registers. 4587 1.1 is mov.w EXC_OPWORD(%a6),%d0 # fetch opcode word 4588 1.1 is mov.w %d0,%d1 # make a copy 4589 1.1 is 4590 1.1 is andi.w &0x3f,%d0 # extract mode field 4591 1.1 is andi.l &0x7,%d1 # extract reg field 4592 1.1 is 4593 1.1 is # jump to the corresponding function for each {MODE,REG} pair. 4594 1.1 is mov.w (tbl_fea_mode.b,%pc,%d0.w*2),%d0 # fetch jmp distance 4595 1.1 is jmp (tbl_fea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode 4596 1.1 is 4597 1.1 is swbeg &64 4598 1.1 is tbl_fea_mode: 4599 1.1 is short tbl_fea_mode - tbl_fea_mode 4600 1.1 is short tbl_fea_mode - tbl_fea_mode 4601 1.1 is short tbl_fea_mode - tbl_fea_mode 4602 1.1 is short tbl_fea_mode - tbl_fea_mode 4603 1.1 is short tbl_fea_mode - tbl_fea_mode 4604 1.1 is short tbl_fea_mode - tbl_fea_mode 4605 1.1 is short tbl_fea_mode - tbl_fea_mode 4606 1.1 is short tbl_fea_mode - tbl_fea_mode 4607 1.1 is 4608 1.1 is short tbl_fea_mode - tbl_fea_mode 4609 1.1 is short tbl_fea_mode - tbl_fea_mode 4610 1.1 is short tbl_fea_mode - tbl_fea_mode 4611 1.1 is short tbl_fea_mode - tbl_fea_mode 4612 1.1 is short tbl_fea_mode - tbl_fea_mode 4613 1.1 is short tbl_fea_mode - tbl_fea_mode 4614 1.1 is short tbl_fea_mode - tbl_fea_mode 4615 1.1 is short tbl_fea_mode - tbl_fea_mode 4616 1.1 is 4617 1.1 is short faddr_ind_a0 - tbl_fea_mode 4618 1.1 is short faddr_ind_a1 - tbl_fea_mode 4619 1.1 is short faddr_ind_a2 - tbl_fea_mode 4620 1.1 is short faddr_ind_a3 - tbl_fea_mode 4621 1.1 is short faddr_ind_a4 - tbl_fea_mode 4622 1.1 is short faddr_ind_a5 - tbl_fea_mode 4623 1.1 is short faddr_ind_a6 - tbl_fea_mode 4624 1.1 is short faddr_ind_a7 - tbl_fea_mode 4625 1.1 is 4626 1.1 is short faddr_ind_p_a0 - tbl_fea_mode 4627 1.1 is short faddr_ind_p_a1 - tbl_fea_mode 4628 1.1 is short faddr_ind_p_a2 - tbl_fea_mode 4629 1.1 is short faddr_ind_p_a3 - tbl_fea_mode 4630 1.1 is short faddr_ind_p_a4 - tbl_fea_mode 4631 1.1 is short faddr_ind_p_a5 - tbl_fea_mode 4632 1.1 is short faddr_ind_p_a6 - tbl_fea_mode 4633 1.1 is short faddr_ind_p_a7 - tbl_fea_mode 4634 1.1 is 4635 1.1 is short faddr_ind_m_a0 - tbl_fea_mode 4636 1.1 is short faddr_ind_m_a1 - tbl_fea_mode 4637 1.1 is short faddr_ind_m_a2 - tbl_fea_mode 4638 1.1 is short faddr_ind_m_a3 - tbl_fea_mode 4639 1.1 is short faddr_ind_m_a4 - tbl_fea_mode 4640 1.1 is short faddr_ind_m_a5 - tbl_fea_mode 4641 1.1 is short faddr_ind_m_a6 - tbl_fea_mode 4642 1.1 is short faddr_ind_m_a7 - tbl_fea_mode 4643 1.1 is 4644 1.1 is short faddr_ind_disp_a0 - tbl_fea_mode 4645 1.1 is short faddr_ind_disp_a1 - tbl_fea_mode 4646 1.1 is short faddr_ind_disp_a2 - tbl_fea_mode 4647 1.1 is short faddr_ind_disp_a3 - tbl_fea_mode 4648 1.1 is short faddr_ind_disp_a4 - tbl_fea_mode 4649 1.1 is short faddr_ind_disp_a5 - tbl_fea_mode 4650 1.1 is short faddr_ind_disp_a6 - tbl_fea_mode 4651 1.1 is short faddr_ind_disp_a7 - tbl_fea_mode 4652 1.1 is 4653 1.1 is short faddr_ind_ext - tbl_fea_mode 4654 1.1 is short faddr_ind_ext - tbl_fea_mode 4655 1.1 is short faddr_ind_ext - tbl_fea_mode 4656 1.1 is short faddr_ind_ext - tbl_fea_mode 4657 1.1 is short faddr_ind_ext - tbl_fea_mode 4658 1.1 is short faddr_ind_ext - tbl_fea_mode 4659 1.1 is short faddr_ind_ext - tbl_fea_mode 4660 1.1 is short faddr_ind_ext - tbl_fea_mode 4661 1.1 is 4662 1.1 is short fabs_short - tbl_fea_mode 4663 1.1 is short fabs_long - tbl_fea_mode 4664 1.1 is short fpc_ind - tbl_fea_mode 4665 1.1 is short fpc_ind_ext - tbl_fea_mode 4666 1.1 is short tbl_fea_mode - tbl_fea_mode 4667 1.1 is short tbl_fea_mode - tbl_fea_mode 4668 1.1 is short tbl_fea_mode - tbl_fea_mode 4669 1.1 is short tbl_fea_mode - tbl_fea_mode 4670 1.1 is 4671 1.1 is ################################### 4672 1.1 is # Address register indirect: (An) # 4673 1.1 is ################################### 4674 1.1 is faddr_ind_a0: 4675 1.1 is mov.l EXC_DREGS+0x8(%a6),%a0 # Get current a0 4676 1.1 is rts 4677 1.1 is 4678 1.1 is faddr_ind_a1: 4679 1.1 is mov.l EXC_DREGS+0xc(%a6),%a0 # Get current a1 4680 1.1 is rts 4681 1.1 is 4682 1.1 is faddr_ind_a2: 4683 1.1 is mov.l %a2,%a0 # Get current a2 4684 1.1 is rts 4685 1.1 is 4686 1.1 is faddr_ind_a3: 4687 1.1 is mov.l %a3,%a0 # Get current a3 4688 1.1 is rts 4689 1.1 is 4690 1.1 is faddr_ind_a4: 4691 1.1 is mov.l %a4,%a0 # Get current a4 4692 1.1 is rts 4693 1.1 is 4694 1.1 is faddr_ind_a5: 4695 1.1 is mov.l %a5,%a0 # Get current a5 4696 1.1 is rts 4697 1.1 is 4698 1.1 is faddr_ind_a6: 4699 1.1 is mov.l (%a6),%a0 # Get current a6 4700 1.1 is rts 4701 1.1 is 4702 1.1 is faddr_ind_a7: 4703 1.1 is mov.l EXC_A7(%a6),%a0 # Get current a7 4704 1.1 is rts 4705 1.1 is 4706 1.1 is ##################################################### 4707 1.1 is # Address register indirect w/ postincrement: (An)+ # 4708 1.1 is ##################################################### 4709 1.1 is faddr_ind_p_a0: 4710 1.1 is mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0 4711 1.1 is mov.l %d0,%d1 4712 1.1 is add.l %a0,%d1 # Increment 4713 1.1 is mov.l %d1,EXC_DREGS+0x8(%a6) # Save incr value 4714 1.1 is mov.l %d0,%a0 4715 1.1 is rts 4716 1.1 is 4717 1.1 is faddr_ind_p_a1: 4718 1.1 is mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1 4719 1.1 is mov.l %d0,%d1 4720 1.1 is add.l %a0,%d1 # Increment 4721 1.1 is mov.l %d1,EXC_DREGS+0xc(%a6) # Save incr value 4722 1.1 is mov.l %d0,%a0 4723 1.1 is rts 4724 1.1 is 4725 1.1 is faddr_ind_p_a2: 4726 1.1 is mov.l %a2,%d0 # Get current a2 4727 1.1 is mov.l %d0,%d1 4728 1.1 is add.l %a0,%d1 # Increment 4729 1.1 is mov.l %d1,%a2 # Save incr value 4730 1.1 is mov.l %d0,%a0 4731 1.1 is rts 4732 1.1 is 4733 1.1 is faddr_ind_p_a3: 4734 1.1 is mov.l %a3,%d0 # Get current a3 4735 1.1 is mov.l %d0,%d1 4736 1.1 is add.l %a0,%d1 # Increment 4737 1.1 is mov.l %d1,%a3 # Save incr value 4738 1.1 is mov.l %d0,%a0 4739 1.1 is rts 4740 1.1 is 4741 1.1 is faddr_ind_p_a4: 4742 1.1 is mov.l %a4,%d0 # Get current a4 4743 1.1 is mov.l %d0,%d1 4744 1.1 is add.l %a0,%d1 # Increment 4745 1.1 is mov.l %d1,%a4 # Save incr value 4746 1.1 is mov.l %d0,%a0 4747 1.1 is rts 4748 1.1 is 4749 1.1 is faddr_ind_p_a5: 4750 1.1 is mov.l %a5,%d0 # Get current a5 4751 1.1 is mov.l %d0,%d1 4752 1.1 is add.l %a0,%d1 # Increment 4753 1.1 is mov.l %d1,%a5 # Save incr value 4754 1.1 is mov.l %d0,%a0 4755 1.1 is rts 4756 1.1 is 4757 1.1 is faddr_ind_p_a6: 4758 1.1 is mov.l (%a6),%d0 # Get current a6 4759 1.1 is mov.l %d0,%d1 4760 1.1 is add.l %a0,%d1 # Increment 4761 1.1 is mov.l %d1,(%a6) # Save incr value 4762 1.1 is mov.l %d0,%a0 4763 1.1 is rts 4764 1.1 is 4765 1.1 is faddr_ind_p_a7: 4766 1.1 is mov.b &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag 4767 1.1 is 4768 1.1 is mov.l EXC_A7(%a6),%d0 # Get current a7 4769 1.1 is mov.l %d0,%d1 4770 1.1 is add.l %a0,%d1 # Increment 4771 1.1 is mov.l %d1,EXC_A7(%a6) # Save incr value 4772 1.1 is mov.l %d0,%a0 4773 1.1 is rts 4774 1.1 is 4775 1.1 is #################################################### 4776 1.1 is # Address register indirect w/ predecrement: -(An) # 4777 1.1 is #################################################### 4778 1.1 is faddr_ind_m_a0: 4779 1.1 is mov.l EXC_DREGS+0x8(%a6),%d0 # Get current a0 4780 1.1 is sub.l %a0,%d0 # Decrement 4781 1.1 is mov.l %d0,EXC_DREGS+0x8(%a6) # Save decr value 4782 1.1 is mov.l %d0,%a0 4783 1.1 is rts 4784 1.1 is 4785 1.1 is faddr_ind_m_a1: 4786 1.1 is mov.l EXC_DREGS+0xc(%a6),%d0 # Get current a1 4787 1.1 is sub.l %a0,%d0 # Decrement 4788 1.1 is mov.l %d0,EXC_DREGS+0xc(%a6) # Save decr value 4789 1.1 is mov.l %d0,%a0 4790 1.1 is rts 4791 1.1 is 4792 1.1 is faddr_ind_m_a2: 4793 1.1 is mov.l %a2,%d0 # Get current a2 4794 1.1 is sub.l %a0,%d0 # Decrement 4795 1.1 is mov.l %d0,%a2 # Save decr value 4796 1.1 is mov.l %d0,%a0 4797 1.1 is rts 4798 1.1 is 4799 1.1 is faddr_ind_m_a3: 4800 1.1 is mov.l %a3,%d0 # Get current a3 4801 1.1 is sub.l %a0,%d0 # Decrement 4802 1.1 is mov.l %d0,%a3 # Save decr value 4803 1.1 is mov.l %d0,%a0 4804 1.1 is rts 4805 1.1 is 4806 1.1 is faddr_ind_m_a4: 4807 1.1 is mov.l %a4,%d0 # Get current a4 4808 1.1 is sub.l %a0,%d0 # Decrement 4809 1.1 is mov.l %d0,%a4 # Save decr value 4810 1.1 is mov.l %d0,%a0 4811 1.1 is rts 4812 1.1 is 4813 1.1 is faddr_ind_m_a5: 4814 1.1 is mov.l %a5,%d0 # Get current a5 4815 1.1 is sub.l %a0,%d0 # Decrement 4816 1.1 is mov.l %d0,%a5 # Save decr value 4817 1.1 is mov.l %d0,%a0 4818 1.1 is rts 4819 1.1 is 4820 1.1 is faddr_ind_m_a6: 4821 1.1 is mov.l (%a6),%d0 # Get current a6 4822 1.1 is sub.l %a0,%d0 # Decrement 4823 1.1 is mov.l %d0,(%a6) # Save decr value 4824 1.1 is mov.l %d0,%a0 4825 1.1 is rts 4826 1.1 is 4827 1.1 is faddr_ind_m_a7: 4828 1.1 is mov.b &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag 4829 1.1 is 4830 1.1 is mov.l EXC_A7(%a6),%d0 # Get current a7 4831 1.1 is sub.l %a0,%d0 # Decrement 4832 1.1 is mov.l %d0,EXC_A7(%a6) # Save decr value 4833 1.1 is mov.l %d0,%a0 4834 1.1 is rts 4835 1.1 is 4836 1.1 is ######################################################## 4837 1.1 is # Address register indirect w/ displacement: (d16, An) # 4838 1.1 is ######################################################## 4839 1.1 is faddr_ind_disp_a0: 4840 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4841 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4842 1.1 is bsr.l _imem_read_word 4843 1.1 is 4844 1.1 is tst.l %d1 # did ifetch fail? 4845 1.1 is bne.l iea_iacc # yes 4846 1.1 is 4847 1.1 is mov.w %d0,%a0 # sign extend displacement 4848 1.1 is 4849 1.1 is add.l EXC_DREGS+0x8(%a6),%a0 # a0 + d16 4850 1.1 is rts 4851 1.1 is 4852 1.1 is faddr_ind_disp_a1: 4853 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4854 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4855 1.1 is bsr.l _imem_read_word 4856 1.1 is 4857 1.1 is tst.l %d1 # did ifetch fail? 4858 1.1 is bne.l iea_iacc # yes 4859 1.1 is 4860 1.1 is mov.w %d0,%a0 # sign extend displacement 4861 1.1 is 4862 1.1 is add.l EXC_DREGS+0xc(%a6),%a0 # a1 + d16 4863 1.1 is rts 4864 1.1 is 4865 1.1 is faddr_ind_disp_a2: 4866 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4867 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4868 1.1 is bsr.l _imem_read_word 4869 1.1 is 4870 1.1 is tst.l %d1 # did ifetch fail? 4871 1.1 is bne.l iea_iacc # yes 4872 1.1 is 4873 1.1 is mov.w %d0,%a0 # sign extend displacement 4874 1.1 is 4875 1.1 is add.l %a2,%a0 # a2 + d16 4876 1.1 is rts 4877 1.1 is 4878 1.1 is faddr_ind_disp_a3: 4879 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4880 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4881 1.1 is bsr.l _imem_read_word 4882 1.1 is 4883 1.1 is tst.l %d1 # did ifetch fail? 4884 1.1 is bne.l iea_iacc # yes 4885 1.1 is 4886 1.1 is mov.w %d0,%a0 # sign extend displacement 4887 1.1 is 4888 1.1 is add.l %a3,%a0 # a3 + d16 4889 1.1 is rts 4890 1.1 is 4891 1.1 is faddr_ind_disp_a4: 4892 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4893 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4894 1.1 is bsr.l _imem_read_word 4895 1.1 is 4896 1.1 is tst.l %d1 # did ifetch fail? 4897 1.1 is bne.l iea_iacc # yes 4898 1.1 is 4899 1.1 is mov.w %d0,%a0 # sign extend displacement 4900 1.1 is 4901 1.1 is add.l %a4,%a0 # a4 + d16 4902 1.1 is rts 4903 1.1 is 4904 1.1 is faddr_ind_disp_a5: 4905 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4906 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4907 1.1 is bsr.l _imem_read_word 4908 1.1 is 4909 1.1 is tst.l %d1 # did ifetch fail? 4910 1.1 is bne.l iea_iacc # yes 4911 1.1 is 4912 1.1 is mov.w %d0,%a0 # sign extend displacement 4913 1.1 is 4914 1.1 is add.l %a5,%a0 # a5 + d16 4915 1.1 is rts 4916 1.1 is 4917 1.1 is faddr_ind_disp_a6: 4918 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4919 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4920 1.1 is bsr.l _imem_read_word 4921 1.1 is 4922 1.1 is tst.l %d1 # did ifetch fail? 4923 1.1 is bne.l iea_iacc # yes 4924 1.1 is 4925 1.1 is mov.w %d0,%a0 # sign extend displacement 4926 1.1 is 4927 1.1 is add.l (%a6),%a0 # a6 + d16 4928 1.1 is rts 4929 1.1 is 4930 1.1 is faddr_ind_disp_a7: 4931 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4932 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4933 1.1 is bsr.l _imem_read_word 4934 1.1 is 4935 1.1 is tst.l %d1 # did ifetch fail? 4936 1.1 is bne.l iea_iacc # yes 4937 1.1 is 4938 1.1 is mov.w %d0,%a0 # sign extend displacement 4939 1.1 is 4940 1.1 is add.l EXC_A7(%a6),%a0 # a7 + d16 4941 1.1 is rts 4942 1.1 is 4943 1.1 is ######################################################################## 4944 1.1 is # Address register indirect w/ index(8-bit displacement): (d8, An, Xn) # 4945 1.1 is # " " " w/ " (base displacement): (bd, An, Xn) # 4946 1.1 is # Memory indirect postindexed: ([bd, An], Xn, od) # 4947 1.1 is # Memory indirect preindexed: ([bd, An, Xn], od) # 4948 1.1 is ######################################################################## 4949 1.1 is faddr_ind_ext: 4950 1.1 is addq.l &0x8,%d1 4951 1.1 is bsr.l fetch_dreg # fetch base areg 4952 1.1 is mov.l %d0,-(%sp) 4953 1.1 is 4954 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 4955 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 4956 1.1 is bsr.l _imem_read_word # fetch extword in d0 4957 1.1 is 4958 1.1 is tst.l %d1 # did ifetch fail? 4959 1.1 is bne.l iea_iacc # yes 4960 1.1 is 4961 1.1 is mov.l (%sp)+,%a0 4962 1.1 is 4963 1.1 is btst &0x8,%d0 4964 1.1 is bne.w fcalc_mem_ind 4965 1.1 is 4966 1.1 is mov.l %d0,L_SCR1(%a6) # hold opword 4967 1.1 is 4968 1.1 is mov.l %d0,%d1 4969 1.1 is rol.w &0x4,%d1 4970 1.1 is andi.w &0xf,%d1 # extract index regno 4971 1.1 is 4972 1.1 is # count on fetch_dreg() not to alter a0... 4973 1.1 is bsr.l fetch_dreg # fetch index 4974 1.1 is 4975 1.1 is mov.l %d2,-(%sp) # save d2 4976 1.1 is mov.l L_SCR1(%a6),%d2 # fetch opword 4977 1.1 is 4978 1.1 is btst &0xb,%d2 # is it word or long? 4979 1.1 is bne.b faii8_long 4980 1.1 is ext.l %d0 # sign extend word index 4981 1.1 is faii8_long: 4982 1.1 is mov.l %d2,%d1 4983 1.1 is rol.w &0x7,%d1 4984 1.1 is andi.l &0x3,%d1 # extract scale value 4985 1.1 is 4986 1.1 is lsl.l %d1,%d0 # shift index by scale 4987 1.1 is 4988 1.1 is extb.l %d2 # sign extend displacement 4989 1.1 is add.l %d2,%d0 # index + disp 4990 1.1 is add.l %d0,%a0 # An + (index + disp) 4991 1.1 is 4992 1.1 is mov.l (%sp)+,%d2 # restore old d2 4993 1.1 is rts 4994 1.1 is 4995 1.1 is ########################### 4996 1.1 is # Absolute short: (XXX).W # 4997 1.1 is ########################### 4998 1.1 is fabs_short: 4999 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5000 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 5001 1.1 is bsr.l _imem_read_word # fetch short address 5002 1.1 is 5003 1.1 is tst.l %d1 # did ifetch fail? 5004 1.1 is bne.l iea_iacc # yes 5005 1.1 is 5006 1.1 is mov.w %d0,%a0 # return <ea> in a0 5007 1.1 is rts 5008 1.1 is 5009 1.1 is ########################## 5010 1.1 is # Absolute long: (XXX).L # 5011 1.1 is ########################## 5012 1.1 is fabs_long: 5013 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5014 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5015 1.1 is bsr.l _imem_read_long # fetch long address 5016 1.1 is 5017 1.1 is tst.l %d1 # did ifetch fail? 5018 1.1 is bne.l iea_iacc # yes 5019 1.1 is 5020 1.1 is mov.l %d0,%a0 # return <ea> in a0 5021 1.1 is rts 5022 1.1 is 5023 1.1 is ####################################################### 5024 1.1 is # Program counter indirect w/ displacement: (d16, PC) # 5025 1.1 is ####################################################### 5026 1.1 is fpc_ind: 5027 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5028 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 5029 1.1 is bsr.l _imem_read_word # fetch word displacement 5030 1.1 is 5031 1.1 is tst.l %d1 # did ifetch fail? 5032 1.1 is bne.l iea_iacc # yes 5033 1.1 is 5034 1.1 is mov.w %d0,%a0 # sign extend displacement 5035 1.1 is 5036 1.1 is add.l EXC_EXTWPTR(%a6),%a0 # pc + d16 5037 1.1 is 5038 1.1 is # _imem_read_word() increased the extwptr by 2. need to adjust here. 5039 1.1 is subq.l &0x2,%a0 # adjust <ea> 5040 1.1 is rts 5041 1.1 is 5042 1.1 is ########################################################## 5043 1.1 is # PC indirect w/ index(8-bit displacement): (d8, PC, An) # 5044 1.1 is # " " w/ " (base displacement): (bd, PC, An) # 5045 1.1 is # PC memory indirect postindexed: ([bd, PC], Xn, od) # 5046 1.1 is # PC memory indirect preindexed: ([bd, PC, Xn], od) # 5047 1.1 is ########################################################## 5048 1.1 is fpc_ind_ext: 5049 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5050 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 5051 1.1 is bsr.l _imem_read_word # fetch ext word 5052 1.1 is 5053 1.1 is tst.l %d1 # did ifetch fail? 5054 1.1 is bne.l iea_iacc # yes 5055 1.1 is 5056 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # put base in a0 5057 1.1 is subq.l &0x2,%a0 # adjust base 5058 1.1 is 5059 1.1 is btst &0x8,%d0 # is disp only 8 bits? 5060 1.1 is bne.w fcalc_mem_ind # calc memory indirect 5061 1.1 is 5062 1.1 is mov.l %d0,L_SCR1(%a6) # store opword 5063 1.1 is 5064 1.1 is mov.l %d0,%d1 # make extword copy 5065 1.1 is rol.w &0x4,%d1 # rotate reg num into place 5066 1.1 is andi.w &0xf,%d1 # extract register number 5067 1.1 is 5068 1.1 is # count on fetch_dreg() not to alter a0... 5069 1.1 is bsr.l fetch_dreg # fetch index 5070 1.1 is 5071 1.1 is mov.l %d2,-(%sp) # save d2 5072 1.1 is mov.l L_SCR1(%a6),%d2 # fetch opword 5073 1.1 is 5074 1.1 is btst &0xb,%d2 # is index word or long? 5075 1.1 is bne.b fpii8_long # long 5076 1.1 is ext.l %d0 # sign extend word index 5077 1.1 is fpii8_long: 5078 1.1 is mov.l %d2,%d1 5079 1.1 is rol.w &0x7,%d1 # rotate scale value into place 5080 1.1 is andi.l &0x3,%d1 # extract scale value 5081 1.1 is 5082 1.1 is lsl.l %d1,%d0 # shift index by scale 5083 1.1 is 5084 1.1 is extb.l %d2 # sign extend displacement 5085 1.1 is add.l %d2,%d0 # disp + index 5086 1.1 is add.l %d0,%a0 # An + (index + disp) 5087 1.1 is 5088 1.1 is mov.l (%sp)+,%d2 # restore temp register 5089 1.1 is rts 5090 1.1 is 5091 1.1 is # d2 = index 5092 1.1 is # d3 = base 5093 1.1 is # d4 = od 5094 1.1 is # d5 = extword 5095 1.1 is fcalc_mem_ind: 5096 1.1 is btst &0x6,%d0 # is the index suppressed? 5097 1.1 is beq.b fcalc_index 5098 1.1 is 5099 1.1 is movm.l &0x3c00,-(%sp) # save d2-d5 5100 1.1 is 5101 1.1 is mov.l %d0,%d5 # put extword in d5 5102 1.1 is mov.l %a0,%d3 # put base in d3 5103 1.1 is 5104 1.1 is clr.l %d2 # yes, so index = 0 5105 1.1 is bra.b fbase_supp_ck 5106 1.1 is 5107 1.1 is # index: 5108 1.1 is fcalc_index: 5109 1.1 is mov.l %d0,L_SCR1(%a6) # save d0 (opword) 5110 1.1 is bfextu %d0{&16:&4},%d1 # fetch dreg index 5111 1.1 is bsr.l fetch_dreg 5112 1.1 is 5113 1.1 is movm.l &0x3c00,-(%sp) # save d2-d5 5114 1.1 is mov.l %d0,%d2 # put index in d2 5115 1.1 is mov.l L_SCR1(%a6),%d5 5116 1.1 is mov.l %a0,%d3 5117 1.1 is 5118 1.1 is btst &0xb,%d5 # is index word or long? 5119 1.1 is bne.b fno_ext 5120 1.1 is ext.l %d2 5121 1.1 is 5122 1.1 is fno_ext: 5123 1.1 is bfextu %d5{&21:&2},%d0 5124 1.1 is lsl.l %d0,%d2 5125 1.1 is 5126 1.1 is # base address (passed as parameter in d3): 5127 1.1 is # we clear the value here if it should actually be suppressed. 5128 1.1 is fbase_supp_ck: 5129 1.1 is btst &0x7,%d5 # is the bd suppressed? 5130 1.1 is beq.b fno_base_sup 5131 1.1 is clr.l %d3 5132 1.1 is 5133 1.1 is # base displacement: 5134 1.1 is fno_base_sup: 5135 1.1 is bfextu %d5{&26:&2},%d0 # get bd size 5136 1.1 is # beq.l fmovm_error # if (size == 0) it's reserved 5137 1.1 is 5138 1.1 is cmpi.b %d0,&0x2 5139 1.1 is blt.b fno_bd 5140 1.1 is beq.b fget_word_bd 5141 1.1 is 5142 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5143 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5144 1.1 is bsr.l _imem_read_long 5145 1.1 is 5146 1.1 is tst.l %d1 # did ifetch fail? 5147 1.1 is bne.l fcea_iacc # yes 5148 1.1 is 5149 1.1 is bra.b fchk_ind 5150 1.1 is 5151 1.1 is fget_word_bd: 5152 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5153 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 5154 1.1 is bsr.l _imem_read_word 5155 1.1 is 5156 1.1 is tst.l %d1 # did ifetch fail? 5157 1.1 is bne.l fcea_iacc # yes 5158 1.1 is 5159 1.1 is ext.l %d0 # sign extend bd 5160 1.1 is 5161 1.1 is fchk_ind: 5162 1.1 is add.l %d0,%d3 # base += bd 5163 1.1 is 5164 1.1 is # outer displacement: 5165 1.1 is fno_bd: 5166 1.1 is bfextu %d5{&30:&2},%d0 # is od suppressed? 5167 1.1 is beq.w faii_bd 5168 1.1 is 5169 1.1 is cmpi.b %d0,&0x2 5170 1.1 is blt.b fnull_od 5171 1.1 is beq.b fword_od 5172 1.1 is 5173 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5174 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5175 1.1 is bsr.l _imem_read_long 5176 1.1 is 5177 1.1 is tst.l %d1 # did ifetch fail? 5178 1.1 is bne.l fcea_iacc # yes 5179 1.1 is 5180 1.1 is bra.b fadd_them 5181 1.1 is 5182 1.1 is fword_od: 5183 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5184 1.1 is addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr 5185 1.1 is bsr.l _imem_read_word 5186 1.1 is 5187 1.1 is tst.l %d1 # did ifetch fail? 5188 1.1 is bne.l fcea_iacc # yes 5189 1.1 is 5190 1.1 is ext.l %d0 # sign extend od 5191 1.1 is bra.b fadd_them 5192 1.1 is 5193 1.1 is fnull_od: 5194 1.1 is clr.l %d0 5195 1.1 is 5196 1.1 is fadd_them: 5197 1.1 is mov.l %d0,%d4 5198 1.1 is 5199 1.1 is btst &0x2,%d5 # pre or post indexing? 5200 1.1 is beq.b fpre_indexed 5201 1.1 is 5202 1.1 is mov.l %d3,%a0 5203 1.1 is bsr.l _dmem_read_long 5204 1.1 is 5205 1.1 is tst.l %d1 # did dfetch fail? 5206 1.1 is bne.w fcea_err # yes 5207 1.1 is 5208 1.1 is add.l %d2,%d0 # <ea> += index 5209 1.1 is add.l %d4,%d0 # <ea> += od 5210 1.1 is bra.b fdone_ea 5211 1.1 is 5212 1.1 is fpre_indexed: 5213 1.1 is add.l %d2,%d3 # preindexing 5214 1.1 is mov.l %d3,%a0 5215 1.1 is bsr.l _dmem_read_long 5216 1.1 is 5217 1.1 is tst.l %d1 # did dfetch fail? 5218 1.1 is bne.w fcea_err # yes 5219 1.1 is 5220 1.1 is add.l %d4,%d0 # ea += od 5221 1.1 is bra.b fdone_ea 5222 1.1 is 5223 1.1 is faii_bd: 5224 1.1 is add.l %d2,%d3 # ea = (base + bd) + index 5225 1.1 is mov.l %d3,%d0 5226 1.1 is fdone_ea: 5227 1.1 is mov.l %d0,%a0 5228 1.1 is 5229 1.1 is movm.l (%sp)+,&0x003c # restore d2-d5 5230 1.1 is rts 5231 1.1 is 5232 1.1 is ######################################################### 5233 1.1 is fcea_err: 5234 1.1 is mov.l %d3,%a0 5235 1.1 is 5236 1.1 is movm.l (%sp)+,&0x003c # restore d2-d5 5237 1.1 is mov.w &0x0101,%d0 5238 1.1 is bra.l iea_dacc 5239 1.1 is 5240 1.1 is fcea_iacc: 5241 1.1 is movm.l (%sp)+,&0x003c # restore d2-d5 5242 1.1 is bra.l iea_iacc 5243 1.1 is 5244 1.1 is fmovm_out_err: 5245 1.1 is bsr.l restore 5246 1.1 is mov.w &0x00e1,%d0 5247 1.1 is bra.b fmovm_err 5248 1.1 is 5249 1.1 is fmovm_in_err: 5250 1.1 is bsr.l restore 5251 1.1 is mov.w &0x0161,%d0 5252 1.1 is 5253 1.1 is fmovm_err: 5254 1.1 is mov.l L_SCR1(%a6),%a0 5255 1.1 is bra.l iea_dacc 5256 1.1 is 5257 1.1 is ######################################################################### 5258 1.1 is # XDEF **************************************************************** # 5259 1.1 is # fmovm_ctrl(): emulate fmovm.l of control registers instr # 5260 1.1 is # # 5261 1.1 is # XREF **************************************************************** # 5262 1.1 is # _imem_read_long() - read longword from memory # 5263 1.1 is # iea_iacc() - _imem_read_long() failed; error recovery # 5264 1.1 is # # 5265 1.1 is # INPUT *************************************************************** # 5266 1.1 is # None # 5267 1.1 is # # 5268 1.1 is # OUTPUT ************************************************************** # 5269 1.1 is # If _imem_read_long() doesn't fail: # 5270 1.1 is # USER_FPCR(a6) = new FPCR value # 5271 1.1 is # USER_FPSR(a6) = new FPSR value # 5272 1.1 is # USER_FPIAR(a6) = new FPIAR value # 5273 1.1 is # # 5274 1.1 is # ALGORITHM *********************************************************** # 5275 1.1 is # Decode the instruction type by looking at the extension word # 5276 1.1 is # in order to see how many control registers to fetch from memory. # 5277 1.1 is # Fetch them using _imem_read_long(). If this fetch fails, exit through # 5278 1.1 is # the special access error exit handler iea_iacc(). # 5279 1.1 is # # 5280 1.1 is # Instruction word decoding: # 5281 1.1 is # # 5282 1.1 is # fmovem.l #<data>, {FPIAR&|FPCR&|FPSR} # 5283 1.1 is # # 5284 1.1 is # WORD1 WORD2 # 5285 1.1 is # 1111 0010 00 111100 100$ $$00 0000 0000 # 5286 1.1 is # # 5287 1.1 is # $$$ (100): FPCR # 5288 1.1 is # (010): FPSR # 5289 1.1 is # (001): FPIAR # 5290 1.1 is # (000): FPIAR # 5291 1.1 is # # 5292 1.1 is ######################################################################### 5293 1.1 is 5294 1.1 is global fmovm_ctrl 5295 1.1 is fmovm_ctrl: 5296 1.1 is mov.b EXC_EXTWORD(%a6),%d0 # fetch reg select bits 5297 1.1 is cmpi.b %d0,&0x9c # fpcr & fpsr & fpiar ? 5298 1.1 is beq.w fctrl_in_7 # yes 5299 1.1 is cmpi.b %d0,&0x98 # fpcr & fpsr ? 5300 1.1 is beq.w fctrl_in_6 # yes 5301 1.1 is cmpi.b %d0,&0x94 # fpcr & fpiar ? 5302 1.1 is beq.b fctrl_in_5 # yes 5303 1.1 is 5304 1.1 is # fmovem.l #<data>, fpsr/fpiar 5305 1.1 is fctrl_in_3: 5306 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5307 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5308 1.1 is bsr.l _imem_read_long # fetch FPSR from mem 5309 1.1 is 5310 1.1 is tst.l %d1 # did ifetch fail? 5311 1.1 is bne.l iea_iacc # yes 5312 1.1 is 5313 1.1 is mov.l %d0,USER_FPSR(%a6) # store new FPSR to stack 5314 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5315 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5316 1.1 is bsr.l _imem_read_long # fetch FPIAR from mem 5317 1.1 is 5318 1.1 is tst.l %d1 # did ifetch fail? 5319 1.1 is bne.l iea_iacc # yes 5320 1.1 is 5321 1.1 is mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack 5322 1.1 is rts 5323 1.1 is 5324 1.1 is # fmovem.l #<data>, fpcr/fpiar 5325 1.1 is fctrl_in_5: 5326 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5327 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5328 1.1 is bsr.l _imem_read_long # fetch FPCR from mem 5329 1.1 is 5330 1.1 is tst.l %d1 # did ifetch fail? 5331 1.1 is bne.l iea_iacc # yes 5332 1.1 is 5333 1.1 is mov.l %d0,USER_FPCR(%a6) # store new FPCR to stack 5334 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5335 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5336 1.1 is bsr.l _imem_read_long # fetch FPIAR from mem 5337 1.1 is 5338 1.1 is tst.l %d1 # did ifetch fail? 5339 1.1 is bne.l iea_iacc # yes 5340 1.1 is 5341 1.1 is mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to stack 5342 1.1 is rts 5343 1.1 is 5344 1.1 is # fmovem.l #<data>, fpcr/fpsr 5345 1.1 is fctrl_in_6: 5346 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5347 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5348 1.1 is bsr.l _imem_read_long # fetch FPCR from mem 5349 1.1 is 5350 1.1 is tst.l %d1 # did ifetch fail? 5351 1.1 is bne.l iea_iacc # yes 5352 1.1 is 5353 1.1 is mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem 5354 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5355 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5356 1.1 is bsr.l _imem_read_long # fetch FPSR from mem 5357 1.1 is 5358 1.1 is tst.l %d1 # did ifetch fail? 5359 1.1 is bne.l iea_iacc # yes 5360 1.1 is 5361 1.1 is mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem 5362 1.1 is rts 5363 1.1 is 5364 1.1 is # fmovem.l #<data>, fpcr/fpsr/fpiar 5365 1.1 is fctrl_in_7: 5366 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5367 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5368 1.1 is bsr.l _imem_read_long # fetch FPCR from mem 5369 1.1 is 5370 1.1 is tst.l %d1 # did ifetch fail? 5371 1.1 is bne.l iea_iacc # yes 5372 1.1 is 5373 1.1 is mov.l %d0,USER_FPCR(%a6) # store new FPCR to mem 5374 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5375 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5376 1.1 is bsr.l _imem_read_long # fetch FPSR from mem 5377 1.1 is 5378 1.1 is tst.l %d1 # did ifetch fail? 5379 1.1 is bne.l iea_iacc # yes 5380 1.1 is 5381 1.1 is mov.l %d0,USER_FPSR(%a6) # store new FPSR to mem 5382 1.1 is mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr 5383 1.1 is addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr 5384 1.1 is bsr.l _imem_read_long # fetch FPIAR from mem 5385 1.1 is 5386 1.1 is tst.l %d1 # did ifetch fail? 5387 1.1 is bne.l iea_iacc # yes 5388 1.1 is 5389 1.1 is mov.l %d0,USER_FPIAR(%a6) # store new FPIAR to mem 5390 1.1 is rts 5391 1.1 is 5392 1.1 is ########################################################################## 5393 1.1 is 5394 1.1 is ######################################################################### 5395 1.1 is # XDEF **************************************************************** # 5396 1.1 is # addsub_scaler2(): scale inputs to fadd/fsub such that no # 5397 1.1 is # OVFL/UNFL exceptions will result # 5398 1.1 is # # 5399 1.1 is # XREF **************************************************************** # 5400 1.1 is # norm() - normalize mantissa after adjusting exponent # 5401 1.1 is # # 5402 1.1 is # INPUT *************************************************************** # 5403 1.1 is # FP_SRC(a6) = fp op1(src) # 5404 1.1 is # FP_DST(a6) = fp op2(dst) # 5405 1.1 is # # 5406 1.1 is # OUTPUT ************************************************************** # 5407 1.1 is # FP_SRC(a6) = fp op1 scaled(src) # 5408 1.1 is # FP_DST(a6) = fp op2 scaled(dst) # 5409 1.1 is # d0 = scale amount # 5410 1.1 is # # 5411 1.1 is # ALGORITHM *********************************************************** # 5412 1.1 is # If the DST exponent is > the SRC exponent, set the DST exponent # 5413 1.1 is # equal to 0x3fff and scale the SRC exponent by the value that the # 5414 1.1 is # DST exponent was scaled by. If the SRC exponent is greater or equal, # 5415 1.1 is # do the opposite. Return this scale factor in d0. # 5416 1.1 is # If the two exponents differ by > the number of mantissa bits # 5417 1.1 is # plus two, then set the smallest exponent to a very small value as a # 5418 1.1 is # quick shortcut. # 5419 1.1 is # # 5420 1.1 is ######################################################################### 5421 1.1 is 5422 1.1 is global addsub_scaler2 5423 1.1 is addsub_scaler2: 5424 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 5425 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 5426 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 5427 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 5428 1.1 is mov.w SRC_EX(%a0),%d0 5429 1.1 is mov.w DST_EX(%a1),%d1 5430 1.1 is mov.w %d0,FP_SCR0_EX(%a6) 5431 1.1 is mov.w %d1,FP_SCR1_EX(%a6) 5432 1.1 is 5433 1.1 is andi.w &0x7fff,%d0 5434 1.1 is andi.w &0x7fff,%d1 5435 1.1 is mov.w %d0,L_SCR1(%a6) # store src exponent 5436 1.1 is mov.w %d1,2+L_SCR1(%a6) # store dst exponent 5437 1.1 is 5438 1.1 is cmp.w %d0, %d1 # is src exp >= dst exp? 5439 1.1 is bge.l src_exp_ge2 5440 1.1 is 5441 1.1 is # dst exp is > src exp; scale dst to exp = 0x3fff 5442 1.1 is dst_exp_gt2: 5443 1.1 is bsr.l scale_to_zero_dst 5444 1.1 is mov.l %d0,-(%sp) # save scale factor 5445 1.1 is 5446 1.1 is cmpi.b STAG(%a6),&DENORM # is dst denormalized? 5447 1.1 is bne.b cmpexp12 5448 1.1 is 5449 1.1 is lea FP_SCR0(%a6),%a0 5450 1.1 is bsr.l norm # normalize the denorm; result is new exp 5451 1.1 is neg.w %d0 # new exp = -(shft val) 5452 1.1 is mov.w %d0,L_SCR1(%a6) # inset new exp 5453 1.1 is 5454 1.1 is cmpexp12: 5455 1.1 is mov.w 2+L_SCR1(%a6),%d0 5456 1.1 is subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp 5457 1.1 is 5458 1.1 is cmp.w %d0,L_SCR1(%a6) # is difference >= len(mantissa)+2? 5459 1.1 is bge.b quick_scale12 5460 1.1 is 5461 1.1 is mov.w L_SCR1(%a6),%d0 5462 1.1 is add.w 0x2(%sp),%d0 # scale src exponent by scale factor 5463 1.1 is mov.w FP_SCR0_EX(%a6),%d1 5464 1.1 is and.w &0x8000,%d1 5465 1.1 is or.w %d1,%d0 # concat {sgn,new exp} 5466 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new dst exponent 5467 1.1 is 5468 1.1 is mov.l (%sp)+,%d0 # return SCALE factor 5469 1.1 is rts 5470 1.1 is 5471 1.1 is quick_scale12: 5472 1.1 is andi.w &0x8000,FP_SCR0_EX(%a6) # zero src exponent 5473 1.1 is bset &0x0,1+FP_SCR0_EX(%a6) # set exp = 1 5474 1.1 is 5475 1.1 is mov.l (%sp)+,%d0 # return SCALE factor 5476 1.1 is rts 5477 1.1 is 5478 1.1 is # src exp is >= dst exp; scale src to exp = 0x3fff 5479 1.1 is src_exp_ge2: 5480 1.1 is bsr.l scale_to_zero_src 5481 1.1 is mov.l %d0,-(%sp) # save scale factor 5482 1.1 is 5483 1.1 is cmpi.b DTAG(%a6),&DENORM # is dst denormalized? 5484 1.1 is bne.b cmpexp22 5485 1.1 is lea FP_SCR1(%a6),%a0 5486 1.1 is bsr.l norm # normalize the denorm; result is new exp 5487 1.1 is neg.w %d0 # new exp = -(shft val) 5488 1.1 is mov.w %d0,2+L_SCR1(%a6) # inset new exp 5489 1.1 is 5490 1.1 is cmpexp22: 5491 1.1 is mov.w L_SCR1(%a6),%d0 5492 1.1 is subi.w &mantissalen+2,%d0 # subtract mantissalen+2 from larger exp 5493 1.1 is 5494 1.1 is cmp.w %d0,2+L_SCR1(%a6) # is difference >= len(mantissa)+2? 5495 1.1 is bge.b quick_scale22 5496 1.1 is 5497 1.1 is mov.w 2+L_SCR1(%a6),%d0 5498 1.1 is add.w 0x2(%sp),%d0 # scale dst exponent by scale factor 5499 1.1 is mov.w FP_SCR1_EX(%a6),%d1 5500 1.1 is andi.w &0x8000,%d1 5501 1.1 is or.w %d1,%d0 # concat {sgn,new exp} 5502 1.1 is mov.w %d0,FP_SCR1_EX(%a6) # insert new dst exponent 5503 1.1 is 5504 1.1 is mov.l (%sp)+,%d0 # return SCALE factor 5505 1.1 is rts 5506 1.1 is 5507 1.1 is quick_scale22: 5508 1.1 is andi.w &0x8000,FP_SCR1_EX(%a6) # zero dst exponent 5509 1.1 is bset &0x0,1+FP_SCR1_EX(%a6) # set exp = 1 5510 1.1 is 5511 1.1 is mov.l (%sp)+,%d0 # return SCALE factor 5512 1.1 is rts 5513 1.1 is 5514 1.1 is ########################################################################## 5515 1.1 is 5516 1.1 is ######################################################################### 5517 1.1 is # XDEF **************************************************************** # 5518 1.1 is # scale_to_zero_src(): scale the exponent of extended precision # 5519 1.1 is # value at FP_SCR0(a6). # 5520 1.1 is # # 5521 1.1 is # XREF **************************************************************** # 5522 1.1 is # norm() - normalize the mantissa if the operand was a DENORM # 5523 1.1 is # # 5524 1.1 is # INPUT *************************************************************** # 5525 1.1 is # FP_SCR0(a6) = extended precision operand to be scaled # 5526 1.1 is # # 5527 1.1 is # OUTPUT ************************************************************** # 5528 1.1 is # FP_SCR0(a6) = scaled extended precision operand # 5529 1.1 is # d0 = scale value # 5530 1.1 is # # 5531 1.1 is # ALGORITHM *********************************************************** # 5532 1.1 is # Set the exponent of the input operand to 0x3fff. Save the value # 5533 1.1 is # of the difference between the original and new exponent. Then, # 5534 1.1 is # normalize the operand if it was a DENORM. Add this normalization # 5535 1.1 is # value to the previous value. Return the result. # 5536 1.1 is # # 5537 1.1 is ######################################################################### 5538 1.1 is 5539 1.1 is global scale_to_zero_src 5540 1.1 is scale_to_zero_src: 5541 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp} 5542 1.1 is mov.w %d1,%d0 # make a copy 5543 1.1 is 5544 1.1 is andi.l &0x7fff,%d1 # extract operand's exponent 5545 1.1 is 5546 1.1 is andi.w &0x8000,%d0 # extract operand's sgn 5547 1.1 is or.w &0x3fff,%d0 # insert new operand's exponent(=0) 5548 1.1 is 5549 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert biased exponent 5550 1.1 is 5551 1.1 is cmpi.b STAG(%a6),&DENORM # is operand normalized? 5552 1.1 is beq.b stzs_denorm # normalize the DENORM 5553 1.1 is 5554 1.1 is stzs_norm: 5555 1.1 is mov.l &0x3fff,%d0 5556 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp) 5557 1.1 is 5558 1.1 is rts 5559 1.1 is 5560 1.1 is stzs_denorm: 5561 1.1 is lea FP_SCR0(%a6),%a0 # pass ptr to src op 5562 1.1 is bsr.l norm # normalize denorm 5563 1.1 is neg.l %d0 # new exponent = -(shft val) 5564 1.1 is mov.l %d0,%d1 # prepare for op_norm call 5565 1.1 is bra.b stzs_norm # finish scaling 5566 1.1 is 5567 1.1 is ### 5568 1.1 is 5569 1.1 is ######################################################################### 5570 1.1 is # XDEF **************************************************************** # 5571 1.1 is # scale_sqrt(): scale the input operand exponent so a subsequent # 5572 1.1 is # fsqrt operation won't take an exception. # 5573 1.1 is # # 5574 1.1 is # XREF **************************************************************** # 5575 1.1 is # norm() - normalize the mantissa if the operand was a DENORM # 5576 1.1 is # # 5577 1.1 is # INPUT *************************************************************** # 5578 1.1 is # FP_SCR0(a6) = extended precision operand to be scaled # 5579 1.1 is # # 5580 1.1 is # OUTPUT ************************************************************** # 5581 1.1 is # FP_SCR0(a6) = scaled extended precision operand # 5582 1.1 is # d0 = scale value # 5583 1.1 is # # 5584 1.1 is # ALGORITHM *********************************************************** # 5585 1.1 is # If the input operand is a DENORM, normalize it. # 5586 1.1 is # If the exponent of the input operand is even, set the exponent # 5587 1.1 is # to 0x3ffe and return a scale factor of "(exp-0x3ffe)/2". If the # 5588 1.1 is # exponent of the input operand is off, set the exponent to ox3fff and # 5589 1.1 is # return a scale factor of "(exp-0x3fff)/2". # 5590 1.1 is # # 5591 1.1 is ######################################################################### 5592 1.1 is 5593 1.1 is global scale_sqrt 5594 1.1 is scale_sqrt: 5595 1.1 is cmpi.b STAG(%a6),&DENORM # is operand normalized? 5596 1.1 is beq.b ss_denorm # normalize the DENORM 5597 1.1 is 5598 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # extract operand's {sgn,exp} 5599 1.1 is andi.l &0x7fff,%d1 # extract operand's exponent 5600 1.1 is 5601 1.1 is andi.w &0x8000,FP_SCR0_EX(%a6) # extract operand's sgn 5602 1.1 is 5603 1.1 is btst &0x0,%d1 # is exp even or odd? 5604 1.1 is beq.b ss_norm_even 5605 1.1 is 5606 1.1 is ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 5607 1.1 is 5608 1.1 is mov.l &0x3fff,%d0 5609 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp) 5610 1.1 is asr.l &0x1,%d0 # divide scale factor by 2 5611 1.1 is rts 5612 1.1 is 5613 1.1 is ss_norm_even: 5614 1.1 is ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 5615 1.1 is 5616 1.1 is mov.l &0x3ffe,%d0 5617 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp) 5618 1.1 is asr.l &0x1,%d0 # divide scale factor by 2 5619 1.1 is rts 5620 1.1 is 5621 1.1 is ss_denorm: 5622 1.1 is lea FP_SCR0(%a6),%a0 # pass ptr to src op 5623 1.1 is bsr.l norm # normalize denorm 5624 1.1 is 5625 1.1 is btst &0x0,%d0 # is exp even or odd? 5626 1.1 is beq.b ss_denorm_even 5627 1.1 is 5628 1.1 is ori.w &0x3fff,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 5629 1.1 is 5630 1.1 is add.l &0x3fff,%d0 5631 1.1 is asr.l &0x1,%d0 # divide scale factor by 2 5632 1.1 is rts 5633 1.1 is 5634 1.1 is ss_denorm_even: 5635 1.1 is ori.w &0x3ffe,FP_SCR0_EX(%a6) # insert new operand's exponent(=0) 5636 1.1 is 5637 1.1 is add.l &0x3ffe,%d0 5638 1.1 is asr.l &0x1,%d0 # divide scale factor by 2 5639 1.1 is rts 5640 1.1 is 5641 1.1 is ### 5642 1.1 is 5643 1.1 is ######################################################################### 5644 1.1 is # XDEF **************************************************************** # 5645 1.1 is # scale_to_zero_dst(): scale the exponent of extended precision # 5646 1.1 is # value at FP_SCR1(a6). # 5647 1.1 is # # 5648 1.1 is # XREF **************************************************************** # 5649 1.1 is # norm() - normalize the mantissa if the operand was a DENORM # 5650 1.1 is # # 5651 1.1 is # INPUT *************************************************************** # 5652 1.1 is # FP_SCR1(a6) = extended precision operand to be scaled # 5653 1.1 is # # 5654 1.1 is # OUTPUT ************************************************************** # 5655 1.1 is # FP_SCR1(a6) = scaled extended precision operand # 5656 1.1 is # d0 = scale value # 5657 1.1 is # # 5658 1.1 is # ALGORITHM *********************************************************** # 5659 1.1 is # Set the exponent of the input operand to 0x3fff. Save the value # 5660 1.1 is # of the difference between the original and new exponent. Then, # 5661 1.1 is # normalize the operand if it was a DENORM. Add this normalization # 5662 1.1 is # value to the previous value. Return the result. # 5663 1.1 is # # 5664 1.1 is ######################################################################### 5665 1.1 is 5666 1.1 is global scale_to_zero_dst 5667 1.1 is scale_to_zero_dst: 5668 1.1 is mov.w FP_SCR1_EX(%a6),%d1 # extract operand's {sgn,exp} 5669 1.1 is mov.w %d1,%d0 # make a copy 5670 1.1 is 5671 1.1 is andi.l &0x7fff,%d1 # extract operand's exponent 5672 1.1 is 5673 1.1 is andi.w &0x8000,%d0 # extract operand's sgn 5674 1.1 is or.w &0x3fff,%d0 # insert new operand's exponent(=0) 5675 1.1 is 5676 1.1 is mov.w %d0,FP_SCR1_EX(%a6) # insert biased exponent 5677 1.1 is 5678 1.1 is cmpi.b DTAG(%a6),&DENORM # is operand normalized? 5679 1.1 is beq.b stzd_denorm # normalize the DENORM 5680 1.1 is 5681 1.1 is stzd_norm: 5682 1.1 is mov.l &0x3fff,%d0 5683 1.1 is sub.l %d1,%d0 # scale = BIAS + (-exp) 5684 1.1 is rts 5685 1.1 is 5686 1.1 is stzd_denorm: 5687 1.1 is lea FP_SCR1(%a6),%a0 # pass ptr to dst op 5688 1.1 is bsr.l norm # normalize denorm 5689 1.1 is neg.l %d0 # new exponent = -(shft val) 5690 1.1 is mov.l %d0,%d1 # prepare for op_norm call 5691 1.1 is bra.b stzd_norm # finish scaling 5692 1.1 is 5693 1.1 is ########################################################################## 5694 1.1 is 5695 1.1 is ######################################################################### 5696 1.1 is # XDEF **************************************************************** # 5697 1.1 is # res_qnan(): return default result w/ QNAN operand for dyadic # 5698 1.1 is # res_snan(): return default result w/ SNAN operand for dyadic # 5699 1.1 is # res_qnan_1op(): return dflt result w/ QNAN operand for monadic # 5700 1.1 is # res_snan_1op(): return dflt result w/ SNAN operand for monadic # 5701 1.1 is # # 5702 1.1 is # XREF **************************************************************** # 5703 1.1 is # None # 5704 1.1 is # # 5705 1.1 is # INPUT *************************************************************** # 5706 1.1 is # FP_SRC(a6) = pointer to extended precision src operand # 5707 1.1 is # FP_DST(a6) = pointer to extended precision dst operand # 5708 1.1 is # # 5709 1.1 is # OUTPUT ************************************************************** # 5710 1.1 is # fp0 = default result # 5711 1.1 is # # 5712 1.1 is # ALGORITHM *********************************************************** # 5713 1.1 is # If either operand (but not both operands) of an operation is a # 5714 1.1 is # nonsignalling NAN, then that NAN is returned as the result. If both # 5715 1.1 is # operands are nonsignalling NANs, then the destination operand # 5716 1.1 is # nonsignalling NAN is returned as the result. # 5717 1.1 is # If either operand to an operation is a signalling NAN (SNAN), # 5718 1.1 is # then, the SNAN bit is set in the FPSR EXC byte. If the SNAN trap # 5719 1.1 is # enable bit is set in the FPCR, then the trap is taken and the # 5720 1.1 is # destination is not modified. If the SNAN trap enable bit is not set, # 5721 1.1 is # then the SNAN is converted to a nonsignalling NAN (by setting the # 5722 1.1 is # SNAN bit in the operand to one), and the operation continues as # 5723 1.1 is # described in the preceding paragraph, for nonsignalling NANs. # 5724 1.1 is # Make sure the appropriate FPSR bits are set before exiting. # 5725 1.1 is # # 5726 1.1 is ######################################################################### 5727 1.1 is 5728 1.1 is global res_qnan 5729 1.1 is global res_snan 5730 1.1 is res_qnan: 5731 1.1 is res_snan: 5732 1.1 is cmp.b DTAG(%a6), &SNAN # is the dst an SNAN? 5733 1.1 is beq.b dst_snan2 5734 1.1 is cmp.b DTAG(%a6), &QNAN # is the dst a QNAN? 5735 1.1 is beq.b dst_qnan2 5736 1.1 is src_nan: 5737 1.1 is cmp.b STAG(%a6), &QNAN 5738 1.1 is beq.b src_qnan2 5739 1.1 is global res_snan_1op 5740 1.1 is res_snan_1op: 5741 1.1 is src_snan2: 5742 1.1 is bset &0x6, FP_SRC_HI(%a6) # set SNAN bit 5743 1.1 is or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6) 5744 1.1 is lea FP_SRC(%a6), %a0 5745 1.1 is bra.b nan_comp 5746 1.1 is global res_qnan_1op 5747 1.1 is res_qnan_1op: 5748 1.1 is src_qnan2: 5749 1.1 is or.l &nan_mask, USER_FPSR(%a6) 5750 1.1 is lea FP_SRC(%a6), %a0 5751 1.1 is bra.b nan_comp 5752 1.1 is dst_snan2: 5753 1.1 is or.l &nan_mask+aiop_mask+snan_mask, USER_FPSR(%a6) 5754 1.1 is bset &0x6, FP_DST_HI(%a6) # set SNAN bit 5755 1.1 is lea FP_DST(%a6), %a0 5756 1.1 is bra.b nan_comp 5757 1.1 is dst_qnan2: 5758 1.1 is lea FP_DST(%a6), %a0 5759 1.1 is cmp.b STAG(%a6), &SNAN 5760 1.1 is bne nan_done 5761 1.1 is or.l &aiop_mask+snan_mask, USER_FPSR(%a6) 5762 1.1 is nan_done: 5763 1.1 is or.l &nan_mask, USER_FPSR(%a6) 5764 1.1 is nan_comp: 5765 1.1 is btst &0x7, FTEMP_EX(%a0) # is NAN neg? 5766 1.1 is beq.b nan_not_neg 5767 1.1 is or.l &neg_mask, USER_FPSR(%a6) 5768 1.1 is nan_not_neg: 5769 1.1 is fmovm.x (%a0), &0x80 5770 1.1 is rts 5771 1.1 is 5772 1.1 is ######################################################################### 5773 1.1 is # XDEF **************************************************************** # 5774 1.1 is # res_operr(): return default result during operand error # 5775 1.1 is # # 5776 1.1 is # XREF **************************************************************** # 5777 1.1 is # None # 5778 1.1 is # # 5779 1.1 is # INPUT *************************************************************** # 5780 1.1 is # None # 5781 1.1 is # # 5782 1.1 is # OUTPUT ************************************************************** # 5783 1.1 is # fp0 = default operand error result # 5784 1.1 is # # 5785 1.1 is # ALGORITHM *********************************************************** # 5786 1.1 is # An nonsignalling NAN is returned as the default result when # 5787 1.1 is # an operand error occurs for the following cases: # 5788 1.1 is # # 5789 1.1 is # Multiply: (Infinity x Zero) # 5790 1.1 is # Divide : (Zero / Zero) || (Infinity / Infinity) # 5791 1.1 is # # 5792 1.1 is ######################################################################### 5793 1.1 is 5794 1.1 is global res_operr 5795 1.1 is res_operr: 5796 1.1 is or.l &nan_mask+operr_mask+aiop_mask, USER_FPSR(%a6) 5797 1.1 is fmovm.x nan_return(%pc), &0x80 5798 1.1 is rts 5799 1.1 is 5800 1.1 is nan_return: 5801 1.1 is long 0x7fff0000, 0xffffffff, 0xffffffff 5802 1.1 is 5803 1.1 is ######################################################################### 5804 1.1 is # XDEF **************************************************************** # 5805 1.1 is # _denorm(): denormalize an intermediate result # 5806 1.1 is # # 5807 1.1 is # XREF **************************************************************** # 5808 1.1 is # None # 5809 1.1 is # # 5810 1.1 is # INPUT *************************************************************** # 5811 1.1 is # a0 = points to the operand to be denormalized # 5812 1.1 is # (in the internal extended format) # 5813 1.1 is # # 5814 1.1 is # d0 = rounding precision # 5815 1.1 is # # 5816 1.1 is # OUTPUT ************************************************************** # 5817 1.1 is # a0 = pointer to the denormalized result # 5818 1.1 is # (in the internal extended format) # 5819 1.1 is # # 5820 1.1 is # d0 = guard,round,sticky # 5821 1.1 is # # 5822 1.1 is # ALGORITHM *********************************************************** # 5823 1.1 is # According to the exponent underflow threshold for the given # 5824 1.1 is # precision, shift the mantissa bits to the right in order raise the # 5825 1.1 is # exponent of the operand to the threshold value. While shifting the # 5826 1.1 is # mantissa bits right, maintain the value of the guard, round, and # 5827 1.1 is # sticky bits. # 5828 1.1 is # other notes: # 5829 1.1 is # (1) _denorm() is called by the underflow routines # 5830 1.1 is # (2) _denorm() does NOT affect the status register # 5831 1.1 is # # 5832 1.1 is ######################################################################### 5833 1.1 is 5834 1.1 is # 5835 1.1 is # table of exponent threshold values for each precision 5836 1.1 is # 5837 1.1 is tbl_thresh: 5838 1.1 is short 0x0 5839 1.1 is short sgl_thresh 5840 1.1 is short dbl_thresh 5841 1.1 is 5842 1.1 is global _denorm 5843 1.1 is _denorm: 5844 1.1 is # 5845 1.1 is # Load the exponent threshold for the precision selected and check 5846 1.1 is # to see if (threshold - exponent) is > 65 in which case we can 5847 1.1 is # simply calculate the sticky bit and zero the mantissa. otherwise 5848 1.1 is # we have to call the denormalization routine. 5849 1.1 is # 5850 1.1 is lsr.b &0x2, %d0 # shift prec to lo bits 5851 1.1 is mov.w (tbl_thresh.b,%pc,%d0.w*2), %d1 # load prec threshold 5852 1.1 is mov.w %d1, %d0 # copy d1 into d0 5853 1.1 is sub.w FTEMP_EX(%a0), %d0 # diff = threshold - exp 5854 1.1 is cmpi.w %d0, &66 # is diff > 65? (mant + g,r bits) 5855 1.1 is bpl.b denorm_set_stky # yes; just calc sticky 5856 1.1 is 5857 1.1 is clr.l %d0 # clear g,r,s 5858 1.1 is btst &inex2_bit, FPSR_EXCEPT(%a6) # yes; was INEX2 set? 5859 1.1 is beq.b denorm_call # no; don't change anything 5860 1.1 is bset &29, %d0 # yes; set sticky bit 5861 1.1 is 5862 1.1 is denorm_call: 5863 1.1 is bsr.l dnrm_lp # denormalize the number 5864 1.1 is rts 5865 1.1 is 5866 1.1 is # 5867 1.1 is # all bit would have been shifted off during the denorm so simply 5868 1.1 is # calculate if the sticky should be set and clear the entire mantissa. 5869 1.1 is # 5870 1.1 is denorm_set_stky: 5871 1.1 is mov.l &0x20000000, %d0 # set sticky bit in return value 5872 1.1 is mov.w %d1, FTEMP_EX(%a0) # load exp with threshold 5873 1.1 is clr.l FTEMP_HI(%a0) # set d1 = 0 (ms mantissa) 5874 1.1 is clr.l FTEMP_LO(%a0) # set d2 = 0 (ms mantissa) 5875 1.1 is rts 5876 1.1 is 5877 1.1 is # # 5878 1.1 is # dnrm_lp(): normalize exponent/mantissa to specified threshhold # 5879 1.1 is # # 5880 1.1 is # INPUT: # 5881 1.1 is # %a0 : points to the operand to be denormalized # 5882 1.1 is # %d0{31:29} : initial guard,round,sticky # 5883 1.1 is # %d1{15:0} : denormalization threshold # 5884 1.1 is # OUTPUT: # 5885 1.1 is # %a0 : points to the denormalized operand # 5886 1.1 is # %d0{31:29} : final guard,round,sticky # 5887 1.1 is # # 5888 1.1 is 5889 1.1 is # *** Local Equates *** # 5890 1.1 is set GRS, L_SCR2 # g,r,s temp storage 5891 1.1 is set FTEMP_LO2, L_SCR1 # FTEMP_LO copy 5892 1.1 is 5893 1.1 is global dnrm_lp 5894 1.1 is dnrm_lp: 5895 1.1 is 5896 1.1 is # 5897 1.1 is # make a copy of FTEMP_LO and place the g,r,s bits directly after it 5898 1.1 is # in memory so as to make the bitfield extraction for denormalization easier. 5899 1.1 is # 5900 1.1 is mov.l FTEMP_LO(%a0), FTEMP_LO2(%a6) # make FTEMP_LO copy 5901 1.1 is mov.l %d0, GRS(%a6) # place g,r,s after it 5902 1.1 is 5903 1.1 is # 5904 1.1 is # check to see how much less than the underflow threshold the operand 5905 1.1 is # exponent is. 5906 1.1 is # 5907 1.1 is mov.l %d1, %d0 # copy the denorm threshold 5908 1.1 is sub.w FTEMP_EX(%a0), %d1 # d1 = threshold - uns exponent 5909 1.1 is ble.b dnrm_no_lp # d1 <= 0 5910 1.1 is cmpi.w %d1, &0x20 # is ( 0 <= d1 < 32) ? 5911 1.1 is blt.b case_1 # yes 5912 1.1 is cmpi.w %d1, &0x40 # is (32 <= d1 < 64) ? 5913 1.1 is blt.b case_2 # yes 5914 1.1 is bra.w case_3 # (d1 >= 64) 5915 1.1 is 5916 1.1 is # 5917 1.1 is # No normalization necessary 5918 1.1 is # 5919 1.1 is dnrm_no_lp: 5920 1.1 is mov.l GRS(%a6), %d0 # restore original g,r,s 5921 1.1 is rts 5922 1.1 is 5923 1.1 is # 5924 1.1 is # case (0<d1<32) 5925 1.1 is # 5926 1.1 is # %d0 = denorm threshold 5927 1.1 is # %d1 = "n" = amt to shift 5928 1.1 is # 5929 1.1 is # --------------------------------------------------------- 5930 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000| 5931 1.1 is # --------------------------------------------------------- 5932 1.1 is # <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)-> 5933 1.1 is # \ \ \ \ 5934 1.1 is # \ \ \ \ 5935 1.1 is # \ \ \ \ 5936 1.1 is # \ \ \ \ 5937 1.1 is # \ \ \ \ 5938 1.1 is # \ \ \ \ 5939 1.1 is # \ \ \ \ 5940 1.1 is # \ \ \ \ 5941 1.1 is # <-(n)-><-(32 - n)-><------(32)-------><------(32)-------> 5942 1.1 is # --------------------------------------------------------- 5943 1.1 is # |0.....0| NEW_HI | NEW_FTEMP_LO |grs | 5944 1.1 is # --------------------------------------------------------- 5945 1.1 is # 5946 1.1 is case_1: 5947 1.1 is mov.l %d2, -(%sp) # create temp storage 5948 1.1 is 5949 1.1 is mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold 5950 1.1 is mov.l &32, %d0 5951 1.1 is sub.w %d1, %d0 # %d0 = 32 - %d1 5952 1.1 is 5953 1.1 is cmpi.w %d1, &29 # is shft amt >= 29 5954 1.1 is blt.b case1_extract # no; no fix needed 5955 1.1 is mov.b GRS(%a6), %d2 5956 1.1 is or.b %d2, 3+FTEMP_LO2(%a6) 5957 1.1 is 5958 1.1 is case1_extract: 5959 1.1 is bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_HI 5960 1.1 is bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new FTEMP_LO 5961 1.1 is bfextu FTEMP_LO2(%a6){%d0:&32}, %d0 # %d0 = new G,R,S 5962 1.1 is 5963 1.1 is mov.l %d2, FTEMP_HI(%a0) # store new FTEMP_HI 5964 1.1 is mov.l %d1, FTEMP_LO(%a0) # store new FTEMP_LO 5965 1.1 is 5966 1.1 is bftst %d0{&2:&30} # were bits shifted off? 5967 1.1 is beq.b case1_sticky_clear # no; go finish 5968 1.1 is bset &rnd_stky_bit, %d0 # yes; set sticky bit 5969 1.1 is 5970 1.1 is case1_sticky_clear: 5971 1.1 is and.l &0xe0000000, %d0 # clear all but G,R,S 5972 1.1 is mov.l (%sp)+, %d2 # restore temp register 5973 1.1 is rts 5974 1.1 is 5975 1.1 is # 5976 1.1 is # case (32<=d1<64) 5977 1.1 is # 5978 1.1 is # %d0 = denorm threshold 5979 1.1 is # %d1 = "n" = amt to shift 5980 1.1 is # 5981 1.1 is # --------------------------------------------------------- 5982 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000| 5983 1.1 is # --------------------------------------------------------- 5984 1.1 is # <-(32 - n)-><-(n)-><-(32 - n)-><-(n)-><-(32 - n)-><-(n)-> 5985 1.1 is # \ \ \ 5986 1.1 is # \ \ \ 5987 1.1 is # \ \ ------------------- 5988 1.1 is # \ -------------------- \ 5989 1.1 is # ------------------- \ \ 5990 1.1 is # \ \ \ 5991 1.1 is # \ \ \ 5992 1.1 is # \ \ \ 5993 1.1 is # <-------(32)------><-(n)-><-(32 - n)-><------(32)-------> 5994 1.1 is # --------------------------------------------------------- 5995 1.1 is # |0...............0|0....0| NEW_LO |grs | 5996 1.1 is # --------------------------------------------------------- 5997 1.1 is # 5998 1.1 is case_2: 5999 1.1 is mov.l %d2, -(%sp) # create temp storage 6000 1.1 is 6001 1.1 is mov.w %d0, FTEMP_EX(%a0) # exponent = denorm threshold 6002 1.1 is subi.w &0x20, %d1 # %d1 now between 0 and 32 6003 1.1 is mov.l &0x20, %d0 6004 1.1 is sub.w %d1, %d0 # %d0 = 32 - %d1 6005 1.1 is 6006 1.1 is # subtle step here; or in the g,r,s at the bottom of FTEMP_LO to minimize 6007 1.1 is # the number of bits to check for the sticky detect. 6008 1.1 is # it only plays a role in shift amounts of 61-63. 6009 1.1 is mov.b GRS(%a6), %d2 6010 1.1 is or.b %d2, 3+FTEMP_LO2(%a6) 6011 1.1 is 6012 1.1 is bfextu FTEMP_HI(%a0){&0:%d0}, %d2 # %d2 = new FTEMP_LO 6013 1.1 is bfextu FTEMP_HI(%a0){%d0:&32}, %d1 # %d1 = new G,R,S 6014 1.1 is 6015 1.1 is bftst %d1{&2:&30} # were any bits shifted off? 6016 1.1 is bne.b case2_set_sticky # yes; set sticky bit 6017 1.1 is bftst FTEMP_LO2(%a6){%d0:&31} # were any bits shifted off? 6018 1.1 is bne.b case2_set_sticky # yes; set sticky bit 6019 1.1 is 6020 1.1 is mov.l %d1, %d0 # move new G,R,S to %d0 6021 1.1 is bra.b case2_end 6022 1.1 is 6023 1.1 is case2_set_sticky: 6024 1.1 is mov.l %d1, %d0 # move new G,R,S to %d0 6025 1.1 is bset &rnd_stky_bit, %d0 # set sticky bit 6026 1.1 is 6027 1.1 is case2_end: 6028 1.1 is clr.l FTEMP_HI(%a0) # store FTEMP_HI = 0 6029 1.1 is mov.l %d2, FTEMP_LO(%a0) # store FTEMP_LO 6030 1.1 is and.l &0xe0000000, %d0 # clear all but G,R,S 6031 1.1 is 6032 1.1 is mov.l (%sp)+,%d2 # restore temp register 6033 1.1 is rts 6034 1.1 is 6035 1.1 is # 6036 1.1 is # case (d1>=64) 6037 1.1 is # 6038 1.1 is # %d0 = denorm threshold 6039 1.1 is # %d1 = amt to shift 6040 1.1 is # 6041 1.1 is case_3: 6042 1.1 is mov.w %d0, FTEMP_EX(%a0) # insert denorm threshold 6043 1.1 is 6044 1.1 is cmpi.w %d1, &65 # is shift amt > 65? 6045 1.1 is blt.b case3_64 # no; it's == 64 6046 1.1 is beq.b case3_65 # no; it's == 65 6047 1.1 is 6048 1.1 is # 6049 1.1 is # case (d1>65) 6050 1.1 is # 6051 1.1 is # Shift value is > 65 and out of range. All bits are shifted off. 6052 1.1 is # Return a zero mantissa with the sticky bit set 6053 1.1 is # 6054 1.1 is clr.l FTEMP_HI(%a0) # clear hi(mantissa) 6055 1.1 is clr.l FTEMP_LO(%a0) # clear lo(mantissa) 6056 1.1 is mov.l &0x20000000, %d0 # set sticky bit 6057 1.1 is rts 6058 1.1 is 6059 1.1 is # 6060 1.1 is # case (d1 == 64) 6061 1.1 is # 6062 1.1 is # --------------------------------------------------------- 6063 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000| 6064 1.1 is # --------------------------------------------------------- 6065 1.1 is # <-------(32)------> 6066 1.1 is # \ \ 6067 1.1 is # \ \ 6068 1.1 is # \ \ 6069 1.1 is # \ ------------------------------ 6070 1.1 is # ------------------------------- \ 6071 1.1 is # \ \ 6072 1.1 is # \ \ 6073 1.1 is # \ \ 6074 1.1 is # <-------(32)------> 6075 1.1 is # --------------------------------------------------------- 6076 1.1 is # |0...............0|0................0|grs | 6077 1.1 is # --------------------------------------------------------- 6078 1.1 is # 6079 1.1 is case3_64: 6080 1.1 is mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa) 6081 1.1 is mov.l %d0, %d1 # make a copy 6082 1.1 is and.l &0xc0000000, %d0 # extract G,R 6083 1.1 is and.l &0x3fffffff, %d1 # extract other bits 6084 1.1 is 6085 1.1 is bra.b case3_complete 6086 1.1 is 6087 1.1 is # 6088 1.1 is # case (d1 == 65) 6089 1.1 is # 6090 1.1 is # --------------------------------------------------------- 6091 1.1 is # | FTEMP_HI | FTEMP_LO |grs000.........000| 6092 1.1 is # --------------------------------------------------------- 6093 1.1 is # <-------(32)------> 6094 1.1 is # \ \ 6095 1.1 is # \ \ 6096 1.1 is # \ \ 6097 1.1 is # \ ------------------------------ 6098 1.1 is # -------------------------------- \ 6099 1.1 is # \ \ 6100 1.1 is # \ \ 6101 1.1 is # \ \ 6102 1.1 is # <-------(31)-----> 6103 1.1 is # --------------------------------------------------------- 6104 1.1 is # |0...............0|0................0|0rs | 6105 1.1 is # --------------------------------------------------------- 6106 1.1 is # 6107 1.1 is case3_65: 6108 1.1 is mov.l FTEMP_HI(%a0), %d0 # fetch hi(mantissa) 6109 1.1 is and.l &0x80000000, %d0 # extract R bit 6110 1.1 is lsr.l &0x1, %d0 # shift high bit into R bit 6111 1.1 is and.l &0x7fffffff, %d1 # extract other bits 6112 1.1 is 6113 1.1 is case3_complete: 6114 1.1 is # last operation done was an "and" of the bits shifted off so the condition 6115 1.1 is # codes are already set so branch accordingly. 6116 1.1 is bne.b case3_set_sticky # yes; go set new sticky 6117 1.1 is tst.l FTEMP_LO(%a0) # were any bits shifted off? 6118 1.1 is bne.b case3_set_sticky # yes; go set new sticky 6119 1.1 is tst.b GRS(%a6) # were any bits shifted off? 6120 1.1 is bne.b case3_set_sticky # yes; go set new sticky 6121 1.1 is 6122 1.1 is # 6123 1.1 is # no bits were shifted off so don't set the sticky bit. 6124 1.1 is # the guard and 6125 1.1 is # the entire mantissa is zero. 6126 1.1 is # 6127 1.1 is clr.l FTEMP_HI(%a0) # clear hi(mantissa) 6128 1.1 is clr.l FTEMP_LO(%a0) # clear lo(mantissa) 6129 1.1 is rts 6130 1.1 is 6131 1.1 is # 6132 1.1 is # some bits were shifted off so set the sticky bit. 6133 1.1 is # the entire mantissa is zero. 6134 1.1 is # 6135 1.1 is case3_set_sticky: 6136 1.1 is bset &rnd_stky_bit,%d0 # set new sticky bit 6137 1.1 is clr.l FTEMP_HI(%a0) # clear hi(mantissa) 6138 1.1 is clr.l FTEMP_LO(%a0) # clear lo(mantissa) 6139 1.1 is rts 6140 1.1 is 6141 1.1 is ######################################################################### 6142 1.1 is # XDEF **************************************************************** # 6143 1.1 is # _round(): round result according to precision/mode # 6144 1.1 is # # 6145 1.1 is # XREF **************************************************************** # 6146 1.1 is # None # 6147 1.1 is # # 6148 1.1 is # INPUT *************************************************************** # 6149 1.1 is # a0 = ptr to input operand in internal extended format # 6150 1.1 is # d1(hi) = contains rounding precision: # 6151 1.1 is # ext = $0000xxxx # 6152 1.1 is # sgl = $0004xxxx # 6153 1.1 is # dbl = $0008xxxx # 6154 1.1 is # d1(lo) = contains rounding mode: # 6155 1.1 is # RN = $xxxx0000 # 6156 1.1 is # RZ = $xxxx0001 # 6157 1.1 is # RM = $xxxx0002 # 6158 1.1 is # RP = $xxxx0003 # 6159 1.1 is # d0{31:29} = contains the g,r,s bits (extended) # 6160 1.1 is # # 6161 1.1 is # OUTPUT ************************************************************** # 6162 1.1 is # a0 = pointer to rounded result # 6163 1.1 is # # 6164 1.1 is # ALGORITHM *********************************************************** # 6165 1.1 is # On return the value pointed to by a0 is correctly rounded, # 6166 1.1 is # a0 is preserved and the g-r-s bits in d0 are cleared. # 6167 1.1 is # The result is not typed - the tag field is invalid. The # 6168 1.1 is # result is still in the internal extended format. # 6169 1.1 is # # 6170 1.1 is # The INEX bit of USER_FPSR will be set if the rounded result was # 6171 1.1 is # inexact (i.e. if any of the g-r-s bits were set). # 6172 1.1 is # # 6173 1.1 is ######################################################################### 6174 1.1 is 6175 1.1 is global _round 6176 1.1 is _round: 6177 1.1 is # 6178 1.1 is # ext_grs() looks at the rounding precision and sets the appropriate 6179 1.1 is # G,R,S bits. 6180 1.1 is # If (G,R,S == 0) then result is exact and round is done, else set 6181 1.1 is # the inex flag in status reg and continue. 6182 1.1 is # 6183 1.1 is bsr.l ext_grs # extract G,R,S 6184 1.1 is 6185 1.1 is tst.l %d0 # are G,R,S zero? 6186 1.1 is beq.w truncate # yes; round is complete 6187 1.1 is 6188 1.1 is or.w &inx2a_mask, 2+USER_FPSR(%a6) # set inex2/ainex 6189 1.1 is 6190 1.1 is # 6191 1.1 is # Use rounding mode as an index into a jump table for these modes. 6192 1.1 is # All of the following assumes grs != 0. 6193 1.1 is # 6194 1.1 is mov.w (tbl_mode.b,%pc,%d1.w*2), %a1 # load jump offset 6195 1.1 is jmp (tbl_mode.b,%pc,%a1) # jmp to rnd mode handler 6196 1.1 is 6197 1.1 is tbl_mode: 6198 1.1 is short rnd_near - tbl_mode 6199 1.1 is short truncate - tbl_mode # RZ always truncates 6200 1.1 is short rnd_mnus - tbl_mode 6201 1.1 is short rnd_plus - tbl_mode 6202 1.1 is 6203 1.1 is ################################################################# 6204 1.1 is # ROUND PLUS INFINITY # 6205 1.1 is # # 6206 1.1 is # If sign of fp number = 0 (positive), then add 1 to l. # 6207 1.1 is ################################################################# 6208 1.1 is rnd_plus: 6209 1.1 is tst.b FTEMP_SGN(%a0) # check for sign 6210 1.1 is bmi.w truncate # if positive then truncate 6211 1.1 is 6212 1.1 is mov.l &0xffffffff, %d0 # force g,r,s to be all f's 6213 1.1 is swap %d1 # set up d1 for round prec. 6214 1.1 is 6215 1.1 is cmpi.b %d1, &s_mode # is prec = sgl? 6216 1.1 is beq.w add_sgl # yes 6217 1.1 is bgt.w add_dbl # no; it's dbl 6218 1.1 is bra.w add_ext # no; it's ext 6219 1.1 is 6220 1.1 is ################################################################# 6221 1.1 is # ROUND MINUS INFINITY # 6222 1.1 is # # 6223 1.1 is # If sign of fp number = 1 (negative), then add 1 to l. # 6224 1.1 is ################################################################# 6225 1.1 is rnd_mnus: 6226 1.1 is tst.b FTEMP_SGN(%a0) # check for sign 6227 1.1 is bpl.w truncate # if negative then truncate 6228 1.1 is 6229 1.1 is mov.l &0xffffffff, %d0 # force g,r,s to be all f's 6230 1.1 is swap %d1 # set up d1 for round prec. 6231 1.1 is 6232 1.1 is cmpi.b %d1, &s_mode # is prec = sgl? 6233 1.1 is beq.w add_sgl # yes 6234 1.1 is bgt.w add_dbl # no; it's dbl 6235 1.1 is bra.w add_ext # no; it's ext 6236 1.1 is 6237 1.1 is ################################################################# 6238 1.1 is # ROUND NEAREST # 6239 1.1 is # # 6240 1.1 is # If (g=1), then add 1 to l and if (r=s=0), then clear l # 6241 1.1 is # Note that this will round to even in case of a tie. # 6242 1.1 is ################################################################# 6243 1.1 is rnd_near: 6244 1.1 is asl.l &0x1, %d0 # shift g-bit to c-bit 6245 1.1 is bcc.w truncate # if (g=1) then 6246 1.1 is 6247 1.1 is swap %d1 # set up d1 for round prec. 6248 1.1 is 6249 1.1 is cmpi.b %d1, &s_mode # is prec = sgl? 6250 1.1 is beq.w add_sgl # yes 6251 1.1 is bgt.w add_dbl # no; it's dbl 6252 1.1 is bra.w add_ext # no; it's ext 6253 1.1 is 6254 1.1 is # *** LOCAL EQUATES *** 6255 1.1 is set ad_1_sgl, 0x00000100 # constant to add 1 to l-bit in sgl prec 6256 1.1 is set ad_1_dbl, 0x00000800 # constant to add 1 to l-bit in dbl prec 6257 1.1 is 6258 1.1 is ######################### 6259 1.1 is # ADD SINGLE # 6260 1.1 is ######################### 6261 1.1 is add_sgl: 6262 1.1 is add.l &ad_1_sgl, FTEMP_HI(%a0) 6263 1.1 is bcc.b scc_clr # no mantissa overflow 6264 1.1 is roxr.w FTEMP_HI(%a0) # shift v-bit back in 6265 1.1 is roxr.w FTEMP_HI+2(%a0) # shift v-bit back in 6266 1.1 is add.w &0x1, FTEMP_EX(%a0) # and incr exponent 6267 1.1 is scc_clr: 6268 1.1 is tst.l %d0 # test for rs = 0 6269 1.1 is bne.b sgl_done 6270 1.1 is and.w &0xfe00, FTEMP_HI+2(%a0) # clear the l-bit 6271 1.1 is sgl_done: 6272 1.1 is and.l &0xffffff00, FTEMP_HI(%a0) # truncate bits beyond sgl limit 6273 1.1 is clr.l FTEMP_LO(%a0) # clear d2 6274 1.1 is rts 6275 1.1 is 6276 1.1 is ######################### 6277 1.1 is # ADD EXTENDED # 6278 1.1 is ######################### 6279 1.1 is add_ext: 6280 1.1 is addq.l &1,FTEMP_LO(%a0) # add 1 to l-bit 6281 1.1 is bcc.b xcc_clr # test for carry out 6282 1.1 is addq.l &1,FTEMP_HI(%a0) # propogate carry 6283 1.1 is bcc.b xcc_clr 6284 1.1 is roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit 6285 1.1 is roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit 6286 1.1 is roxr.w FTEMP_LO(%a0) 6287 1.1 is roxr.w FTEMP_LO+2(%a0) 6288 1.1 is add.w &0x1,FTEMP_EX(%a0) # and inc exp 6289 1.1 is xcc_clr: 6290 1.1 is tst.l %d0 # test rs = 0 6291 1.1 is bne.b add_ext_done 6292 1.1 is and.b &0xfe,FTEMP_LO+3(%a0) # clear the l bit 6293 1.1 is add_ext_done: 6294 1.1 is rts 6295 1.1 is 6296 1.1 is ######################### 6297 1.1 is # ADD DOUBLE # 6298 1.1 is ######################### 6299 1.1 is add_dbl: 6300 1.1 is add.l &ad_1_dbl, FTEMP_LO(%a0) # add 1 to lsb 6301 1.1 is bcc.b dcc_clr # no carry 6302 1.1 is addq.l &0x1, FTEMP_HI(%a0) # propogate carry 6303 1.1 is bcc.b dcc_clr # no carry 6304 1.1 is 6305 1.1 is roxr.w FTEMP_HI(%a0) # mant is 0 so restore v-bit 6306 1.1 is roxr.w FTEMP_HI+2(%a0) # mant is 0 so restore v-bit 6307 1.1 is roxr.w FTEMP_LO(%a0) 6308 1.1 is roxr.w FTEMP_LO+2(%a0) 6309 1.1 is addq.w &0x1, FTEMP_EX(%a0) # incr exponent 6310 1.1 is dcc_clr: 6311 1.1 is tst.l %d0 # test for rs = 0 6312 1.1 is bne.b dbl_done 6313 1.1 is and.w &0xf000, FTEMP_LO+2(%a0) # clear the l-bit 6314 1.1 is 6315 1.1 is dbl_done: 6316 1.1 is and.l &0xfffff800,FTEMP_LO(%a0) # truncate bits beyond dbl limit 6317 1.1 is rts 6318 1.1 is 6319 1.1 is ########################### 6320 1.1 is # Truncate all other bits # 6321 1.1 is ########################### 6322 1.1 is truncate: 6323 1.1 is swap %d1 # select rnd prec 6324 1.1 is 6325 1.1 is cmpi.b %d1, &s_mode # is prec sgl? 6326 1.1 is beq.w sgl_done # yes 6327 1.1 is bgt.b dbl_done # no; it's dbl 6328 1.1 is rts # no; it's ext 6329 1.1 is 6330 1.1 is 6331 1.1 is # 6332 1.1 is # ext_grs(): extract guard, round and sticky bits according to 6333 1.1 is # rounding precision. 6334 1.1 is # 6335 1.1 is # INPUT 6336 1.1 is # d0 = extended precision g,r,s (in d0{31:29}) 6337 1.1 is # d1 = {PREC,ROUND} 6338 1.1 is # OUTPUT 6339 1.1 is # d0{31:29} = guard, round, sticky 6340 1.1 is # 6341 1.1 is # The ext_grs extract the guard/round/sticky bits according to the 6342 1.1 is # selected rounding precision. It is called by the round subroutine 6343 1.1 is # only. All registers except d0 are kept intact. d0 becomes an 6344 1.1 is # updated guard,round,sticky in d0{31:29} 6345 1.1 is # 6346 1.1 is # Notes: the ext_grs uses the round PREC, and therefore has to swap d1 6347 1.1 is # prior to usage, and needs to restore d1 to original. this 6348 1.1 is # routine is tightly tied to the round routine and not meant to 6349 1.1 is # uphold standard subroutine calling practices. 6350 1.1 is # 6351 1.1 is 6352 1.1 is ext_grs: 6353 1.1 is swap %d1 # have d1.w point to round precision 6354 1.1 is tst.b %d1 # is rnd prec = extended? 6355 1.1 is bne.b ext_grs_not_ext # no; go handle sgl or dbl 6356 1.1 is 6357 1.1 is # 6358 1.1 is # %d0 actually already hold g,r,s since _round() had it before calling 6359 1.1 is # this function. so, as long as we don't disturb it, we are "returning" it. 6360 1.1 is # 6361 1.1 is ext_grs_ext: 6362 1.1 is swap %d1 # yes; return to correct positions 6363 1.1 is rts 6364 1.1 is 6365 1.1 is ext_grs_not_ext: 6366 1.1 is movm.l &0x3000, -(%sp) # make some temp registers {d2/d3} 6367 1.1 is 6368 1.1 is cmpi.b %d1, &s_mode # is rnd prec = sgl? 6369 1.1 is bne.b ext_grs_dbl # no; go handle dbl 6370 1.1 is 6371 1.1 is # 6372 1.1 is # sgl: 6373 1.1 is # 96 64 40 32 0 6374 1.1 is # ----------------------------------------------------- 6375 1.1 is # | EXP |XXXXXXX| |xx | |grs| 6376 1.1 is # ----------------------------------------------------- 6377 1.1 is # <--(24)--->nn\ / 6378 1.1 is # ee --------------------- 6379 1.1 is # ww | 6380 1.1 is # v 6381 1.1 is # gr new sticky 6382 1.1 is # 6383 1.1 is ext_grs_sgl: 6384 1.1 is bfextu FTEMP_HI(%a0){&24:&2}, %d3 # sgl prec. g-r are 2 bits right 6385 1.1 is mov.l &30, %d2 # of the sgl prec. limits 6386 1.1 is lsl.l %d2, %d3 # shift g-r bits to MSB of d3 6387 1.1 is mov.l FTEMP_HI(%a0), %d2 # get word 2 for s-bit test 6388 1.1 is and.l &0x0000003f, %d2 # s bit is the or of all other 6389 1.1 is bne.b ext_grs_st_stky # bits to the right of g-r 6390 1.1 is tst.l FTEMP_LO(%a0) # test lower mantissa 6391 1.1 is bne.b ext_grs_st_stky # if any are set, set sticky 6392 1.1 is tst.l %d0 # test original g,r,s 6393 1.1 is bne.b ext_grs_st_stky # if any are set, set sticky 6394 1.1 is bra.b ext_grs_end_sd # if words 3 and 4 are clr, exit 6395 1.1 is 6396 1.1 is # 6397 1.1 is # dbl: 6398 1.1 is # 96 64 32 11 0 6399 1.1 is # ----------------------------------------------------- 6400 1.1 is # | EXP |XXXXXXX| | |xx |grs| 6401 1.1 is # ----------------------------------------------------- 6402 1.1 is # nn\ / 6403 1.1 is # ee ------- 6404 1.1 is # ww | 6405 1.1 is # v 6406 1.1 is # gr new sticky 6407 1.1 is # 6408 1.1 is ext_grs_dbl: 6409 1.1 is bfextu FTEMP_LO(%a0){&21:&2}, %d3 # dbl-prec. g-r are 2 bits right 6410 1.1 is mov.l &30, %d2 # of the dbl prec. limits 6411 1.1 is lsl.l %d2, %d3 # shift g-r bits to the MSB of d3 6412 1.1 is mov.l FTEMP_LO(%a0), %d2 # get lower mantissa for s-bit test 6413 1.1 is and.l &0x000001ff, %d2 # s bit is the or-ing of all 6414 1.1 is bne.b ext_grs_st_stky # other bits to the right of g-r 6415 1.1 is tst.l %d0 # test word original g,r,s 6416 1.1 is bne.b ext_grs_st_stky # if any are set, set sticky 6417 1.1 is bra.b ext_grs_end_sd # if clear, exit 6418 1.1 is 6419 1.1 is ext_grs_st_stky: 6420 1.1 is bset &rnd_stky_bit, %d3 # set sticky bit 6421 1.1 is ext_grs_end_sd: 6422 1.1 is mov.l %d3, %d0 # return grs to d0 6423 1.1 is 6424 1.1 is movm.l (%sp)+, &0xc # restore scratch registers {d2/d3} 6425 1.1 is 6426 1.1 is swap %d1 # restore d1 to original 6427 1.1 is rts 6428 1.1 is 6429 1.1 is ######################################################################### 6430 1.1 is # norm(): normalize the mantissa of an extended precision input. the # 6431 1.1 is # input operand should not be normalized already. # 6432 1.1 is # # 6433 1.1 is # XDEF **************************************************************** # 6434 1.1 is # norm() # 6435 1.1 is # # 6436 1.1 is # XREF **************************************************************** # 6437 1.1 is # none # 6438 1.1 is # # 6439 1.1 is # INPUT *************************************************************** # 6440 1.1 is # a0 = pointer fp extended precision operand to normalize # 6441 1.1 is # # 6442 1.1 is # OUTPUT ************************************************************** # 6443 1.1 is # d0 = number of bit positions the mantissa was shifted # 6444 1.1 is # a0 = the input operand's mantissa is normalized; the exponent # 6445 1.1 is # is unchanged. # 6446 1.1 is # # 6447 1.1 is ######################################################################### 6448 1.1 is global norm 6449 1.1 is norm: 6450 1.1 is mov.l %d2, -(%sp) # create some temp regs 6451 1.1 is mov.l %d3, -(%sp) 6452 1.1 is 6453 1.1 is mov.l FTEMP_HI(%a0), %d0 # load hi(mantissa) 6454 1.1 is mov.l FTEMP_LO(%a0), %d1 # load lo(mantissa) 6455 1.1 is 6456 1.1 is bfffo %d0{&0:&32}, %d2 # how many places to shift? 6457 1.1 is beq.b norm_lo # hi(man) is all zeroes! 6458 1.1 is 6459 1.1 is norm_hi: 6460 1.1 is lsl.l %d2, %d0 # left shift hi(man) 6461 1.1 is bfextu %d1{&0:%d2}, %d3 # extract lo bits 6462 1.1 is 6463 1.1 is or.l %d3, %d0 # create hi(man) 6464 1.1 is lsl.l %d2, %d1 # create lo(man) 6465 1.1 is 6466 1.1 is mov.l %d0, FTEMP_HI(%a0) # store new hi(man) 6467 1.1 is mov.l %d1, FTEMP_LO(%a0) # store new lo(man) 6468 1.1 is 6469 1.1 is mov.l %d2, %d0 # return shift amount 6470 1.1 is 6471 1.1 is mov.l (%sp)+, %d3 # restore temp regs 6472 1.1 is mov.l (%sp)+, %d2 6473 1.1 is 6474 1.1 is rts 6475 1.1 is 6476 1.1 is norm_lo: 6477 1.1 is bfffo %d1{&0:&32}, %d2 # how many places to shift? 6478 1.1 is lsl.l %d2, %d1 # shift lo(man) 6479 1.1 is add.l &32, %d2 # add 32 to shft amount 6480 1.1 is 6481 1.1 is mov.l %d1, FTEMP_HI(%a0) # store hi(man) 6482 1.1 is clr.l FTEMP_LO(%a0) # lo(man) is now zero 6483 1.1 is 6484 1.1 is mov.l %d2, %d0 # return shift amount 6485 1.1 is 6486 1.1 is mov.l (%sp)+, %d3 # restore temp regs 6487 1.1 is mov.l (%sp)+, %d2 6488 1.1 is 6489 1.1 is rts 6490 1.1 is 6491 1.1 is ######################################################################### 6492 1.1 is # unnorm_fix(): - changes an UNNORM to one of NORM, DENORM, or ZERO # 6493 1.1 is # - returns corresponding optype tag # 6494 1.1 is # # 6495 1.1 is # XDEF **************************************************************** # 6496 1.1 is # unnorm_fix() # 6497 1.1 is # # 6498 1.1 is # XREF **************************************************************** # 6499 1.1 is # norm() - normalize the mantissa # 6500 1.1 is # # 6501 1.1 is # INPUT *************************************************************** # 6502 1.1 is # a0 = pointer to unnormalized extended precision number # 6503 1.1 is # # 6504 1.1 is # OUTPUT ************************************************************** # 6505 1.1 is # d0 = optype tag - is corrected to one of NORM, DENORM, or ZERO # 6506 1.1 is # a0 = input operand has been converted to a norm, denorm, or # 6507 1.1 is # zero; both the exponent and mantissa are changed. # 6508 1.1 is # # 6509 1.1 is ######################################################################### 6510 1.1 is 6511 1.1 is global unnorm_fix 6512 1.1 is unnorm_fix: 6513 1.1 is bfffo FTEMP_HI(%a0){&0:&32}, %d0 # how many shifts are needed? 6514 1.1 is bne.b unnorm_shift # hi(man) is not all zeroes 6515 1.1 is 6516 1.1 is # 6517 1.1 is # hi(man) is all zeroes so see if any bits in lo(man) are set 6518 1.1 is # 6519 1.1 is unnorm_chk_lo: 6520 1.1 is bfffo FTEMP_LO(%a0){&0:&32}, %d0 # is operand really a zero? 6521 1.1 is beq.w unnorm_zero # yes 6522 1.1 is 6523 1.1 is add.w &32, %d0 # no; fix shift distance 6524 1.1 is 6525 1.1 is # 6526 1.1 is # d0 = # shifts needed for complete normalization 6527 1.1 is # 6528 1.1 is unnorm_shift: 6529 1.1 is clr.l %d1 # clear top word 6530 1.1 is mov.w FTEMP_EX(%a0), %d1 # extract exponent 6531 1.1 is and.w &0x7fff, %d1 # strip off sgn 6532 1.1 is 6533 1.1 is cmp.w %d0, %d1 # will denorm push exp < 0? 6534 1.1 is bgt.b unnorm_nrm_zero # yes; denorm only until exp = 0 6535 1.1 is 6536 1.1 is # 6537 1.1 is # exponent would not go < 0. therefore, number stays normalized 6538 1.1 is # 6539 1.1 is sub.w %d0, %d1 # shift exponent value 6540 1.1 is mov.w FTEMP_EX(%a0), %d0 # load old exponent 6541 1.1 is and.w &0x8000, %d0 # save old sign 6542 1.1 is or.w %d0, %d1 # {sgn,new exp} 6543 1.1 is mov.w %d1, FTEMP_EX(%a0) # insert new exponent 6544 1.1 is 6545 1.1 is bsr.l norm # normalize UNNORM 6546 1.1 is 6547 1.1 is mov.b &NORM, %d0 # return new optype tag 6548 1.1 is rts 6549 1.1 is 6550 1.1 is # 6551 1.1 is # exponent would go < 0, so only denormalize until exp = 0 6552 1.1 is # 6553 1.1 is unnorm_nrm_zero: 6554 1.1 is cmp.b %d1, &32 # is exp <= 32? 6555 1.1 is bgt.b unnorm_nrm_zero_lrg # no; go handle large exponent 6556 1.1 is 6557 1.1 is bfextu FTEMP_HI(%a0){%d1:&32}, %d0 # extract new hi(man) 6558 1.1 is mov.l %d0, FTEMP_HI(%a0) # save new hi(man) 6559 1.1 is 6560 1.1 is mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man) 6561 1.1 is lsl.l %d1, %d0 # extract new lo(man) 6562 1.1 is mov.l %d0, FTEMP_LO(%a0) # save new lo(man) 6563 1.1 is 6564 1.1 is and.w &0x8000, FTEMP_EX(%a0) # set exp = 0 6565 1.1 is 6566 1.1 is mov.b &DENORM, %d0 # return new optype tag 6567 1.1 is rts 6568 1.1 is 6569 1.1 is # 6570 1.1 is # only mantissa bits set are in lo(man) 6571 1.1 is # 6572 1.1 is unnorm_nrm_zero_lrg: 6573 1.1 is sub.w &32, %d1 # adjust shft amt by 32 6574 1.1 is 6575 1.1 is mov.l FTEMP_LO(%a0), %d0 # fetch old lo(man) 6576 1.1 is lsl.l %d1, %d0 # left shift lo(man) 6577 1.1 is 6578 1.1 is mov.l %d0, FTEMP_HI(%a0) # store new hi(man) 6579 1.1 is clr.l FTEMP_LO(%a0) # lo(man) = 0 6580 1.1 is 6581 1.1 is and.w &0x8000, FTEMP_EX(%a0) # set exp = 0 6582 1.1 is 6583 1.1 is mov.b &DENORM, %d0 # return new optype tag 6584 1.1 is rts 6585 1.1 is 6586 1.1 is # 6587 1.1 is # whole mantissa is zero so this UNNORM is actually a zero 6588 1.1 is # 6589 1.1 is unnorm_zero: 6590 1.1 is and.w &0x8000, FTEMP_EX(%a0) # force exponent to zero 6591 1.1 is 6592 1.1 is mov.b &ZERO, %d0 # fix optype tag 6593 1.1 is rts 6594 1.1 is 6595 1.1 is ######################################################################### 6596 1.1 is # XDEF **************************************************************** # 6597 1.1 is # set_tag_x(): return the optype of the input ext fp number # 6598 1.1 is # # 6599 1.1 is # XREF **************************************************************** # 6600 1.1 is # None # 6601 1.1 is # # 6602 1.1 is # INPUT *************************************************************** # 6603 1.1 is # a0 = pointer to extended precision operand # 6604 1.1 is # # 6605 1.1 is # OUTPUT ************************************************************** # 6606 1.1 is # d0 = value of type tag # 6607 1.1 is # one of: NORM, INF, QNAN, SNAN, DENORM, UNNORM, ZERO # 6608 1.1 is # # 6609 1.1 is # ALGORITHM *********************************************************** # 6610 1.1 is # Simply test the exponent, j-bit, and mantissa values to # 6611 1.1 is # determine the type of operand. # 6612 1.1 is # If it's an unnormalized zero, alter the operand and force it # 6613 1.1 is # to be a normal zero. # 6614 1.1 is # # 6615 1.1 is ######################################################################### 6616 1.1 is 6617 1.1 is global set_tag_x 6618 1.1 is set_tag_x: 6619 1.1 is mov.w FTEMP_EX(%a0), %d0 # extract exponent 6620 1.1 is andi.w &0x7fff, %d0 # strip off sign 6621 1.1 is cmpi.w %d0, &0x7fff # is (EXP == MAX)? 6622 1.1 is beq.b inf_or_nan_x 6623 1.1 is not_inf_or_nan_x: 6624 1.1 is btst &0x7,FTEMP_HI(%a0) 6625 1.1 is beq.b not_norm_x 6626 1.1 is is_norm_x: 6627 1.1 is mov.b &NORM, %d0 6628 1.1 is rts 6629 1.1 is not_norm_x: 6630 1.1 is tst.w %d0 # is exponent = 0? 6631 1.1 is bne.b is_unnorm_x 6632 1.1 is not_unnorm_x: 6633 1.1 is tst.l FTEMP_HI(%a0) 6634 1.1 is bne.b is_denorm_x 6635 1.1 is tst.l FTEMP_LO(%a0) 6636 1.1 is bne.b is_denorm_x 6637 1.1 is is_zero_x: 6638 1.1 is mov.b &ZERO, %d0 6639 1.1 is rts 6640 1.1 is is_denorm_x: 6641 1.1 is mov.b &DENORM, %d0 6642 1.1 is rts 6643 1.1 is # must distinguish now "Unnormalized zeroes" which we 6644 1.1 is # must convert to zero. 6645 1.1 is is_unnorm_x: 6646 1.1 is tst.l FTEMP_HI(%a0) 6647 1.1 is bne.b is_unnorm_reg_x 6648 1.1 is tst.l FTEMP_LO(%a0) 6649 1.1 is bne.b is_unnorm_reg_x 6650 1.1 is # it's an "unnormalized zero". let's convert it to an actual zero... 6651 1.1 is andi.w &0x8000,FTEMP_EX(%a0) # clear exponent 6652 1.1 is mov.b &ZERO, %d0 6653 1.1 is rts 6654 1.1 is is_unnorm_reg_x: 6655 1.1 is mov.b &UNNORM, %d0 6656 1.1 is rts 6657 1.1 is inf_or_nan_x: 6658 1.1 is tst.l FTEMP_LO(%a0) 6659 1.1 is bne.b is_nan_x 6660 1.1 is mov.l FTEMP_HI(%a0), %d0 6661 1.1 is and.l &0x7fffffff, %d0 # msb is a don't care! 6662 1.1 is bne.b is_nan_x 6663 1.1 is is_inf_x: 6664 1.1 is mov.b &INF, %d0 6665 1.1 is rts 6666 1.1 is is_nan_x: 6667 1.1 is btst &0x6, FTEMP_HI(%a0) 6668 1.1 is beq.b is_snan_x 6669 1.1 is mov.b &QNAN, %d0 6670 1.1 is rts 6671 1.1 is is_snan_x: 6672 1.1 is mov.b &SNAN, %d0 6673 1.1 is rts 6674 1.1 is 6675 1.1 is ######################################################################### 6676 1.1 is # XDEF **************************************************************** # 6677 1.1 is # set_tag_d(): return the optype of the input dbl fp number # 6678 1.1 is # # 6679 1.1 is # XREF **************************************************************** # 6680 1.1 is # None # 6681 1.1 is # # 6682 1.1 is # INPUT *************************************************************** # 6683 1.1 is # a0 = points to double precision operand # 6684 1.1 is # # 6685 1.1 is # OUTPUT ************************************************************** # 6686 1.1 is # d0 = value of type tag # 6687 1.1 is # one of: NORM, INF, QNAN, SNAN, DENORM, ZERO # 6688 1.1 is # # 6689 1.1 is # ALGORITHM *********************************************************** # 6690 1.1 is # Simply test the exponent, j-bit, and mantissa values to # 6691 1.1 is # determine the type of operand. # 6692 1.1 is # # 6693 1.1 is ######################################################################### 6694 1.1 is 6695 1.1 is global set_tag_d 6696 1.1 is set_tag_d: 6697 1.1 is mov.l FTEMP(%a0), %d0 6698 1.1 is mov.l %d0, %d1 6699 1.1 is 6700 1.1 is andi.l &0x7ff00000, %d0 6701 1.1 is beq.b zero_or_denorm_d 6702 1.1 is 6703 1.1 is cmpi.l %d0, &0x7ff00000 6704 1.1 is beq.b inf_or_nan_d 6705 1.1 is 6706 1.1 is is_norm_d: 6707 1.1 is mov.b &NORM, %d0 6708 1.1 is rts 6709 1.1 is zero_or_denorm_d: 6710 1.1 is and.l &0x000fffff, %d1 6711 1.1 is bne is_denorm_d 6712 1.1 is tst.l 4+FTEMP(%a0) 6713 1.1 is bne is_denorm_d 6714 1.1 is is_zero_d: 6715 1.1 is mov.b &ZERO, %d0 6716 1.1 is rts 6717 1.1 is is_denorm_d: 6718 1.1 is mov.b &DENORM, %d0 6719 1.1 is rts 6720 1.1 is inf_or_nan_d: 6721 1.1 is and.l &0x000fffff, %d1 6722 1.1 is bne is_nan_d 6723 1.1 is tst.l 4+FTEMP(%a0) 6724 1.1 is bne is_nan_d 6725 1.1 is is_inf_d: 6726 1.1 is mov.b &INF, %d0 6727 1.1 is rts 6728 1.1 is is_nan_d: 6729 1.1 is btst &19, %d1 6730 1.1 is bne is_qnan_d 6731 1.1 is is_snan_d: 6732 1.1 is mov.b &SNAN, %d0 6733 1.1 is rts 6734 1.1 is is_qnan_d: 6735 1.1 is mov.b &QNAN, %d0 6736 1.1 is rts 6737 1.1 is 6738 1.1 is ######################################################################### 6739 1.1 is # XDEF **************************************************************** # 6740 1.1 is # set_tag_s(): return the optype of the input sgl fp number # 6741 1.1 is # # 6742 1.1 is # XREF **************************************************************** # 6743 1.1 is # None # 6744 1.1 is # # 6745 1.1 is # INPUT *************************************************************** # 6746 1.1 is # a0 = pointer to single precision operand # 6747 1.1 is # # 6748 1.1 is # OUTPUT ************************************************************** # 6749 1.1 is # d0 = value of type tag # 6750 1.1 is # one of: NORM, INF, QNAN, SNAN, DENORM, ZERO # 6751 1.1 is # # 6752 1.1 is # ALGORITHM *********************************************************** # 6753 1.1 is # Simply test the exponent, j-bit, and mantissa values to # 6754 1.1 is # determine the type of operand. # 6755 1.1 is # # 6756 1.1 is ######################################################################### 6757 1.1 is 6758 1.1 is global set_tag_s 6759 1.1 is set_tag_s: 6760 1.1 is mov.l FTEMP(%a0), %d0 6761 1.1 is mov.l %d0, %d1 6762 1.1 is 6763 1.1 is andi.l &0x7f800000, %d0 6764 1.1 is beq.b zero_or_denorm_s 6765 1.1 is 6766 1.1 is cmpi.l %d0, &0x7f800000 6767 1.1 is beq.b inf_or_nan_s 6768 1.1 is 6769 1.1 is is_norm_s: 6770 1.1 is mov.b &NORM, %d0 6771 1.1 is rts 6772 1.1 is zero_or_denorm_s: 6773 1.1 is and.l &0x007fffff, %d1 6774 1.1 is bne is_denorm_s 6775 1.1 is is_zero_s: 6776 1.1 is mov.b &ZERO, %d0 6777 1.1 is rts 6778 1.1 is is_denorm_s: 6779 1.1 is mov.b &DENORM, %d0 6780 1.1 is rts 6781 1.1 is inf_or_nan_s: 6782 1.1 is and.l &0x007fffff, %d1 6783 1.1 is bne is_nan_s 6784 1.1 is is_inf_s: 6785 1.1 is mov.b &INF, %d0 6786 1.1 is rts 6787 1.1 is is_nan_s: 6788 1.1 is btst &22, %d1 6789 1.1 is bne is_qnan_s 6790 1.1 is is_snan_s: 6791 1.1 is mov.b &SNAN, %d0 6792 1.1 is rts 6793 1.1 is is_qnan_s: 6794 1.1 is mov.b &QNAN, %d0 6795 1.1 is rts 6796 1.1 is 6797 1.1 is ######################################################################### 6798 1.1 is # XDEF **************************************************************** # 6799 1.1 is # unf_res(): routine to produce default underflow result of a # 6800 1.1 is # scaled extended precision number; this is used by # 6801 1.1 is # fadd/fdiv/fmul/etc. emulation routines. # 6802 1.1 is # unf_res4(): same as above but for fsglmul/fsgldiv which use # 6803 1.1 is # single round prec and extended prec mode. # 6804 1.1 is # # 6805 1.1 is # XREF **************************************************************** # 6806 1.1 is # _denorm() - denormalize according to scale factor # 6807 1.1 is # _round() - round denormalized number according to rnd prec # 6808 1.1 is # # 6809 1.1 is # INPUT *************************************************************** # 6810 1.1 is # a0 = pointer to extended precison operand # 6811 1.1 is # d0 = scale factor # 6812 1.1 is # d1 = rounding precision/mode # 6813 1.1 is # # 6814 1.1 is # OUTPUT ************************************************************** # 6815 1.1 is # a0 = pointer to default underflow result in extended precision # 6816 1.1 is # d0.b = result FPSR_cc which caller may or may not want to save # 6817 1.1 is # # 6818 1.1 is # ALGORITHM *********************************************************** # 6819 1.1 is # Convert the input operand to "internal format" which means the # 6820 1.1 is # exponent is extended to 16 bits and the sign is stored in the unused # 6821 1.1 is # portion of the extended precison operand. Denormalize the number # 6822 1.1 is # according to the scale factor passed in d0. Then, round the # 6823 1.1 is # denormalized result. # 6824 1.1 is # Set the FPSR_exc bits as appropriate but return the cc bits in # 6825 1.1 is # d0 in case the caller doesn't want to save them (as is the case for # 6826 1.1 is # fmove out). # 6827 1.1 is # unf_res4() for fsglmul/fsgldiv forces the denorm to extended # 6828 1.1 is # precision and the rounding mode to single. # 6829 1.1 is # # 6830 1.1 is ######################################################################### 6831 1.1 is global unf_res 6832 1.1 is unf_res: 6833 1.1 is mov.l %d1, -(%sp) # save rnd prec,mode on stack 6834 1.1 is 6835 1.1 is btst &0x7, FTEMP_EX(%a0) # make "internal" format 6836 1.1 is sne FTEMP_SGN(%a0) 6837 1.1 is 6838 1.1 is mov.w FTEMP_EX(%a0), %d1 # extract exponent 6839 1.1 is and.w &0x7fff, %d1 6840 1.1 is sub.w %d0, %d1 6841 1.1 is mov.w %d1, FTEMP_EX(%a0) # insert 16 bit exponent 6842 1.1 is 6843 1.1 is mov.l %a0, -(%sp) # save operand ptr during calls 6844 1.1 is 6845 1.1 is mov.l 0x4(%sp),%d0 # pass rnd prec. 6846 1.1 is andi.w &0x00c0,%d0 6847 1.1 is lsr.w &0x4,%d0 6848 1.1 is bsr.l _denorm # denorm result 6849 1.1 is 6850 1.1 is mov.l (%sp),%a0 6851 1.1 is mov.w 0x6(%sp),%d1 # load prec:mode into %d1 6852 1.1 is andi.w &0xc0,%d1 # extract rnd prec 6853 1.1 is lsr.w &0x4,%d1 6854 1.1 is swap %d1 6855 1.1 is mov.w 0x6(%sp),%d1 6856 1.1 is andi.w &0x30,%d1 6857 1.1 is lsr.w &0x4,%d1 6858 1.1 is bsr.l _round # round the denorm 6859 1.1 is 6860 1.1 is mov.l (%sp)+, %a0 6861 1.1 is 6862 1.1 is # result is now rounded properly. convert back to normal format 6863 1.1 is bclr &0x7, FTEMP_EX(%a0) # clear sgn first; may have residue 6864 1.1 is tst.b FTEMP_SGN(%a0) # is "internal result" sign set? 6865 1.1 is beq.b unf_res_chkifzero # no; result is positive 6866 1.1 is bset &0x7, FTEMP_EX(%a0) # set result sgn 6867 1.1 is clr.b FTEMP_SGN(%a0) # clear temp sign 6868 1.1 is 6869 1.1 is # the number may have become zero after rounding. set ccodes accordingly. 6870 1.1 is unf_res_chkifzero: 6871 1.1 is clr.l %d0 6872 1.1 is tst.l FTEMP_HI(%a0) # is value now a zero? 6873 1.1 is bne.b unf_res_cont # no 6874 1.1 is tst.l FTEMP_LO(%a0) 6875 1.1 is bne.b unf_res_cont # no 6876 1.1 is # bset &z_bit, FPSR_CC(%a6) # yes; set zero ccode bit 6877 1.1 is bset &z_bit, %d0 # yes; set zero ccode bit 6878 1.1 is 6879 1.1 is unf_res_cont: 6880 1.1 is 6881 1.1 is # 6882 1.1 is # can inex1 also be set along with unfl and inex2??? 6883 1.1 is # 6884 1.1 is # we know that underflow has occurred. aunfl should be set if INEX2 is also set. 6885 1.1 is # 6886 1.1 is btst &inex2_bit, FPSR_EXCEPT(%a6) # is INEX2 set? 6887 1.1 is beq.b unf_res_end # no 6888 1.1 is bset &aunfl_bit, FPSR_AEXCEPT(%a6) # yes; set aunfl 6889 1.1 is 6890 1.1 is unf_res_end: 6891 1.1 is add.l &0x4, %sp # clear stack 6892 1.1 is rts 6893 1.1 is 6894 1.1 is # unf_res() for fsglmul() and fsgldiv(). 6895 1.1 is global unf_res4 6896 1.1 is unf_res4: 6897 1.1 is mov.l %d1,-(%sp) # save rnd prec,mode on stack 6898 1.1 is 6899 1.1 is btst &0x7,FTEMP_EX(%a0) # make "internal" format 6900 1.1 is sne FTEMP_SGN(%a0) 6901 1.1 is 6902 1.1 is mov.w FTEMP_EX(%a0),%d1 # extract exponent 6903 1.1 is and.w &0x7fff,%d1 6904 1.1 is sub.w %d0,%d1 6905 1.1 is mov.w %d1,FTEMP_EX(%a0) # insert 16 bit exponent 6906 1.1 is 6907 1.1 is mov.l %a0,-(%sp) # save operand ptr during calls 6908 1.1 is 6909 1.1 is clr.l %d0 # force rnd prec = ext 6910 1.1 is bsr.l _denorm # denorm result 6911 1.1 is 6912 1.1 is mov.l (%sp),%a0 6913 1.1 is mov.w &s_mode,%d1 # force rnd prec = sgl 6914 1.1 is swap %d1 6915 1.1 is mov.w 0x6(%sp),%d1 # load rnd mode 6916 1.1 is andi.w &0x30,%d1 # extract rnd prec 6917 1.1 is lsr.w &0x4,%d1 6918 1.1 is bsr.l _round # round the denorm 6919 1.1 is 6920 1.1 is mov.l (%sp)+,%a0 6921 1.1 is 6922 1.1 is # result is now rounded properly. convert back to normal format 6923 1.1 is bclr &0x7,FTEMP_EX(%a0) # clear sgn first; may have residue 6924 1.1 is tst.b FTEMP_SGN(%a0) # is "internal result" sign set? 6925 1.1 is beq.b unf_res4_chkifzero # no; result is positive 6926 1.1 is bset &0x7,FTEMP_EX(%a0) # set result sgn 6927 1.1 is clr.b FTEMP_SGN(%a0) # clear temp sign 6928 1.1 is 6929 1.1 is # the number may have become zero after rounding. set ccodes accordingly. 6930 1.1 is unf_res4_chkifzero: 6931 1.1 is clr.l %d0 6932 1.1 is tst.l FTEMP_HI(%a0) # is value now a zero? 6933 1.1 is bne.b unf_res4_cont # no 6934 1.1 is tst.l FTEMP_LO(%a0) 6935 1.1 is bne.b unf_res4_cont # no 6936 1.1 is # bset &z_bit,FPSR_CC(%a6) # yes; set zero ccode bit 6937 1.1 is bset &z_bit,%d0 # yes; set zero ccode bit 6938 1.1 is 6939 1.1 is unf_res4_cont: 6940 1.1 is 6941 1.1 is # 6942 1.1 is # can inex1 also be set along with unfl and inex2??? 6943 1.1 is # 6944 1.1 is # we know that underflow has occurred. aunfl should be set if INEX2 is also set. 6945 1.1 is # 6946 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set? 6947 1.1 is beq.b unf_res4_end # no 6948 1.1 is bset &aunfl_bit,FPSR_AEXCEPT(%a6) # yes; set aunfl 6949 1.1 is 6950 1.1 is unf_res4_end: 6951 1.1 is add.l &0x4,%sp # clear stack 6952 1.1 is rts 6953 1.1 is 6954 1.1 is ######################################################################### 6955 1.1 is # XDEF **************************************************************** # 6956 1.1 is # ovf_res(): routine to produce the default overflow result of # 6957 1.1 is # an overflowing number. # 6958 1.1 is # ovf_res2(): same as above but the rnd mode/prec are passed # 6959 1.1 is # differently. # 6960 1.1 is # # 6961 1.1 is # XREF **************************************************************** # 6962 1.1 is # none # 6963 1.1 is # # 6964 1.1 is # INPUT *************************************************************** # 6965 1.1 is # d1.b = '-1' => (-); '0' => (+) # 6966 1.1 is # ovf_res(): # 6967 1.1 is # d0 = rnd mode/prec # 6968 1.1 is # ovf_res2(): # 6969 1.1 is # hi(d0) = rnd prec # 6970 1.1 is # lo(d0) = rnd mode # 6971 1.1 is # # 6972 1.1 is # OUTPUT ************************************************************** # 6973 1.1 is # a0 = points to extended precision result # 6974 1.1 is # d0.b = condition code bits # 6975 1.1 is # # 6976 1.1 is # ALGORITHM *********************************************************** # 6977 1.1 is # The default overflow result can be determined by the sign of # 6978 1.1 is # the result and the rounding mode/prec in effect. These bits are # 6979 1.1 is # concatenated together to create an index into the default result # 6980 1.1 is # table. A pointer to the correct result is returned in a0. The # 6981 1.1 is # resulting condition codes are returned in d0 in case the caller # 6982 1.1 is # doesn't want FPSR_cc altered (as is the case for fmove out). # 6983 1.1 is # # 6984 1.1 is ######################################################################### 6985 1.1 is 6986 1.1 is global ovf_res 6987 1.1 is ovf_res: 6988 1.1 is andi.w &0x10,%d1 # keep result sign 6989 1.1 is lsr.b &0x4,%d0 # shift prec/mode 6990 1.1 is or.b %d0,%d1 # concat the two 6991 1.1 is mov.w %d1,%d0 # make a copy 6992 1.1 is lsl.b &0x1,%d1 # multiply d1 by 2 6993 1.1 is bra.b ovf_res_load 6994 1.1 is 6995 1.1 is global ovf_res2 6996 1.1 is ovf_res2: 6997 1.1 is and.w &0x10, %d1 # keep result sign 6998 1.1 is or.b %d0, %d1 # insert rnd mode 6999 1.1 is swap %d0 7000 1.1 is or.b %d0, %d1 # insert rnd prec 7001 1.1 is mov.w %d1, %d0 # make a copy 7002 1.1 is lsl.b &0x1, %d1 # shift left by 1 7003 1.1 is 7004 1.1 is # 7005 1.1 is # use the rounding mode, precision, and result sign as in index into the 7006 1.1 is # two tables below to fetch the default result and the result ccodes. 7007 1.1 is # 7008 1.1 is ovf_res_load: 7009 1.1 is mov.b (tbl_ovfl_cc.b,%pc,%d0.w*1), %d0 # fetch result ccodes 7010 1.1 is lea (tbl_ovfl_result.b,%pc,%d1.w*8), %a0 # return result ptr 7011 1.1 is 7012 1.1 is rts 7013 1.1 is 7014 1.1 is tbl_ovfl_cc: 7015 1.1 is byte 0x2, 0x0, 0x0, 0x2 7016 1.1 is byte 0x2, 0x0, 0x0, 0x2 7017 1.1 is byte 0x2, 0x0, 0x0, 0x2 7018 1.1 is byte 0x0, 0x0, 0x0, 0x0 7019 1.1 is byte 0x2+0x8, 0x8, 0x2+0x8, 0x8 7020 1.1 is byte 0x2+0x8, 0x8, 0x2+0x8, 0x8 7021 1.1 is byte 0x2+0x8, 0x8, 0x2+0x8, 0x8 7022 1.1 is 7023 1.1 is tbl_ovfl_result: 7024 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN 7025 1.1 is long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RZ 7026 1.1 is long 0x7ffe0000,0xffffffff,0xffffffff,0x00000000 # +EXT; RM 7027 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP 7028 1.1 is 7029 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN 7030 1.1 is long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RZ 7031 1.1 is long 0x407e0000,0xffffff00,0x00000000,0x00000000 # +SGL; RM 7032 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP 7033 1.1 is 7034 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RN 7035 1.1 is long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RZ 7036 1.1 is long 0x43fe0000,0xffffffff,0xfffff800,0x00000000 # +DBL; RM 7037 1.1 is long 0x7fff0000,0x00000000,0x00000000,0x00000000 # +INF; RP 7038 1.1 is 7039 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000 7040 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000 7041 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000 7042 1.1 is long 0x00000000,0x00000000,0x00000000,0x00000000 7043 1.1 is 7044 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN 7045 1.1 is long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RZ 7046 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM 7047 1.1 is long 0xfffe0000,0xffffffff,0xffffffff,0x00000000 # -EXT; RP 7048 1.1 is 7049 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN 7050 1.1 is long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RZ 7051 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM 7052 1.1 is long 0xc07e0000,0xffffff00,0x00000000,0x00000000 # -SGL; RP 7053 1.1 is 7054 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RN 7055 1.1 is long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RZ 7056 1.1 is long 0xffff0000,0x00000000,0x00000000,0x00000000 # -INF; RM 7057 1.1 is long 0xc3fe0000,0xffffffff,0xfffff800,0x00000000 # -DBL; RP 7058 1.1 is 7059 1.1 is ######################################################################### 7060 1.1 is # XDEF **************************************************************** # 7061 1.1 is # fout(): move from fp register to memory or data register # 7062 1.1 is # # 7063 1.1 is # XREF **************************************************************** # 7064 1.1 is # _round() - needed to create EXOP for sgl/dbl precision # 7065 1.1 is # norm() - needed to create EXOP for extended precision # 7066 1.1 is # ovf_res() - create default overflow result for sgl/dbl precision# 7067 1.1 is # unf_res() - create default underflow result for sgl/dbl prec. # 7068 1.1 is # dst_dbl() - create rounded dbl precision result. # 7069 1.1 is # dst_sgl() - create rounded sgl precision result. # 7070 1.1 is # fetch_dreg() - fetch dynamic k-factor reg for packed. # 7071 1.1 is # bindec() - convert FP binary number to packed number. # 7072 1.1 is # _mem_write() - write data to memory. # 7073 1.1 is # _mem_write2() - write data to memory unless supv mode -(a7) exc.# 7074 1.1 is # _dmem_write_{byte,word,long}() - write data to memory. # 7075 1.1 is # store_dreg_{b,w,l}() - store data to data register file. # 7076 1.1 is # facc_out_{b,w,l,d,x}() - data access error occurred. # 7077 1.1 is # # 7078 1.1 is # INPUT *************************************************************** # 7079 1.1 is # a0 = pointer to extended precision source operand # 7080 1.1 is # d0 = round prec,mode # 7081 1.1 is # # 7082 1.1 is # OUTPUT ************************************************************** # 7083 1.1 is # fp0 : intermediate underflow or overflow result if # 7084 1.1 is # OVFL/UNFL occurred for a sgl or dbl operand # 7085 1.1 is # # 7086 1.1 is # ALGORITHM *********************************************************** # 7087 1.1 is # This routine is accessed by many handlers that need to do an # 7088 1.1 is # opclass three move of an operand out to memory. # 7089 1.1 is # Decode an fmove out (opclass 3) instruction to determine if # 7090 1.1 is # it's b,w,l,s,d,x, or p in size. b,w,l can be stored to either a data # 7091 1.1 is # register or memory. The algorithm uses a standard "fmove" to create # 7092 1.1 is # the rounded result. Also, since exceptions are disabled, this also # 7093 1.1 is # create the correct OPERR default result if appropriate. # 7094 1.1 is # For sgl or dbl precision, overflow or underflow can occur. If # 7095 1.1 is # either occurs and is enabled, the EXOP. # 7096 1.1 is # For extended precision, the stacked <ea> must be fixed along # 7097 1.1 is # w/ the address index register as appropriate w/ _calc_ea_fout(). If # 7098 1.1 is # the source is a denorm and if underflow is enabled, an EXOP must be # 7099 1.1 is # created. # 7100 1.1 is # For packed, the k-factor must be fetched from the instruction # 7101 1.1 is # word or a data register. The <ea> must be fixed as w/ extended # 7102 1.1 is # precision. Then, bindec() is called to create the appropriate # 7103 1.1 is # packed result. # 7104 1.1 is # If at any time an access error is flagged by one of the move- # 7105 1.1 is # to-memory routines, then a special exit must be made so that the # 7106 1.1 is # access error can be handled properly. # 7107 1.1 is # # 7108 1.1 is ######################################################################### 7109 1.1 is 7110 1.1 is global fout 7111 1.1 is fout: 7112 1.1 is bfextu EXC_CMDREG(%a6){&3:&3},%d1 # extract dst fmt 7113 1.1 is mov.w (tbl_fout.b,%pc,%d1.w*2),%a1 # use as index 7114 1.1 is jmp (tbl_fout.b,%pc,%a1) # jump to routine 7115 1.1 is 7116 1.1 is swbeg &0x8 7117 1.1 is tbl_fout: 7118 1.1 is short fout_long - tbl_fout 7119 1.1 is short fout_sgl - tbl_fout 7120 1.1 is short fout_ext - tbl_fout 7121 1.1 is short fout_pack - tbl_fout 7122 1.1 is short fout_word - tbl_fout 7123 1.1 is short fout_dbl - tbl_fout 7124 1.1 is short fout_byte - tbl_fout 7125 1.1 is short fout_pack - tbl_fout 7126 1.1 is 7127 1.1 is ################################################################# 7128 1.1 is # fmove.b out ################################################### 7129 1.1 is ################################################################# 7130 1.1 is 7131 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand 7132 1.1 is # is either a DENORM or a NORM. 7133 1.1 is fout_byte: 7134 1.1 is tst.b STAG(%a6) # is operand normalized? 7135 1.1 is bne.b fout_byte_denorm # no 7136 1.1 is 7137 1.1 is fmovm.x SRC(%a0),&0x80 # load value 7138 1.1 is 7139 1.1 is fout_byte_norm: 7140 1.1 is fmov.l %d0,%fpcr # insert rnd prec,mode 7141 1.1 is 7142 1.1 is fmov.b %fp0,%d0 # exec move out w/ correct rnd mode 7143 1.1 is 7144 1.1 is fmov.l &0x0,%fpcr # clear FPCR 7145 1.1 is fmov.l %fpsr,%d1 # fetch FPSR 7146 1.1 is or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits 7147 1.1 is 7148 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 7149 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 7150 1.1 is beq.b fout_byte_dn # must save to integer regfile 7151 1.1 is 7152 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 7153 1.1 is bsr.l _dmem_write_byte # write byte 7154 1.1 is 7155 1.1 is tst.l %d1 # did dstore fail? 7156 1.1 is bne.l facc_out_b # yes 7157 1.1 is 7158 1.1 is rts 7159 1.1 is 7160 1.1 is fout_byte_dn: 7161 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 7162 1.1 is andi.w &0x7,%d1 7163 1.1 is bsr.l store_dreg_b 7164 1.1 is rts 7165 1.1 is 7166 1.1 is fout_byte_denorm: 7167 1.1 is mov.l SRC_EX(%a0),%d1 7168 1.1 is andi.l &0x80000000,%d1 # keep DENORM sign 7169 1.1 is ori.l &0x00800000,%d1 # make smallest sgl 7170 1.1 is fmov.s %d1,%fp0 7171 1.1 is bra.b fout_byte_norm 7172 1.1 is 7173 1.1 is ################################################################# 7174 1.1 is # fmove.w out ################################################### 7175 1.1 is ################################################################# 7176 1.1 is 7177 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand 7178 1.1 is # is either a DENORM or a NORM. 7179 1.1 is fout_word: 7180 1.1 is tst.b STAG(%a6) # is operand normalized? 7181 1.1 is bne.b fout_word_denorm # no 7182 1.1 is 7183 1.1 is fmovm.x SRC(%a0),&0x80 # load value 7184 1.1 is 7185 1.1 is fout_word_norm: 7186 1.1 is fmov.l %d0,%fpcr # insert rnd prec:mode 7187 1.1 is 7188 1.1 is fmov.w %fp0,%d0 # exec move out w/ correct rnd mode 7189 1.1 is 7190 1.1 is fmov.l &0x0,%fpcr # clear FPCR 7191 1.1 is fmov.l %fpsr,%d1 # fetch FPSR 7192 1.1 is or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits 7193 1.1 is 7194 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 7195 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 7196 1.1 is beq.b fout_word_dn # must save to integer regfile 7197 1.1 is 7198 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 7199 1.1 is bsr.l _dmem_write_word # write word 7200 1.1 is 7201 1.1 is tst.l %d1 # did dstore fail? 7202 1.1 is bne.l facc_out_w # yes 7203 1.1 is 7204 1.1 is rts 7205 1.1 is 7206 1.1 is fout_word_dn: 7207 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 7208 1.1 is andi.w &0x7,%d1 7209 1.1 is bsr.l store_dreg_w 7210 1.1 is rts 7211 1.1 is 7212 1.1 is fout_word_denorm: 7213 1.1 is mov.l SRC_EX(%a0),%d1 7214 1.1 is andi.l &0x80000000,%d1 # keep DENORM sign 7215 1.1 is ori.l &0x00800000,%d1 # make smallest sgl 7216 1.1 is fmov.s %d1,%fp0 7217 1.1 is bra.b fout_word_norm 7218 1.1 is 7219 1.1 is ################################################################# 7220 1.1 is # fmove.l out ################################################### 7221 1.1 is ################################################################# 7222 1.1 is 7223 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand 7224 1.1 is # is either a DENORM or a NORM. 7225 1.1 is fout_long: 7226 1.1 is tst.b STAG(%a6) # is operand normalized? 7227 1.1 is bne.b fout_long_denorm # no 7228 1.1 is 7229 1.1 is fmovm.x SRC(%a0),&0x80 # load value 7230 1.1 is 7231 1.1 is fout_long_norm: 7232 1.1 is fmov.l %d0,%fpcr # insert rnd prec:mode 7233 1.1 is 7234 1.1 is fmov.l %fp0,%d0 # exec move out w/ correct rnd mode 7235 1.1 is 7236 1.1 is fmov.l &0x0,%fpcr # clear FPCR 7237 1.1 is fmov.l %fpsr,%d1 # fetch FPSR 7238 1.1 is or.w %d1,2+USER_FPSR(%a6) # save new exc,accrued bits 7239 1.1 is 7240 1.1 is fout_long_write: 7241 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 7242 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 7243 1.1 is beq.b fout_long_dn # must save to integer regfile 7244 1.1 is 7245 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 7246 1.1 is bsr.l _dmem_write_long # write long 7247 1.1 is 7248 1.1 is tst.l %d1 # did dstore fail? 7249 1.1 is bne.l facc_out_l # yes 7250 1.1 is 7251 1.1 is rts 7252 1.1 is 7253 1.1 is fout_long_dn: 7254 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 7255 1.1 is andi.w &0x7,%d1 7256 1.1 is bsr.l store_dreg_l 7257 1.1 is rts 7258 1.1 is 7259 1.1 is fout_long_denorm: 7260 1.1 is mov.l SRC_EX(%a0),%d1 7261 1.1 is andi.l &0x80000000,%d1 # keep DENORM sign 7262 1.1 is ori.l &0x00800000,%d1 # make smallest sgl 7263 1.1 is fmov.s %d1,%fp0 7264 1.1 is bra.b fout_long_norm 7265 1.1 is 7266 1.1 is ################################################################# 7267 1.1 is # fmove.x out ################################################### 7268 1.1 is ################################################################# 7269 1.1 is 7270 1.1 is # Only "Unimplemented Data Type" exceptions enter here. The operand 7271 1.1 is # is either a DENORM or a NORM. 7272 1.1 is # The DENORM causes an Underflow exception. 7273 1.1 is fout_ext: 7274 1.1 is 7275 1.1 is # we copy the extended precision result to FP_SCR0 so that the reserved 7276 1.1 is # 16-bit field gets zeroed. we do this since we promise not to disturb 7277 1.1 is # what's at SRC(a0). 7278 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 7279 1.1 is clr.w 2+FP_SCR0_EX(%a6) # clear reserved field 7280 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 7281 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 7282 1.1 is 7283 1.1 is fmovm.x SRC(%a0),&0x80 # return result 7284 1.1 is 7285 1.1 is bsr.l _calc_ea_fout # fix stacked <ea> 7286 1.1 is 7287 1.1 is mov.l %a0,%a1 # pass: dst addr 7288 1.1 is lea FP_SCR0(%a6),%a0 # pass: src addr 7289 1.1 is mov.l &0xc,%d0 # pass: opsize is 12 bytes 7290 1.1 is 7291 1.1 is # we must not yet write the extended precision data to the stack 7292 1.1 is # in the pre-decrement case from supervisor mode or else we'll corrupt 7293 1.1 is # the stack frame. so, leave it in FP_SRC for now and deal with it later... 7294 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg 7295 1.1 is beq.b fout_ext_a7 7296 1.1 is 7297 1.1 is bsr.l _dmem_write # write ext prec number to memory 7298 1.1 is 7299 1.1 is tst.l %d1 # did dstore fail? 7300 1.1 is bne.w fout_ext_err # yes 7301 1.1 is 7302 1.1 is tst.b STAG(%a6) # is operand normalized? 7303 1.1 is bne.b fout_ext_denorm # no 7304 1.1 is rts 7305 1.1 is 7306 1.1 is # the number is a DENORM. must set the underflow exception bit 7307 1.1 is fout_ext_denorm: 7308 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set underflow exc bit 7309 1.1 is 7310 1.1 is mov.b FPCR_ENABLE(%a6),%d0 7311 1.1 is andi.b &0x0a,%d0 # is UNFL or INEX enabled? 7312 1.1 is bne.b fout_ext_exc # yes 7313 1.1 is rts 7314 1.1 is 7315 1.1 is # we don't want to do the write if the exception occurred in supervisor mode 7316 1.1 is # so _mem_write2() handles this for us. 7317 1.1 is fout_ext_a7: 7318 1.1 is bsr.l _mem_write2 # write ext prec number to memory 7319 1.1 is 7320 1.1 is tst.l %d1 # did dstore fail? 7321 1.1 is bne.w fout_ext_err # yes 7322 1.1 is 7323 1.1 is tst.b STAG(%a6) # is operand normalized? 7324 1.1 is bne.b fout_ext_denorm # no 7325 1.1 is rts 7326 1.1 is 7327 1.1 is fout_ext_exc: 7328 1.1 is lea FP_SCR0(%a6),%a0 7329 1.1 is bsr.l norm # normalize the mantissa 7330 1.1 is neg.w %d0 # new exp = -(shft amt) 7331 1.1 is andi.w &0x7fff,%d0 7332 1.1 is andi.w &0x8000,FP_SCR0_EX(%a6) # keep only old sign 7333 1.1 is or.w %d0,FP_SCR0_EX(%a6) # insert new exponent 7334 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 7335 1.1 is rts 7336 1.1 is 7337 1.1 is fout_ext_err: 7338 1.1 is mov.l EXC_A6(%a6),(%a6) # fix stacked a6 7339 1.1 is bra.l facc_out_x 7340 1.1 is 7341 1.1 is ######################################################################### 7342 1.1 is # fmove.s out ########################################################### 7343 1.1 is ######################################################################### 7344 1.1 is fout_sgl: 7345 1.1 is andi.b &0x30,%d0 # clear rnd prec 7346 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec 7347 1.1 is mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack 7348 1.1 is 7349 1.1 is # 7350 1.1 is # operand is a normalized number. first, we check to see if the move out 7351 1.1 is # would cause either an underflow or overflow. these cases are handled 7352 1.1 is # separately. otherwise, set the FPCR to the proper rounding mode and 7353 1.1 is # execute the move. 7354 1.1 is # 7355 1.1 is mov.w SRC_EX(%a0),%d0 # extract exponent 7356 1.1 is andi.w &0x7fff,%d0 # strip sign 7357 1.1 is 7358 1.1 is cmpi.w %d0,&SGL_HI # will operand overflow? 7359 1.1 is bgt.w fout_sgl_ovfl # yes; go handle OVFL 7360 1.1 is beq.w fout_sgl_may_ovfl # maybe; go handle possible OVFL 7361 1.1 is cmpi.w %d0,&SGL_LO # will operand underflow? 7362 1.1 is blt.w fout_sgl_unfl # yes; go handle underflow 7363 1.1 is 7364 1.1 is # 7365 1.1 is # NORMs(in range) can be stored out by a simple "fmov.s" 7366 1.1 is # Unnormalized inputs can come through this point. 7367 1.1 is # 7368 1.1 is fout_sgl_exg: 7369 1.1 is fmovm.x SRC(%a0),&0x80 # fetch fop from stack 7370 1.1 is 7371 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 7372 1.1 is fmov.l &0x0,%fpsr # clear FPSR 7373 1.1 is 7374 1.1 is fmov.s %fp0,%d0 # store does convert and round 7375 1.1 is 7376 1.1 is fmov.l &0x0,%fpcr # clear FPCR 7377 1.1 is fmov.l %fpsr,%d1 # save FPSR 7378 1.1 is 7379 1.1 is or.w %d1,2+USER_FPSR(%a6) # set possible inex2/ainex 7380 1.1 is 7381 1.1 is fout_sgl_exg_write: 7382 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 7383 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 7384 1.1 is beq.b fout_sgl_exg_write_dn # must save to integer regfile 7385 1.1 is 7386 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 7387 1.1 is bsr.l _dmem_write_long # write long 7388 1.1 is 7389 1.1 is tst.l %d1 # did dstore fail? 7390 1.1 is bne.l facc_out_l # yes 7391 1.1 is 7392 1.1 is rts 7393 1.1 is 7394 1.1 is fout_sgl_exg_write_dn: 7395 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 7396 1.1 is andi.w &0x7,%d1 7397 1.1 is bsr.l store_dreg_l 7398 1.1 is rts 7399 1.1 is 7400 1.1 is # 7401 1.1 is # here, we know that the operand would UNFL if moved out to single prec, 7402 1.1 is # so, denorm and round and then use generic store single routine to 7403 1.1 is # write the value to memory. 7404 1.1 is # 7405 1.1 is fout_sgl_unfl: 7406 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL 7407 1.1 is 7408 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 7409 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 7410 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 7411 1.1 is mov.l %a0,-(%sp) 7412 1.1 is 7413 1.1 is clr.l %d0 # pass: S.F. = 0 7414 1.1 is 7415 1.1 is cmpi.b STAG(%a6),&DENORM # fetch src optype tag 7416 1.1 is bne.b fout_sgl_unfl_cont # let DENORMs fall through 7417 1.1 is 7418 1.1 is lea FP_SCR0(%a6),%a0 7419 1.1 is bsr.l norm # normalize the DENORM 7420 1.1 is 7421 1.1 is fout_sgl_unfl_cont: 7422 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand 7423 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 7424 1.1 is bsr.l unf_res # calc default underflow result 7425 1.1 is 7426 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to fop 7427 1.1 is bsr.l dst_sgl # convert to single prec 7428 1.1 is 7429 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 7430 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 7431 1.1 is beq.b fout_sgl_unfl_dn # must save to integer regfile 7432 1.1 is 7433 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 7434 1.1 is bsr.l _dmem_write_long # write long 7435 1.1 is 7436 1.1 is tst.l %d1 # did dstore fail? 7437 1.1 is bne.l facc_out_l # yes 7438 1.1 is 7439 1.1 is bra.b fout_sgl_unfl_chkexc 7440 1.1 is 7441 1.1 is fout_sgl_unfl_dn: 7442 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 7443 1.1 is andi.w &0x7,%d1 7444 1.1 is bsr.l store_dreg_l 7445 1.1 is 7446 1.1 is fout_sgl_unfl_chkexc: 7447 1.1 is mov.b FPCR_ENABLE(%a6),%d1 7448 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled? 7449 1.1 is bne.w fout_sd_exc_unfl # yes 7450 1.1 is addq.l &0x4,%sp 7451 1.1 is rts 7452 1.1 is 7453 1.1 is # 7454 1.1 is # it's definitely an overflow so call ovf_res to get the correct answer 7455 1.1 is # 7456 1.1 is fout_sgl_ovfl: 7457 1.1 is tst.b 3+SRC_HI(%a0) # is result inexact? 7458 1.1 is bne.b fout_sgl_ovfl_inex2 7459 1.1 is tst.l SRC_LO(%a0) # is result inexact? 7460 1.1 is bne.b fout_sgl_ovfl_inex2 7461 1.1 is ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex 7462 1.1 is bra.b fout_sgl_ovfl_cont 7463 1.1 is fout_sgl_ovfl_inex2: 7464 1.1 is ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2 7465 1.1 is 7466 1.1 is fout_sgl_ovfl_cont: 7467 1.1 is mov.l %a0,-(%sp) 7468 1.1 is 7469 1.1 is # call ovf_res() w/ sgl prec and the correct rnd mode to create the default 7470 1.1 is # overflow result. DON'T save the returned ccodes from ovf_res() since 7471 1.1 is # fmove out doesn't alter them. 7472 1.1 is tst.b SRC_EX(%a0) # is operand negative? 7473 1.1 is smi %d1 # set if so 7474 1.1 is mov.l L_SCR3(%a6),%d0 # pass: sgl prec,rnd mode 7475 1.1 is bsr.l ovf_res # calc OVFL result 7476 1.1 is fmovm.x (%a0),&0x80 # load default overflow result 7477 1.1 is fmov.s %fp0,%d0 # store to single 7478 1.1 is 7479 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract dst mode 7480 1.1 is andi.b &0x38,%d1 # is mode == 0? (Dreg dst) 7481 1.1 is beq.b fout_sgl_ovfl_dn # must save to integer regfile 7482 1.1 is 7483 1.1 is mov.l EXC_EA(%a6),%a0 # stacked <ea> is correct 7484 1.1 is bsr.l _dmem_write_long # write long 7485 1.1 is 7486 1.1 is tst.l %d1 # did dstore fail? 7487 1.1 is bne.l facc_out_l # yes 7488 1.1 is 7489 1.1 is bra.b fout_sgl_ovfl_chkexc 7490 1.1 is 7491 1.1 is fout_sgl_ovfl_dn: 7492 1.1 is mov.b 1+EXC_OPWORD(%a6),%d1 # extract Dn 7493 1.1 is andi.w &0x7,%d1 7494 1.1 is bsr.l store_dreg_l 7495 1.1 is 7496 1.1 is fout_sgl_ovfl_chkexc: 7497 1.1 is mov.b FPCR_ENABLE(%a6),%d1 7498 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled? 7499 1.1 is bne.w fout_sd_exc_ovfl # yes 7500 1.1 is addq.l &0x4,%sp 7501 1.1 is rts 7502 1.1 is 7503 1.1 is # 7504 1.1 is # move out MAY overflow: 7505 1.1 is # (1) force the exp to 0x3fff 7506 1.1 is # (2) do a move w/ appropriate rnd mode 7507 1.1 is # (3) if exp still equals zero, then insert original exponent 7508 1.1 is # for the correct result. 7509 1.1 is # if exp now equals one, then it overflowed so call ovf_res. 7510 1.1 is # 7511 1.1 is fout_sgl_may_ovfl: 7512 1.1 is mov.w SRC_EX(%a0),%d1 # fetch current sign 7513 1.1 is andi.w &0x8000,%d1 # keep it,clear exp 7514 1.1 is ori.w &0x3fff,%d1 # insert exp = 0 7515 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp 7516 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man) 7517 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man) 7518 1.1 is 7519 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 7520 1.1 is 7521 1.1 is fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded 7522 1.1 is fmov.l &0x0,%fpcr # clear FPCR 7523 1.1 is 7524 1.1 is fabs.x %fp0 # need absolute value 7525 1.1 is fcmp.b %fp0,&0x2 # did exponent increase? 7526 1.1 is fblt.w fout_sgl_exg # no; go finish NORM 7527 1.1 is bra.w fout_sgl_ovfl # yes; go handle overflow 7528 1.1 is 7529 1.1 is ################ 7530 1.1 is 7531 1.1 is fout_sd_exc_unfl: 7532 1.1 is mov.l (%sp)+,%a0 7533 1.1 is 7534 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 7535 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 7536 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 7537 1.1 is 7538 1.1 is cmpi.b STAG(%a6),&DENORM # was src a DENORM? 7539 1.1 is bne.b fout_sd_exc_cont # no 7540 1.1 is 7541 1.1 is lea FP_SCR0(%a6),%a0 7542 1.1 is bsr.l norm 7543 1.1 is neg.l %d0 7544 1.1 is andi.w &0x7fff,%d0 7545 1.1 is bfins %d0,FP_SCR0_EX(%a6){&1:&15} 7546 1.1 is bra.b fout_sd_exc_cont 7547 1.1 is 7548 1.1 is fout_sd_exc: 7549 1.1 is fout_sd_exc_ovfl: 7550 1.1 is mov.l (%sp)+,%a0 # restore a0 7551 1.1 is 7552 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 7553 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 7554 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 7555 1.1 is 7556 1.1 is fout_sd_exc_cont: 7557 1.1 is bclr &0x7,FP_SCR0_EX(%a6) # clear sign bit 7558 1.1 is sne.b 2+FP_SCR0_EX(%a6) # set internal sign bit 7559 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to DENORM 7560 1.1 is 7561 1.1 is mov.b 3+L_SCR3(%a6),%d1 7562 1.1 is lsr.b &0x4,%d1 7563 1.1 is andi.w &0x0c,%d1 7564 1.1 is swap %d1 7565 1.1 is mov.b 3+L_SCR3(%a6),%d1 7566 1.1 is lsr.b &0x4,%d1 7567 1.1 is andi.w &0x03,%d1 7568 1.1 is clr.l %d0 # pass: zero g,r,s 7569 1.1 is bsr.l _round # round the DENORM 7570 1.1 is 7571 1.1 is tst.b 2+FP_SCR0_EX(%a6) # is EXOP negative? 7572 1.1 is beq.b fout_sd_exc_done # no 7573 1.1 is bset &0x7,FP_SCR0_EX(%a6) # yes 7574 1.1 is 7575 1.1 is fout_sd_exc_done: 7576 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 7577 1.1 is rts 7578 1.1 is 7579 1.1 is ################################################################# 7580 1.1 is # fmove.d out ################################################### 7581 1.1 is ################################################################# 7582 1.1 is fout_dbl: 7583 1.1 is andi.b &0x30,%d0 # clear rnd prec 7584 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec 7585 1.1 is mov.l %d0,L_SCR3(%a6) # save rnd prec,mode on stack 7586 1.1 is 7587 1.1 is # 7588 1.1 is # operand is a normalized number. first, we check to see if the move out 7589 1.1 is # would cause either an underflow or overflow. these cases are handled 7590 1.1 is # separately. otherwise, set the FPCR to the proper rounding mode and 7591 1.1 is # execute the move. 7592 1.1 is # 7593 1.1 is mov.w SRC_EX(%a0),%d0 # extract exponent 7594 1.1 is andi.w &0x7fff,%d0 # strip sign 7595 1.1 is 7596 1.1 is cmpi.w %d0,&DBL_HI # will operand overflow? 7597 1.1 is bgt.w fout_dbl_ovfl # yes; go handle OVFL 7598 1.1 is beq.w fout_dbl_may_ovfl # maybe; go handle possible OVFL 7599 1.1 is cmpi.w %d0,&DBL_LO # will operand underflow? 7600 1.1 is blt.w fout_dbl_unfl # yes; go handle underflow 7601 1.1 is 7602 1.1 is # 7603 1.1 is # NORMs(in range) can be stored out by a simple "fmov.d" 7604 1.1 is # Unnormalized inputs can come through this point. 7605 1.1 is # 7606 1.1 is fout_dbl_exg: 7607 1.1 is fmovm.x SRC(%a0),&0x80 # fetch fop from stack 7608 1.1 is 7609 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 7610 1.1 is fmov.l &0x0,%fpsr # clear FPSR 7611 1.1 is 7612 1.1 is fmov.d %fp0,L_SCR1(%a6) # store does convert and round 7613 1.1 is 7614 1.1 is fmov.l &0x0,%fpcr # clear FPCR 7615 1.1 is fmov.l %fpsr,%d0 # save FPSR 7616 1.1 is 7617 1.1 is or.w %d0,2+USER_FPSR(%a6) # set possible inex2/ainex 7618 1.1 is 7619 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr 7620 1.1 is lea L_SCR1(%a6),%a0 # pass: src addr 7621 1.1 is movq.l &0x8,%d0 # pass: opsize is 8 bytes 7622 1.1 is bsr.l _dmem_write # store dbl fop to memory 7623 1.1 is 7624 1.1 is tst.l %d1 # did dstore fail? 7625 1.1 is bne.l facc_out_d # yes 7626 1.1 is 7627 1.1 is rts # no; so we're finished 7628 1.1 is 7629 1.1 is # 7630 1.1 is # here, we know that the operand would UNFL if moved out to double prec, 7631 1.1 is # so, denorm and round and then use generic store double routine to 7632 1.1 is # write the value to memory. 7633 1.1 is # 7634 1.1 is fout_dbl_unfl: 7635 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set UNFL 7636 1.1 is 7637 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 7638 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 7639 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 7640 1.1 is mov.l %a0,-(%sp) 7641 1.1 is 7642 1.1 is clr.l %d0 # pass: S.F. = 0 7643 1.1 is 7644 1.1 is cmpi.b STAG(%a6),&DENORM # fetch src optype tag 7645 1.1 is bne.b fout_dbl_unfl_cont # let DENORMs fall through 7646 1.1 is 7647 1.1 is lea FP_SCR0(%a6),%a0 7648 1.1 is bsr.l norm # normalize the DENORM 7649 1.1 is 7650 1.1 is fout_dbl_unfl_cont: 7651 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand 7652 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 7653 1.1 is bsr.l unf_res # calc default underflow result 7654 1.1 is 7655 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to fop 7656 1.1 is bsr.l dst_dbl # convert to single prec 7657 1.1 is mov.l %d0,L_SCR1(%a6) 7658 1.1 is mov.l %d1,L_SCR2(%a6) 7659 1.1 is 7660 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr 7661 1.1 is lea L_SCR1(%a6),%a0 # pass: src addr 7662 1.1 is movq.l &0x8,%d0 # pass: opsize is 8 bytes 7663 1.1 is bsr.l _dmem_write # store dbl fop to memory 7664 1.1 is 7665 1.1 is tst.l %d1 # did dstore fail? 7666 1.1 is bne.l facc_out_d # yes 7667 1.1 is 7668 1.1 is mov.b FPCR_ENABLE(%a6),%d1 7669 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled? 7670 1.1 is bne.w fout_sd_exc_unfl # yes 7671 1.1 is addq.l &0x4,%sp 7672 1.1 is rts 7673 1.1 is 7674 1.1 is # 7675 1.1 is # it's definitely an overflow so call ovf_res to get the correct answer 7676 1.1 is # 7677 1.1 is fout_dbl_ovfl: 7678 1.1 is mov.w 2+SRC_LO(%a0),%d0 7679 1.1 is andi.w &0x7ff,%d0 7680 1.1 is bne.b fout_dbl_ovfl_inex2 7681 1.1 is 7682 1.1 is ori.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex 7683 1.1 is bra.b fout_dbl_ovfl_cont 7684 1.1 is fout_dbl_ovfl_inex2: 7685 1.1 is ori.w &ovfinx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex/inex2 7686 1.1 is 7687 1.1 is fout_dbl_ovfl_cont: 7688 1.1 is mov.l %a0,-(%sp) 7689 1.1 is 7690 1.1 is # call ovf_res() w/ dbl prec and the correct rnd mode to create the default 7691 1.1 is # overflow result. DON'T save the returned ccodes from ovf_res() since 7692 1.1 is # fmove out doesn't alter them. 7693 1.1 is tst.b SRC_EX(%a0) # is operand negative? 7694 1.1 is smi %d1 # set if so 7695 1.1 is mov.l L_SCR3(%a6),%d0 # pass: dbl prec,rnd mode 7696 1.1 is bsr.l ovf_res # calc OVFL result 7697 1.1 is fmovm.x (%a0),&0x80 # load default overflow result 7698 1.1 is fmov.d %fp0,L_SCR1(%a6) # store to double 7699 1.1 is 7700 1.1 is mov.l EXC_EA(%a6),%a1 # pass: dst addr 7701 1.1 is lea L_SCR1(%a6),%a0 # pass: src addr 7702 1.1 is movq.l &0x8,%d0 # pass: opsize is 8 bytes 7703 1.1 is bsr.l _dmem_write # store dbl fop to memory 7704 1.1 is 7705 1.1 is tst.l %d1 # did dstore fail? 7706 1.1 is bne.l facc_out_d # yes 7707 1.1 is 7708 1.1 is mov.b FPCR_ENABLE(%a6),%d1 7709 1.1 is andi.b &0x0a,%d1 # is UNFL or INEX enabled? 7710 1.1 is bne.w fout_sd_exc_ovfl # yes 7711 1.1 is addq.l &0x4,%sp 7712 1.1 is rts 7713 1.1 is 7714 1.1 is # 7715 1.1 is # move out MAY overflow: 7716 1.1 is # (1) force the exp to 0x3fff 7717 1.1 is # (2) do a move w/ appropriate rnd mode 7718 1.1 is # (3) if exp still equals zero, then insert original exponent 7719 1.1 is # for the correct result. 7720 1.1 is # if exp now equals one, then it overflowed so call ovf_res. 7721 1.1 is # 7722 1.1 is fout_dbl_may_ovfl: 7723 1.1 is mov.w SRC_EX(%a0),%d1 # fetch current sign 7724 1.1 is andi.w &0x8000,%d1 # keep it,clear exp 7725 1.1 is ori.w &0x3fff,%d1 # insert exp = 0 7726 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert scaled exp 7727 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) # copy hi(man) 7728 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) # copy lo(man) 7729 1.1 is 7730 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 7731 1.1 is 7732 1.1 is fmov.x FP_SCR0(%a6),%fp0 # force fop to be rounded 7733 1.1 is fmov.l &0x0,%fpcr # clear FPCR 7734 1.1 is 7735 1.1 is fabs.x %fp0 # need absolute value 7736 1.1 is fcmp.b %fp0,&0x2 # did exponent increase? 7737 1.1 is fblt.w fout_dbl_exg # no; go finish NORM 7738 1.1 is bra.w fout_dbl_ovfl # yes; go handle overflow 7739 1.1 is 7740 1.1 is ######################################################################### 7741 1.1 is # XDEF **************************************************************** # 7742 1.1 is # dst_dbl(): create double precision value from extended prec. # 7743 1.1 is # # 7744 1.1 is # XREF **************************************************************** # 7745 1.1 is # None # 7746 1.1 is # # 7747 1.1 is # INPUT *************************************************************** # 7748 1.1 is # a0 = pointer to source operand in extended precision # 7749 1.1 is # # 7750 1.1 is # OUTPUT ************************************************************** # 7751 1.1 is # d0 = hi(double precision result) # 7752 1.1 is # d1 = lo(double precision result) # 7753 1.1 is # # 7754 1.1 is # ALGORITHM *********************************************************** # 7755 1.1 is # # 7756 1.1 is # Changes extended precision to double precision. # 7757 1.1 is # Note: no attempt is made to round the extended value to double. # 7758 1.1 is # dbl_sign = ext_sign # 7759 1.1 is # dbl_exp = ext_exp - $3fff(ext bias) + $7ff(dbl bias) # 7760 1.1 is # get rid of ext integer bit # 7761 1.1 is # dbl_mant = ext_mant{62:12} # 7762 1.1 is # # 7763 1.1 is # --------------- --------------- --------------- # 7764 1.1 is # extended -> |s| exp | |1| ms mant | | ls mant | # 7765 1.1 is # --------------- --------------- --------------- # 7766 1.1 is # 95 64 63 62 32 31 11 0 # 7767 1.1 is # | | # 7768 1.1 is # | | # 7769 1.1 is # | | # 7770 1.1 is # v v # 7771 1.1 is # --------------- --------------- # 7772 1.1 is # double -> |s|exp| mant | | mant | # 7773 1.1 is # --------------- --------------- # 7774 1.1 is # 63 51 32 31 0 # 7775 1.1 is # # 7776 1.1 is ######################################################################### 7777 1.1 is 7778 1.1 is dst_dbl: 7779 1.1 is clr.l %d0 # clear d0 7780 1.1 is mov.w FTEMP_EX(%a0),%d0 # get exponent 7781 1.1 is subi.w &EXT_BIAS,%d0 # subtract extended precision bias 7782 1.1 is addi.w &DBL_BIAS,%d0 # add double precision bias 7783 1.1 is tst.b FTEMP_HI(%a0) # is number a denorm? 7784 1.1 is bmi.b dst_get_dupper # no 7785 1.1 is subq.w &0x1,%d0 # yes; denorm bias = DBL_BIAS - 1 7786 1.1 is dst_get_dupper: 7787 1.1 is swap %d0 # d0 now in upper word 7788 1.1 is lsl.l &0x4,%d0 # d0 in proper place for dbl prec exp 7789 1.1 is tst.b FTEMP_EX(%a0) # test sign 7790 1.1 is bpl.b dst_get_dman # if postive, go process mantissa 7791 1.1 is bset &0x1f,%d0 # if negative, set sign 7792 1.1 is dst_get_dman: 7793 1.1 is mov.l FTEMP_HI(%a0),%d1 # get ms mantissa 7794 1.1 is bfextu %d1{&1:&20},%d1 # get upper 20 bits of ms 7795 1.1 is or.l %d1,%d0 # put these bits in ms word of double 7796 1.1 is mov.l %d0,L_SCR1(%a6) # put the new exp back on the stack 7797 1.1 is mov.l FTEMP_HI(%a0),%d1 # get ms mantissa 7798 1.1 is mov.l &21,%d0 # load shift count 7799 1.1 is lsl.l %d0,%d1 # put lower 11 bits in upper bits 7800 1.1 is mov.l %d1,L_SCR2(%a6) # build lower lword in memory 7801 1.1 is mov.l FTEMP_LO(%a0),%d1 # get ls mantissa 7802 1.1 is bfextu %d1{&0:&21},%d0 # get ls 21 bits of double 7803 1.1 is mov.l L_SCR2(%a6),%d1 7804 1.1 is or.l %d0,%d1 # put them in double result 7805 1.1 is mov.l L_SCR1(%a6),%d0 7806 1.1 is rts 7807 1.1 is 7808 1.1 is ######################################################################### 7809 1.1 is # XDEF **************************************************************** # 7810 1.1 is # dst_sgl(): create single precision value from extended prec # 7811 1.1 is # # 7812 1.1 is # XREF **************************************************************** # 7813 1.1 is # # 7814 1.1 is # INPUT *************************************************************** # 7815 1.1 is # a0 = pointer to source operand in extended precision # 7816 1.1 is # # 7817 1.1 is # OUTPUT ************************************************************** # 7818 1.1 is # d0 = single precision result # 7819 1.1 is # # 7820 1.1 is # ALGORITHM *********************************************************** # 7821 1.1 is # # 7822 1.1 is # Changes extended precision to single precision. # 7823 1.1 is # sgl_sign = ext_sign # 7824 1.1 is # sgl_exp = ext_exp - $3fff(ext bias) + $7f(sgl bias) # 7825 1.1 is # get rid of ext integer bit # 7826 1.1 is # sgl_mant = ext_mant{62:12} # 7827 1.1 is # # 7828 1.1 is # --------------- --------------- --------------- # 7829 1.1 is # extended -> |s| exp | |1| ms mant | | ls mant | # 7830 1.1 is # --------------- --------------- --------------- # 7831 1.1 is # 95 64 63 62 40 32 31 12 0 # 7832 1.1 is # | | # 7833 1.1 is # | | # 7834 1.1 is # | | # 7835 1.1 is # v v # 7836 1.1 is # --------------- # 7837 1.1 is # single -> |s|exp| mant | # 7838 1.1 is # --------------- # 7839 1.1 is # 31 22 0 # 7840 1.1 is # # 7841 1.1 is ######################################################################### 7842 1.1 is 7843 1.1 is dst_sgl: 7844 1.1 is clr.l %d0 7845 1.1 is mov.w FTEMP_EX(%a0),%d0 # get exponent 7846 1.1 is subi.w &EXT_BIAS,%d0 # subtract extended precision bias 7847 1.1 is addi.w &SGL_BIAS,%d0 # add single precision bias 7848 1.1 is tst.b FTEMP_HI(%a0) # is number a denorm? 7849 1.1 is bmi.b dst_get_supper # no 7850 1.1 is subq.w &0x1,%d0 # yes; denorm bias = SGL_BIAS - 1 7851 1.1 is dst_get_supper: 7852 1.1 is swap %d0 # put exp in upper word of d0 7853 1.1 is lsl.l &0x7,%d0 # shift it into single exp bits 7854 1.1 is tst.b FTEMP_EX(%a0) # test sign 7855 1.1 is bpl.b dst_get_sman # if positive, continue 7856 1.1 is bset &0x1f,%d0 # if negative, put in sign first 7857 1.1 is dst_get_sman: 7858 1.1 is mov.l FTEMP_HI(%a0),%d1 # get ms mantissa 7859 1.1 is andi.l &0x7fffff00,%d1 # get upper 23 bits of ms 7860 1.1 is lsr.l &0x8,%d1 # and put them flush right 7861 1.1 is or.l %d1,%d0 # put these bits in ms word of single 7862 1.1 is rts 7863 1.1 is 7864 1.1 is ############################################################################## 7865 1.1 is fout_pack: 7866 1.1 is bsr.l _calc_ea_fout # fetch the <ea> 7867 1.1 is mov.l %a0,-(%sp) 7868 1.1 is 7869 1.1 is mov.b STAG(%a6),%d0 # fetch input type 7870 1.1 is bne.w fout_pack_not_norm # input is not NORM 7871 1.1 is 7872 1.1 is fout_pack_norm: 7873 1.1 is btst &0x4,EXC_CMDREG(%a6) # static or dynamic? 7874 1.1 is beq.b fout_pack_s # static 7875 1.1 is 7876 1.1 is fout_pack_d: 7877 1.1 is mov.b 1+EXC_CMDREG(%a6),%d1 # fetch dynamic reg 7878 1.1 is lsr.b &0x4,%d1 7879 1.1 is andi.w &0x7,%d1 7880 1.1 is 7881 1.1 is bsr.l fetch_dreg # fetch Dn w/ k-factor 7882 1.1 is 7883 1.1 is bra.b fout_pack_type 7884 1.1 is fout_pack_s: 7885 1.1 is mov.b 1+EXC_CMDREG(%a6),%d0 # fetch static field 7886 1.1 is 7887 1.1 is fout_pack_type: 7888 1.1 is bfexts %d0{&25:&7},%d0 # extract k-factor 7889 1.1 is mov.l %d0,-(%sp) 7890 1.1 is 7891 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to input 7892 1.1 is 7893 1.1 is # bindec is currently scrambling FP_SRC for denorm inputs. 7894 1.1 is # we'll have to change this, but for now, tough luck!!! 7895 1.1 is bsr.l bindec # convert xprec to packed 7896 1.1 is 7897 1.1 is # andi.l &0xcfff000f,FP_SCR0(%a6) # clear unused fields 7898 1.1 is andi.l &0xcffff00f,FP_SCR0(%a6) # clear unused fields 7899 1.1 is 7900 1.1 is mov.l (%sp)+,%d0 7901 1.1 is 7902 1.1 is tst.b 3+FP_SCR0_EX(%a6) 7903 1.1 is bne.b fout_pack_set 7904 1.1 is tst.l FP_SCR0_HI(%a6) 7905 1.1 is bne.b fout_pack_set 7906 1.1 is tst.l FP_SCR0_LO(%a6) 7907 1.1 is bne.b fout_pack_set 7908 1.1 is 7909 1.1 is # add the extra condition that only if the k-factor was zero, too, should 7910 1.1 is # we zero the exponent 7911 1.1 is tst.l %d0 7912 1.1 is bne.b fout_pack_set 7913 1.1 is # "mantissa" is all zero which means that the answer is zero. but, the '040 7914 1.1 is # algorithm allows the exponent to be non-zero. the 881/2 do not. therefore, 7915 1.1 is # if the mantissa is zero, I will zero the exponent, too. 7916 1.1 is # the question now is whether the exponents sign bit is allowed to be non-zero 7917 1.1 is # for a zero, also... 7918 1.1 is andi.w &0xf000,FP_SCR0(%a6) 7919 1.1 is 7920 1.1 is fout_pack_set: 7921 1.1 is 7922 1.1 is lea FP_SCR0(%a6),%a0 # pass: src addr 7923 1.1 is 7924 1.1 is fout_pack_write: 7925 1.1 is mov.l (%sp)+,%a1 # pass: dst addr 7926 1.1 is mov.l &0xc,%d0 # pass: opsize is 12 bytes 7927 1.1 is 7928 1.1 is cmpi.b SPCOND_FLG(%a6),&mda7_flg 7929 1.1 is beq.b fout_pack_a7 7930 1.1 is 7931 1.1 is bsr.l _dmem_write # write ext prec number to memory 7932 1.1 is 7933 1.1 is tst.l %d1 # did dstore fail? 7934 1.1 is bne.w fout_ext_err # yes 7935 1.1 is 7936 1.1 is rts 7937 1.1 is 7938 1.1 is # we don't want to do the write if the exception occurred in supervisor mode 7939 1.1 is # so _mem_write2() handles this for us. 7940 1.1 is fout_pack_a7: 7941 1.1 is bsr.l _mem_write2 # write ext prec number to memory 7942 1.1 is 7943 1.1 is tst.l %d1 # did dstore fail? 7944 1.1 is bne.w fout_ext_err # yes 7945 1.1 is 7946 1.1 is rts 7947 1.1 is 7948 1.1 is fout_pack_not_norm: 7949 1.1 is cmpi.b %d0,&DENORM # is it a DENORM? 7950 1.1 is beq.w fout_pack_norm # yes 7951 1.1 is lea FP_SRC(%a6),%a0 7952 1.1 is clr.w 2+FP_SRC_EX(%a6) 7953 1.1 is cmpi.b %d0,&SNAN # is it an SNAN? 7954 1.1 is beq.b fout_pack_snan # yes 7955 1.1 is bra.b fout_pack_write # no 7956 1.1 is 7957 1.1 is fout_pack_snan: 7958 1.1 is ori.w &snaniop2_mask,FPSR_EXCEPT(%a6) # set SNAN/AIOP 7959 1.1 is bset &0x6,FP_SRC_HI(%a6) # set snan bit 7960 1.1 is bra.b fout_pack_write 7961 1.1 is 7962 1.1 is ######################################################################### 7963 1.1 is # XDEF **************************************************************** # 7964 1.1 is # fmul(): emulates the fmul instruction # 7965 1.1 is # fsmul(): emulates the fsmul instruction # 7966 1.1 is # fdmul(): emulates the fdmul instruction # 7967 1.1 is # # 7968 1.1 is # XREF **************************************************************** # 7969 1.1 is # scale_to_zero_src() - scale src exponent to zero # 7970 1.1 is # scale_to_zero_dst() - scale dst exponent to zero # 7971 1.1 is # unf_res() - return default underflow result # 7972 1.1 is # ovf_res() - return default overflow result # 7973 1.1 is # res_qnan() - return QNAN result # 7974 1.1 is # res_snan() - return SNAN result # 7975 1.1 is # # 7976 1.1 is # INPUT *************************************************************** # 7977 1.1 is # a0 = pointer to extended precision source operand # 7978 1.1 is # a1 = pointer to extended precision destination operand # 7979 1.1 is # d0 rnd prec,mode # 7980 1.1 is # # 7981 1.1 is # OUTPUT ************************************************************** # 7982 1.1 is # fp0 = result # 7983 1.1 is # fp1 = EXOP (if exception occurred) # 7984 1.1 is # # 7985 1.1 is # ALGORITHM *********************************************************** # 7986 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 7987 1.1 is # norms/denorms into ext/sgl/dbl precision. # 7988 1.1 is # For norms/denorms, scale the exponents such that a multiply # 7989 1.1 is # instruction won't cause an exception. Use the regular fmul to # 7990 1.1 is # compute a result. Check if the regular operands would have taken # 7991 1.1 is # an exception. If so, return the default overflow/underflow result # 7992 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the # 7993 1.1 is # result operand to the proper exponent. # 7994 1.1 is # # 7995 1.1 is ######################################################################### 7996 1.1 is 7997 1.1 is align 0x10 7998 1.1 is tbl_fmul_ovfl: 7999 1.1 is long 0x3fff - 0x7ffe # ext_max 8000 1.1 is long 0x3fff - 0x407e # sgl_max 8001 1.1 is long 0x3fff - 0x43fe # dbl_max 8002 1.1 is tbl_fmul_unfl: 8003 1.1 is long 0x3fff + 0x0001 # ext_unfl 8004 1.1 is long 0x3fff - 0x3f80 # sgl_unfl 8005 1.1 is long 0x3fff - 0x3c00 # dbl_unfl 8006 1.1 is 8007 1.1 is global fsmul 8008 1.1 is fsmul: 8009 1.1 is andi.b &0x30,%d0 # clear rnd prec 8010 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec 8011 1.1 is bra.b fmul 8012 1.1 is 8013 1.1 is global fdmul 8014 1.1 is fdmul: 8015 1.1 is andi.b &0x30,%d0 8016 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec 8017 1.1 is 8018 1.1 is global fmul 8019 1.1 is fmul: 8020 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 8021 1.1 is 8022 1.1 is clr.w %d1 8023 1.1 is mov.b DTAG(%a6),%d1 8024 1.1 is lsl.b &0x3,%d1 8025 1.1 is or.b STAG(%a6),%d1 # combine src tags 8026 1.1 is bne.w fmul_not_norm # optimize on non-norm input 8027 1.1 is 8028 1.1 is fmul_norm: 8029 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 8030 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 8031 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 8032 1.1 is 8033 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 8034 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 8035 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 8036 1.1 is 8037 1.1 is bsr.l scale_to_zero_src # scale src exponent 8038 1.1 is mov.l %d0,-(%sp) # save scale factor 1 8039 1.1 is 8040 1.1 is bsr.l scale_to_zero_dst # scale dst exponent 8041 1.1 is 8042 1.1 is add.l %d0,(%sp) # SCALE_FACTOR = scale1 + scale2 8043 1.1 is 8044 1.1 is mov.w 2+L_SCR3(%a6),%d1 # fetch precision 8045 1.1 is lsr.b &0x6,%d1 # shift to lo bits 8046 1.1 is mov.l (%sp)+,%d0 # load S.F. 8047 1.1 is cmp.l %d0,(tbl_fmul_ovfl.w,%pc,%d1.w*4) # would result ovfl? 8048 1.1 is beq.w fmul_may_ovfl # result may rnd to overflow 8049 1.1 is blt.w fmul_ovfl # result will overflow 8050 1.1 is 8051 1.1 is cmp.l %d0,(tbl_fmul_unfl.w,%pc,%d1.w*4) # would result unfl? 8052 1.1 is beq.w fmul_may_unfl # result may rnd to no unfl 8053 1.1 is bgt.w fmul_unfl # result will underflow 8054 1.1 is 8055 1.1 is # 8056 1.1 is # NORMAL: 8057 1.1 is # - the result of the multiply operation will neither overflow nor underflow. 8058 1.1 is # - do the multiply to the proper precision and rounding mode. 8059 1.1 is # - scale the result exponent using the scale factor. if both operands were 8060 1.1 is # normalized then we really don't need to go through this scaling. but for now, 8061 1.1 is # this will do. 8062 1.1 is # 8063 1.1 is fmul_normal: 8064 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 8065 1.1 is 8066 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8067 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8068 1.1 is 8069 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply 8070 1.1 is 8071 1.1 is fmov.l %fpsr,%d1 # save status 8072 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8073 1.1 is 8074 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8075 1.1 is 8076 1.1 is fmul_normal_exit: 8077 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 8078 1.1 is mov.l %d2,-(%sp) # save d2 8079 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 8080 1.1 is mov.l %d1,%d2 # make a copy 8081 1.1 is andi.l &0x7fff,%d1 # strip sign 8082 1.1 is andi.w &0x8000,%d2 # keep old sign 8083 1.1 is sub.l %d0,%d1 # add scale factor 8084 1.1 is or.w %d2,%d1 # concat old sign,new exp 8085 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 8086 1.1 is mov.l (%sp)+,%d2 # restore d2 8087 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 8088 1.1 is rts 8089 1.1 is 8090 1.1 is # 8091 1.1 is # OVERFLOW: 8092 1.1 is # - the result of the multiply operation is an overflow. 8093 1.1 is # - do the multiply to the proper precision and rounding mode in order to 8094 1.1 is # set the inexact bits. 8095 1.1 is # - calculate the default result and return it in fp0. 8096 1.1 is # - if overflow or inexact is enabled, we need a multiply result rounded to 8097 1.1 is # extended precision. if the original operation was extended, then we have this 8098 1.1 is # result. if the original operation was single or double, we have to do another 8099 1.1 is # multiply using extended precision and the correct rounding mode. the result 8100 1.1 is # of this operation then has its exponent scaled by -0x6000 to create the 8101 1.1 is # exceptional operand. 8102 1.1 is # 8103 1.1 is fmul_ovfl: 8104 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 8105 1.1 is 8106 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8107 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8108 1.1 is 8109 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply 8110 1.1 is 8111 1.1 is fmov.l %fpsr,%d1 # save status 8112 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8113 1.1 is 8114 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8115 1.1 is 8116 1.1 is # save setting this until now because this is where fmul_may_ovfl may jump in 8117 1.1 is fmul_ovfl_tst: 8118 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 8119 1.1 is 8120 1.1 is mov.b FPCR_ENABLE(%a6),%d1 8121 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 8122 1.1 is bne.b fmul_ovfl_ena # yes 8123 1.1 is 8124 1.1 is # calculate the default result 8125 1.1 is fmul_ovfl_dis: 8126 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 8127 1.1 is sne %d1 # set sign param accordingly 8128 1.1 is mov.l L_SCR3(%a6),%d0 # pass rnd prec,mode 8129 1.1 is bsr.l ovf_res # calculate default result 8130 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 8131 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 8132 1.1 is rts 8133 1.1 is 8134 1.1 is # 8135 1.1 is # OVFL is enabled; Create EXOP: 8136 1.1 is # - if precision is extended, then we have the EXOP. simply bias the exponent 8137 1.1 is # with an extra -0x6000. if the precision is single or double, we need to 8138 1.1 is # calculate a result rounded to extended precision. 8139 1.1 is # 8140 1.1 is fmul_ovfl_ena: 8141 1.1 is mov.l L_SCR3(%a6),%d1 8142 1.1 is andi.b &0xc0,%d1 # test the rnd prec 8143 1.1 is bne.b fmul_ovfl_ena_sd # it's sgl or dbl 8144 1.1 is 8145 1.1 is fmul_ovfl_ena_cont: 8146 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 8147 1.1 is 8148 1.1 is mov.l %d2,-(%sp) # save d2 8149 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 8150 1.1 is mov.w %d1,%d2 # make a copy 8151 1.1 is andi.l &0x7fff,%d1 # strip sign 8152 1.1 is sub.l %d0,%d1 # add scale factor 8153 1.1 is subi.l &0x6000,%d1 # subtract bias 8154 1.1 is andi.w &0x7fff,%d1 # clear sign bit 8155 1.1 is andi.w &0x8000,%d2 # keep old sign 8156 1.1 is or.w %d2,%d1 # concat old sign,new exp 8157 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 8158 1.1 is mov.l (%sp)+,%d2 # restore d2 8159 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 8160 1.1 is bra.b fmul_ovfl_dis 8161 1.1 is 8162 1.1 is fmul_ovfl_ena_sd: 8163 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 8164 1.1 is 8165 1.1 is mov.l L_SCR3(%a6),%d1 8166 1.1 is andi.b &0x30,%d1 # keep rnd mode only 8167 1.1 is fmov.l %d1,%fpcr # set FPCR 8168 1.1 is 8169 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply 8170 1.1 is 8171 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8172 1.1 is bra.b fmul_ovfl_ena_cont 8173 1.1 is 8174 1.1 is # 8175 1.1 is # may OVERFLOW: 8176 1.1 is # - the result of the multiply operation MAY overflow. 8177 1.1 is # - do the multiply to the proper precision and rounding mode in order to 8178 1.1 is # set the inexact bits. 8179 1.1 is # - calculate the default result and return it in fp0. 8180 1.1 is # 8181 1.1 is fmul_may_ovfl: 8182 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 8183 1.1 is 8184 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8185 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8186 1.1 is 8187 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply 8188 1.1 is 8189 1.1 is fmov.l %fpsr,%d1 # save status 8190 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8191 1.1 is 8192 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8193 1.1 is 8194 1.1 is fabs.x %fp0,%fp1 # make a copy of result 8195 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b? 8196 1.1 is fbge.w fmul_ovfl_tst # yes; overflow has occurred 8197 1.1 is 8198 1.1 is # no, it didn't overflow; we have correct result 8199 1.1 is bra.w fmul_normal_exit 8200 1.1 is 8201 1.1 is # 8202 1.1 is # UNDERFLOW: 8203 1.1 is # - the result of the multiply operation is an underflow. 8204 1.1 is # - do the multiply to the proper precision and rounding mode in order to 8205 1.1 is # set the inexact bits. 8206 1.1 is # - calculate the default result and return it in fp0. 8207 1.1 is # - if overflow or inexact is enabled, we need a multiply result rounded to 8208 1.1 is # extended precision. if the original operation was extended, then we have this 8209 1.1 is # result. if the original operation was single or double, we have to do another 8210 1.1 is # multiply using extended precision and the correct rounding mode. the result 8211 1.1 is # of this operation then has its exponent scaled by -0x6000 to create the 8212 1.1 is # exceptional operand. 8213 1.1 is # 8214 1.1 is fmul_unfl: 8215 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 8216 1.1 is 8217 1.1 is # for fun, let's use only extended precision, round to zero. then, let 8218 1.1 is # the unf_res() routine figure out all the rest. 8219 1.1 is # will we get the correct answer. 8220 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 8221 1.1 is 8222 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR 8223 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8224 1.1 is 8225 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply 8226 1.1 is 8227 1.1 is fmov.l %fpsr,%d1 # save status 8228 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8229 1.1 is 8230 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8231 1.1 is 8232 1.1 is mov.b FPCR_ENABLE(%a6),%d1 8233 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 8234 1.1 is bne.b fmul_unfl_ena # yes 8235 1.1 is 8236 1.1 is fmul_unfl_dis: 8237 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 8238 1.1 is 8239 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 8240 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 8241 1.1 is bsr.l unf_res # calculate default result 8242 1.1 is or.b %d0,FPSR_CC(%a6) # unf_res2 may have set 'Z' 8243 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 8244 1.1 is rts 8245 1.1 is 8246 1.1 is # 8247 1.1 is # UNFL is enabled. 8248 1.1 is # 8249 1.1 is fmul_unfl_ena: 8250 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op 8251 1.1 is 8252 1.1 is mov.l L_SCR3(%a6),%d1 8253 1.1 is andi.b &0xc0,%d1 # is precision extended? 8254 1.1 is bne.b fmul_unfl_ena_sd # no, sgl or dbl 8255 1.1 is 8256 1.1 is # if the rnd mode is anything but RZ, then we have to re-do the above 8257 1.3 wiz # multiplication because we used RZ for all. 8258 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8259 1.1 is 8260 1.1 is fmul_unfl_ena_cont: 8261 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8262 1.1 is 8263 1.1 is fmul.x FP_SCR0(%a6),%fp1 # execute multiply 8264 1.1 is 8265 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8266 1.1 is 8267 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 8268 1.1 is mov.l %d2,-(%sp) # save d2 8269 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 8270 1.1 is mov.l %d1,%d2 # make a copy 8271 1.1 is andi.l &0x7fff,%d1 # strip sign 8272 1.1 is andi.w &0x8000,%d2 # keep old sign 8273 1.1 is sub.l %d0,%d1 # add scale factor 8274 1.1 is addi.l &0x6000,%d1 # add bias 8275 1.1 is andi.w &0x7fff,%d1 8276 1.1 is or.w %d2,%d1 # concat old sign,new exp 8277 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 8278 1.1 is mov.l (%sp)+,%d2 # restore d2 8279 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 8280 1.1 is bra.w fmul_unfl_dis 8281 1.1 is 8282 1.1 is fmul_unfl_ena_sd: 8283 1.1 is mov.l L_SCR3(%a6),%d1 8284 1.1 is andi.b &0x30,%d1 # use only rnd mode 8285 1.1 is fmov.l %d1,%fpcr # set FPCR 8286 1.1 is 8287 1.1 is bra.b fmul_unfl_ena_cont 8288 1.1 is 8289 1.1 is # MAY UNDERFLOW: 8290 1.1 is # -use the correct rounding mode and precision. this code favors operations 8291 1.1 is # that do not underflow. 8292 1.1 is fmul_may_unfl: 8293 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 8294 1.1 is 8295 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8296 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8297 1.1 is 8298 1.1 is fmul.x FP_SCR0(%a6),%fp0 # execute multiply 8299 1.1 is 8300 1.1 is fmov.l %fpsr,%d1 # save status 8301 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8302 1.1 is 8303 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8304 1.1 is 8305 1.1 is fabs.x %fp0,%fp1 # make a copy of result 8306 1.1 is fcmp.b %fp1,&0x2 # is |result| > 2.b? 8307 1.1 is fbgt.w fmul_normal_exit # no; no underflow occurred 8308 1.1 is fblt.w fmul_unfl # yes; underflow occurred 8309 1.1 is 8310 1.1 is # 8311 1.1 is # we still don't know if underflow occurred. result is ~ equal to 2. but, 8312 1.1 is # we don't know if the result was an underflow that rounded up to a 2 or 8313 1.1 is # a normalized number that rounded down to a 2. so, redo the entire operation 8314 1.1 is # using RZ as the rounding mode to see what the pre-rounded result is. 8315 1.1 is # this case should be relatively rare. 8316 1.1 is # 8317 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst operand 8318 1.1 is 8319 1.1 is mov.l L_SCR3(%a6),%d1 8320 1.1 is andi.b &0xc0,%d1 # keep rnd prec 8321 1.1 is ori.b &rz_mode*0x10,%d1 # insert RZ 8322 1.1 is 8323 1.1 is fmov.l %d1,%fpcr # set FPCR 8324 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8325 1.1 is 8326 1.1 is fmul.x FP_SCR0(%a6),%fp1 # execute multiply 8327 1.1 is 8328 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8329 1.1 is fabs.x %fp1 # make absolute value 8330 1.1 is fcmp.b %fp1,&0x2 # is |result| < 2.b? 8331 1.1 is fbge.w fmul_normal_exit # no; no underflow occurred 8332 1.1 is bra.w fmul_unfl # yes, underflow occurred 8333 1.1 is 8334 1.1 is ################################################################################ 8335 1.1 is 8336 1.1 is # 8337 1.1 is # Multiply: inputs are not both normalized; what are they? 8338 1.1 is # 8339 1.1 is fmul_not_norm: 8340 1.1 is mov.w (tbl_fmul_op.b,%pc,%d1.w*2),%d1 8341 1.1 is jmp (tbl_fmul_op.b,%pc,%d1.w) 8342 1.1 is 8343 1.1 is swbeg &48 8344 1.1 is tbl_fmul_op: 8345 1.1 is short fmul_norm - tbl_fmul_op # NORM x NORM 8346 1.1 is short fmul_zero - tbl_fmul_op # NORM x ZERO 8347 1.1 is short fmul_inf_src - tbl_fmul_op # NORM x INF 8348 1.1 is short fmul_res_qnan - tbl_fmul_op # NORM x QNAN 8349 1.1 is short fmul_norm - tbl_fmul_op # NORM x DENORM 8350 1.1 is short fmul_res_snan - tbl_fmul_op # NORM x SNAN 8351 1.1 is short tbl_fmul_op - tbl_fmul_op # 8352 1.1 is short tbl_fmul_op - tbl_fmul_op # 8353 1.1 is 8354 1.1 is short fmul_zero - tbl_fmul_op # ZERO x NORM 8355 1.1 is short fmul_zero - tbl_fmul_op # ZERO x ZERO 8356 1.1 is short fmul_res_operr - tbl_fmul_op # ZERO x INF 8357 1.1 is short fmul_res_qnan - tbl_fmul_op # ZERO x QNAN 8358 1.1 is short fmul_zero - tbl_fmul_op # ZERO x DENORM 8359 1.1 is short fmul_res_snan - tbl_fmul_op # ZERO x SNAN 8360 1.1 is short tbl_fmul_op - tbl_fmul_op # 8361 1.1 is short tbl_fmul_op - tbl_fmul_op # 8362 1.1 is 8363 1.1 is short fmul_inf_dst - tbl_fmul_op # INF x NORM 8364 1.1 is short fmul_res_operr - tbl_fmul_op # INF x ZERO 8365 1.1 is short fmul_inf_dst - tbl_fmul_op # INF x INF 8366 1.1 is short fmul_res_qnan - tbl_fmul_op # INF x QNAN 8367 1.1 is short fmul_inf_dst - tbl_fmul_op # INF x DENORM 8368 1.1 is short fmul_res_snan - tbl_fmul_op # INF x SNAN 8369 1.1 is short tbl_fmul_op - tbl_fmul_op # 8370 1.1 is short tbl_fmul_op - tbl_fmul_op # 8371 1.1 is 8372 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x NORM 8373 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x ZERO 8374 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x INF 8375 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x QNAN 8376 1.1 is short fmul_res_qnan - tbl_fmul_op # QNAN x DENORM 8377 1.1 is short fmul_res_snan - tbl_fmul_op # QNAN x SNAN 8378 1.1 is short tbl_fmul_op - tbl_fmul_op # 8379 1.1 is short tbl_fmul_op - tbl_fmul_op # 8380 1.1 is 8381 1.1 is short fmul_norm - tbl_fmul_op # NORM x NORM 8382 1.1 is short fmul_zero - tbl_fmul_op # NORM x ZERO 8383 1.1 is short fmul_inf_src - tbl_fmul_op # NORM x INF 8384 1.1 is short fmul_res_qnan - tbl_fmul_op # NORM x QNAN 8385 1.1 is short fmul_norm - tbl_fmul_op # NORM x DENORM 8386 1.1 is short fmul_res_snan - tbl_fmul_op # NORM x SNAN 8387 1.1 is short tbl_fmul_op - tbl_fmul_op # 8388 1.1 is short tbl_fmul_op - tbl_fmul_op # 8389 1.1 is 8390 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x NORM 8391 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x ZERO 8392 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x INF 8393 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x QNAN 8394 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x DENORM 8395 1.1 is short fmul_res_snan - tbl_fmul_op # SNAN x SNAN 8396 1.1 is short tbl_fmul_op - tbl_fmul_op # 8397 1.1 is short tbl_fmul_op - tbl_fmul_op # 8398 1.1 is 8399 1.1 is fmul_res_operr: 8400 1.1 is bra.l res_operr 8401 1.1 is fmul_res_snan: 8402 1.1 is bra.l res_snan 8403 1.1 is fmul_res_qnan: 8404 1.1 is bra.l res_qnan 8405 1.1 is 8406 1.1 is # 8407 1.1 is # Multiply: (Zero x Zero) || (Zero x norm) || (Zero x denorm) 8408 1.1 is # 8409 1.1 is global fmul_zero # global for fsglmul 8410 1.1 is fmul_zero: 8411 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs 8412 1.1 is mov.b DST_EX(%a1),%d1 8413 1.1 is eor.b %d0,%d1 8414 1.1 is bpl.b fmul_zero_p # result ZERO is pos. 8415 1.1 is fmul_zero_n: 8416 1.1 is fmov.s &0x80000000,%fp0 # load -ZERO 8417 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N 8418 1.1 is rts 8419 1.1 is fmul_zero_p: 8420 1.1 is fmov.s &0x00000000,%fp0 # load +ZERO 8421 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z 8422 1.1 is rts 8423 1.1 is 8424 1.1 is # 8425 1.1 is # Multiply: (inf x inf) || (inf x norm) || (inf x denorm) 8426 1.1 is # 8427 1.1 is # Note: The j-bit for an infinity is a don't-care. However, to be 8428 1.1 is # strictly compatible w/ the 68881/882, we make sure to return an 8429 1.1 is # INF w/ the j-bit set if the input INF j-bit was set. Destination 8430 1.1 is # INFs take priority. 8431 1.1 is # 8432 1.1 is global fmul_inf_dst # global for fsglmul 8433 1.1 is fmul_inf_dst: 8434 1.1 is fmovm.x DST(%a1),&0x80 # return INF result in fp0 8435 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs 8436 1.1 is mov.b DST_EX(%a1),%d1 8437 1.1 is eor.b %d0,%d1 8438 1.1 is bpl.b fmul_inf_dst_p # result INF is pos. 8439 1.1 is fmul_inf_dst_n: 8440 1.1 is fabs.x %fp0 # clear result sign 8441 1.1 is fneg.x %fp0 # set result sign 8442 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N 8443 1.1 is rts 8444 1.1 is fmul_inf_dst_p: 8445 1.1 is fabs.x %fp0 # clear result sign 8446 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF 8447 1.1 is rts 8448 1.1 is 8449 1.1 is global fmul_inf_src # global for fsglmul 8450 1.1 is fmul_inf_src: 8451 1.1 is fmovm.x SRC(%a0),&0x80 # return INF result in fp0 8452 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs 8453 1.1 is mov.b DST_EX(%a1),%d1 8454 1.1 is eor.b %d0,%d1 8455 1.1 is bpl.b fmul_inf_dst_p # result INF is pos. 8456 1.1 is bra.b fmul_inf_dst_n 8457 1.1 is 8458 1.1 is ######################################################################### 8459 1.1 is # XDEF **************************************************************** # 8460 1.1 is # fin(): emulates the fmove instruction # 8461 1.1 is # fsin(): emulates the fsmove instruction # 8462 1.1 is # fdin(): emulates the fdmove instruction # 8463 1.1 is # # 8464 1.1 is # XREF **************************************************************** # 8465 1.1 is # norm() - normalize mantissa for EXOP on denorm # 8466 1.1 is # scale_to_zero_src() - scale src exponent to zero # 8467 1.1 is # ovf_res() - return default overflow result # 8468 1.1 is # unf_res() - return default underflow result # 8469 1.1 is # res_qnan_1op() - return QNAN result # 8470 1.1 is # res_snan_1op() - return SNAN result # 8471 1.1 is # # 8472 1.1 is # INPUT *************************************************************** # 8473 1.1 is # a0 = pointer to extended precision source operand # 8474 1.1 is # d0 = round prec/mode # 8475 1.1 is # # 8476 1.1 is # OUTPUT ************************************************************** # 8477 1.1 is # fp0 = result # 8478 1.1 is # fp1 = EXOP (if exception occurred) # 8479 1.1 is # # 8480 1.1 is # ALGORITHM *********************************************************** # 8481 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 8482 1.1 is # norms into extended, single, and double precision. # 8483 1.1 is # Norms can be emulated w/ a regular fmove instruction. For # 8484 1.1 is # sgl/dbl, must scale exponent and perform an "fmove". Check to see # 8485 1.1 is # if the result would have overflowed/underflowed. If so, use unf_res() # 8486 1.1 is # or ovf_res() to return the default result. Also return EXOP if # 8487 1.1 is # exception is enabled. If no exception, return the default result. # 8488 1.1 is # Unnorms don't pass through here. # 8489 1.1 is # # 8490 1.1 is ######################################################################### 8491 1.1 is 8492 1.1 is global fsin 8493 1.1 is fsin: 8494 1.1 is andi.b &0x30,%d0 # clear rnd prec 8495 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision 8496 1.1 is bra.b fin 8497 1.1 is 8498 1.1 is global fdin 8499 1.1 is fdin: 8500 1.1 is andi.b &0x30,%d0 # clear rnd prec 8501 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl precision 8502 1.1 is 8503 1.1 is global fin 8504 1.1 is fin: 8505 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 8506 1.1 is 8507 1.1 is mov.b STAG(%a6),%d1 # fetch src optype tag 8508 1.1 is bne.w fin_not_norm # optimize on non-norm input 8509 1.1 is 8510 1.1 is # 8511 1.1 is # FP MOVE IN: NORMs and DENORMs ONLY! 8512 1.1 is # 8513 1.1 is fin_norm: 8514 1.1 is andi.b &0xc0,%d0 # is precision extended? 8515 1.1 is bne.w fin_not_ext # no, so go handle dbl or sgl 8516 1.1 is 8517 1.1 is # 8518 1.1 is # precision selected is extended. so...we cannot get an underflow 8519 1.1 is # or overflow because of rounding to the correct precision. so... 8520 1.1 is # skip the scaling and unscaling... 8521 1.1 is # 8522 1.1 is tst.b SRC_EX(%a0) # is the operand negative? 8523 1.1 is bpl.b fin_norm_done # no 8524 1.1 is bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit 8525 1.1 is fin_norm_done: 8526 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0 8527 1.1 is rts 8528 1.1 is 8529 1.1 is # 8530 1.1 is # for an extended precision DENORM, the UNFL exception bit is set 8531 1.1 is # the accrued bit is NOT set in this instance(no inexactness!) 8532 1.1 is # 8533 1.1 is fin_denorm: 8534 1.1 is andi.b &0xc0,%d0 # is precision extended? 8535 1.1 is bne.w fin_not_ext # no, so go handle dbl or sgl 8536 1.1 is 8537 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 8538 1.1 is tst.b SRC_EX(%a0) # is the operand negative? 8539 1.1 is bpl.b fin_denorm_done # no 8540 1.1 is bset &neg_bit,FPSR_CC(%a6) # yes, so set 'N' ccode bit 8541 1.1 is fin_denorm_done: 8542 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0 8543 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled? 8544 1.1 is bne.b fin_denorm_unfl_ena # yes 8545 1.1 is rts 8546 1.1 is 8547 1.1 is # 8548 1.1 is # the input is an extended DENORM and underflow is enabled in the FPCR. 8549 1.1 is # normalize the mantissa and add the bias of 0x6000 to the resulting negative 8550 1.1 is # exponent and insert back into the operand. 8551 1.1 is # 8552 1.1 is fin_denorm_unfl_ena: 8553 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 8554 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 8555 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 8556 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand 8557 1.1 is bsr.l norm # normalize result 8558 1.1 is neg.w %d0 # new exponent = -(shft val) 8559 1.1 is addi.w &0x6000,%d0 # add new bias to exponent 8560 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp 8561 1.1 is andi.w &0x8000,%d1 # keep old sign 8562 1.1 is andi.w &0x7fff,%d0 # clear sign position 8563 1.1 is or.w %d1,%d0 # concat new exo,old sign 8564 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent 8565 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 8566 1.1 is rts 8567 1.1 is 8568 1.1 is # 8569 1.1 is # operand is to be rounded to single or double precision 8570 1.1 is # 8571 1.1 is fin_not_ext: 8572 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 8573 1.1 is bne.b fin_dbl 8574 1.1 is 8575 1.1 is # 8576 1.1 is # operand is to be rounded to single precision 8577 1.1 is # 8578 1.1 is fin_sgl: 8579 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 8580 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 8581 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 8582 1.1 is bsr.l scale_to_zero_src # calculate scale factor 8583 1.1 is 8584 1.1 is cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow? 8585 1.1 is bge.w fin_sd_unfl # yes; go handle underflow 8586 1.1 is cmpi.l %d0,&0x3fff-0x407e # will move in overflow? 8587 1.1 is beq.w fin_sd_may_ovfl # maybe; go check 8588 1.1 is blt.w fin_sd_ovfl # yes; go handle overflow 8589 1.1 is 8590 1.1 is # 8591 1.1 is # operand will NOT overflow or underflow when moved into the fp reg file 8592 1.1 is # 8593 1.1 is fin_sd_normal: 8594 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8595 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8596 1.1 is 8597 1.1 is fmov.x FP_SCR0(%a6),%fp0 # perform move 8598 1.1 is 8599 1.1 is fmov.l %fpsr,%d1 # save FPSR 8600 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8601 1.1 is 8602 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8603 1.1 is 8604 1.1 is fin_sd_normal_exit: 8605 1.1 is mov.l %d2,-(%sp) # save d2 8606 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 8607 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 8608 1.1 is mov.w %d1,%d2 # make a copy 8609 1.1 is andi.l &0x7fff,%d1 # strip sign 8610 1.1 is sub.l %d0,%d1 # add scale factor 8611 1.1 is andi.w &0x8000,%d2 # keep old sign 8612 1.1 is or.w %d1,%d2 # concat old sign,new exponent 8613 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 8614 1.1 is mov.l (%sp)+,%d2 # restore d2 8615 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 8616 1.1 is rts 8617 1.1 is 8618 1.1 is # 8619 1.1 is # operand is to be rounded to double precision 8620 1.1 is # 8621 1.1 is fin_dbl: 8622 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 8623 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 8624 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 8625 1.1 is bsr.l scale_to_zero_src # calculate scale factor 8626 1.1 is 8627 1.1 is cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow? 8628 1.1 is bge.w fin_sd_unfl # yes; go handle underflow 8629 1.1 is cmpi.l %d0,&0x3fff-0x43fe # will move in overflow? 8630 1.1 is beq.w fin_sd_may_ovfl # maybe; go check 8631 1.1 is blt.w fin_sd_ovfl # yes; go handle overflow 8632 1.1 is bra.w fin_sd_normal # no; ho handle normalized op 8633 1.1 is 8634 1.1 is # 8635 1.1 is # operand WILL underflow when moved in to the fp register file 8636 1.1 is # 8637 1.1 is fin_sd_unfl: 8638 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 8639 1.1 is 8640 1.1 is tst.b FP_SCR0_EX(%a6) # is operand negative? 8641 1.1 is bpl.b fin_sd_unfl_tst 8642 1.1 is bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit 8643 1.1 is 8644 1.1 is # if underflow or inexact is enabled, then go calculate the EXOP first. 8645 1.1 is fin_sd_unfl_tst: 8646 1.1 is mov.b FPCR_ENABLE(%a6),%d1 8647 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 8648 1.1 is bne.b fin_sd_unfl_ena # yes 8649 1.1 is 8650 1.1 is fin_sd_unfl_dis: 8651 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 8652 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 8653 1.1 is bsr.l unf_res # calculate default result 8654 1.1 is or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z' 8655 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 8656 1.1 is rts 8657 1.1 is 8658 1.1 is # 8659 1.1 is # operand will underflow AND underflow or inexact is enabled. 8660 1.1 is # therefore, we must return the result rounded to extended precision. 8661 1.1 is # 8662 1.1 is fin_sd_unfl_ena: 8663 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 8664 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 8665 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 8666 1.1 is 8667 1.1 is mov.l %d2,-(%sp) # save d2 8668 1.1 is mov.w %d1,%d2 # make a copy 8669 1.1 is andi.l &0x7fff,%d1 # strip sign 8670 1.1 is sub.l %d0,%d1 # subtract scale factor 8671 1.1 is andi.w &0x8000,%d2 # extract old sign 8672 1.1 is addi.l &0x6000,%d1 # add new bias 8673 1.1 is andi.w &0x7fff,%d1 8674 1.1 is or.w %d1,%d2 # concat old sign,new exp 8675 1.1 is mov.w %d2,FP_SCR1_EX(%a6) # insert new exponent 8676 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 8677 1.1 is mov.l (%sp)+,%d2 # restore d2 8678 1.1 is bra.b fin_sd_unfl_dis 8679 1.1 is 8680 1.1 is # 8681 1.1 is # operand WILL overflow. 8682 1.1 is # 8683 1.1 is fin_sd_ovfl: 8684 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8685 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8686 1.1 is 8687 1.1 is fmov.x FP_SCR0(%a6),%fp0 # perform move 8688 1.1 is 8689 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8690 1.1 is fmov.l %fpsr,%d1 # save FPSR 8691 1.1 is 8692 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8693 1.1 is 8694 1.1 is fin_sd_ovfl_tst: 8695 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 8696 1.1 is 8697 1.1 is mov.b FPCR_ENABLE(%a6),%d1 8698 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 8699 1.1 is bne.b fin_sd_ovfl_ena # yes 8700 1.1 is 8701 1.1 is # 8702 1.1 is # OVFL is not enabled; therefore, we must create the default result by 8703 1.1 is # calling ovf_res(). 8704 1.1 is # 8705 1.1 is fin_sd_ovfl_dis: 8706 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 8707 1.1 is sne %d1 # set sign param accordingly 8708 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode 8709 1.1 is bsr.l ovf_res # calculate default result 8710 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 8711 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 8712 1.1 is rts 8713 1.1 is 8714 1.1 is # 8715 1.1 is # OVFL is enabled. 8716 1.1 is # the INEX2 bit has already been updated by the round to the correct precision. 8717 1.1 is # now, round to extended(and don't alter the FPSR). 8718 1.1 is # 8719 1.1 is fin_sd_ovfl_ena: 8720 1.1 is mov.l %d2,-(%sp) # save d2 8721 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 8722 1.1 is mov.l %d1,%d2 # make a copy 8723 1.1 is andi.l &0x7fff,%d1 # strip sign 8724 1.1 is andi.w &0x8000,%d2 # keep old sign 8725 1.1 is sub.l %d0,%d1 # add scale factor 8726 1.1 is sub.l &0x6000,%d1 # subtract bias 8727 1.1 is andi.w &0x7fff,%d1 8728 1.1 is or.w %d2,%d1 8729 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 8730 1.1 is mov.l (%sp)+,%d2 # restore d2 8731 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 8732 1.1 is bra.b fin_sd_ovfl_dis 8733 1.1 is 8734 1.1 is # 8735 1.1 is # the move in MAY overflow. so... 8736 1.1 is # 8737 1.1 is fin_sd_may_ovfl: 8738 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8739 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8740 1.1 is 8741 1.1 is fmov.x FP_SCR0(%a6),%fp0 # perform the move 8742 1.1 is 8743 1.1 is fmov.l %fpsr,%d1 # save status 8744 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8745 1.1 is 8746 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8747 1.1 is 8748 1.1 is fabs.x %fp0,%fp1 # make a copy of result 8749 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b? 8750 1.1 is fbge.w fin_sd_ovfl_tst # yes; overflow has occurred 8751 1.1 is 8752 1.1 is # no, it didn't overflow; we have correct result 8753 1.1 is bra.w fin_sd_normal_exit 8754 1.1 is 8755 1.1 is ########################################################################## 8756 1.1 is 8757 1.1 is # 8758 1.1 is # operand is not a NORM: check its optype and branch accordingly 8759 1.1 is # 8760 1.1 is fin_not_norm: 8761 1.1 is cmpi.b %d1,&DENORM # weed out DENORM 8762 1.1 is beq.w fin_denorm 8763 1.1 is cmpi.b %d1,&SNAN # weed out SNANs 8764 1.1 is beq.l res_snan_1op 8765 1.1 is cmpi.b %d1,&QNAN # weed out QNANs 8766 1.1 is beq.l res_qnan_1op 8767 1.1 is 8768 1.1 is # 8769 1.1 is # do the fmove in; at this point, only possible ops are ZERO and INF. 8770 1.1 is # use fmov to determine ccodes. 8771 1.1 is # prec:mode should be zero at this point but it won't affect answer anyways. 8772 1.1 is # 8773 1.1 is fmov.x SRC(%a0),%fp0 # do fmove in 8774 1.1 is fmov.l %fpsr,%d0 # no exceptions possible 8775 1.1 is rol.l &0x8,%d0 # put ccodes in lo byte 8776 1.1 is mov.b %d0,FPSR_CC(%a6) # insert correct ccodes 8777 1.1 is rts 8778 1.1 is 8779 1.1 is ######################################################################### 8780 1.1 is # XDEF **************************************************************** # 8781 1.1 is # fdiv(): emulates the fdiv instruction # 8782 1.1 is # fsdiv(): emulates the fsdiv instruction # 8783 1.1 is # fddiv(): emulates the fddiv instruction # 8784 1.1 is # # 8785 1.1 is # XREF **************************************************************** # 8786 1.1 is # scale_to_zero_src() - scale src exponent to zero # 8787 1.1 is # scale_to_zero_dst() - scale dst exponent to zero # 8788 1.1 is # unf_res() - return default underflow result # 8789 1.1 is # ovf_res() - return default overflow result # 8790 1.1 is # res_qnan() - return QNAN result # 8791 1.1 is # res_snan() - return SNAN result # 8792 1.1 is # # 8793 1.1 is # INPUT *************************************************************** # 8794 1.1 is # a0 = pointer to extended precision source operand # 8795 1.1 is # a1 = pointer to extended precision destination operand # 8796 1.1 is # d0 rnd prec,mode # 8797 1.1 is # # 8798 1.1 is # OUTPUT ************************************************************** # 8799 1.1 is # fp0 = result # 8800 1.1 is # fp1 = EXOP (if exception occurred) # 8801 1.1 is # # 8802 1.1 is # ALGORITHM *********************************************************** # 8803 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 8804 1.1 is # norms/denorms into ext/sgl/dbl precision. # 8805 1.1 is # For norms/denorms, scale the exponents such that a divide # 8806 1.1 is # instruction won't cause an exception. Use the regular fdiv to # 8807 1.1 is # compute a result. Check if the regular operands would have taken # 8808 1.1 is # an exception. If so, return the default overflow/underflow result # 8809 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the # 8810 1.1 is # result operand to the proper exponent. # 8811 1.1 is # # 8812 1.1 is ######################################################################### 8813 1.1 is 8814 1.1 is align 0x10 8815 1.1 is tbl_fdiv_unfl: 8816 1.1 is long 0x3fff - 0x0000 # ext_unfl 8817 1.1 is long 0x3fff - 0x3f81 # sgl_unfl 8818 1.1 is long 0x3fff - 0x3c01 # dbl_unfl 8819 1.1 is 8820 1.1 is tbl_fdiv_ovfl: 8821 1.1 is long 0x3fff - 0x7ffe # ext overflow exponent 8822 1.1 is long 0x3fff - 0x407e # sgl overflow exponent 8823 1.1 is long 0x3fff - 0x43fe # dbl overflow exponent 8824 1.1 is 8825 1.1 is global fsdiv 8826 1.1 is fsdiv: 8827 1.1 is andi.b &0x30,%d0 # clear rnd prec 8828 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec 8829 1.1 is bra.b fdiv 8830 1.1 is 8831 1.1 is global fddiv 8832 1.1 is fddiv: 8833 1.1 is andi.b &0x30,%d0 # clear rnd prec 8834 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec 8835 1.1 is 8836 1.1 is global fdiv 8837 1.1 is fdiv: 8838 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 8839 1.1 is 8840 1.1 is clr.w %d1 8841 1.1 is mov.b DTAG(%a6),%d1 8842 1.1 is lsl.b &0x3,%d1 8843 1.1 is or.b STAG(%a6),%d1 # combine src tags 8844 1.1 is 8845 1.1 is bne.w fdiv_not_norm # optimize on non-norm input 8846 1.1 is 8847 1.1 is # 8848 1.1 is # DIVIDE: NORMs and DENORMs ONLY! 8849 1.1 is # 8850 1.1 is fdiv_norm: 8851 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 8852 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 8853 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 8854 1.1 is 8855 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 8856 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 8857 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 8858 1.1 is 8859 1.1 is bsr.l scale_to_zero_src # scale src exponent 8860 1.1 is mov.l %d0,-(%sp) # save scale factor 1 8861 1.1 is 8862 1.1 is bsr.l scale_to_zero_dst # scale dst exponent 8863 1.1 is 8864 1.1 is neg.l (%sp) # SCALE FACTOR = scale1 - scale2 8865 1.1 is add.l %d0,(%sp) 8866 1.1 is 8867 1.1 is mov.w 2+L_SCR3(%a6),%d1 # fetch precision 8868 1.1 is lsr.b &0x6,%d1 # shift to lo bits 8869 1.1 is mov.l (%sp)+,%d0 # load S.F. 8870 1.1 is cmp.l %d0,(tbl_fdiv_ovfl.b,%pc,%d1.w*4) # will result overflow? 8871 1.1 is ble.w fdiv_may_ovfl # result will overflow 8872 1.1 is 8873 1.1 is cmp.l %d0,(tbl_fdiv_unfl.w,%pc,%d1.w*4) # will result underflow? 8874 1.1 is beq.w fdiv_may_unfl # maybe 8875 1.1 is bgt.w fdiv_unfl # yes; go handle underflow 8876 1.1 is 8877 1.1 is fdiv_normal: 8878 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 8879 1.1 is 8880 1.1 is fmov.l L_SCR3(%a6),%fpcr # save FPCR 8881 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8882 1.1 is 8883 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # perform divide 8884 1.1 is 8885 1.1 is fmov.l %fpsr,%d1 # save FPSR 8886 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8887 1.1 is 8888 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 8889 1.1 is 8890 1.1 is fdiv_normal_exit: 8891 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store result on stack 8892 1.1 is mov.l %d2,-(%sp) # store d2 8893 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 8894 1.1 is mov.l %d1,%d2 # make a copy 8895 1.1 is andi.l &0x7fff,%d1 # strip sign 8896 1.1 is andi.w &0x8000,%d2 # keep old sign 8897 1.1 is sub.l %d0,%d1 # add scale factor 8898 1.1 is or.w %d2,%d1 # concat old sign,new exp 8899 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 8900 1.1 is mov.l (%sp)+,%d2 # restore d2 8901 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 8902 1.1 is rts 8903 1.1 is 8904 1.1 is tbl_fdiv_ovfl2: 8905 1.1 is long 0x7fff 8906 1.1 is long 0x407f 8907 1.1 is long 0x43ff 8908 1.1 is 8909 1.1 is fdiv_no_ovfl: 8910 1.1 is mov.l (%sp)+,%d0 # restore scale factor 8911 1.1 is bra.b fdiv_normal_exit 8912 1.1 is 8913 1.1 is fdiv_may_ovfl: 8914 1.1 is mov.l %d0,-(%sp) # save scale factor 8915 1.1 is 8916 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 8917 1.1 is 8918 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 8919 1.1 is fmov.l &0x0,%fpsr # set FPSR 8920 1.1 is 8921 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide 8922 1.1 is 8923 1.1 is fmov.l %fpsr,%d0 8924 1.1 is fmov.l &0x0,%fpcr 8925 1.1 is 8926 1.1 is or.l %d0,USER_FPSR(%a6) # save INEX,N 8927 1.1 is 8928 1.1 is fmovm.x &0x01,-(%sp) # save result to stack 8929 1.1 is mov.w (%sp),%d0 # fetch new exponent 8930 1.1 is add.l &0xc,%sp # clear result from stack 8931 1.1 is andi.l &0x7fff,%d0 # strip sign 8932 1.1 is sub.l (%sp),%d0 # add scale factor 8933 1.1 is cmp.l %d0,(tbl_fdiv_ovfl2.b,%pc,%d1.w*4) 8934 1.1 is blt.b fdiv_no_ovfl 8935 1.1 is mov.l (%sp)+,%d0 8936 1.1 is 8937 1.1 is fdiv_ovfl_tst: 8938 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 8939 1.1 is 8940 1.1 is mov.b FPCR_ENABLE(%a6),%d1 8941 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 8942 1.1 is bne.b fdiv_ovfl_ena # yes 8943 1.1 is 8944 1.1 is fdiv_ovfl_dis: 8945 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 8946 1.1 is sne %d1 # set sign param accordingly 8947 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd 8948 1.1 is bsr.l ovf_res # calculate default result 8949 1.1 is or.b %d0,FPSR_CC(%a6) # set INF if applicable 8950 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 8951 1.1 is rts 8952 1.1 is 8953 1.1 is fdiv_ovfl_ena: 8954 1.1 is mov.l L_SCR3(%a6),%d1 8955 1.1 is andi.b &0xc0,%d1 # is precision extended? 8956 1.1 is bne.b fdiv_ovfl_ena_sd # no, do sgl or dbl 8957 1.1 is 8958 1.1 is fdiv_ovfl_ena_cont: 8959 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 8960 1.1 is 8961 1.1 is mov.l %d2,-(%sp) # save d2 8962 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 8963 1.1 is mov.w %d1,%d2 # make a copy 8964 1.1 is andi.l &0x7fff,%d1 # strip sign 8965 1.1 is sub.l %d0,%d1 # add scale factor 8966 1.1 is subi.l &0x6000,%d1 # subtract bias 8967 1.1 is andi.w &0x7fff,%d1 # clear sign bit 8968 1.1 is andi.w &0x8000,%d2 # keep old sign 8969 1.1 is or.w %d2,%d1 # concat old sign,new exp 8970 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 8971 1.1 is mov.l (%sp)+,%d2 # restore d2 8972 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 8973 1.1 is bra.b fdiv_ovfl_dis 8974 1.1 is 8975 1.1 is fdiv_ovfl_ena_sd: 8976 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst operand 8977 1.1 is 8978 1.1 is mov.l L_SCR3(%a6),%d1 8979 1.1 is andi.b &0x30,%d1 # keep rnd mode 8980 1.1 is fmov.l %d1,%fpcr # set FPCR 8981 1.1 is 8982 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide 8983 1.1 is 8984 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8985 1.1 is bra.b fdiv_ovfl_ena_cont 8986 1.1 is 8987 1.1 is fdiv_unfl: 8988 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 8989 1.1 is 8990 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 8991 1.1 is 8992 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR 8993 1.1 is fmov.l &0x0,%fpsr # clear FPSR 8994 1.1 is 8995 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide 8996 1.1 is 8997 1.1 is fmov.l %fpsr,%d1 # save status 8998 1.1 is fmov.l &0x0,%fpcr # clear FPCR 8999 1.1 is 9000 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 9001 1.1 is 9002 1.1 is mov.b FPCR_ENABLE(%a6),%d1 9003 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 9004 1.1 is bne.b fdiv_unfl_ena # yes 9005 1.1 is 9006 1.1 is fdiv_unfl_dis: 9007 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 9008 1.1 is 9009 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 9010 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 9011 1.1 is bsr.l unf_res # calculate default result 9012 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' may have been set 9013 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 9014 1.1 is rts 9015 1.1 is 9016 1.1 is # 9017 1.1 is # UNFL is enabled. 9018 1.1 is # 9019 1.1 is fdiv_unfl_ena: 9020 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op 9021 1.1 is 9022 1.1 is mov.l L_SCR3(%a6),%d1 9023 1.1 is andi.b &0xc0,%d1 # is precision extended? 9024 1.1 is bne.b fdiv_unfl_ena_sd # no, sgl or dbl 9025 1.1 is 9026 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 9027 1.1 is 9028 1.1 is fdiv_unfl_ena_cont: 9029 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9030 1.1 is 9031 1.1 is fdiv.x FP_SCR0(%a6),%fp1 # execute divide 9032 1.1 is 9033 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9034 1.1 is 9035 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 9036 1.1 is mov.l %d2,-(%sp) # save d2 9037 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 9038 1.1 is mov.l %d1,%d2 # make a copy 9039 1.1 is andi.l &0x7fff,%d1 # strip sign 9040 1.1 is andi.w &0x8000,%d2 # keep old sign 9041 1.1 is sub.l %d0,%d1 # add scale factoer 9042 1.1 is addi.l &0x6000,%d1 # add bias 9043 1.1 is andi.w &0x7fff,%d1 9044 1.1 is or.w %d2,%d1 # concat old sign,new exp 9045 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exp 9046 1.1 is mov.l (%sp)+,%d2 # restore d2 9047 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 9048 1.1 is bra.w fdiv_unfl_dis 9049 1.1 is 9050 1.1 is fdiv_unfl_ena_sd: 9051 1.1 is mov.l L_SCR3(%a6),%d1 9052 1.1 is andi.b &0x30,%d1 # use only rnd mode 9053 1.1 is fmov.l %d1,%fpcr # set FPCR 9054 1.1 is 9055 1.1 is bra.b fdiv_unfl_ena_cont 9056 1.1 is 9057 1.1 is # 9058 1.1 is # the divide operation MAY underflow: 9059 1.1 is # 9060 1.1 is fdiv_may_unfl: 9061 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 9062 1.1 is 9063 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 9064 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9065 1.1 is 9066 1.1 is fdiv.x FP_SCR0(%a6),%fp0 # execute divide 9067 1.1 is 9068 1.1 is fmov.l %fpsr,%d1 # save status 9069 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9070 1.1 is 9071 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 9072 1.1 is 9073 1.1 is fabs.x %fp0,%fp1 # make a copy of result 9074 1.1 is fcmp.b %fp1,&0x1 # is |result| > 1.b? 9075 1.1 is fbgt.w fdiv_normal_exit # no; no underflow occurred 9076 1.1 is fblt.w fdiv_unfl # yes; underflow occurred 9077 1.1 is 9078 1.1 is # 9079 1.1 is # we still don't know if underflow occurred. result is ~ equal to 1. but, 9080 1.1 is # we don't know if the result was an underflow that rounded up to a 1 9081 1.1 is # or a normalized number that rounded down to a 1. so, redo the entire 9082 1.1 is # operation using RZ as the rounding mode to see what the pre-rounded 9083 1.1 is # result is. this case should be relatively rare. 9084 1.1 is # 9085 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 9086 1.1 is 9087 1.1 is mov.l L_SCR3(%a6),%d1 9088 1.1 is andi.b &0xc0,%d1 # keep rnd prec 9089 1.1 is ori.b &rz_mode*0x10,%d1 # insert RZ 9090 1.1 is 9091 1.1 is fmov.l %d1,%fpcr # set FPCR 9092 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9093 1.1 is 9094 1.1 is fdiv.x FP_SCR0(%a6),%fp1 # execute divide 9095 1.1 is 9096 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9097 1.1 is fabs.x %fp1 # make absolute value 9098 1.1 is fcmp.b %fp1,&0x1 # is |result| < 1.b? 9099 1.1 is fbge.w fdiv_normal_exit # no; no underflow occurred 9100 1.1 is bra.w fdiv_unfl # yes; underflow occurred 9101 1.1 is 9102 1.1 is ############################################################################ 9103 1.1 is 9104 1.1 is # 9105 1.1 is # Divide: inputs are not both normalized; what are they? 9106 1.1 is # 9107 1.1 is fdiv_not_norm: 9108 1.1 is mov.w (tbl_fdiv_op.b,%pc,%d1.w*2),%d1 9109 1.1 is jmp (tbl_fdiv_op.b,%pc,%d1.w*1) 9110 1.1 is 9111 1.1 is swbeg &48 9112 1.1 is tbl_fdiv_op: 9113 1.1 is short fdiv_norm - tbl_fdiv_op # NORM / NORM 9114 1.1 is short fdiv_inf_load - tbl_fdiv_op # NORM / ZERO 9115 1.1 is short fdiv_zero_load - tbl_fdiv_op # NORM / INF 9116 1.1 is short fdiv_res_qnan - tbl_fdiv_op # NORM / QNAN 9117 1.1 is short fdiv_norm - tbl_fdiv_op # NORM / DENORM 9118 1.1 is short fdiv_res_snan - tbl_fdiv_op # NORM / SNAN 9119 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9120 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9121 1.1 is 9122 1.1 is short fdiv_zero_load - tbl_fdiv_op # ZERO / NORM 9123 1.1 is short fdiv_res_operr - tbl_fdiv_op # ZERO / ZERO 9124 1.1 is short fdiv_zero_load - tbl_fdiv_op # ZERO / INF 9125 1.1 is short fdiv_res_qnan - tbl_fdiv_op # ZERO / QNAN 9126 1.1 is short fdiv_zero_load - tbl_fdiv_op # ZERO / DENORM 9127 1.1 is short fdiv_res_snan - tbl_fdiv_op # ZERO / SNAN 9128 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9129 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9130 1.1 is 9131 1.1 is short fdiv_inf_dst - tbl_fdiv_op # INF / NORM 9132 1.1 is short fdiv_inf_dst - tbl_fdiv_op # INF / ZERO 9133 1.1 is short fdiv_res_operr - tbl_fdiv_op # INF / INF 9134 1.1 is short fdiv_res_qnan - tbl_fdiv_op # INF / QNAN 9135 1.1 is short fdiv_inf_dst - tbl_fdiv_op # INF / DENORM 9136 1.1 is short fdiv_res_snan - tbl_fdiv_op # INF / SNAN 9137 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9138 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9139 1.1 is 9140 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / NORM 9141 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / ZERO 9142 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / INF 9143 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / QNAN 9144 1.1 is short fdiv_res_qnan - tbl_fdiv_op # QNAN / DENORM 9145 1.1 is short fdiv_res_snan - tbl_fdiv_op # QNAN / SNAN 9146 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9147 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9148 1.1 is 9149 1.1 is short fdiv_norm - tbl_fdiv_op # DENORM / NORM 9150 1.1 is short fdiv_inf_load - tbl_fdiv_op # DENORM / ZERO 9151 1.1 is short fdiv_zero_load - tbl_fdiv_op # DENORM / INF 9152 1.1 is short fdiv_res_qnan - tbl_fdiv_op # DENORM / QNAN 9153 1.1 is short fdiv_norm - tbl_fdiv_op # DENORM / DENORM 9154 1.1 is short fdiv_res_snan - tbl_fdiv_op # DENORM / SNAN 9155 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9156 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9157 1.1 is 9158 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / NORM 9159 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / ZERO 9160 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / INF 9161 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / QNAN 9162 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / DENORM 9163 1.1 is short fdiv_res_snan - tbl_fdiv_op # SNAN / SNAN 9164 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9165 1.1 is short tbl_fdiv_op - tbl_fdiv_op # 9166 1.1 is 9167 1.1 is fdiv_res_qnan: 9168 1.1 is bra.l res_qnan 9169 1.1 is fdiv_res_snan: 9170 1.1 is bra.l res_snan 9171 1.1 is fdiv_res_operr: 9172 1.1 is bra.l res_operr 9173 1.1 is 9174 1.1 is global fdiv_zero_load # global for fsgldiv 9175 1.1 is fdiv_zero_load: 9176 1.1 is mov.b SRC_EX(%a0),%d0 # result sign is exclusive 9177 1.1 is mov.b DST_EX(%a1),%d1 # or of input signs. 9178 1.1 is eor.b %d0,%d1 9179 1.1 is bpl.b fdiv_zero_load_p # result is positive 9180 1.1 is fmov.s &0x80000000,%fp0 # load a -ZERO 9181 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/N 9182 1.1 is rts 9183 1.1 is fdiv_zero_load_p: 9184 1.1 is fmov.s &0x00000000,%fp0 # load a +ZERO 9185 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z 9186 1.1 is rts 9187 1.1 is 9188 1.1 is # 9189 1.1 is # The destination was In Range and the source was a ZERO. The result, 9190 1.1 is # therefore, is an INF w/ the proper sign. 9191 1.1 is # So, determine the sign and return a new INF (w/ the j-bit cleared). 9192 1.1 is # 9193 1.1 is global fdiv_inf_load # global for fsgldiv 9194 1.1 is fdiv_inf_load: 9195 1.1 is ori.w &dz_mask+adz_mask,2+USER_FPSR(%a6) # no; set DZ/ADZ 9196 1.1 is mov.b SRC_EX(%a0),%d0 # load both signs 9197 1.1 is mov.b DST_EX(%a1),%d1 9198 1.1 is eor.b %d0,%d1 9199 1.1 is bpl.b fdiv_inf_load_p # result is positive 9200 1.1 is fmov.s &0xff800000,%fp0 # make result -INF 9201 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/N 9202 1.1 is rts 9203 1.1 is fdiv_inf_load_p: 9204 1.1 is fmov.s &0x7f800000,%fp0 # make result +INF 9205 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF 9206 1.1 is rts 9207 1.1 is 9208 1.1 is # 9209 1.1 is # The destination was an INF w/ an In Range or ZERO source, the result is 9210 1.1 is # an INF w/ the proper sign. 9211 1.1 is # The 68881/882 returns the destination INF w/ the new sign(if the j-bit of the 9212 1.1 is # dst INF is set, then then j-bit of the result INF is also set). 9213 1.1 is # 9214 1.1 is global fdiv_inf_dst # global for fsgldiv 9215 1.1 is fdiv_inf_dst: 9216 1.1 is mov.b DST_EX(%a1),%d0 # load both signs 9217 1.1 is mov.b SRC_EX(%a0),%d1 9218 1.1 is eor.b %d0,%d1 9219 1.1 is bpl.b fdiv_inf_dst_p # result is positive 9220 1.1 is 9221 1.1 is fmovm.x DST(%a1),&0x80 # return result in fp0 9222 1.1 is fabs.x %fp0 # clear sign bit 9223 1.1 is fneg.x %fp0 # set sign bit 9224 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set INF/NEG 9225 1.1 is rts 9226 1.1 is 9227 1.1 is fdiv_inf_dst_p: 9228 1.1 is fmovm.x DST(%a1),&0x80 # return result in fp0 9229 1.1 is fabs.x %fp0 # return positive INF 9230 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF 9231 1.1 is rts 9232 1.1 is 9233 1.1 is ######################################################################### 9234 1.1 is # XDEF **************************************************************** # 9235 1.1 is # fneg(): emulates the fneg instruction # 9236 1.1 is # fsneg(): emulates the fsneg instruction # 9237 1.1 is # fdneg(): emulates the fdneg instruction # 9238 1.1 is # # 9239 1.1 is # XREF **************************************************************** # 9240 1.1 is # norm() - normalize a denorm to provide EXOP # 9241 1.1 is # scale_to_zero_src() - scale sgl/dbl source exponent # 9242 1.1 is # ovf_res() - return default overflow result # 9243 1.1 is # unf_res() - return default underflow result # 9244 1.1 is # res_qnan_1op() - return QNAN result # 9245 1.1 is # res_snan_1op() - return SNAN result # 9246 1.1 is # # 9247 1.1 is # INPUT *************************************************************** # 9248 1.1 is # a0 = pointer to extended precision source operand # 9249 1.1 is # d0 = rnd prec,mode # 9250 1.1 is # # 9251 1.1 is # OUTPUT ************************************************************** # 9252 1.1 is # fp0 = result # 9253 1.1 is # fp1 = EXOP (if exception occurred) # 9254 1.1 is # # 9255 1.1 is # ALGORITHM *********************************************************** # 9256 1.1 is # Handle NANs, zeroes, and infinities as special cases. Separate # 9257 1.1 is # norms/denorms into ext/sgl/dbl precisions. Extended precision can be # 9258 1.1 is # emulated by simply setting sign bit. Sgl/dbl operands must be scaled # 9259 1.1 is # and an actual fneg performed to see if overflow/underflow would have # 9260 1.1 is # occurred. If so, return default underflow/overflow result. Else, # 9261 1.1 is # scale the result exponent and return result. FPSR gets set based on # 9262 1.1 is # the result value. # 9263 1.1 is # # 9264 1.1 is ######################################################################### 9265 1.1 is 9266 1.1 is global fsneg 9267 1.1 is fsneg: 9268 1.1 is andi.b &0x30,%d0 # clear rnd prec 9269 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision 9270 1.1 is bra.b fneg 9271 1.1 is 9272 1.1 is global fdneg 9273 1.1 is fdneg: 9274 1.1 is andi.b &0x30,%d0 # clear rnd prec 9275 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec 9276 1.1 is 9277 1.1 is global fneg 9278 1.1 is fneg: 9279 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 9280 1.1 is mov.b STAG(%a6),%d1 9281 1.1 is bne.w fneg_not_norm # optimize on non-norm input 9282 1.1 is 9283 1.1 is # 9284 1.1 is # NEGATE SIGN : norms and denorms ONLY! 9285 1.1 is # 9286 1.1 is fneg_norm: 9287 1.1 is andi.b &0xc0,%d0 # is precision extended? 9288 1.1 is bne.w fneg_not_ext # no; go handle sgl or dbl 9289 1.1 is 9290 1.1 is # 9291 1.1 is # precision selected is extended. so...we can not get an underflow 9292 1.1 is # or overflow because of rounding to the correct precision. so... 9293 1.1 is # skip the scaling and unscaling... 9294 1.1 is # 9295 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 9296 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 9297 1.1 is mov.w SRC_EX(%a0),%d0 9298 1.1 is eori.w &0x8000,%d0 # negate sign 9299 1.1 is bpl.b fneg_norm_load # sign is positive 9300 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 9301 1.1 is fneg_norm_load: 9302 1.1 is mov.w %d0,FP_SCR0_EX(%a6) 9303 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 9304 1.1 is rts 9305 1.1 is 9306 1.1 is # 9307 1.1 is # for an extended precision DENORM, the UNFL exception bit is set 9308 1.1 is # the accrued bit is NOT set in this instance(no inexactness!) 9309 1.1 is # 9310 1.1 is fneg_denorm: 9311 1.1 is andi.b &0xc0,%d0 # is precision extended? 9312 1.1 is bne.b fneg_not_ext # no; go handle sgl or dbl 9313 1.1 is 9314 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 9315 1.1 is 9316 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 9317 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 9318 1.1 is mov.w SRC_EX(%a0),%d0 9319 1.1 is eori.w &0x8000,%d0 # negate sign 9320 1.1 is bpl.b fneg_denorm_done # no 9321 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # yes, set 'N' ccode bit 9322 1.1 is fneg_denorm_done: 9323 1.1 is mov.w %d0,FP_SCR0_EX(%a6) 9324 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 9325 1.1 is 9326 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled? 9327 1.1 is bne.b fneg_ext_unfl_ena # yes 9328 1.1 is rts 9329 1.1 is 9330 1.1 is # 9331 1.1 is # the input is an extended DENORM and underflow is enabled in the FPCR. 9332 1.1 is # normalize the mantissa and add the bias of 0x6000 to the resulting negative 9333 1.1 is # exponent and insert back into the operand. 9334 1.1 is # 9335 1.1 is fneg_ext_unfl_ena: 9336 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand 9337 1.1 is bsr.l norm # normalize result 9338 1.1 is neg.w %d0 # new exponent = -(shft val) 9339 1.1 is addi.w &0x6000,%d0 # add new bias to exponent 9340 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp 9341 1.1 is andi.w &0x8000,%d1 # keep old sign 9342 1.1 is andi.w &0x7fff,%d0 # clear sign position 9343 1.1 is or.w %d1,%d0 # concat old sign, new exponent 9344 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent 9345 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 9346 1.1 is rts 9347 1.1 is 9348 1.1 is # 9349 1.1 is # operand is either single or double 9350 1.1 is # 9351 1.1 is fneg_not_ext: 9352 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 9353 1.1 is bne.b fneg_dbl 9354 1.1 is 9355 1.1 is # 9356 1.1 is # operand is to be rounded to single precision 9357 1.1 is # 9358 1.1 is fneg_sgl: 9359 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 9360 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 9361 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 9362 1.1 is bsr.l scale_to_zero_src # calculate scale factor 9363 1.1 is 9364 1.1 is cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow? 9365 1.1 is bge.w fneg_sd_unfl # yes; go handle underflow 9366 1.1 is cmpi.l %d0,&0x3fff-0x407e # will move in overflow? 9367 1.1 is beq.w fneg_sd_may_ovfl # maybe; go check 9368 1.1 is blt.w fneg_sd_ovfl # yes; go handle overflow 9369 1.1 is 9370 1.1 is # 9371 1.1 is # operand will NOT overflow or underflow when moved in to the fp reg file 9372 1.1 is # 9373 1.1 is fneg_sd_normal: 9374 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9375 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 9376 1.1 is 9377 1.1 is fneg.x FP_SCR0(%a6),%fp0 # perform negation 9378 1.1 is 9379 1.1 is fmov.l %fpsr,%d1 # save FPSR 9380 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9381 1.1 is 9382 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 9383 1.1 is 9384 1.1 is fneg_sd_normal_exit: 9385 1.1 is mov.l %d2,-(%sp) # save d2 9386 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 9387 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp 9388 1.1 is mov.w %d1,%d2 # make a copy 9389 1.1 is andi.l &0x7fff,%d1 # strip sign 9390 1.1 is sub.l %d0,%d1 # add scale factor 9391 1.1 is andi.w &0x8000,%d2 # keep old sign 9392 1.1 is or.w %d1,%d2 # concat old sign,new exp 9393 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 9394 1.1 is mov.l (%sp)+,%d2 # restore d2 9395 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 9396 1.1 is rts 9397 1.1 is 9398 1.1 is # 9399 1.1 is # operand is to be rounded to double precision 9400 1.1 is # 9401 1.1 is fneg_dbl: 9402 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 9403 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 9404 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 9405 1.1 is bsr.l scale_to_zero_src # calculate scale factor 9406 1.1 is 9407 1.1 is cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow? 9408 1.1 is bge.b fneg_sd_unfl # yes; go handle underflow 9409 1.1 is cmpi.l %d0,&0x3fff-0x43fe # will move in overflow? 9410 1.1 is beq.w fneg_sd_may_ovfl # maybe; go check 9411 1.1 is blt.w fneg_sd_ovfl # yes; go handle overflow 9412 1.1 is bra.w fneg_sd_normal # no; ho handle normalized op 9413 1.1 is 9414 1.1 is # 9415 1.1 is # operand WILL underflow when moved in to the fp register file 9416 1.1 is # 9417 1.1 is fneg_sd_unfl: 9418 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 9419 1.1 is 9420 1.1 is eori.b &0x80,FP_SCR0_EX(%a6) # negate sign 9421 1.1 is bpl.b fneg_sd_unfl_tst 9422 1.1 is bset &neg_bit,FPSR_CC(%a6) # set 'N' ccode bit 9423 1.1 is 9424 1.1 is # if underflow or inexact is enabled, go calculate EXOP first. 9425 1.1 is fneg_sd_unfl_tst: 9426 1.1 is mov.b FPCR_ENABLE(%a6),%d1 9427 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 9428 1.1 is bne.b fneg_sd_unfl_ena # yes 9429 1.1 is 9430 1.1 is fneg_sd_unfl_dis: 9431 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 9432 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 9433 1.1 is bsr.l unf_res # calculate default result 9434 1.1 is or.b %d0,FPSR_CC(%a6) # unf_res may have set 'Z' 9435 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 9436 1.1 is rts 9437 1.1 is 9438 1.1 is # 9439 1.1 is # operand will underflow AND underflow is enabled. 9440 1.1 is # therefore, we must return the result rounded to extended precision. 9441 1.1 is # 9442 1.1 is fneg_sd_unfl_ena: 9443 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 9444 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 9445 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 9446 1.1 is 9447 1.1 is mov.l %d2,-(%sp) # save d2 9448 1.1 is mov.l %d1,%d2 # make a copy 9449 1.1 is andi.l &0x7fff,%d1 # strip sign 9450 1.1 is andi.w &0x8000,%d2 # keep old sign 9451 1.1 is sub.l %d0,%d1 # subtract scale factor 9452 1.1 is addi.l &0x6000,%d1 # add new bias 9453 1.1 is andi.w &0x7fff,%d1 9454 1.1 is or.w %d2,%d1 # concat new sign,new exp 9455 1.1 is mov.w %d1,FP_SCR1_EX(%a6) # insert new exp 9456 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 9457 1.1 is mov.l (%sp)+,%d2 # restore d2 9458 1.1 is bra.b fneg_sd_unfl_dis 9459 1.1 is 9460 1.1 is # 9461 1.1 is # operand WILL overflow. 9462 1.1 is # 9463 1.1 is fneg_sd_ovfl: 9464 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9465 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 9466 1.1 is 9467 1.1 is fneg.x FP_SCR0(%a6),%fp0 # perform negation 9468 1.1 is 9469 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9470 1.1 is fmov.l %fpsr,%d1 # save FPSR 9471 1.1 is 9472 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 9473 1.1 is 9474 1.1 is fneg_sd_ovfl_tst: 9475 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 9476 1.1 is 9477 1.1 is mov.b FPCR_ENABLE(%a6),%d1 9478 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 9479 1.1 is bne.b fneg_sd_ovfl_ena # yes 9480 1.1 is 9481 1.1 is # 9482 1.1 is # OVFL is not enabled; therefore, we must create the default result by 9483 1.1 is # calling ovf_res(). 9484 1.1 is # 9485 1.1 is fneg_sd_ovfl_dis: 9486 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 9487 1.1 is sne %d1 # set sign param accordingly 9488 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode 9489 1.1 is bsr.l ovf_res # calculate default result 9490 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 9491 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 9492 1.1 is rts 9493 1.1 is 9494 1.1 is # 9495 1.1 is # OVFL is enabled. 9496 1.1 is # the INEX2 bit has already been updated by the round to the correct precision. 9497 1.1 is # now, round to extended(and don't alter the FPSR). 9498 1.1 is # 9499 1.1 is fneg_sd_ovfl_ena: 9500 1.1 is mov.l %d2,-(%sp) # save d2 9501 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 9502 1.1 is mov.l %d1,%d2 # make a copy 9503 1.1 is andi.l &0x7fff,%d1 # strip sign 9504 1.1 is andi.w &0x8000,%d2 # keep old sign 9505 1.1 is sub.l %d0,%d1 # add scale factor 9506 1.1 is subi.l &0x6000,%d1 # subtract bias 9507 1.1 is andi.w &0x7fff,%d1 9508 1.1 is or.w %d2,%d1 # concat sign,exp 9509 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 9510 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 9511 1.1 is mov.l (%sp)+,%d2 # restore d2 9512 1.1 is bra.b fneg_sd_ovfl_dis 9513 1.1 is 9514 1.1 is # 9515 1.1 is # the move in MAY underflow. so... 9516 1.1 is # 9517 1.1 is fneg_sd_may_ovfl: 9518 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9519 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 9520 1.1 is 9521 1.1 is fneg.x FP_SCR0(%a6),%fp0 # perform negation 9522 1.1 is 9523 1.1 is fmov.l %fpsr,%d1 # save status 9524 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9525 1.1 is 9526 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 9527 1.1 is 9528 1.1 is fabs.x %fp0,%fp1 # make a copy of result 9529 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b? 9530 1.1 is fbge.w fneg_sd_ovfl_tst # yes; overflow has occurred 9531 1.1 is 9532 1.1 is # no, it didn't overflow; we have correct result 9533 1.1 is bra.w fneg_sd_normal_exit 9534 1.1 is 9535 1.1 is ########################################################################## 9536 1.1 is 9537 1.1 is # 9538 1.1 is # input is not normalized; what is it? 9539 1.1 is # 9540 1.1 is fneg_not_norm: 9541 1.1 is cmpi.b %d1,&DENORM # weed out DENORM 9542 1.1 is beq.w fneg_denorm 9543 1.1 is cmpi.b %d1,&SNAN # weed out SNAN 9544 1.1 is beq.l res_snan_1op 9545 1.1 is cmpi.b %d1,&QNAN # weed out QNAN 9546 1.1 is beq.l res_qnan_1op 9547 1.1 is 9548 1.1 is # 9549 1.1 is # do the fneg; at this point, only possible ops are ZERO and INF. 9550 1.1 is # use fneg to determine ccodes. 9551 1.1 is # prec:mode should be zero at this point but it won't affect answer anyways. 9552 1.1 is # 9553 1.1 is fneg.x SRC_EX(%a0),%fp0 # do fneg 9554 1.1 is fmov.l %fpsr,%d0 9555 1.1 is rol.l &0x8,%d0 # put ccodes in lo byte 9556 1.1 is mov.b %d0,FPSR_CC(%a6) # insert correct ccodes 9557 1.1 is rts 9558 1.1 is 9559 1.1 is ######################################################################### 9560 1.1 is # XDEF **************************************************************** # 9561 1.1 is # ftst(): emulates the ftest instruction # 9562 1.1 is # # 9563 1.1 is # XREF **************************************************************** # 9564 1.1 is # res{s,q}nan_1op() - set NAN result for monadic instruction # 9565 1.1 is # # 9566 1.1 is # INPUT *************************************************************** # 9567 1.1 is # a0 = pointer to extended precision source operand # 9568 1.1 is # # 9569 1.1 is # OUTPUT ************************************************************** # 9570 1.1 is # none # 9571 1.1 is # # 9572 1.1 is # ALGORITHM *********************************************************** # 9573 1.1 is # Check the source operand tag (STAG) and set the FPCR according # 9574 1.1 is # to the operand type and sign. # 9575 1.1 is # # 9576 1.1 is ######################################################################### 9577 1.1 is 9578 1.1 is global ftst 9579 1.1 is ftst: 9580 1.1 is mov.b STAG(%a6),%d1 9581 1.1 is bne.b ftst_not_norm # optimize on non-norm input 9582 1.1 is 9583 1.1 is # 9584 1.1 is # Norm: 9585 1.1 is # 9586 1.1 is ftst_norm: 9587 1.1 is tst.b SRC_EX(%a0) # is operand negative? 9588 1.1 is bmi.b ftst_norm_m # yes 9589 1.1 is rts 9590 1.1 is ftst_norm_m: 9591 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 9592 1.1 is rts 9593 1.1 is 9594 1.1 is # 9595 1.1 is # input is not normalized; what is it? 9596 1.1 is # 9597 1.1 is ftst_not_norm: 9598 1.1 is cmpi.b %d1,&ZERO # weed out ZERO 9599 1.1 is beq.b ftst_zero 9600 1.1 is cmpi.b %d1,&INF # weed out INF 9601 1.1 is beq.b ftst_inf 9602 1.1 is cmpi.b %d1,&SNAN # weed out SNAN 9603 1.1 is beq.l res_snan_1op 9604 1.1 is cmpi.b %d1,&QNAN # weed out QNAN 9605 1.1 is beq.l res_qnan_1op 9606 1.1 is 9607 1.1 is # 9608 1.1 is # Denorm: 9609 1.1 is # 9610 1.1 is ftst_denorm: 9611 1.1 is tst.b SRC_EX(%a0) # is operand negative? 9612 1.1 is bmi.b ftst_denorm_m # yes 9613 1.1 is rts 9614 1.1 is ftst_denorm_m: 9615 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'N' ccode bit 9616 1.1 is rts 9617 1.1 is 9618 1.1 is # 9619 1.1 is # Infinity: 9620 1.1 is # 9621 1.1 is ftst_inf: 9622 1.1 is tst.b SRC_EX(%a0) # is operand negative? 9623 1.1 is bmi.b ftst_inf_m # yes 9624 1.1 is ftst_inf_p: 9625 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 9626 1.1 is rts 9627 1.1 is ftst_inf_m: 9628 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'I','N' ccode bits 9629 1.1 is rts 9630 1.1 is 9631 1.1 is # 9632 1.1 is # Zero: 9633 1.1 is # 9634 1.1 is ftst_zero: 9635 1.1 is tst.b SRC_EX(%a0) # is operand negative? 9636 1.1 is bmi.b ftst_zero_m # yes 9637 1.1 is ftst_zero_p: 9638 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'N' ccode bit 9639 1.1 is rts 9640 1.1 is ftst_zero_m: 9641 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 9642 1.1 is rts 9643 1.1 is 9644 1.1 is ######################################################################### 9645 1.1 is # XDEF **************************************************************** # 9646 1.1 is # fint(): emulates the fint instruction # 9647 1.1 is # # 9648 1.1 is # XREF **************************************************************** # 9649 1.1 is # res_{s,q}nan_1op() - set NAN result for monadic operation # 9650 1.1 is # # 9651 1.1 is # INPUT *************************************************************** # 9652 1.1 is # a0 = pointer to extended precision source operand # 9653 1.1 is # d0 = round precision/mode # 9654 1.1 is # # 9655 1.1 is # OUTPUT ************************************************************** # 9656 1.1 is # fp0 = result # 9657 1.1 is # # 9658 1.1 is # ALGORITHM *********************************************************** # 9659 1.1 is # Separate according to operand type. Unnorms don't pass through # 9660 1.1 is # here. For norms, load the rounding mode/prec, execute a "fint", then # 9661 1.1 is # store the resulting FPSR bits. # 9662 1.1 is # For denorms, force the j-bit to a one and do the same as for # 9663 1.1 is # norms. Denorms are so low that the answer will either be a zero or a # 9664 1.1 is # one. # 9665 1.1 is # For zeroes/infs/NANs, return the same while setting the FPSR # 9666 1.1 is # as appropriate. # 9667 1.1 is # # 9668 1.1 is ######################################################################### 9669 1.1 is 9670 1.1 is global fint 9671 1.1 is fint: 9672 1.1 is mov.b STAG(%a6),%d1 9673 1.1 is bne.b fint_not_norm # optimize on non-norm input 9674 1.1 is 9675 1.1 is # 9676 1.1 is # Norm: 9677 1.1 is # 9678 1.1 is fint_norm: 9679 1.1 is andi.b &0x30,%d0 # set prec = ext 9680 1.1 is 9681 1.1 is fmov.l %d0,%fpcr # set FPCR 9682 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9683 1.1 is 9684 1.1 is fint.x SRC(%a0),%fp0 # execute fint 9685 1.1 is 9686 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9687 1.1 is fmov.l %fpsr,%d0 # save FPSR 9688 1.1 is or.l %d0,USER_FPSR(%a6) # set exception bits 9689 1.1 is 9690 1.1 is rts 9691 1.1 is 9692 1.1 is # 9693 1.1 is # input is not normalized; what is it? 9694 1.1 is # 9695 1.1 is fint_not_norm: 9696 1.1 is cmpi.b %d1,&ZERO # weed out ZERO 9697 1.1 is beq.b fint_zero 9698 1.1 is cmpi.b %d1,&INF # weed out INF 9699 1.1 is beq.b fint_inf 9700 1.1 is cmpi.b %d1,&DENORM # weed out DENORM 9701 1.1 is beq.b fint_denorm 9702 1.1 is cmpi.b %d1,&SNAN # weed out SNAN 9703 1.1 is beq.l res_snan_1op 9704 1.1 is bra.l res_qnan_1op # weed out QNAN 9705 1.1 is 9706 1.1 is # 9707 1.1 is # Denorm: 9708 1.1 is # 9709 1.1 is # for DENORMs, the result will be either (+/-)ZERO or (+/-)1. 9710 1.1 is # also, the INEX2 and AINEX exception bits will be set. 9711 1.1 is # so, we could either set these manually or force the DENORM 9712 1.1 is # to a very small NORM and ship it to the NORM routine. 9713 1.1 is # I do the latter. 9714 1.1 is # 9715 1.1 is fint_denorm: 9716 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp 9717 1.1 is mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM 9718 1.1 is lea FP_SCR0(%a6),%a0 9719 1.1 is bra.b fint_norm 9720 1.1 is 9721 1.1 is # 9722 1.1 is # Zero: 9723 1.1 is # 9724 1.1 is fint_zero: 9725 1.1 is tst.b SRC_EX(%a0) # is ZERO negative? 9726 1.1 is bmi.b fint_zero_m # yes 9727 1.1 is fint_zero_p: 9728 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO in fp0 9729 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 9730 1.1 is rts 9731 1.1 is fint_zero_m: 9732 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO in fp0 9733 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 9734 1.1 is rts 9735 1.1 is 9736 1.1 is # 9737 1.1 is # Infinity: 9738 1.1 is # 9739 1.1 is fint_inf: 9740 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0 9741 1.1 is tst.b SRC_EX(%a0) # is INF negative? 9742 1.1 is bmi.b fint_inf_m # yes 9743 1.1 is fint_inf_p: 9744 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 9745 1.1 is rts 9746 1.1 is fint_inf_m: 9747 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits 9748 1.1 is rts 9749 1.1 is 9750 1.1 is ######################################################################### 9751 1.1 is # XDEF **************************************************************** # 9752 1.1 is # fintrz(): emulates the fintrz instruction # 9753 1.1 is # # 9754 1.1 is # XREF **************************************************************** # 9755 1.1 is # res_{s,q}nan_1op() - set NAN result for monadic operation # 9756 1.1 is # # 9757 1.1 is # INPUT *************************************************************** # 9758 1.1 is # a0 = pointer to extended precision source operand # 9759 1.1 is # d0 = round precision/mode # 9760 1.1 is # # 9761 1.1 is # OUTPUT ************************************************************** # 9762 1.1 is # fp0 = result # 9763 1.1 is # # 9764 1.1 is # ALGORITHM *********************************************************** # 9765 1.1 is # Separate according to operand type. Unnorms don't pass through # 9766 1.1 is # here. For norms, load the rounding mode/prec, execute a "fintrz", # 9767 1.1 is # then store the resulting FPSR bits. # 9768 1.1 is # For denorms, force the j-bit to a one and do the same as for # 9769 1.1 is # norms. Denorms are so low that the answer will either be a zero or a # 9770 1.1 is # one. # 9771 1.1 is # For zeroes/infs/NANs, return the same while setting the FPSR # 9772 1.1 is # as appropriate. # 9773 1.1 is # # 9774 1.1 is ######################################################################### 9775 1.1 is 9776 1.1 is global fintrz 9777 1.1 is fintrz: 9778 1.1 is mov.b STAG(%a6),%d1 9779 1.1 is bne.b fintrz_not_norm # optimize on non-norm input 9780 1.1 is 9781 1.1 is # 9782 1.1 is # Norm: 9783 1.1 is # 9784 1.1 is fintrz_norm: 9785 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9786 1.1 is 9787 1.1 is fintrz.x SRC(%a0),%fp0 # execute fintrz 9788 1.1 is 9789 1.1 is fmov.l %fpsr,%d0 # save FPSR 9790 1.1 is or.l %d0,USER_FPSR(%a6) # set exception bits 9791 1.1 is 9792 1.1 is rts 9793 1.1 is 9794 1.1 is # 9795 1.1 is # input is not normalized; what is it? 9796 1.1 is # 9797 1.1 is fintrz_not_norm: 9798 1.1 is cmpi.b %d1,&ZERO # weed out ZERO 9799 1.1 is beq.b fintrz_zero 9800 1.1 is cmpi.b %d1,&INF # weed out INF 9801 1.1 is beq.b fintrz_inf 9802 1.1 is cmpi.b %d1,&DENORM # weed out DENORM 9803 1.1 is beq.b fintrz_denorm 9804 1.1 is cmpi.b %d1,&SNAN # weed out SNAN 9805 1.1 is beq.l res_snan_1op 9806 1.1 is bra.l res_qnan_1op # weed out QNAN 9807 1.1 is 9808 1.1 is # 9809 1.1 is # Denorm: 9810 1.1 is # 9811 1.1 is # for DENORMs, the result will be (+/-)ZERO. 9812 1.1 is # also, the INEX2 and AINEX exception bits will be set. 9813 1.1 is # so, we could either set these manually or force the DENORM 9814 1.1 is # to a very small NORM and ship it to the NORM routine. 9815 1.1 is # I do the latter. 9816 1.1 is # 9817 1.1 is fintrz_denorm: 9818 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) # copy sign, zero exp 9819 1.1 is mov.b &0x80,FP_SCR0_HI(%a6) # force DENORM ==> small NORM 9820 1.1 is lea FP_SCR0(%a6),%a0 9821 1.1 is bra.b fintrz_norm 9822 1.1 is 9823 1.1 is # 9824 1.1 is # Zero: 9825 1.1 is # 9826 1.1 is fintrz_zero: 9827 1.1 is tst.b SRC_EX(%a0) # is ZERO negative? 9828 1.1 is bmi.b fintrz_zero_m # yes 9829 1.1 is fintrz_zero_p: 9830 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO in fp0 9831 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 9832 1.1 is rts 9833 1.1 is fintrz_zero_m: 9834 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO in fp0 9835 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 9836 1.1 is rts 9837 1.1 is 9838 1.1 is # 9839 1.1 is # Infinity: 9840 1.1 is # 9841 1.1 is fintrz_inf: 9842 1.1 is fmovm.x SRC(%a0),&0x80 # return result in fp0 9843 1.1 is tst.b SRC_EX(%a0) # is INF negative? 9844 1.1 is bmi.b fintrz_inf_m # yes 9845 1.1 is fintrz_inf_p: 9846 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 9847 1.1 is rts 9848 1.1 is fintrz_inf_m: 9849 1.1 is mov.b &inf_bmask+neg_bmask,FPSR_CC(%a6) # set 'N','I' ccode bits 9850 1.1 is rts 9851 1.1 is 9852 1.1 is ######################################################################### 9853 1.1 is # XDEF **************************************************************** # 9854 1.1 is # fabs(): emulates the fabs instruction # 9855 1.1 is # fsabs(): emulates the fsabs instruction # 9856 1.1 is # fdabs(): emulates the fdabs instruction # 9857 1.1 is # # 9858 1.1 is # XREF **************************************************************** # 9859 1.1 is # norm() - normalize denorm mantissa to provide EXOP # 9860 1.1 is # scale_to_zero_src() - make exponent. = 0; get scale factor # 9861 1.1 is # unf_res() - calculate underflow result # 9862 1.1 is # ovf_res() - calculate overflow result # 9863 1.1 is # res_{s,q}nan_1op() - set NAN result for monadic operation # 9864 1.1 is # # 9865 1.1 is # INPUT *************************************************************** # 9866 1.1 is # a0 = pointer to extended precision source operand # 9867 1.1 is # d0 = rnd precision/mode # 9868 1.1 is # # 9869 1.1 is # OUTPUT ************************************************************** # 9870 1.1 is # fp0 = result # 9871 1.1 is # fp1 = EXOP (if exception occurred) # 9872 1.1 is # # 9873 1.1 is # ALGORITHM *********************************************************** # 9874 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 9875 1.1 is # norms into extended, single, and double precision. # 9876 1.1 is # Simply clear sign for extended precision norm. Ext prec denorm # 9877 1.1 is # gets an EXOP created for it since it's an underflow. # 9878 1.1 is # Double and single precision can overflow and underflow. First, # 9879 1.1 is # scale the operand such that the exponent is zero. Perform an "fabs" # 9880 1.1 is # using the correct rnd mode/prec. Check to see if the original # 9881 1.1 is # exponent would take an exception. If so, use unf_res() or ovf_res() # 9882 1.1 is # to calculate the default result. Also, create the EXOP for the # 9883 1.1 is # exceptional case. If no exception should occur, insert the correct # 9884 1.1 is # result exponent and return. # 9885 1.1 is # Unnorms don't pass through here. # 9886 1.1 is # # 9887 1.1 is ######################################################################### 9888 1.1 is 9889 1.1 is global fsabs 9890 1.1 is fsabs: 9891 1.1 is andi.b &0x30,%d0 # clear rnd prec 9892 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision 9893 1.1 is bra.b fabs 9894 1.1 is 9895 1.1 is global fdabs 9896 1.1 is fdabs: 9897 1.1 is andi.b &0x30,%d0 # clear rnd prec 9898 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl precision 9899 1.1 is 9900 1.1 is global fabs 9901 1.1 is fabs: 9902 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 9903 1.1 is mov.b STAG(%a6),%d1 9904 1.1 is bne.w fabs_not_norm # optimize on non-norm input 9905 1.1 is 9906 1.1 is # 9907 1.1 is # ABSOLUTE VALUE: norms and denorms ONLY! 9908 1.1 is # 9909 1.1 is fabs_norm: 9910 1.1 is andi.b &0xc0,%d0 # is precision extended? 9911 1.1 is bne.b fabs_not_ext # no; go handle sgl or dbl 9912 1.1 is 9913 1.1 is # 9914 1.1 is # precision selected is extended. so...we can not get an underflow 9915 1.1 is # or overflow because of rounding to the correct precision. so... 9916 1.1 is # skip the scaling and unscaling... 9917 1.1 is # 9918 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 9919 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 9920 1.1 is mov.w SRC_EX(%a0),%d1 9921 1.1 is bclr &15,%d1 # force absolute value 9922 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert exponent 9923 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 9924 1.1 is rts 9925 1.1 is 9926 1.1 is # 9927 1.1 is # for an extended precision DENORM, the UNFL exception bit is set 9928 1.1 is # the accrued bit is NOT set in this instance(no inexactness!) 9929 1.1 is # 9930 1.1 is fabs_denorm: 9931 1.1 is andi.b &0xc0,%d0 # is precision extended? 9932 1.1 is bne.b fabs_not_ext # no 9933 1.1 is 9934 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 9935 1.1 is 9936 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 9937 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 9938 1.1 is mov.w SRC_EX(%a0),%d0 9939 1.1 is bclr &15,%d0 # clear sign 9940 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert exponent 9941 1.1 is 9942 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 9943 1.1 is 9944 1.1 is btst &unfl_bit,FPCR_ENABLE(%a6) # is UNFL enabled? 9945 1.1 is bne.b fabs_ext_unfl_ena 9946 1.1 is rts 9947 1.1 is 9948 1.1 is # 9949 1.1 is # the input is an extended DENORM and underflow is enabled in the FPCR. 9950 1.1 is # normalize the mantissa and add the bias of 0x6000 to the resulting negative 9951 1.1 is # exponent and insert back into the operand. 9952 1.1 is # 9953 1.1 is fabs_ext_unfl_ena: 9954 1.1 is lea FP_SCR0(%a6),%a0 # pass: ptr to operand 9955 1.1 is bsr.l norm # normalize result 9956 1.1 is neg.w %d0 # new exponent = -(shft val) 9957 1.1 is addi.w &0x6000,%d0 # add new bias to exponent 9958 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch old sign,exp 9959 1.1 is andi.w &0x8000,%d1 # keep old sign 9960 1.1 is andi.w &0x7fff,%d0 # clear sign position 9961 1.1 is or.w %d1,%d0 # concat old sign, new exponent 9962 1.1 is mov.w %d0,FP_SCR0_EX(%a6) # insert new exponent 9963 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 9964 1.1 is rts 9965 1.1 is 9966 1.1 is # 9967 1.1 is # operand is either single or double 9968 1.1 is # 9969 1.1 is fabs_not_ext: 9970 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 9971 1.1 is bne.b fabs_dbl 9972 1.1 is 9973 1.1 is # 9974 1.1 is # operand is to be rounded to single precision 9975 1.1 is # 9976 1.1 is fabs_sgl: 9977 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 9978 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 9979 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 9980 1.1 is bsr.l scale_to_zero_src # calculate scale factor 9981 1.1 is 9982 1.1 is cmpi.l %d0,&0x3fff-0x3f80 # will move in underflow? 9983 1.1 is bge.w fabs_sd_unfl # yes; go handle underflow 9984 1.1 is cmpi.l %d0,&0x3fff-0x407e # will move in overflow? 9985 1.1 is beq.w fabs_sd_may_ovfl # maybe; go check 9986 1.1 is blt.w fabs_sd_ovfl # yes; go handle overflow 9987 1.1 is 9988 1.1 is # 9989 1.1 is # operand will NOT overflow or underflow when moved in to the fp reg file 9990 1.1 is # 9991 1.1 is fabs_sd_normal: 9992 1.1 is fmov.l &0x0,%fpsr # clear FPSR 9993 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 9994 1.1 is 9995 1.1 is fabs.x FP_SCR0(%a6),%fp0 # perform absolute 9996 1.1 is 9997 1.1 is fmov.l %fpsr,%d1 # save FPSR 9998 1.1 is fmov.l &0x0,%fpcr # clear FPCR 9999 1.1 is 10000 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10001 1.1 is 10002 1.1 is fabs_sd_normal_exit: 10003 1.1 is mov.l %d2,-(%sp) # save d2 10004 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 10005 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp 10006 1.1 is mov.l %d1,%d2 # make a copy 10007 1.1 is andi.l &0x7fff,%d1 # strip sign 10008 1.1 is sub.l %d0,%d1 # add scale factor 10009 1.1 is andi.w &0x8000,%d2 # keep old sign 10010 1.1 is or.w %d1,%d2 # concat old sign,new exp 10011 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 10012 1.1 is mov.l (%sp)+,%d2 # restore d2 10013 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 10014 1.1 is rts 10015 1.1 is 10016 1.1 is # 10017 1.1 is # operand is to be rounded to double precision 10018 1.1 is # 10019 1.1 is fabs_dbl: 10020 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 10021 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 10022 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 10023 1.1 is bsr.l scale_to_zero_src # calculate scale factor 10024 1.1 is 10025 1.1 is cmpi.l %d0,&0x3fff-0x3c00 # will move in underflow? 10026 1.1 is bge.b fabs_sd_unfl # yes; go handle underflow 10027 1.1 is cmpi.l %d0,&0x3fff-0x43fe # will move in overflow? 10028 1.1 is beq.w fabs_sd_may_ovfl # maybe; go check 10029 1.1 is blt.w fabs_sd_ovfl # yes; go handle overflow 10030 1.1 is bra.w fabs_sd_normal # no; ho handle normalized op 10031 1.1 is 10032 1.1 is # 10033 1.1 is # operand WILL underflow when moved in to the fp register file 10034 1.1 is # 10035 1.1 is fabs_sd_unfl: 10036 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 10037 1.1 is 10038 1.1 is bclr &0x7,FP_SCR0_EX(%a6) # force absolute value 10039 1.1 is 10040 1.1 is # if underflow or inexact is enabled, go calculate EXOP first. 10041 1.1 is mov.b FPCR_ENABLE(%a6),%d1 10042 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 10043 1.1 is bne.b fabs_sd_unfl_ena # yes 10044 1.1 is 10045 1.1 is fabs_sd_unfl_dis: 10046 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 10047 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 10048 1.1 is bsr.l unf_res # calculate default result 10049 1.1 is or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode 10050 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 10051 1.1 is rts 10052 1.1 is 10053 1.1 is # 10054 1.1 is # operand will underflow AND underflow is enabled. 10055 1.1 is # therefore, we must return the result rounded to extended precision. 10056 1.1 is # 10057 1.1 is fabs_sd_unfl_ena: 10058 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 10059 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 10060 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 10061 1.1 is 10062 1.1 is mov.l %d2,-(%sp) # save d2 10063 1.1 is mov.l %d1,%d2 # make a copy 10064 1.1 is andi.l &0x7fff,%d1 # strip sign 10065 1.1 is andi.w &0x8000,%d2 # keep old sign 10066 1.1 is sub.l %d0,%d1 # subtract scale factor 10067 1.1 is addi.l &0x6000,%d1 # add new bias 10068 1.1 is andi.w &0x7fff,%d1 10069 1.1 is or.w %d2,%d1 # concat new sign,new exp 10070 1.1 is mov.w %d1,FP_SCR1_EX(%a6) # insert new exp 10071 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 10072 1.1 is mov.l (%sp)+,%d2 # restore d2 10073 1.1 is bra.b fabs_sd_unfl_dis 10074 1.1 is 10075 1.1 is # 10076 1.1 is # operand WILL overflow. 10077 1.1 is # 10078 1.1 is fabs_sd_ovfl: 10079 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10080 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10081 1.1 is 10082 1.1 is fabs.x FP_SCR0(%a6),%fp0 # perform absolute 10083 1.1 is 10084 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10085 1.1 is fmov.l %fpsr,%d1 # save FPSR 10086 1.1 is 10087 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10088 1.1 is 10089 1.1 is fabs_sd_ovfl_tst: 10090 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 10091 1.1 is 10092 1.1 is mov.b FPCR_ENABLE(%a6),%d1 10093 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 10094 1.1 is bne.b fabs_sd_ovfl_ena # yes 10095 1.1 is 10096 1.1 is # 10097 1.1 is # OVFL is not enabled; therefore, we must create the default result by 10098 1.1 is # calling ovf_res(). 10099 1.1 is # 10100 1.1 is fabs_sd_ovfl_dis: 10101 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 10102 1.1 is sne %d1 # set sign param accordingly 10103 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode 10104 1.1 is bsr.l ovf_res # calculate default result 10105 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 10106 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 10107 1.1 is rts 10108 1.1 is 10109 1.1 is # 10110 1.1 is # OVFL is enabled. 10111 1.1 is # the INEX2 bit has already been updated by the round to the correct precision. 10112 1.1 is # now, round to extended(and don't alter the FPSR). 10113 1.1 is # 10114 1.1 is fabs_sd_ovfl_ena: 10115 1.1 is mov.l %d2,-(%sp) # save d2 10116 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 10117 1.1 is mov.l %d1,%d2 # make a copy 10118 1.1 is andi.l &0x7fff,%d1 # strip sign 10119 1.1 is andi.w &0x8000,%d2 # keep old sign 10120 1.1 is sub.l %d0,%d1 # add scale factor 10121 1.1 is subi.l &0x6000,%d1 # subtract bias 10122 1.1 is andi.w &0x7fff,%d1 10123 1.1 is or.w %d2,%d1 # concat sign,exp 10124 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 10125 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 10126 1.1 is mov.l (%sp)+,%d2 # restore d2 10127 1.1 is bra.b fabs_sd_ovfl_dis 10128 1.1 is 10129 1.1 is # 10130 1.1 is # the move in MAY underflow. so... 10131 1.1 is # 10132 1.1 is fabs_sd_may_ovfl: 10133 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10134 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10135 1.1 is 10136 1.1 is fabs.x FP_SCR0(%a6),%fp0 # perform absolute 10137 1.1 is 10138 1.1 is fmov.l %fpsr,%d1 # save status 10139 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10140 1.1 is 10141 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10142 1.1 is 10143 1.1 is fabs.x %fp0,%fp1 # make a copy of result 10144 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b? 10145 1.1 is fbge.w fabs_sd_ovfl_tst # yes; overflow has occurred 10146 1.1 is 10147 1.1 is # no, it didn't overflow; we have correct result 10148 1.1 is bra.w fabs_sd_normal_exit 10149 1.1 is 10150 1.1 is ########################################################################## 10151 1.1 is 10152 1.1 is # 10153 1.1 is # input is not normalized; what is it? 10154 1.1 is # 10155 1.1 is fabs_not_norm: 10156 1.1 is cmpi.b %d1,&DENORM # weed out DENORM 10157 1.1 is beq.w fabs_denorm 10158 1.1 is cmpi.b %d1,&SNAN # weed out SNAN 10159 1.1 is beq.l res_snan_1op 10160 1.1 is cmpi.b %d1,&QNAN # weed out QNAN 10161 1.1 is beq.l res_qnan_1op 10162 1.1 is 10163 1.1 is fabs.x SRC(%a0),%fp0 # force absolute value 10164 1.1 is 10165 1.1 is cmpi.b %d1,&INF # weed out INF 10166 1.1 is beq.b fabs_inf 10167 1.1 is fabs_zero: 10168 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 10169 1.1 is rts 10170 1.1 is fabs_inf: 10171 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 10172 1.1 is rts 10173 1.1 is 10174 1.1 is ######################################################################### 10175 1.1 is # XDEF **************************************************************** # 10176 1.1 is # fcmp(): fp compare op routine # 10177 1.1 is # # 10178 1.1 is # XREF **************************************************************** # 10179 1.1 is # res_qnan() - return QNAN result # 10180 1.1 is # res_snan() - return SNAN result # 10181 1.1 is # # 10182 1.1 is # INPUT *************************************************************** # 10183 1.1 is # a0 = pointer to extended precision source operand # 10184 1.1 is # a1 = pointer to extended precision destination operand # 10185 1.1 is # d0 = round prec/mode # 10186 1.1 is # # 10187 1.1 is # OUTPUT ************************************************************** # 10188 1.1 is # None # 10189 1.1 is # # 10190 1.1 is # ALGORITHM *********************************************************** # 10191 1.1 is # Handle NANs and denorms as special cases. For everything else, # 10192 1.1 is # just use the actual fcmp instruction to produce the correct condition # 10193 1.1 is # codes. # 10194 1.1 is # # 10195 1.1 is ######################################################################### 10196 1.1 is 10197 1.1 is global fcmp 10198 1.1 is fcmp: 10199 1.1 is clr.w %d1 10200 1.1 is mov.b DTAG(%a6),%d1 10201 1.1 is lsl.b &0x3,%d1 10202 1.1 is or.b STAG(%a6),%d1 10203 1.1 is bne.b fcmp_not_norm # optimize on non-norm input 10204 1.1 is 10205 1.1 is # 10206 1.1 is # COMPARE FP OPs : NORMs, ZEROs, INFs, and "corrected" DENORMs 10207 1.1 is # 10208 1.1 is fcmp_norm: 10209 1.1 is fmovm.x DST(%a1),&0x80 # load dst op 10210 1.1 is 10211 1.1 is fcmp.x %fp0,SRC(%a0) # do compare 10212 1.1 is 10213 1.1 is fmov.l %fpsr,%d0 # save FPSR 10214 1.1 is rol.l &0x8,%d0 # extract ccode bits 10215 1.1 is mov.b %d0,FPSR_CC(%a6) # set ccode bits(no exc bits are set) 10216 1.1 is 10217 1.1 is rts 10218 1.1 is 10219 1.1 is # 10220 1.1 is # fcmp: inputs are not both normalized; what are they? 10221 1.1 is # 10222 1.1 is fcmp_not_norm: 10223 1.1 is mov.w (tbl_fcmp_op.b,%pc,%d1.w*2),%d1 10224 1.1 is jmp (tbl_fcmp_op.b,%pc,%d1.w*1) 10225 1.1 is 10226 1.1 is swbeg &48 10227 1.1 is tbl_fcmp_op: 10228 1.1 is short fcmp_norm - tbl_fcmp_op # NORM - NORM 10229 1.1 is short fcmp_norm - tbl_fcmp_op # NORM - ZERO 10230 1.1 is short fcmp_norm - tbl_fcmp_op # NORM - INF 10231 1.1 is short fcmp_res_qnan - tbl_fcmp_op # NORM - QNAN 10232 1.1 is short fcmp_nrm_dnrm - tbl_fcmp_op # NORM - DENORM 10233 1.1 is short fcmp_res_snan - tbl_fcmp_op # NORM - SNAN 10234 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10235 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10236 1.1 is 10237 1.1 is short fcmp_norm - tbl_fcmp_op # ZERO - NORM 10238 1.1 is short fcmp_norm - tbl_fcmp_op # ZERO - ZERO 10239 1.1 is short fcmp_norm - tbl_fcmp_op # ZERO - INF 10240 1.1 is short fcmp_res_qnan - tbl_fcmp_op # ZERO - QNAN 10241 1.1 is short fcmp_dnrm_s - tbl_fcmp_op # ZERO - DENORM 10242 1.1 is short fcmp_res_snan - tbl_fcmp_op # ZERO - SNAN 10243 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10244 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10245 1.1 is 10246 1.1 is short fcmp_norm - tbl_fcmp_op # INF - NORM 10247 1.1 is short fcmp_norm - tbl_fcmp_op # INF - ZERO 10248 1.1 is short fcmp_norm - tbl_fcmp_op # INF - INF 10249 1.1 is short fcmp_res_qnan - tbl_fcmp_op # INF - QNAN 10250 1.1 is short fcmp_dnrm_s - tbl_fcmp_op # INF - DENORM 10251 1.1 is short fcmp_res_snan - tbl_fcmp_op # INF - SNAN 10252 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10253 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10254 1.1 is 10255 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - NORM 10256 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - ZERO 10257 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - INF 10258 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - QNAN 10259 1.1 is short fcmp_res_qnan - tbl_fcmp_op # QNAN - DENORM 10260 1.1 is short fcmp_res_snan - tbl_fcmp_op # QNAN - SNAN 10261 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10262 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10263 1.1 is 10264 1.1 is short fcmp_dnrm_nrm - tbl_fcmp_op # DENORM - NORM 10265 1.1 is short fcmp_dnrm_d - tbl_fcmp_op # DENORM - ZERO 10266 1.1 is short fcmp_dnrm_d - tbl_fcmp_op # DENORM - INF 10267 1.1 is short fcmp_res_qnan - tbl_fcmp_op # DENORM - QNAN 10268 1.1 is short fcmp_dnrm_sd - tbl_fcmp_op # DENORM - DENORM 10269 1.1 is short fcmp_res_snan - tbl_fcmp_op # DENORM - SNAN 10270 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10271 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10272 1.1 is 10273 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - NORM 10274 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - ZERO 10275 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - INF 10276 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - QNAN 10277 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - DENORM 10278 1.1 is short fcmp_res_snan - tbl_fcmp_op # SNAN - SNAN 10279 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10280 1.1 is short tbl_fcmp_op - tbl_fcmp_op # 10281 1.1 is 10282 1.1 is # unlike all other functions for QNAN and SNAN, fcmp does NOT set the 10283 1.1 is # 'N' bit for a negative QNAN or SNAN input so we must squelch it here. 10284 1.1 is fcmp_res_qnan: 10285 1.1 is bsr.l res_qnan 10286 1.1 is andi.b &0xf7,FPSR_CC(%a6) 10287 1.1 is rts 10288 1.1 is fcmp_res_snan: 10289 1.1 is bsr.l res_snan 10290 1.1 is andi.b &0xf7,FPSR_CC(%a6) 10291 1.1 is rts 10292 1.1 is 10293 1.1 is # 10294 1.1 is # DENORMs are a little more difficult. 10295 1.1 is # If you have a 2 DENORMs, then you can just force the j-bit to a one 10296 1.1 is # and use the fcmp_norm routine. 10297 1.1 is # If you have a DENORM and an INF or ZERO, just force the DENORM's j-bit to a one 10298 1.1 is # and use the fcmp_norm routine. 10299 1.1 is # If you have a DENORM and a NORM with opposite signs, then use fcmp_norm, also. 10300 1.1 is # But with a DENORM and a NORM of the same sign, the neg bit is set if the 10301 1.1 is # (1) signs are (+) and the DENORM is the dst or 10302 1.1 is # (2) signs are (-) and the DENORM is the src 10303 1.1 is # 10304 1.1 is 10305 1.1 is fcmp_dnrm_s: 10306 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 10307 1.1 is mov.l SRC_HI(%a0),%d0 10308 1.1 is bset &31,%d0 # DENORM src; make into small norm 10309 1.1 is mov.l %d0,FP_SCR0_HI(%a6) 10310 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 10311 1.1 is lea FP_SCR0(%a6),%a0 10312 1.1 is bra.w fcmp_norm 10313 1.1 is 10314 1.1 is fcmp_dnrm_d: 10315 1.1 is mov.l DST_EX(%a1),FP_SCR0_EX(%a6) 10316 1.1 is mov.l DST_HI(%a1),%d0 10317 1.1 is bset &31,%d0 # DENORM src; make into small norm 10318 1.1 is mov.l %d0,FP_SCR0_HI(%a6) 10319 1.1 is mov.l DST_LO(%a1),FP_SCR0_LO(%a6) 10320 1.1 is lea FP_SCR0(%a6),%a1 10321 1.1 is bra.w fcmp_norm 10322 1.1 is 10323 1.1 is fcmp_dnrm_sd: 10324 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 10325 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 10326 1.1 is mov.l DST_HI(%a1),%d0 10327 1.1 is bset &31,%d0 # DENORM dst; make into small norm 10328 1.1 is mov.l %d0,FP_SCR1_HI(%a6) 10329 1.1 is mov.l SRC_HI(%a0),%d0 10330 1.1 is bset &31,%d0 # DENORM dst; make into small norm 10331 1.1 is mov.l %d0,FP_SCR0_HI(%a6) 10332 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 10333 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 10334 1.1 is lea FP_SCR1(%a6),%a1 10335 1.1 is lea FP_SCR0(%a6),%a0 10336 1.1 is bra.w fcmp_norm 10337 1.1 is 10338 1.1 is fcmp_nrm_dnrm: 10339 1.1 is mov.b SRC_EX(%a0),%d0 # determine if like signs 10340 1.1 is mov.b DST_EX(%a1),%d1 10341 1.1 is eor.b %d0,%d1 10342 1.1 is bmi.w fcmp_dnrm_s 10343 1.1 is 10344 1.1 is # signs are the same, so must determine the answer ourselves. 10345 1.1 is tst.b %d0 # is src op negative? 10346 1.1 is bmi.b fcmp_nrm_dnrm_m # yes 10347 1.1 is rts 10348 1.1 is fcmp_nrm_dnrm_m: 10349 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 10350 1.1 is rts 10351 1.1 is 10352 1.1 is fcmp_dnrm_nrm: 10353 1.1 is mov.b SRC_EX(%a0),%d0 # determine if like signs 10354 1.1 is mov.b DST_EX(%a1),%d1 10355 1.1 is eor.b %d0,%d1 10356 1.1 is bmi.w fcmp_dnrm_d 10357 1.1 is 10358 1.1 is # signs are the same, so must determine the answer ourselves. 10359 1.1 is tst.b %d0 # is src op negative? 10360 1.1 is bpl.b fcmp_dnrm_nrm_m # no 10361 1.1 is rts 10362 1.1 is fcmp_dnrm_nrm_m: 10363 1.1 is mov.b &neg_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 10364 1.1 is rts 10365 1.1 is 10366 1.1 is ######################################################################### 10367 1.1 is # XDEF **************************************************************** # 10368 1.1 is # fsglmul(): emulates the fsglmul instruction # 10369 1.1 is # # 10370 1.1 is # XREF **************************************************************** # 10371 1.1 is # scale_to_zero_src() - scale src exponent to zero # 10372 1.1 is # scale_to_zero_dst() - scale dst exponent to zero # 10373 1.1 is # unf_res4() - return default underflow result for sglop # 10374 1.1 is # ovf_res() - return default overflow result # 10375 1.1 is # res_qnan() - return QNAN result # 10376 1.1 is # res_snan() - return SNAN result # 10377 1.1 is # # 10378 1.1 is # INPUT *************************************************************** # 10379 1.1 is # a0 = pointer to extended precision source operand # 10380 1.1 is # a1 = pointer to extended precision destination operand # 10381 1.1 is # d0 rnd prec,mode # 10382 1.1 is # # 10383 1.1 is # OUTPUT ************************************************************** # 10384 1.1 is # fp0 = result # 10385 1.1 is # fp1 = EXOP (if exception occurred) # 10386 1.1 is # # 10387 1.1 is # ALGORITHM *********************************************************** # 10388 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 10389 1.1 is # norms/denorms into ext/sgl/dbl precision. # 10390 1.1 is # For norms/denorms, scale the exponents such that a multiply # 10391 1.1 is # instruction won't cause an exception. Use the regular fsglmul to # 10392 1.1 is # compute a result. Check if the regular operands would have taken # 10393 1.1 is # an exception. If so, return the default overflow/underflow result # 10394 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the # 10395 1.1 is # result operand to the proper exponent. # 10396 1.1 is # # 10397 1.1 is ######################################################################### 10398 1.1 is 10399 1.1 is global fsglmul 10400 1.1 is fsglmul: 10401 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 10402 1.1 is 10403 1.1 is clr.w %d1 10404 1.1 is mov.b DTAG(%a6),%d1 10405 1.1 is lsl.b &0x3,%d1 10406 1.1 is or.b STAG(%a6),%d1 10407 1.1 is 10408 1.1 is bne.w fsglmul_not_norm # optimize on non-norm input 10409 1.1 is 10410 1.1 is fsglmul_norm: 10411 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 10412 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 10413 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 10414 1.1 is 10415 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 10416 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 10417 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 10418 1.1 is 10419 1.1 is bsr.l scale_to_zero_src # scale exponent 10420 1.1 is mov.l %d0,-(%sp) # save scale factor 1 10421 1.1 is 10422 1.1 is bsr.l scale_to_zero_dst # scale dst exponent 10423 1.1 is 10424 1.1 is add.l (%sp)+,%d0 # SCALE_FACTOR = scale1 + scale2 10425 1.1 is 10426 1.1 is cmpi.l %d0,&0x3fff-0x7ffe # would result ovfl? 10427 1.1 is beq.w fsglmul_may_ovfl # result may rnd to overflow 10428 1.1 is blt.w fsglmul_ovfl # result will overflow 10429 1.1 is 10430 1.1 is cmpi.l %d0,&0x3fff+0x0001 # would result unfl? 10431 1.1 is beq.w fsglmul_may_unfl # result may rnd to no unfl 10432 1.1 is bgt.w fsglmul_unfl # result will underflow 10433 1.1 is 10434 1.1 is fsglmul_normal: 10435 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10436 1.1 is 10437 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10438 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10439 1.1 is 10440 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 10441 1.1 is 10442 1.1 is fmov.l %fpsr,%d1 # save status 10443 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10444 1.1 is 10445 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10446 1.1 is 10447 1.1 is fsglmul_normal_exit: 10448 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 10449 1.1 is mov.l %d2,-(%sp) # save d2 10450 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 10451 1.1 is mov.l %d1,%d2 # make a copy 10452 1.1 is andi.l &0x7fff,%d1 # strip sign 10453 1.1 is andi.w &0x8000,%d2 # keep old sign 10454 1.1 is sub.l %d0,%d1 # add scale factor 10455 1.1 is or.w %d2,%d1 # concat old sign,new exp 10456 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 10457 1.1 is mov.l (%sp)+,%d2 # restore d2 10458 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 10459 1.1 is rts 10460 1.1 is 10461 1.1 is fsglmul_ovfl: 10462 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10463 1.1 is 10464 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10465 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10466 1.1 is 10467 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 10468 1.1 is 10469 1.1 is fmov.l %fpsr,%d1 # save status 10470 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10471 1.1 is 10472 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10473 1.1 is 10474 1.1 is fsglmul_ovfl_tst: 10475 1.1 is 10476 1.1 is # save setting this until now because this is where fsglmul_may_ovfl may jump in 10477 1.1 is or.l &ovfl_inx_mask, USER_FPSR(%a6) # set ovfl/aovfl/ainex 10478 1.1 is 10479 1.1 is mov.b FPCR_ENABLE(%a6),%d1 10480 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 10481 1.1 is bne.b fsglmul_ovfl_ena # yes 10482 1.1 is 10483 1.1 is fsglmul_ovfl_dis: 10484 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 10485 1.1 is sne %d1 # set sign param accordingly 10486 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd 10487 1.1 is andi.b &0x30,%d0 # force prec = ext 10488 1.1 is bsr.l ovf_res # calculate default result 10489 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 10490 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 10491 1.1 is rts 10492 1.1 is 10493 1.1 is fsglmul_ovfl_ena: 10494 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 10495 1.1 is 10496 1.1 is mov.l %d2,-(%sp) # save d2 10497 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 10498 1.1 is mov.l %d1,%d2 # make a copy 10499 1.1 is andi.l &0x7fff,%d1 # strip sign 10500 1.1 is sub.l %d0,%d1 # add scale factor 10501 1.1 is subi.l &0x6000,%d1 # subtract bias 10502 1.1 is andi.w &0x7fff,%d1 10503 1.1 is andi.w &0x8000,%d2 # keep old sign 10504 1.1 is or.w %d2,%d1 # concat old sign,new exp 10505 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 10506 1.1 is mov.l (%sp)+,%d2 # restore d2 10507 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 10508 1.1 is bra.b fsglmul_ovfl_dis 10509 1.1 is 10510 1.1 is fsglmul_may_ovfl: 10511 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10512 1.1 is 10513 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10514 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10515 1.1 is 10516 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 10517 1.1 is 10518 1.1 is fmov.l %fpsr,%d1 # save status 10519 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10520 1.1 is 10521 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10522 1.1 is 10523 1.1 is fabs.x %fp0,%fp1 # make a copy of result 10524 1.1 is fcmp.b %fp1,&0x2 # is |result| >= 2.b? 10525 1.1 is fbge.w fsglmul_ovfl_tst # yes; overflow has occurred 10526 1.1 is 10527 1.1 is # no, it didn't overflow; we have correct result 10528 1.1 is bra.w fsglmul_normal_exit 10529 1.1 is 10530 1.1 is fsglmul_unfl: 10531 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 10532 1.1 is 10533 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10534 1.1 is 10535 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR 10536 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10537 1.1 is 10538 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 10539 1.1 is 10540 1.1 is fmov.l %fpsr,%d1 # save status 10541 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10542 1.1 is 10543 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10544 1.1 is 10545 1.1 is mov.b FPCR_ENABLE(%a6),%d1 10546 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 10547 1.1 is bne.b fsglmul_unfl_ena # yes 10548 1.1 is 10549 1.1 is fsglmul_unfl_dis: 10550 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 10551 1.1 is 10552 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 10553 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 10554 1.1 is bsr.l unf_res4 # calculate default result 10555 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set 10556 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 10557 1.1 is rts 10558 1.1 is 10559 1.1 is # 10560 1.1 is # UNFL is enabled. 10561 1.1 is # 10562 1.1 is fsglmul_unfl_ena: 10563 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op 10564 1.1 is 10565 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10566 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10567 1.1 is 10568 1.1 is fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply 10569 1.1 is 10570 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10571 1.1 is 10572 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 10573 1.1 is mov.l %d2,-(%sp) # save d2 10574 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 10575 1.1 is mov.l %d1,%d2 # make a copy 10576 1.1 is andi.l &0x7fff,%d1 # strip sign 10577 1.1 is andi.w &0x8000,%d2 # keep old sign 10578 1.1 is sub.l %d0,%d1 # add scale factor 10579 1.1 is addi.l &0x6000,%d1 # add bias 10580 1.1 is andi.w &0x7fff,%d1 10581 1.1 is or.w %d2,%d1 # concat old sign,new exp 10582 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 10583 1.1 is mov.l (%sp)+,%d2 # restore d2 10584 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 10585 1.1 is bra.w fsglmul_unfl_dis 10586 1.1 is 10587 1.1 is fsglmul_may_unfl: 10588 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10589 1.1 is 10590 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10591 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10592 1.1 is 10593 1.1 is fsglmul.x FP_SCR0(%a6),%fp0 # execute sgl multiply 10594 1.1 is 10595 1.1 is fmov.l %fpsr,%d1 # save status 10596 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10597 1.1 is 10598 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10599 1.1 is 10600 1.1 is fabs.x %fp0,%fp1 # make a copy of result 10601 1.1 is fcmp.b %fp1,&0x2 # is |result| > 2.b? 10602 1.1 is fbgt.w fsglmul_normal_exit # no; no underflow occurred 10603 1.1 is fblt.w fsglmul_unfl # yes; underflow occurred 10604 1.1 is 10605 1.1 is # 10606 1.1 is # we still don't know if underflow occurred. result is ~ equal to 2. but, 10607 1.1 is # we don't know if the result was an underflow that rounded up to a 2 or 10608 1.1 is # a normalized number that rounded down to a 2. so, redo the entire operation 10609 1.1 is # using RZ as the rounding mode to see what the pre-rounded result is. 10610 1.1 is # this case should be relatively rare. 10611 1.1 is # 10612 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 10613 1.1 is 10614 1.1 is mov.l L_SCR3(%a6),%d1 10615 1.1 is andi.b &0xc0,%d1 # keep rnd prec 10616 1.1 is ori.b &rz_mode*0x10,%d1 # insert RZ 10617 1.1 is 10618 1.1 is fmov.l %d1,%fpcr # set FPCR 10619 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10620 1.1 is 10621 1.1 is fsglmul.x FP_SCR0(%a6),%fp1 # execute sgl multiply 10622 1.1 is 10623 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10624 1.1 is fabs.x %fp1 # make absolute value 10625 1.1 is fcmp.b %fp1,&0x2 # is |result| < 2.b? 10626 1.1 is fbge.w fsglmul_normal_exit # no; no underflow occurred 10627 1.1 is bra.w fsglmul_unfl # yes, underflow occurred 10628 1.1 is 10629 1.1 is ############################################################################## 10630 1.1 is 10631 1.1 is # 10632 1.1 is # Single Precision Multiply: inputs are not both normalized; what are they? 10633 1.1 is # 10634 1.1 is fsglmul_not_norm: 10635 1.1 is mov.w (tbl_fsglmul_op.b,%pc,%d1.w*2),%d1 10636 1.1 is jmp (tbl_fsglmul_op.b,%pc,%d1.w*1) 10637 1.1 is 10638 1.1 is swbeg &48 10639 1.1 is tbl_fsglmul_op: 10640 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x NORM 10641 1.1 is short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO 10642 1.1 is short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF 10643 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN 10644 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM 10645 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN 10646 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10647 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10648 1.1 is 10649 1.1 is short fsglmul_zero - tbl_fsglmul_op # ZERO x NORM 10650 1.1 is short fsglmul_zero - tbl_fsglmul_op # ZERO x ZERO 10651 1.1 is short fsglmul_res_operr - tbl_fsglmul_op # ZERO x INF 10652 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # ZERO x QNAN 10653 1.1 is short fsglmul_zero - tbl_fsglmul_op # ZERO x DENORM 10654 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # ZERO x SNAN 10655 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10656 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10657 1.1 is 10658 1.1 is short fsglmul_inf_dst - tbl_fsglmul_op # INF x NORM 10659 1.1 is short fsglmul_res_operr - tbl_fsglmul_op # INF x ZERO 10660 1.1 is short fsglmul_inf_dst - tbl_fsglmul_op # INF x INF 10661 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # INF x QNAN 10662 1.1 is short fsglmul_inf_dst - tbl_fsglmul_op # INF x DENORM 10663 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # INF x SNAN 10664 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10665 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10666 1.1 is 10667 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x NORM 10668 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x ZERO 10669 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x INF 10670 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x QNAN 10671 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # QNAN x DENORM 10672 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # QNAN x SNAN 10673 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10674 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10675 1.1 is 10676 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x NORM 10677 1.1 is short fsglmul_zero - tbl_fsglmul_op # NORM x ZERO 10678 1.1 is short fsglmul_inf_src - tbl_fsglmul_op # NORM x INF 10679 1.1 is short fsglmul_res_qnan - tbl_fsglmul_op # NORM x QNAN 10680 1.1 is short fsglmul_norm - tbl_fsglmul_op # NORM x DENORM 10681 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # NORM x SNAN 10682 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10683 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10684 1.1 is 10685 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x NORM 10686 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x ZERO 10687 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x INF 10688 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x QNAN 10689 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x DENORM 10690 1.1 is short fsglmul_res_snan - tbl_fsglmul_op # SNAN x SNAN 10691 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10692 1.1 is short tbl_fsglmul_op - tbl_fsglmul_op # 10693 1.1 is 10694 1.1 is fsglmul_res_operr: 10695 1.1 is bra.l res_operr 10696 1.1 is fsglmul_res_snan: 10697 1.1 is bra.l res_snan 10698 1.1 is fsglmul_res_qnan: 10699 1.1 is bra.l res_qnan 10700 1.1 is fsglmul_zero: 10701 1.1 is bra.l fmul_zero 10702 1.1 is fsglmul_inf_src: 10703 1.1 is bra.l fmul_inf_src 10704 1.1 is fsglmul_inf_dst: 10705 1.1 is bra.l fmul_inf_dst 10706 1.1 is 10707 1.1 is ######################################################################### 10708 1.1 is # XDEF **************************************************************** # 10709 1.1 is # fsgldiv(): emulates the fsgldiv instruction # 10710 1.1 is # # 10711 1.1 is # XREF **************************************************************** # 10712 1.1 is # scale_to_zero_src() - scale src exponent to zero # 10713 1.1 is # scale_to_zero_dst() - scale dst exponent to zero # 10714 1.1 is # unf_res4() - return default underflow result for sglop # 10715 1.1 is # ovf_res() - return default overflow result # 10716 1.1 is # res_qnan() - return QNAN result # 10717 1.1 is # res_snan() - return SNAN result # 10718 1.1 is # # 10719 1.1 is # INPUT *************************************************************** # 10720 1.1 is # a0 = pointer to extended precision source operand # 10721 1.1 is # a1 = pointer to extended precision destination operand # 10722 1.1 is # d0 rnd prec,mode # 10723 1.1 is # # 10724 1.1 is # OUTPUT ************************************************************** # 10725 1.1 is # fp0 = result # 10726 1.1 is # fp1 = EXOP (if exception occurred) # 10727 1.1 is # # 10728 1.1 is # ALGORITHM *********************************************************** # 10729 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 10730 1.1 is # norms/denorms into ext/sgl/dbl precision. # 10731 1.1 is # For norms/denorms, scale the exponents such that a divide # 10732 1.1 is # instruction won't cause an exception. Use the regular fsgldiv to # 10733 1.1 is # compute a result. Check if the regular operands would have taken # 10734 1.1 is # an exception. If so, return the default overflow/underflow result # 10735 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the # 10736 1.1 is # result operand to the proper exponent. # 10737 1.1 is # # 10738 1.1 is ######################################################################### 10739 1.1 is 10740 1.1 is global fsgldiv 10741 1.1 is fsgldiv: 10742 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 10743 1.1 is 10744 1.1 is clr.w %d1 10745 1.1 is mov.b DTAG(%a6),%d1 10746 1.1 is lsl.b &0x3,%d1 10747 1.1 is or.b STAG(%a6),%d1 # combine src tags 10748 1.1 is 10749 1.1 is bne.w fsgldiv_not_norm # optimize on non-norm input 10750 1.1 is 10751 1.1 is # 10752 1.1 is # DIVIDE: NORMs and DENORMs ONLY! 10753 1.1 is # 10754 1.1 is fsgldiv_norm: 10755 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 10756 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 10757 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 10758 1.1 is 10759 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 10760 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 10761 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 10762 1.1 is 10763 1.1 is bsr.l scale_to_zero_src # calculate scale factor 1 10764 1.1 is mov.l %d0,-(%sp) # save scale factor 1 10765 1.1 is 10766 1.1 is bsr.l scale_to_zero_dst # calculate scale factor 2 10767 1.1 is 10768 1.1 is neg.l (%sp) # S.F. = scale1 - scale2 10769 1.1 is add.l %d0,(%sp) 10770 1.1 is 10771 1.1 is mov.w 2+L_SCR3(%a6),%d1 # fetch precision,mode 10772 1.1 is lsr.b &0x6,%d1 10773 1.1 is mov.l (%sp)+,%d0 10774 1.1 is cmpi.l %d0,&0x3fff-0x7ffe 10775 1.1 is ble.w fsgldiv_may_ovfl 10776 1.1 is 10777 1.1 is cmpi.l %d0,&0x3fff-0x0000 # will result underflow? 10778 1.1 is beq.w fsgldiv_may_unfl # maybe 10779 1.1 is bgt.w fsgldiv_unfl # yes; go handle underflow 10780 1.1 is 10781 1.1 is fsgldiv_normal: 10782 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10783 1.1 is 10784 1.1 is fmov.l L_SCR3(%a6),%fpcr # save FPCR 10785 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10786 1.1 is 10787 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # perform sgl divide 10788 1.1 is 10789 1.1 is fmov.l %fpsr,%d1 # save FPSR 10790 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10791 1.1 is 10792 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10793 1.1 is 10794 1.1 is fsgldiv_normal_exit: 10795 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store result on stack 10796 1.1 is mov.l %d2,-(%sp) # save d2 10797 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load {sgn,exp} 10798 1.1 is mov.l %d1,%d2 # make a copy 10799 1.1 is andi.l &0x7fff,%d1 # strip sign 10800 1.1 is andi.w &0x8000,%d2 # keep old sign 10801 1.1 is sub.l %d0,%d1 # add scale factor 10802 1.1 is or.w %d2,%d1 # concat old sign,new exp 10803 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 10804 1.1 is mov.l (%sp)+,%d2 # restore d2 10805 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 10806 1.1 is rts 10807 1.1 is 10808 1.1 is fsgldiv_may_ovfl: 10809 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10810 1.1 is 10811 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10812 1.1 is fmov.l &0x0,%fpsr # set FPSR 10813 1.1 is 10814 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # execute divide 10815 1.1 is 10816 1.1 is fmov.l %fpsr,%d1 10817 1.1 is fmov.l &0x0,%fpcr 10818 1.1 is 10819 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX,N 10820 1.1 is 10821 1.1 is fmovm.x &0x01,-(%sp) # save result to stack 10822 1.1 is mov.w (%sp),%d1 # fetch new exponent 10823 1.1 is add.l &0xc,%sp # clear result 10824 1.1 is andi.l &0x7fff,%d1 # strip sign 10825 1.1 is sub.l %d0,%d1 # add scale factor 10826 1.1 is cmp.l %d1,&0x7fff # did divide overflow? 10827 1.1 is blt.b fsgldiv_normal_exit 10828 1.1 is 10829 1.1 is fsgldiv_ovfl_tst: 10830 1.1 is or.w &ovfl_inx_mask,2+USER_FPSR(%a6) # set ovfl/aovfl/ainex 10831 1.1 is 10832 1.1 is mov.b FPCR_ENABLE(%a6),%d1 10833 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 10834 1.1 is bne.b fsgldiv_ovfl_ena # yes 10835 1.1 is 10836 1.1 is fsgldiv_ovfl_dis: 10837 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative 10838 1.1 is sne %d1 # set sign param accordingly 10839 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd 10840 1.1 is andi.b &0x30,%d0 # kill precision 10841 1.1 is bsr.l ovf_res # calculate default result 10842 1.1 is or.b %d0,FPSR_CC(%a6) # set INF if applicable 10843 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 10844 1.1 is rts 10845 1.1 is 10846 1.1 is fsgldiv_ovfl_ena: 10847 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # move result to stack 10848 1.1 is 10849 1.1 is mov.l %d2,-(%sp) # save d2 10850 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 10851 1.1 is mov.l %d1,%d2 # make a copy 10852 1.1 is andi.l &0x7fff,%d1 # strip sign 10853 1.1 is andi.w &0x8000,%d2 # keep old sign 10854 1.1 is sub.l %d0,%d1 # add scale factor 10855 1.1 is subi.l &0x6000,%d1 # subtract new bias 10856 1.1 is andi.w &0x7fff,%d1 # clear ms bit 10857 1.1 is or.w %d2,%d1 # concat old sign,new exp 10858 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 10859 1.1 is mov.l (%sp)+,%d2 # restore d2 10860 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 10861 1.1 is bra.b fsgldiv_ovfl_dis 10862 1.1 is 10863 1.1 is fsgldiv_unfl: 10864 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 10865 1.1 is 10866 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10867 1.1 is 10868 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR 10869 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10870 1.1 is 10871 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide 10872 1.1 is 10873 1.1 is fmov.l %fpsr,%d1 # save status 10874 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10875 1.1 is 10876 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10877 1.1 is 10878 1.1 is mov.b FPCR_ENABLE(%a6),%d1 10879 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 10880 1.1 is bne.b fsgldiv_unfl_ena # yes 10881 1.1 is 10882 1.1 is fsgldiv_unfl_dis: 10883 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 10884 1.1 is 10885 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 10886 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 10887 1.1 is bsr.l unf_res4 # calculate default result 10888 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set 10889 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 10890 1.1 is rts 10891 1.1 is 10892 1.1 is # 10893 1.1 is # UNFL is enabled. 10894 1.1 is # 10895 1.1 is fsgldiv_unfl_ena: 10896 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op 10897 1.1 is 10898 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10899 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10900 1.1 is 10901 1.1 is fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide 10902 1.1 is 10903 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10904 1.1 is 10905 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 10906 1.1 is mov.l %d2,-(%sp) # save d2 10907 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 10908 1.1 is mov.l %d1,%d2 # make a copy 10909 1.1 is andi.l &0x7fff,%d1 # strip sign 10910 1.1 is andi.w &0x8000,%d2 # keep old sign 10911 1.1 is sub.l %d0,%d1 # add scale factor 10912 1.1 is addi.l &0x6000,%d1 # add bias 10913 1.1 is andi.w &0x7fff,%d1 # clear top bit 10914 1.1 is or.w %d2,%d1 # concat old sign, new exp 10915 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 10916 1.1 is mov.l (%sp)+,%d2 # restore d2 10917 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 10918 1.1 is bra.b fsgldiv_unfl_dis 10919 1.1 is 10920 1.1 is # 10921 1.1 is # the divide operation MAY underflow: 10922 1.1 is # 10923 1.1 is fsgldiv_may_unfl: 10924 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 10925 1.1 is 10926 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 10927 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10928 1.1 is 10929 1.1 is fsgldiv.x FP_SCR0(%a6),%fp0 # execute sgl divide 10930 1.1 is 10931 1.1 is fmov.l %fpsr,%d1 # save status 10932 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10933 1.1 is 10934 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 10935 1.1 is 10936 1.1 is fabs.x %fp0,%fp1 # make a copy of result 10937 1.1 is fcmp.b %fp1,&0x1 # is |result| > 1.b? 10938 1.1 is fbgt.w fsgldiv_normal_exit # no; no underflow occurred 10939 1.1 is fblt.w fsgldiv_unfl # yes; underflow occurred 10940 1.1 is 10941 1.1 is # 10942 1.1 is # we still don't know if underflow occurred. result is ~ equal to 1. but, 10943 1.1 is # we don't know if the result was an underflow that rounded up to a 1 10944 1.1 is # or a normalized number that rounded down to a 1. so, redo the entire 10945 1.1 is # operation using RZ as the rounding mode to see what the pre-rounded 10946 1.1 is # result is. this case should be relatively rare. 10947 1.1 is # 10948 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into %fp1 10949 1.1 is 10950 1.1 is clr.l %d1 # clear scratch register 10951 1.1 is ori.b &rz_mode*0x10,%d1 # force RZ rnd mode 10952 1.1 is 10953 1.1 is fmov.l %d1,%fpcr # set FPCR 10954 1.1 is fmov.l &0x0,%fpsr # clear FPSR 10955 1.1 is 10956 1.1 is fsgldiv.x FP_SCR0(%a6),%fp1 # execute sgl divide 10957 1.1 is 10958 1.1 is fmov.l &0x0,%fpcr # clear FPCR 10959 1.1 is fabs.x %fp1 # make absolute value 10960 1.1 is fcmp.b %fp1,&0x1 # is |result| < 1.b? 10961 1.1 is fbge.w fsgldiv_normal_exit # no; no underflow occurred 10962 1.1 is bra.w fsgldiv_unfl # yes; underflow occurred 10963 1.1 is 10964 1.1 is ############################################################################ 10965 1.1 is 10966 1.1 is # 10967 1.1 is # Divide: inputs are not both normalized; what are they? 10968 1.1 is # 10969 1.1 is fsgldiv_not_norm: 10970 1.1 is mov.w (tbl_fsgldiv_op.b,%pc,%d1.w*2),%d1 10971 1.1 is jmp (tbl_fsgldiv_op.b,%pc,%d1.w*1) 10972 1.1 is 10973 1.1 is swbeg &48 10974 1.1 is tbl_fsgldiv_op: 10975 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # NORM / NORM 10976 1.1 is short fsgldiv_inf_load - tbl_fsgldiv_op # NORM / ZERO 10977 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # NORM / INF 10978 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # NORM / QNAN 10979 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # NORM / DENORM 10980 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # NORM / SNAN 10981 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 10982 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 10983 1.1 is 10984 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / NORM 10985 1.1 is short fsgldiv_res_operr - tbl_fsgldiv_op # ZERO / ZERO 10986 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / INF 10987 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # ZERO / QNAN 10988 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # ZERO / DENORM 10989 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # ZERO / SNAN 10990 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 10991 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 10992 1.1 is 10993 1.1 is short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / NORM 10994 1.1 is short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / ZERO 10995 1.1 is short fsgldiv_res_operr - tbl_fsgldiv_op # INF / INF 10996 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # INF / QNAN 10997 1.1 is short fsgldiv_inf_dst - tbl_fsgldiv_op # INF / DENORM 10998 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # INF / SNAN 10999 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11000 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11001 1.1 is 11002 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / NORM 11003 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / ZERO 11004 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / INF 11005 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / QNAN 11006 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # QNAN / DENORM 11007 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # QNAN / SNAN 11008 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11009 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11010 1.1 is 11011 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # DENORM / NORM 11012 1.1 is short fsgldiv_inf_load - tbl_fsgldiv_op # DENORM / ZERO 11013 1.1 is short fsgldiv_zero_load - tbl_fsgldiv_op # DENORM / INF 11014 1.1 is short fsgldiv_res_qnan - tbl_fsgldiv_op # DENORM / QNAN 11015 1.1 is short fsgldiv_norm - tbl_fsgldiv_op # DENORM / DENORM 11016 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # DENORM / SNAN 11017 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11018 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11019 1.1 is 11020 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / NORM 11021 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / ZERO 11022 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / INF 11023 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / QNAN 11024 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / DENORM 11025 1.1 is short fsgldiv_res_snan - tbl_fsgldiv_op # SNAN / SNAN 11026 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11027 1.1 is short tbl_fsgldiv_op - tbl_fsgldiv_op # 11028 1.1 is 11029 1.1 is fsgldiv_res_qnan: 11030 1.1 is bra.l res_qnan 11031 1.1 is fsgldiv_res_snan: 11032 1.1 is bra.l res_snan 11033 1.1 is fsgldiv_res_operr: 11034 1.1 is bra.l res_operr 11035 1.1 is fsgldiv_inf_load: 11036 1.1 is bra.l fdiv_inf_load 11037 1.1 is fsgldiv_zero_load: 11038 1.1 is bra.l fdiv_zero_load 11039 1.1 is fsgldiv_inf_dst: 11040 1.1 is bra.l fdiv_inf_dst 11041 1.1 is 11042 1.1 is ######################################################################### 11043 1.1 is # XDEF **************************************************************** # 11044 1.1 is # fadd(): emulates the fadd instruction # 11045 1.1 is # fsadd(): emulates the fadd instruction # 11046 1.1 is # fdadd(): emulates the fdadd instruction # 11047 1.1 is # # 11048 1.1 is # XREF **************************************************************** # 11049 1.1 is # addsub_scaler2() - scale the operands so they won't take exc # 11050 1.1 is # ovf_res() - return default overflow result # 11051 1.1 is # unf_res() - return default underflow result # 11052 1.1 is # res_qnan() - set QNAN result # 11053 1.1 is # res_snan() - set SNAN result # 11054 1.1 is # res_operr() - set OPERR result # 11055 1.1 is # scale_to_zero_src() - set src operand exponent equal to zero # 11056 1.1 is # scale_to_zero_dst() - set dst operand exponent equal to zero # 11057 1.1 is # # 11058 1.1 is # INPUT *************************************************************** # 11059 1.1 is # a0 = pointer to extended precision source operand # 11060 1.1 is # a1 = pointer to extended precision destination operand # 11061 1.1 is # # 11062 1.1 is # OUTPUT ************************************************************** # 11063 1.1 is # fp0 = result # 11064 1.1 is # fp1 = EXOP (if exception occurred) # 11065 1.1 is # # 11066 1.1 is # ALGORITHM *********************************************************** # 11067 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 11068 1.1 is # norms into extended, single, and double precision. # 11069 1.1 is # Do addition after scaling exponents such that exception won't # 11070 1.1 is # occur. Then, check result exponent to see if exception would have # 11071 1.1 is # occurred. If so, return default result and maybe EXOP. Else, insert # 11072 1.1 is # the correct result exponent and return. Set FPSR bits as appropriate. # 11073 1.1 is # # 11074 1.1 is ######################################################################### 11075 1.1 is 11076 1.1 is global fsadd 11077 1.1 is fsadd: 11078 1.1 is andi.b &0x30,%d0 # clear rnd prec 11079 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec 11080 1.1 is bra.b fadd 11081 1.1 is 11082 1.1 is global fdadd 11083 1.1 is fdadd: 11084 1.1 is andi.b &0x30,%d0 # clear rnd prec 11085 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec 11086 1.1 is 11087 1.1 is global fadd 11088 1.1 is fadd: 11089 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 11090 1.1 is 11091 1.1 is clr.w %d1 11092 1.1 is mov.b DTAG(%a6),%d1 11093 1.1 is lsl.b &0x3,%d1 11094 1.1 is or.b STAG(%a6),%d1 # combine src tags 11095 1.1 is 11096 1.1 is bne.w fadd_not_norm # optimize on non-norm input 11097 1.1 is 11098 1.1 is # 11099 1.1 is # ADD: norms and denorms 11100 1.1 is # 11101 1.1 is fadd_norm: 11102 1.1 is bsr.l addsub_scaler2 # scale exponents 11103 1.1 is 11104 1.1 is fadd_zero_entry: 11105 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 11106 1.1 is 11107 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11108 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 11109 1.1 is 11110 1.1 is fadd.x FP_SCR0(%a6),%fp0 # execute add 11111 1.1 is 11112 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11113 1.1 is fmov.l %fpsr,%d1 # fetch INEX2,N,Z 11114 1.1 is 11115 1.1 is or.l %d1,USER_FPSR(%a6) # save exc and ccode bits 11116 1.1 is 11117 1.1 is fbeq.w fadd_zero_exit # if result is zero, end now 11118 1.1 is 11119 1.1 is mov.l %d2,-(%sp) # save d2 11120 1.1 is 11121 1.1 is fmovm.x &0x01,-(%sp) # save result to stack 11122 1.1 is 11123 1.1 is mov.w 2+L_SCR3(%a6),%d1 11124 1.1 is lsr.b &0x6,%d1 11125 1.1 is 11126 1.1 is mov.w (%sp),%d2 # fetch new sign, exp 11127 1.1 is andi.l &0x7fff,%d2 # strip sign 11128 1.1 is sub.l %d0,%d2 # add scale factor 11129 1.1 is 11130 1.1 is cmp.l %d2,(tbl_fadd_ovfl.b,%pc,%d1.w*4) # is it an overflow? 11131 1.1 is bge.b fadd_ovfl # yes 11132 1.1 is 11133 1.1 is cmp.l %d2,(tbl_fadd_unfl.b,%pc,%d1.w*4) # is it an underflow? 11134 1.1 is blt.w fadd_unfl # yes 11135 1.1 is beq.w fadd_may_unfl # maybe; go find out 11136 1.1 is 11137 1.1 is fadd_normal: 11138 1.1 is mov.w (%sp),%d1 11139 1.1 is andi.w &0x8000,%d1 # keep sign 11140 1.1 is or.w %d2,%d1 # concat sign,new exp 11141 1.1 is mov.w %d1,(%sp) # insert new exponent 11142 1.1 is 11143 1.1 is fmovm.x (%sp)+,&0x80 # return result in fp0 11144 1.1 is 11145 1.1 is mov.l (%sp)+,%d2 # restore d2 11146 1.1 is rts 11147 1.1 is 11148 1.1 is fadd_zero_exit: 11149 1.1 is # fmov.s &0x00000000,%fp0 # return zero in fp0 11150 1.1 is rts 11151 1.1 is 11152 1.1 is tbl_fadd_ovfl: 11153 1.1 is long 0x7fff # ext ovfl 11154 1.1 is long 0x407f # sgl ovfl 11155 1.1 is long 0x43ff # dbl ovfl 11156 1.1 is 11157 1.1 is tbl_fadd_unfl: 11158 1.1 is long 0x0000 # ext unfl 11159 1.1 is long 0x3f81 # sgl unfl 11160 1.1 is long 0x3c01 # dbl unfl 11161 1.1 is 11162 1.1 is fadd_ovfl: 11163 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 11164 1.1 is 11165 1.1 is mov.b FPCR_ENABLE(%a6),%d1 11166 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 11167 1.1 is bne.b fadd_ovfl_ena # yes 11168 1.1 is 11169 1.1 is add.l &0xc,%sp 11170 1.1 is fadd_ovfl_dis: 11171 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 11172 1.1 is sne %d1 # set sign param accordingly 11173 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd 11174 1.1 is bsr.l ovf_res # calculate default result 11175 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 11176 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 11177 1.1 is mov.l (%sp)+,%d2 # restore d2 11178 1.1 is rts 11179 1.1 is 11180 1.1 is fadd_ovfl_ena: 11181 1.1 is mov.b L_SCR3(%a6),%d1 11182 1.1 is andi.b &0xc0,%d1 # is precision extended? 11183 1.1 is bne.b fadd_ovfl_ena_sd # no; prec = sgl or dbl 11184 1.1 is 11185 1.1 is fadd_ovfl_ena_cont: 11186 1.1 is mov.w (%sp),%d1 11187 1.1 is andi.w &0x8000,%d1 # keep sign 11188 1.1 is subi.l &0x6000,%d2 # add extra bias 11189 1.1 is andi.w &0x7fff,%d2 11190 1.1 is or.w %d2,%d1 # concat sign,new exp 11191 1.1 is mov.w %d1,(%sp) # insert new exponent 11192 1.1 is 11193 1.1 is fmovm.x (%sp)+,&0x40 # return EXOP in fp1 11194 1.1 is bra.b fadd_ovfl_dis 11195 1.1 is 11196 1.1 is fadd_ovfl_ena_sd: 11197 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 11198 1.1 is 11199 1.1 is mov.l L_SCR3(%a6),%d1 11200 1.1 is andi.b &0x30,%d1 # keep rnd mode 11201 1.1 is fmov.l %d1,%fpcr # set FPCR 11202 1.1 is 11203 1.1 is fadd.x FP_SCR0(%a6),%fp0 # execute add 11204 1.1 is 11205 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11206 1.1 is 11207 1.1 is add.l &0xc,%sp 11208 1.1 is fmovm.x &0x01,-(%sp) 11209 1.1 is bra.b fadd_ovfl_ena_cont 11210 1.1 is 11211 1.1 is fadd_unfl: 11212 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 11213 1.1 is 11214 1.1 is add.l &0xc,%sp 11215 1.1 is 11216 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 11217 1.1 is 11218 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR 11219 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11220 1.1 is 11221 1.1 is fadd.x FP_SCR0(%a6),%fp0 # execute add 11222 1.1 is 11223 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11224 1.1 is fmov.l %fpsr,%d1 # save status 11225 1.1 is 11226 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX,N 11227 1.1 is 11228 1.1 is mov.b FPCR_ENABLE(%a6),%d1 11229 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 11230 1.1 is bne.b fadd_unfl_ena # yes 11231 1.1 is 11232 1.1 is fadd_unfl_dis: 11233 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 11234 1.1 is 11235 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 11236 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 11237 1.1 is bsr.l unf_res # calculate default result 11238 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' bit may have been set 11239 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 11240 1.1 is mov.l (%sp)+,%d2 # restore d2 11241 1.1 is rts 11242 1.1 is 11243 1.1 is fadd_unfl_ena: 11244 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op 11245 1.1 is 11246 1.1 is mov.l L_SCR3(%a6),%d1 11247 1.1 is andi.b &0xc0,%d1 # is precision extended? 11248 1.1 is bne.b fadd_unfl_ena_sd # no; sgl or dbl 11249 1.1 is 11250 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 11251 1.1 is 11252 1.1 is fadd_unfl_ena_cont: 11253 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11254 1.1 is 11255 1.1 is fadd.x FP_SCR0(%a6),%fp1 # execute multiply 11256 1.1 is 11257 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11258 1.1 is 11259 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # save result to stack 11260 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 11261 1.1 is mov.l %d1,%d2 # make a copy 11262 1.1 is andi.l &0x7fff,%d1 # strip sign 11263 1.1 is andi.w &0x8000,%d2 # keep old sign 11264 1.1 is sub.l %d0,%d1 # add scale factor 11265 1.1 is addi.l &0x6000,%d1 # add new bias 11266 1.1 is andi.w &0x7fff,%d1 # clear top bit 11267 1.1 is or.w %d2,%d1 # concat sign,new exp 11268 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 11269 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 11270 1.1 is bra.w fadd_unfl_dis 11271 1.1 is 11272 1.1 is fadd_unfl_ena_sd: 11273 1.1 is mov.l L_SCR3(%a6),%d1 11274 1.1 is andi.b &0x30,%d1 # use only rnd mode 11275 1.1 is fmov.l %d1,%fpcr # set FPCR 11276 1.1 is 11277 1.1 is bra.b fadd_unfl_ena_cont 11278 1.1 is 11279 1.1 is # 11280 1.1 is # result is equal to the smallest normalized number in the selected precision 11281 1.1 is # if the precision is extended, this result could not have come from an 11282 1.1 is # underflow that rounded up. 11283 1.1 is # 11284 1.1 is fadd_may_unfl: 11285 1.1 is mov.l L_SCR3(%a6),%d1 11286 1.1 is andi.b &0xc0,%d1 11287 1.1 is beq.w fadd_normal # yes; no underflow occurred 11288 1.1 is 11289 1.1 is mov.l 0x4(%sp),%d1 # extract hi(man) 11290 1.1 is cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000? 11291 1.1 is bne.w fadd_normal # no; no underflow occurred 11292 1.1 is 11293 1.1 is tst.l 0x8(%sp) # is lo(man) = 0x0? 11294 1.1 is bne.w fadd_normal # no; no underflow occurred 11295 1.1 is 11296 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set? 11297 1.1 is beq.w fadd_normal # no; no underflow occurred 11298 1.1 is 11299 1.1 is # 11300 1.1 is # ok, so now the result has a exponent equal to the smallest normalized 11301 1.1 is # exponent for the selected precision. also, the mantissa is equal to 11302 1.1 is # 0x8000000000000000 and this mantissa is the result of rounding non-zero 11303 1.1 is # g,r,s. 11304 1.1 is # now, we must determine whether the pre-rounded result was an underflow 11305 1.1 is # rounded "up" or a normalized number rounded "down". 11306 1.1 is # so, we do this be re-executing the add using RZ as the rounding mode and 11307 1.1 is # seeing if the new result is smaller or equal to the current result. 11308 1.1 is # 11309 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 11310 1.1 is 11311 1.1 is mov.l L_SCR3(%a6),%d1 11312 1.1 is andi.b &0xc0,%d1 # keep rnd prec 11313 1.1 is ori.b &rz_mode*0x10,%d1 # insert rnd mode 11314 1.1 is fmov.l %d1,%fpcr # set FPCR 11315 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11316 1.1 is 11317 1.1 is fadd.x FP_SCR0(%a6),%fp1 # execute add 11318 1.1 is 11319 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11320 1.1 is 11321 1.1 is fabs.x %fp0 # compare absolute values 11322 1.1 is fabs.x %fp1 11323 1.1 is fcmp.x %fp0,%fp1 # is first result > second? 11324 1.1 is 11325 1.1 is fbgt.w fadd_unfl # yes; it's an underflow 11326 1.1 is bra.w fadd_normal # no; it's not an underflow 11327 1.1 is 11328 1.1 is ########################################################################## 11329 1.1 is 11330 1.1 is # 11331 1.1 is # Add: inputs are not both normalized; what are they? 11332 1.1 is # 11333 1.1 is fadd_not_norm: 11334 1.1 is mov.w (tbl_fadd_op.b,%pc,%d1.w*2),%d1 11335 1.1 is jmp (tbl_fadd_op.b,%pc,%d1.w*1) 11336 1.1 is 11337 1.1 is swbeg &48 11338 1.1 is tbl_fadd_op: 11339 1.1 is short fadd_norm - tbl_fadd_op # NORM + NORM 11340 1.1 is short fadd_zero_src - tbl_fadd_op # NORM + ZERO 11341 1.1 is short fadd_inf_src - tbl_fadd_op # NORM + INF 11342 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 11343 1.1 is short fadd_norm - tbl_fadd_op # NORM + DENORM 11344 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN 11345 1.1 is short tbl_fadd_op - tbl_fadd_op # 11346 1.1 is short tbl_fadd_op - tbl_fadd_op # 11347 1.1 is 11348 1.1 is short fadd_zero_dst - tbl_fadd_op # ZERO + NORM 11349 1.1 is short fadd_zero_2 - tbl_fadd_op # ZERO + ZERO 11350 1.1 is short fadd_inf_src - tbl_fadd_op # ZERO + INF 11351 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 11352 1.1 is short fadd_zero_dst - tbl_fadd_op # ZERO + DENORM 11353 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN 11354 1.1 is short tbl_fadd_op - tbl_fadd_op # 11355 1.1 is short tbl_fadd_op - tbl_fadd_op # 11356 1.1 is 11357 1.1 is short fadd_inf_dst - tbl_fadd_op # INF + NORM 11358 1.1 is short fadd_inf_dst - tbl_fadd_op # INF + ZERO 11359 1.1 is short fadd_inf_2 - tbl_fadd_op # INF + INF 11360 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 11361 1.1 is short fadd_inf_dst - tbl_fadd_op # INF + DENORM 11362 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN 11363 1.1 is short tbl_fadd_op - tbl_fadd_op # 11364 1.1 is short tbl_fadd_op - tbl_fadd_op # 11365 1.1 is 11366 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + NORM 11367 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + ZERO 11368 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + INF 11369 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + QNAN 11370 1.1 is short fadd_res_qnan - tbl_fadd_op # QNAN + DENORM 11371 1.1 is short fadd_res_snan - tbl_fadd_op # QNAN + SNAN 11372 1.1 is short tbl_fadd_op - tbl_fadd_op # 11373 1.1 is short tbl_fadd_op - tbl_fadd_op # 11374 1.1 is 11375 1.1 is short fadd_norm - tbl_fadd_op # DENORM + NORM 11376 1.1 is short fadd_zero_src - tbl_fadd_op # DENORM + ZERO 11377 1.1 is short fadd_inf_src - tbl_fadd_op # DENORM + INF 11378 1.1 is short fadd_res_qnan - tbl_fadd_op # NORM + QNAN 11379 1.1 is short fadd_norm - tbl_fadd_op # DENORM + DENORM 11380 1.1 is short fadd_res_snan - tbl_fadd_op # NORM + SNAN 11381 1.1 is short tbl_fadd_op - tbl_fadd_op # 11382 1.1 is short tbl_fadd_op - tbl_fadd_op # 11383 1.1 is 11384 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + NORM 11385 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + ZERO 11386 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + INF 11387 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + QNAN 11388 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + DENORM 11389 1.1 is short fadd_res_snan - tbl_fadd_op # SNAN + SNAN 11390 1.1 is short tbl_fadd_op - tbl_fadd_op # 11391 1.1 is short tbl_fadd_op - tbl_fadd_op # 11392 1.1 is 11393 1.1 is fadd_res_qnan: 11394 1.1 is bra.l res_qnan 11395 1.1 is fadd_res_snan: 11396 1.1 is bra.l res_snan 11397 1.1 is 11398 1.1 is # 11399 1.1 is # both operands are ZEROes 11400 1.1 is # 11401 1.1 is fadd_zero_2: 11402 1.1 is mov.b SRC_EX(%a0),%d0 # are the signs opposite 11403 1.1 is mov.b DST_EX(%a1),%d1 11404 1.1 is eor.b %d0,%d1 11405 1.1 is bmi.w fadd_zero_2_chk_rm # weed out (-ZERO)+(+ZERO) 11406 1.1 is 11407 1.1 is # the signs are the same. so determine whether they are positive or negative 11408 1.1 is # and return the appropriately signed zero. 11409 1.1 is tst.b %d0 # are ZEROes positive or negative? 11410 1.1 is bmi.b fadd_zero_rm # negative 11411 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO 11412 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z 11413 1.1 is rts 11414 1.1 is 11415 1.1 is # 11416 1.1 is # the ZEROes have opposite signs: 11417 1.1 is # - therefore, we return +ZERO if the rounding modes are RN,RZ, or RP. 11418 1.1 is # - -ZERO is returned in the case of RM. 11419 1.1 is # 11420 1.1 is fadd_zero_2_chk_rm: 11421 1.1 is mov.b 3+L_SCR3(%a6),%d1 11422 1.1 is andi.b &0x30,%d1 # extract rnd mode 11423 1.1 is cmpi.b %d1,&rm_mode*0x10 # is rnd mode == RM? 11424 1.1 is beq.b fadd_zero_rm # yes 11425 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO 11426 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z 11427 1.1 is rts 11428 1.1 is 11429 1.1 is fadd_zero_rm: 11430 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO 11431 1.1 is mov.b &neg_bmask+z_bmask,FPSR_CC(%a6) # set NEG/Z 11432 1.1 is rts 11433 1.1 is 11434 1.1 is # 11435 1.1 is # one operand is a ZERO and the other is a DENORM or NORM. scale 11436 1.1 is # the DENORM or NORM and jump to the regular fadd routine. 11437 1.1 is # 11438 1.1 is fadd_zero_dst: 11439 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 11440 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 11441 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 11442 1.1 is bsr.l scale_to_zero_src # scale the operand 11443 1.1 is clr.w FP_SCR1_EX(%a6) 11444 1.1 is clr.l FP_SCR1_HI(%a6) 11445 1.1 is clr.l FP_SCR1_LO(%a6) 11446 1.1 is bra.w fadd_zero_entry # go execute fadd 11447 1.1 is 11448 1.1 is fadd_zero_src: 11449 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 11450 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 11451 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 11452 1.1 is bsr.l scale_to_zero_dst # scale the operand 11453 1.1 is clr.w FP_SCR0_EX(%a6) 11454 1.1 is clr.l FP_SCR0_HI(%a6) 11455 1.1 is clr.l FP_SCR0_LO(%a6) 11456 1.1 is bra.w fadd_zero_entry # go execute fadd 11457 1.1 is 11458 1.1 is # 11459 1.1 is # both operands are INFs. an OPERR will result if the INFs have 11460 1.1 is # different signs. else, an INF of the same sign is returned 11461 1.1 is # 11462 1.1 is fadd_inf_2: 11463 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs 11464 1.1 is mov.b DST_EX(%a1),%d1 11465 1.1 is eor.b %d1,%d0 11466 1.1 is bmi.l res_operr # weed out (-INF)+(+INF) 11467 1.1 is 11468 1.1 is # ok, so it's not an OPERR. but, we do have to remember to return the 11469 1.1 is # src INF since that's where the 881/882 gets the j-bit from... 11470 1.1 is 11471 1.1 is # 11472 1.1 is # operands are INF and one of {ZERO, INF, DENORM, NORM} 11473 1.1 is # 11474 1.1 is fadd_inf_src: 11475 1.1 is fmovm.x SRC(%a0),&0x80 # return src INF 11476 1.1 is tst.b SRC_EX(%a0) # is INF positive? 11477 1.1 is bpl.b fadd_inf_done # yes; we're done 11478 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 11479 1.1 is rts 11480 1.1 is 11481 1.1 is # 11482 1.1 is # operands are INF and one of {ZERO, INF, DENORM, NORM} 11483 1.1 is # 11484 1.1 is fadd_inf_dst: 11485 1.1 is fmovm.x DST(%a1),&0x80 # return dst INF 11486 1.1 is tst.b DST_EX(%a1) # is INF positive? 11487 1.1 is bpl.b fadd_inf_done # yes; we're done 11488 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 11489 1.1 is rts 11490 1.1 is 11491 1.1 is fadd_inf_done: 11492 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF 11493 1.1 is rts 11494 1.1 is 11495 1.1 is ######################################################################### 11496 1.1 is # XDEF **************************************************************** # 11497 1.1 is # fsub(): emulates the fsub instruction # 11498 1.1 is # fssub(): emulates the fssub instruction # 11499 1.1 is # fdsub(): emulates the fdsub instruction # 11500 1.1 is # # 11501 1.1 is # XREF **************************************************************** # 11502 1.1 is # addsub_scaler2() - scale the operands so they won't take exc # 11503 1.1 is # ovf_res() - return default overflow result # 11504 1.1 is # unf_res() - return default underflow result # 11505 1.1 is # res_qnan() - set QNAN result # 11506 1.1 is # res_snan() - set SNAN result # 11507 1.1 is # res_operr() - set OPERR result # 11508 1.1 is # scale_to_zero_src() - set src operand exponent equal to zero # 11509 1.1 is # scale_to_zero_dst() - set dst operand exponent equal to zero # 11510 1.1 is # # 11511 1.1 is # INPUT *************************************************************** # 11512 1.1 is # a0 = pointer to extended precision source operand # 11513 1.1 is # a1 = pointer to extended precision destination operand # 11514 1.1 is # # 11515 1.1 is # OUTPUT ************************************************************** # 11516 1.1 is # fp0 = result # 11517 1.1 is # fp1 = EXOP (if exception occurred) # 11518 1.1 is # # 11519 1.1 is # ALGORITHM *********************************************************** # 11520 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 11521 1.1 is # norms into extended, single, and double precision. # 11522 1.1 is # Do subtraction after scaling exponents such that exception won't# 11523 1.1 is # occur. Then, check result exponent to see if exception would have # 11524 1.1 is # occurred. If so, return default result and maybe EXOP. Else, insert # 11525 1.1 is # the correct result exponent and return. Set FPSR bits as appropriate. # 11526 1.1 is # # 11527 1.1 is ######################################################################### 11528 1.1 is 11529 1.1 is global fssub 11530 1.1 is fssub: 11531 1.1 is andi.b &0x30,%d0 # clear rnd prec 11532 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl prec 11533 1.1 is bra.b fsub 11534 1.1 is 11535 1.1 is global fdsub 11536 1.1 is fdsub: 11537 1.1 is andi.b &0x30,%d0 # clear rnd prec 11538 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl prec 11539 1.1 is 11540 1.1 is global fsub 11541 1.1 is fsub: 11542 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 11543 1.1 is 11544 1.1 is clr.w %d1 11545 1.1 is mov.b DTAG(%a6),%d1 11546 1.1 is lsl.b &0x3,%d1 11547 1.1 is or.b STAG(%a6),%d1 # combine src tags 11548 1.1 is 11549 1.1 is bne.w fsub_not_norm # optimize on non-norm input 11550 1.1 is 11551 1.1 is # 11552 1.1 is # SUB: norms and denorms 11553 1.1 is # 11554 1.1 is fsub_norm: 11555 1.1 is bsr.l addsub_scaler2 # scale exponents 11556 1.1 is 11557 1.1 is fsub_zero_entry: 11558 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 11559 1.1 is 11560 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11561 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 11562 1.1 is 11563 1.1 is fsub.x FP_SCR0(%a6),%fp0 # execute subtract 11564 1.1 is 11565 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11566 1.1 is fmov.l %fpsr,%d1 # fetch INEX2, N, Z 11567 1.1 is 11568 1.1 is or.l %d1,USER_FPSR(%a6) # save exc and ccode bits 11569 1.1 is 11570 1.1 is fbeq.w fsub_zero_exit # if result zero, end now 11571 1.1 is 11572 1.1 is mov.l %d2,-(%sp) # save d2 11573 1.1 is 11574 1.1 is fmovm.x &0x01,-(%sp) # save result to stack 11575 1.1 is 11576 1.1 is mov.w 2+L_SCR3(%a6),%d1 11577 1.1 is lsr.b &0x6,%d1 11578 1.1 is 11579 1.1 is mov.w (%sp),%d2 # fetch new exponent 11580 1.1 is andi.l &0x7fff,%d2 # strip sign 11581 1.1 is sub.l %d0,%d2 # add scale factor 11582 1.1 is 11583 1.1 is cmp.l %d2,(tbl_fsub_ovfl.b,%pc,%d1.w*4) # is it an overflow? 11584 1.1 is bge.b fsub_ovfl # yes 11585 1.1 is 11586 1.1 is cmp.l %d2,(tbl_fsub_unfl.b,%pc,%d1.w*4) # is it an underflow? 11587 1.1 is blt.w fsub_unfl # yes 11588 1.1 is beq.w fsub_may_unfl # maybe; go find out 11589 1.1 is 11590 1.1 is fsub_normal: 11591 1.1 is mov.w (%sp),%d1 11592 1.1 is andi.w &0x8000,%d1 # keep sign 11593 1.1 is or.w %d2,%d1 # insert new exponent 11594 1.1 is mov.w %d1,(%sp) # insert new exponent 11595 1.1 is 11596 1.1 is fmovm.x (%sp)+,&0x80 # return result in fp0 11597 1.1 is 11598 1.1 is mov.l (%sp)+,%d2 # restore d2 11599 1.1 is rts 11600 1.1 is 11601 1.1 is fsub_zero_exit: 11602 1.1 is # fmov.s &0x00000000,%fp0 # return zero in fp0 11603 1.1 is rts 11604 1.1 is 11605 1.1 is tbl_fsub_ovfl: 11606 1.1 is long 0x7fff # ext ovfl 11607 1.1 is long 0x407f # sgl ovfl 11608 1.1 is long 0x43ff # dbl ovfl 11609 1.1 is 11610 1.1 is tbl_fsub_unfl: 11611 1.1 is long 0x0000 # ext unfl 11612 1.1 is long 0x3f81 # sgl unfl 11613 1.1 is long 0x3c01 # dbl unfl 11614 1.1 is 11615 1.1 is fsub_ovfl: 11616 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 11617 1.1 is 11618 1.1 is mov.b FPCR_ENABLE(%a6),%d1 11619 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 11620 1.1 is bne.b fsub_ovfl_ena # yes 11621 1.1 is 11622 1.1 is add.l &0xc,%sp 11623 1.1 is fsub_ovfl_dis: 11624 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 11625 1.1 is sne %d1 # set sign param accordingly 11626 1.1 is mov.l L_SCR3(%a6),%d0 # pass prec:rnd 11627 1.1 is bsr.l ovf_res # calculate default result 11628 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 11629 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 11630 1.1 is mov.l (%sp)+,%d2 # restore d2 11631 1.1 is rts 11632 1.1 is 11633 1.1 is fsub_ovfl_ena: 11634 1.1 is mov.b L_SCR3(%a6),%d1 11635 1.1 is andi.b &0xc0,%d1 # is precision extended? 11636 1.1 is bne.b fsub_ovfl_ena_sd # no 11637 1.1 is 11638 1.1 is fsub_ovfl_ena_cont: 11639 1.1 is mov.w (%sp),%d1 # fetch {sgn,exp} 11640 1.1 is andi.w &0x8000,%d1 # keep sign 11641 1.1 is subi.l &0x6000,%d2 # subtract new bias 11642 1.1 is andi.w &0x7fff,%d2 # clear top bit 11643 1.1 is or.w %d2,%d1 # concat sign,exp 11644 1.1 is mov.w %d1,(%sp) # insert new exponent 11645 1.1 is 11646 1.1 is fmovm.x (%sp)+,&0x40 # return EXOP in fp1 11647 1.1 is bra.b fsub_ovfl_dis 11648 1.1 is 11649 1.1 is fsub_ovfl_ena_sd: 11650 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 11651 1.1 is 11652 1.1 is mov.l L_SCR3(%a6),%d1 11653 1.1 is andi.b &0x30,%d1 # clear rnd prec 11654 1.1 is fmov.l %d1,%fpcr # set FPCR 11655 1.1 is 11656 1.1 is fsub.x FP_SCR0(%a6),%fp0 # execute subtract 11657 1.1 is 11658 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11659 1.1 is 11660 1.1 is add.l &0xc,%sp 11661 1.1 is fmovm.x &0x01,-(%sp) 11662 1.1 is bra.b fsub_ovfl_ena_cont 11663 1.1 is 11664 1.1 is fsub_unfl: 11665 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 11666 1.1 is 11667 1.1 is add.l &0xc,%sp 11668 1.1 is 11669 1.1 is fmovm.x FP_SCR1(%a6),&0x80 # load dst op 11670 1.1 is 11671 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR 11672 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11673 1.1 is 11674 1.1 is fsub.x FP_SCR0(%a6),%fp0 # execute subtract 11675 1.1 is 11676 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11677 1.1 is fmov.l %fpsr,%d1 # save status 11678 1.1 is 11679 1.1 is or.l %d1,USER_FPSR(%a6) 11680 1.1 is 11681 1.1 is mov.b FPCR_ENABLE(%a6),%d1 11682 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 11683 1.1 is bne.b fsub_unfl_ena # yes 11684 1.1 is 11685 1.1 is fsub_unfl_dis: 11686 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 11687 1.1 is 11688 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 11689 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 11690 1.1 is bsr.l unf_res # calculate default result 11691 1.1 is or.b %d0,FPSR_CC(%a6) # 'Z' may have been set 11692 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 11693 1.1 is mov.l (%sp)+,%d2 # restore d2 11694 1.1 is rts 11695 1.1 is 11696 1.1 is fsub_unfl_ena: 11697 1.1 is fmovm.x FP_SCR1(%a6),&0x40 11698 1.1 is 11699 1.1 is mov.l L_SCR3(%a6),%d1 11700 1.1 is andi.b &0xc0,%d1 # is precision extended? 11701 1.1 is bne.b fsub_unfl_ena_sd # no 11702 1.1 is 11703 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 11704 1.1 is 11705 1.1 is fsub_unfl_ena_cont: 11706 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11707 1.1 is 11708 1.1 is fsub.x FP_SCR0(%a6),%fp1 # execute subtract 11709 1.1 is 11710 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11711 1.1 is 11712 1.1 is fmovm.x &0x40,FP_SCR0(%a6) # store result to stack 11713 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 11714 1.1 is mov.l %d1,%d2 # make a copy 11715 1.1 is andi.l &0x7fff,%d1 # strip sign 11716 1.1 is andi.w &0x8000,%d2 # keep old sign 11717 1.1 is sub.l %d0,%d1 # add scale factor 11718 1.1 is addi.l &0x6000,%d1 # subtract new bias 11719 1.1 is andi.w &0x7fff,%d1 # clear top bit 11720 1.1 is or.w %d2,%d1 # concat sgn,exp 11721 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 11722 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 11723 1.1 is bra.w fsub_unfl_dis 11724 1.1 is 11725 1.1 is fsub_unfl_ena_sd: 11726 1.1 is mov.l L_SCR3(%a6),%d1 11727 1.1 is andi.b &0x30,%d1 # clear rnd prec 11728 1.1 is fmov.l %d1,%fpcr # set FPCR 11729 1.1 is 11730 1.1 is bra.b fsub_unfl_ena_cont 11731 1.1 is 11732 1.1 is # 11733 1.1 is # result is equal to the smallest normalized number in the selected precision 11734 1.1 is # if the precision is extended, this result could not have come from an 11735 1.1 is # underflow that rounded up. 11736 1.1 is # 11737 1.1 is fsub_may_unfl: 11738 1.1 is mov.l L_SCR3(%a6),%d1 11739 1.1 is andi.b &0xc0,%d1 # fetch rnd prec 11740 1.1 is beq.w fsub_normal # yes; no underflow occurred 11741 1.1 is 11742 1.1 is mov.l 0x4(%sp),%d1 11743 1.1 is cmpi.l %d1,&0x80000000 # is hi(man) = 0x80000000? 11744 1.1 is bne.w fsub_normal # no; no underflow occurred 11745 1.1 is 11746 1.1 is tst.l 0x8(%sp) # is lo(man) = 0x0? 11747 1.1 is bne.w fsub_normal # no; no underflow occurred 11748 1.1 is 11749 1.1 is btst &inex2_bit,FPSR_EXCEPT(%a6) # is INEX2 set? 11750 1.1 is beq.w fsub_normal # no; no underflow occurred 11751 1.1 is 11752 1.1 is # 11753 1.1 is # ok, so now the result has a exponent equal to the smallest normalized 11754 1.1 is # exponent for the selected precision. also, the mantissa is equal to 11755 1.1 is # 0x8000000000000000 and this mantissa is the result of rounding non-zero 11756 1.1 is # g,r,s. 11757 1.1 is # now, we must determine whether the pre-rounded result was an underflow 11758 1.1 is # rounded "up" or a normalized number rounded "down". 11759 1.1 is # so, we do this be re-executing the add using RZ as the rounding mode and 11760 1.1 is # seeing if the new result is smaller or equal to the current result. 11761 1.1 is # 11762 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # load dst op into fp1 11763 1.1 is 11764 1.1 is mov.l L_SCR3(%a6),%d1 11765 1.1 is andi.b &0xc0,%d1 # keep rnd prec 11766 1.1 is ori.b &rz_mode*0x10,%d1 # insert rnd mode 11767 1.1 is fmov.l %d1,%fpcr # set FPCR 11768 1.1 is fmov.l &0x0,%fpsr # clear FPSR 11769 1.1 is 11770 1.1 is fsub.x FP_SCR0(%a6),%fp1 # execute subtract 11771 1.1 is 11772 1.1 is fmov.l &0x0,%fpcr # clear FPCR 11773 1.1 is 11774 1.1 is fabs.x %fp0 # compare absolute values 11775 1.1 is fabs.x %fp1 11776 1.1 is fcmp.x %fp0,%fp1 # is first result > second? 11777 1.1 is 11778 1.1 is fbgt.w fsub_unfl # yes; it's an underflow 11779 1.1 is bra.w fsub_normal # no; it's not an underflow 11780 1.1 is 11781 1.1 is ########################################################################## 11782 1.1 is 11783 1.1 is # 11784 1.1 is # Sub: inputs are not both normalized; what are they? 11785 1.1 is # 11786 1.1 is fsub_not_norm: 11787 1.1 is mov.w (tbl_fsub_op.b,%pc,%d1.w*2),%d1 11788 1.1 is jmp (tbl_fsub_op.b,%pc,%d1.w*1) 11789 1.1 is 11790 1.1 is swbeg &48 11791 1.1 is tbl_fsub_op: 11792 1.1 is short fsub_norm - tbl_fsub_op # NORM - NORM 11793 1.1 is short fsub_zero_src - tbl_fsub_op # NORM - ZERO 11794 1.1 is short fsub_inf_src - tbl_fsub_op # NORM - INF 11795 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 11796 1.1 is short fsub_norm - tbl_fsub_op # NORM - DENORM 11797 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN 11798 1.1 is short tbl_fsub_op - tbl_fsub_op # 11799 1.1 is short tbl_fsub_op - tbl_fsub_op # 11800 1.1 is 11801 1.1 is short fsub_zero_dst - tbl_fsub_op # ZERO - NORM 11802 1.1 is short fsub_zero_2 - tbl_fsub_op # ZERO - ZERO 11803 1.1 is short fsub_inf_src - tbl_fsub_op # ZERO - INF 11804 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 11805 1.1 is short fsub_zero_dst - tbl_fsub_op # ZERO - DENORM 11806 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN 11807 1.1 is short tbl_fsub_op - tbl_fsub_op # 11808 1.1 is short tbl_fsub_op - tbl_fsub_op # 11809 1.1 is 11810 1.1 is short fsub_inf_dst - tbl_fsub_op # INF - NORM 11811 1.1 is short fsub_inf_dst - tbl_fsub_op # INF - ZERO 11812 1.1 is short fsub_inf_2 - tbl_fsub_op # INF - INF 11813 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 11814 1.1 is short fsub_inf_dst - tbl_fsub_op # INF - DENORM 11815 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN 11816 1.1 is short tbl_fsub_op - tbl_fsub_op # 11817 1.1 is short tbl_fsub_op - tbl_fsub_op # 11818 1.1 is 11819 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - NORM 11820 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - ZERO 11821 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - INF 11822 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - QNAN 11823 1.1 is short fsub_res_qnan - tbl_fsub_op # QNAN - DENORM 11824 1.1 is short fsub_res_snan - tbl_fsub_op # QNAN - SNAN 11825 1.1 is short tbl_fsub_op - tbl_fsub_op # 11826 1.1 is short tbl_fsub_op - tbl_fsub_op # 11827 1.1 is 11828 1.1 is short fsub_norm - tbl_fsub_op # DENORM - NORM 11829 1.1 is short fsub_zero_src - tbl_fsub_op # DENORM - ZERO 11830 1.1 is short fsub_inf_src - tbl_fsub_op # DENORM - INF 11831 1.1 is short fsub_res_qnan - tbl_fsub_op # NORM - QNAN 11832 1.1 is short fsub_norm - tbl_fsub_op # DENORM - DENORM 11833 1.1 is short fsub_res_snan - tbl_fsub_op # NORM - SNAN 11834 1.1 is short tbl_fsub_op - tbl_fsub_op # 11835 1.1 is short tbl_fsub_op - tbl_fsub_op # 11836 1.1 is 11837 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - NORM 11838 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - ZERO 11839 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - INF 11840 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - QNAN 11841 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - DENORM 11842 1.1 is short fsub_res_snan - tbl_fsub_op # SNAN - SNAN 11843 1.1 is short tbl_fsub_op - tbl_fsub_op # 11844 1.1 is short tbl_fsub_op - tbl_fsub_op # 11845 1.1 is 11846 1.1 is fsub_res_qnan: 11847 1.1 is bra.l res_qnan 11848 1.1 is fsub_res_snan: 11849 1.1 is bra.l res_snan 11850 1.1 is 11851 1.1 is # 11852 1.1 is # both operands are ZEROes 11853 1.1 is # 11854 1.1 is fsub_zero_2: 11855 1.1 is mov.b SRC_EX(%a0),%d0 11856 1.1 is mov.b DST_EX(%a1),%d1 11857 1.1 is eor.b %d1,%d0 11858 1.1 is bpl.b fsub_zero_2_chk_rm 11859 1.1 is 11860 1.1 is # the signs are opposite, so, return a ZERO w/ the sign of the dst ZERO 11861 1.1 is tst.b %d0 # is dst negative? 11862 1.1 is bmi.b fsub_zero_2_rm # yes 11863 1.1 is fmov.s &0x00000000,%fp0 # no; return +ZERO 11864 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z 11865 1.1 is rts 11866 1.1 is 11867 1.1 is # 11868 1.1 is # the ZEROes have the same signs: 11869 1.1 is # - therefore, we return +ZERO if the rounding mode is RN,RZ, or RP 11870 1.1 is # - -ZERO is returned in the case of RM. 11871 1.1 is # 11872 1.1 is fsub_zero_2_chk_rm: 11873 1.1 is mov.b 3+L_SCR3(%a6),%d1 11874 1.1 is andi.b &0x30,%d1 # extract rnd mode 11875 1.1 is cmpi.b %d1,&rm_mode*0x10 # is rnd mode = RM? 11876 1.1 is beq.b fsub_zero_2_rm # yes 11877 1.1 is fmov.s &0x00000000,%fp0 # no; return +ZERO 11878 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set Z 11879 1.1 is rts 11880 1.1 is 11881 1.1 is fsub_zero_2_rm: 11882 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO 11883 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set Z/NEG 11884 1.1 is rts 11885 1.1 is 11886 1.1 is # 11887 1.1 is # one operand is a ZERO and the other is a DENORM or a NORM. 11888 1.1 is # scale the DENORM or NORM and jump to the regular fsub routine. 11889 1.1 is # 11890 1.1 is fsub_zero_dst: 11891 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 11892 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 11893 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 11894 1.1 is bsr.l scale_to_zero_src # scale the operand 11895 1.1 is clr.w FP_SCR1_EX(%a6) 11896 1.1 is clr.l FP_SCR1_HI(%a6) 11897 1.1 is clr.l FP_SCR1_LO(%a6) 11898 1.1 is bra.w fsub_zero_entry # go execute fsub 11899 1.1 is 11900 1.1 is fsub_zero_src: 11901 1.1 is mov.w DST_EX(%a1),FP_SCR1_EX(%a6) 11902 1.1 is mov.l DST_HI(%a1),FP_SCR1_HI(%a6) 11903 1.1 is mov.l DST_LO(%a1),FP_SCR1_LO(%a6) 11904 1.1 is bsr.l scale_to_zero_dst # scale the operand 11905 1.1 is clr.w FP_SCR0_EX(%a6) 11906 1.1 is clr.l FP_SCR0_HI(%a6) 11907 1.1 is clr.l FP_SCR0_LO(%a6) 11908 1.1 is bra.w fsub_zero_entry # go execute fsub 11909 1.1 is 11910 1.1 is # 11911 1.1 is # both operands are INFs. an OPERR will result if the INFs have the 11912 1.1 is # same signs. else, 11913 1.1 is # 11914 1.1 is fsub_inf_2: 11915 1.1 is mov.b SRC_EX(%a0),%d0 # exclusive or the signs 11916 1.1 is mov.b DST_EX(%a1),%d1 11917 1.1 is eor.b %d1,%d0 11918 1.1 is bpl.l res_operr # weed out (-INF)+(+INF) 11919 1.1 is 11920 1.1 is # ok, so it's not an OPERR. but we do have to remember to return 11921 1.1 is # the src INF since that's where the 881/882 gets the j-bit. 11922 1.1 is 11923 1.1 is fsub_inf_src: 11924 1.1 is fmovm.x SRC(%a0),&0x80 # return src INF 11925 1.1 is fneg.x %fp0 # invert sign 11926 1.1 is fbge.w fsub_inf_done # sign is now positive 11927 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 11928 1.1 is rts 11929 1.1 is 11930 1.1 is fsub_inf_dst: 11931 1.1 is fmovm.x DST(%a1),&0x80 # return dst INF 11932 1.1 is tst.b DST_EX(%a1) # is INF negative? 11933 1.1 is bpl.b fsub_inf_done # no 11934 1.1 is mov.b &neg_bmask+inf_bmask,FPSR_CC(%a6) # set INF/NEG 11935 1.1 is rts 11936 1.1 is 11937 1.1 is fsub_inf_done: 11938 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set INF 11939 1.1 is rts 11940 1.1 is 11941 1.1 is ######################################################################### 11942 1.1 is # XDEF **************************************************************** # 11943 1.1 is # fsqrt(): emulates the fsqrt instruction # 11944 1.1 is # fssqrt(): emulates the fssqrt instruction # 11945 1.1 is # fdsqrt(): emulates the fdsqrt instruction # 11946 1.1 is # # 11947 1.1 is # XREF **************************************************************** # 11948 1.1 is # scale_sqrt() - scale the source operand # 11949 1.1 is # unf_res() - return default underflow result # 11950 1.1 is # ovf_res() - return default overflow result # 11951 1.1 is # res_qnan_1op() - return QNAN result # 11952 1.1 is # res_snan_1op() - return SNAN result # 11953 1.1 is # # 11954 1.1 is # INPUT *************************************************************** # 11955 1.1 is # a0 = pointer to extended precision source operand # 11956 1.1 is # d0 rnd prec,mode # 11957 1.1 is # # 11958 1.1 is # OUTPUT ************************************************************** # 11959 1.1 is # fp0 = result # 11960 1.1 is # fp1 = EXOP (if exception occurred) # 11961 1.1 is # # 11962 1.1 is # ALGORITHM *********************************************************** # 11963 1.1 is # Handle NANs, infinities, and zeroes as special cases. Divide # 11964 1.1 is # norms/denorms into ext/sgl/dbl precision. # 11965 1.1 is # For norms/denorms, scale the exponents such that a sqrt # 11966 1.1 is # instruction won't cause an exception. Use the regular fsqrt to # 11967 1.1 is # compute a result. Check if the regular operands would have taken # 11968 1.1 is # an exception. If so, return the default overflow/underflow result # 11969 1.1 is # and return the EXOP if exceptions are enabled. Else, scale the # 11970 1.1 is # result operand to the proper exponent. # 11971 1.1 is # # 11972 1.1 is ######################################################################### 11973 1.1 is 11974 1.1 is global fssqrt 11975 1.1 is fssqrt: 11976 1.1 is andi.b &0x30,%d0 # clear rnd prec 11977 1.1 is ori.b &s_mode*0x10,%d0 # insert sgl precision 11978 1.1 is bra.b fsqrt 11979 1.1 is 11980 1.1 is global fdsqrt 11981 1.1 is fdsqrt: 11982 1.1 is andi.b &0x30,%d0 # clear rnd prec 11983 1.1 is ori.b &d_mode*0x10,%d0 # insert dbl precision 11984 1.1 is 11985 1.1 is global fsqrt 11986 1.1 is fsqrt: 11987 1.1 is mov.l %d0,L_SCR3(%a6) # store rnd info 11988 1.1 is clr.w %d1 11989 1.1 is mov.b STAG(%a6),%d1 11990 1.1 is bne.w fsqrt_not_norm # optimize on non-norm input 11991 1.1 is 11992 1.1 is # 11993 1.1 is # SQUARE ROOT: norms and denorms ONLY! 11994 1.1 is # 11995 1.1 is fsqrt_norm: 11996 1.1 is tst.b SRC_EX(%a0) # is operand negative? 11997 1.1 is bmi.l res_operr # yes 11998 1.1 is 11999 1.1 is andi.b &0xc0,%d0 # is precision extended? 12000 1.1 is bne.b fsqrt_not_ext # no; go handle sgl or dbl 12001 1.1 is 12002 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 12003 1.1 is fmov.l &0x0,%fpsr # clear FPSR 12004 1.1 is 12005 1.1 is fsqrt.x (%a0),%fp0 # execute square root 12006 1.1 is 12007 1.1 is fmov.l %fpsr,%d1 12008 1.1 is or.l %d1,USER_FPSR(%a6) # set N,INEX 12009 1.1 is 12010 1.1 is rts 12011 1.1 is 12012 1.1 is fsqrt_denorm: 12013 1.1 is tst.b SRC_EX(%a0) # is operand negative? 12014 1.1 is bmi.l res_operr # yes 12015 1.1 is 12016 1.1 is andi.b &0xc0,%d0 # is precision extended? 12017 1.1 is bne.b fsqrt_not_ext # no; go handle sgl or dbl 12018 1.1 is 12019 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12020 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12021 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12022 1.1 is 12023 1.1 is bsr.l scale_sqrt # calculate scale factor 12024 1.1 is 12025 1.1 is bra.w fsqrt_sd_normal 12026 1.1 is 12027 1.1 is # 12028 1.1 is # operand is either single or double 12029 1.1 is # 12030 1.1 is fsqrt_not_ext: 12031 1.1 is cmpi.b %d0,&s_mode*0x10 # separate sgl/dbl prec 12032 1.1 is bne.w fsqrt_dbl 12033 1.1 is 12034 1.1 is # 12035 1.1 is # operand is to be rounded to single precision 12036 1.1 is # 12037 1.1 is fsqrt_sgl: 12038 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12039 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12040 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12041 1.1 is 12042 1.1 is bsr.l scale_sqrt # calculate scale factor 12043 1.1 is 12044 1.1 is cmpi.l %d0,&0x3fff-0x3f81 # will move in underflow? 12045 1.1 is beq.w fsqrt_sd_may_unfl 12046 1.1 is bgt.w fsqrt_sd_unfl # yes; go handle underflow 12047 1.1 is cmpi.l %d0,&0x3fff-0x407f # will move in overflow? 12048 1.1 is beq.w fsqrt_sd_may_ovfl # maybe; go check 12049 1.1 is blt.w fsqrt_sd_ovfl # yes; go handle overflow 12050 1.1 is 12051 1.1 is # 12052 1.1 is # operand will NOT overflow or underflow when moved in to the fp reg file 12053 1.1 is # 12054 1.1 is fsqrt_sd_normal: 12055 1.1 is fmov.l &0x0,%fpsr # clear FPSR 12056 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 12057 1.1 is 12058 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute 12059 1.1 is 12060 1.1 is fmov.l %fpsr,%d1 # save FPSR 12061 1.1 is fmov.l &0x0,%fpcr # clear FPCR 12062 1.1 is 12063 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 12064 1.1 is 12065 1.1 is fsqrt_sd_normal_exit: 12066 1.1 is mov.l %d2,-(%sp) # save d2 12067 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 12068 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load sgn,exp 12069 1.1 is mov.l %d1,%d2 # make a copy 12070 1.1 is andi.l &0x7fff,%d1 # strip sign 12071 1.1 is sub.l %d0,%d1 # add scale factor 12072 1.1 is andi.w &0x8000,%d2 # keep old sign 12073 1.1 is or.w %d1,%d2 # concat old sign,new exp 12074 1.1 is mov.w %d2,FP_SCR0_EX(%a6) # insert new exponent 12075 1.1 is mov.l (%sp)+,%d2 # restore d2 12076 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return result in fp0 12077 1.1 is rts 12078 1.1 is 12079 1.1 is # 12080 1.1 is # operand is to be rounded to double precision 12081 1.1 is # 12082 1.1 is fsqrt_dbl: 12083 1.1 is mov.w SRC_EX(%a0),FP_SCR0_EX(%a6) 12084 1.1 is mov.l SRC_HI(%a0),FP_SCR0_HI(%a6) 12085 1.1 is mov.l SRC_LO(%a0),FP_SCR0_LO(%a6) 12086 1.1 is 12087 1.1 is bsr.l scale_sqrt # calculate scale factor 12088 1.1 is 12089 1.1 is cmpi.l %d0,&0x3fff-0x3c01 # will move in underflow? 12090 1.1 is beq.w fsqrt_sd_may_unfl 12091 1.1 is bgt.b fsqrt_sd_unfl # yes; go handle underflow 12092 1.1 is cmpi.l %d0,&0x3fff-0x43ff # will move in overflow? 12093 1.1 is beq.w fsqrt_sd_may_ovfl # maybe; go check 12094 1.1 is blt.w fsqrt_sd_ovfl # yes; go handle overflow 12095 1.1 is bra.w fsqrt_sd_normal # no; ho handle normalized op 12096 1.1 is 12097 1.1 is # we're on the line here and the distinguising characteristic is whether 12098 1.1 is # the exponent is 3fff or 3ffe. if it's 3ffe, then it's a safe number 12099 1.1 is # elsewise fall through to underflow. 12100 1.1 is fsqrt_sd_may_unfl: 12101 1.1 is btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff? 12102 1.1 is bne.w fsqrt_sd_normal # yes, so no underflow 12103 1.1 is 12104 1.1 is # 12105 1.1 is # operand WILL underflow when moved in to the fp register file 12106 1.1 is # 12107 1.1 is fsqrt_sd_unfl: 12108 1.1 is bset &unfl_bit,FPSR_EXCEPT(%a6) # set unfl exc bit 12109 1.1 is 12110 1.1 is fmov.l &rz_mode*0x10,%fpcr # set FPCR 12111 1.1 is fmov.l &0x0,%fpsr # clear FPSR 12112 1.1 is 12113 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # execute square root 12114 1.1 is 12115 1.1 is fmov.l %fpsr,%d1 # save status 12116 1.1 is fmov.l &0x0,%fpcr # clear FPCR 12117 1.1 is 12118 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 12119 1.1 is 12120 1.1 is # if underflow or inexact is enabled, go calculate EXOP first. 12121 1.1 is mov.b FPCR_ENABLE(%a6),%d1 12122 1.1 is andi.b &0x0b,%d1 # is UNFL or INEX enabled? 12123 1.1 is bne.b fsqrt_sd_unfl_ena # yes 12124 1.1 is 12125 1.1 is fsqrt_sd_unfl_dis: 12126 1.1 is fmovm.x &0x80,FP_SCR0(%a6) # store out result 12127 1.1 is 12128 1.1 is lea FP_SCR0(%a6),%a0 # pass: result addr 12129 1.1 is mov.l L_SCR3(%a6),%d1 # pass: rnd prec,mode 12130 1.1 is bsr.l unf_res # calculate default result 12131 1.1 is or.b %d0,FPSR_CC(%a6) # set possible 'Z' ccode 12132 1.1 is fmovm.x FP_SCR0(%a6),&0x80 # return default result in fp0 12133 1.1 is rts 12134 1.1 is 12135 1.1 is # 12136 1.1 is # operand will underflow AND underflow is enabled. 12137 1.1 is # therefore, we must return the result rounded to extended precision. 12138 1.1 is # 12139 1.1 is fsqrt_sd_unfl_ena: 12140 1.1 is mov.l FP_SCR0_HI(%a6),FP_SCR1_HI(%a6) 12141 1.1 is mov.l FP_SCR0_LO(%a6),FP_SCR1_LO(%a6) 12142 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # load current exponent 12143 1.1 is 12144 1.1 is mov.l %d2,-(%sp) # save d2 12145 1.1 is mov.l %d1,%d2 # make a copy 12146 1.1 is andi.l &0x7fff,%d1 # strip sign 12147 1.1 is andi.w &0x8000,%d2 # keep old sign 12148 1.1 is sub.l %d0,%d1 # subtract scale factor 12149 1.1 is addi.l &0x6000,%d1 # add new bias 12150 1.1 is andi.w &0x7fff,%d1 12151 1.1 is or.w %d2,%d1 # concat new sign,new exp 12152 1.1 is mov.w %d1,FP_SCR1_EX(%a6) # insert new exp 12153 1.1 is fmovm.x FP_SCR1(%a6),&0x40 # return EXOP in fp1 12154 1.1 is mov.l (%sp)+,%d2 # restore d2 12155 1.1 is bra.b fsqrt_sd_unfl_dis 12156 1.1 is 12157 1.1 is # 12158 1.1 is # operand WILL overflow. 12159 1.1 is # 12160 1.1 is fsqrt_sd_ovfl: 12161 1.1 is fmov.l &0x0,%fpsr # clear FPSR 12162 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 12163 1.1 is 12164 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # perform square root 12165 1.1 is 12166 1.1 is fmov.l &0x0,%fpcr # clear FPCR 12167 1.1 is fmov.l %fpsr,%d1 # save FPSR 12168 1.1 is 12169 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 12170 1.1 is 12171 1.1 is fsqrt_sd_ovfl_tst: 12172 1.1 is or.l &ovfl_inx_mask,USER_FPSR(%a6) # set ovfl/aovfl/ainex 12173 1.1 is 12174 1.1 is mov.b FPCR_ENABLE(%a6),%d1 12175 1.1 is andi.b &0x13,%d1 # is OVFL or INEX enabled? 12176 1.1 is bne.b fsqrt_sd_ovfl_ena # yes 12177 1.1 is 12178 1.1 is # 12179 1.1 is # OVFL is not enabled; therefore, we must create the default result by 12180 1.1 is # calling ovf_res(). 12181 1.1 is # 12182 1.1 is fsqrt_sd_ovfl_dis: 12183 1.1 is btst &neg_bit,FPSR_CC(%a6) # is result negative? 12184 1.1 is sne %d1 # set sign param accordingly 12185 1.1 is mov.l L_SCR3(%a6),%d0 # pass: prec,mode 12186 1.1 is bsr.l ovf_res # calculate default result 12187 1.1 is or.b %d0,FPSR_CC(%a6) # set INF,N if applicable 12188 1.1 is fmovm.x (%a0),&0x80 # return default result in fp0 12189 1.1 is rts 12190 1.1 is 12191 1.1 is # 12192 1.1 is # OVFL is enabled. 12193 1.1 is # the INEX2 bit has already been updated by the round to the correct precision. 12194 1.1 is # now, round to extended(and don't alter the FPSR). 12195 1.1 is # 12196 1.1 is fsqrt_sd_ovfl_ena: 12197 1.1 is mov.l %d2,-(%sp) # save d2 12198 1.1 is mov.w FP_SCR0_EX(%a6),%d1 # fetch {sgn,exp} 12199 1.1 is mov.l %d1,%d2 # make a copy 12200 1.1 is andi.l &0x7fff,%d1 # strip sign 12201 1.1 is andi.w &0x8000,%d2 # keep old sign 12202 1.1 is sub.l %d0,%d1 # add scale factor 12203 1.1 is subi.l &0x6000,%d1 # subtract bias 12204 1.1 is andi.w &0x7fff,%d1 12205 1.1 is or.w %d2,%d1 # concat sign,exp 12206 1.1 is mov.w %d1,FP_SCR0_EX(%a6) # insert new exponent 12207 1.1 is fmovm.x FP_SCR0(%a6),&0x40 # return EXOP in fp1 12208 1.1 is mov.l (%sp)+,%d2 # restore d2 12209 1.1 is bra.b fsqrt_sd_ovfl_dis 12210 1.1 is 12211 1.1 is # 12212 1.1 is # the move in MAY underflow. so... 12213 1.1 is # 12214 1.1 is fsqrt_sd_may_ovfl: 12215 1.1 is btst &0x0,1+FP_SCR0_EX(%a6) # is exponent 0x3fff? 12216 1.1 is bne.w fsqrt_sd_ovfl # yes, so overflow 12217 1.1 is 12218 1.1 is fmov.l &0x0,%fpsr # clear FPSR 12219 1.1 is fmov.l L_SCR3(%a6),%fpcr # set FPCR 12220 1.1 is 12221 1.1 is fsqrt.x FP_SCR0(%a6),%fp0 # perform absolute 12222 1.1 is 12223 1.1 is fmov.l %fpsr,%d1 # save status 12224 1.1 is fmov.l &0x0,%fpcr # clear FPCR 12225 1.1 is 12226 1.1 is or.l %d1,USER_FPSR(%a6) # save INEX2,N 12227 1.1 is 12228 1.1 is fmov.x %fp0,%fp1 # make a copy of result 12229 1.1 is fcmp.b %fp1,&0x1 # is |result| >= 1.b? 12230 1.1 is fbge.w fsqrt_sd_ovfl_tst # yes; overflow has occurred 12231 1.1 is 12232 1.1 is # no, it didn't overflow; we have correct result 12233 1.1 is bra.w fsqrt_sd_normal_exit 12234 1.1 is 12235 1.1 is ########################################################################## 12236 1.1 is 12237 1.1 is # 12238 1.1 is # input is not normalized; what is it? 12239 1.1 is # 12240 1.1 is fsqrt_not_norm: 12241 1.1 is cmpi.b %d1,&DENORM # weed out DENORM 12242 1.1 is beq.w fsqrt_denorm 12243 1.1 is cmpi.b %d1,&ZERO # weed out ZERO 12244 1.1 is beq.b fsqrt_zero 12245 1.1 is cmpi.b %d1,&INF # weed out INF 12246 1.1 is beq.b fsqrt_inf 12247 1.1 is cmpi.b %d1,&SNAN # weed out SNAN 12248 1.1 is beq.l res_snan_1op 12249 1.1 is bra.l res_qnan_1op 12250 1.1 is 12251 1.1 is # 12252 1.1 is # fsqrt(+0) = +0 12253 1.1 is # fsqrt(-0) = -0 12254 1.1 is # fsqrt(+INF) = +INF 12255 1.1 is # fsqrt(-INF) = OPERR 12256 1.1 is # 12257 1.1 is fsqrt_zero: 12258 1.1 is tst.b SRC_EX(%a0) # is ZERO positive or negative? 12259 1.1 is bmi.b fsqrt_zero_m # negative 12260 1.1 is fsqrt_zero_p: 12261 1.1 is fmov.s &0x00000000,%fp0 # return +ZERO 12262 1.1 is mov.b &z_bmask,FPSR_CC(%a6) # set 'Z' ccode bit 12263 1.1 is rts 12264 1.1 is fsqrt_zero_m: 12265 1.1 is fmov.s &0x80000000,%fp0 # return -ZERO 12266 1.1 is mov.b &z_bmask+neg_bmask,FPSR_CC(%a6) # set 'Z','N' ccode bits 12267 1.1 is rts 12268 1.1 is 12269 1.1 is fsqrt_inf: 12270 1.1 is tst.b SRC_EX(%a0) # is INF positive or negative? 12271 1.1 is bmi.l res_operr # negative 12272 1.1 is fsqrt_inf_p: 12273 1.1 is fmovm.x SRC(%a0),&0x80 # return +INF in fp0 12274 1.1 is mov.b &inf_bmask,FPSR_CC(%a6) # set 'I' ccode bit 12275 1.1 is rts 12276 1.1 is 12277 1.1 is ######################################################################### 12278 1.1 is # XDEF **************************************************************** # 12279 1.1 is # fetch_dreg(): fetch register according to index in d1 # 12280 1.1 is # # 12281 1.1 is # XREF **************************************************************** # 12282 1.1 is # None # 12283 1.1 is # # 12284 1.1 is # INPUT *************************************************************** # 12285 1.1 is # d1 = index of register to fetch from # 12286 1.1 is # # 12287 1.1 is # OUTPUT ************************************************************** # 12288 1.1 is # d0 = value of register fetched # 12289 1.1 is # # 12290 1.1 is # ALGORITHM *********************************************************** # 12291 1.1 is # According to the index value in d1 which can range from zero # 12292 1.1 is # to fifteen, load the corresponding register file value (where # 12293 1.1 is # address register indexes start at 8). D0/D1/A0/A1/A6/A7 are on the # 12294 1.1 is # stack. The rest should still be in their original places. # 12295 1.1 is # # 12296 1.1 is ######################################################################### 12297 1.1 is 12298 1.1 is # this routine leaves d1 intact for subsequent store_dreg calls. 12299 1.1 is global fetch_dreg 12300 1.1 is fetch_dreg: 12301 1.1 is mov.w (tbl_fdreg.b,%pc,%d1.w*2),%d0 12302 1.1 is jmp (tbl_fdreg.b,%pc,%d0.w*1) 12303 1.1 is 12304 1.1 is tbl_fdreg: 12305 1.1 is short fdreg0 - tbl_fdreg 12306 1.1 is short fdreg1 - tbl_fdreg 12307 1.1 is short fdreg2 - tbl_fdreg 12308 1.1 is short fdreg3 - tbl_fdreg 12309 1.1 is short fdreg4 - tbl_fdreg 12310 1.1 is short fdreg5 - tbl_fdreg 12311 1.1 is short fdreg6 - tbl_fdreg 12312 1.1 is short fdreg7 - tbl_fdreg 12313 1.1 is short fdreg8 - tbl_fdreg 12314 1.1 is short fdreg9 - tbl_fdreg 12315 1.1 is short fdrega - tbl_fdreg 12316 1.1 is short fdregb - tbl_fdreg 12317 1.1 is short fdregc - tbl_fdreg 12318 1.1 is short fdregd - tbl_fdreg 12319 1.1 is short fdrege - tbl_fdreg 12320 1.1 is short fdregf - tbl_fdreg 12321 1.1 is 12322 1.1 is fdreg0: 12323 1.1 is mov.l EXC_DREGS+0x0(%a6),%d0 12324 1.1 is rts 12325 1.1 is fdreg1: 12326 1.1 is mov.l EXC_DREGS+0x4(%a6),%d0 12327 1.1 is rts 12328 1.1 is fdreg2: 12329 1.1 is mov.l %d2,%d0 12330 1.1 is rts 12331 1.1 is fdreg3: 12332 1.1 is mov.l %d3,%d0 12333 1.1 is rts 12334 1.1 is fdreg4: 12335 1.1 is mov.l %d4,%d0 12336 1.1 is rts 12337 1.1 is fdreg5: 12338 1.1 is mov.l %d5,%d0 12339 1.1 is rts 12340 1.1 is fdreg6: 12341 1.1 is mov.l %d6,%d0 12342 1.1 is rts 12343 1.1 is fdreg7: 12344 1.1 is mov.l %d7,%d0 12345 1.1 is rts 12346 1.1 is fdreg8: 12347 1.1 is mov.l EXC_DREGS+0x8(%a6),%d0 12348 1.1 is rts 12349 1.1 is fdreg9: 12350 1.1 is mov.l EXC_DREGS+0xc(%a6),%d0 12351 1.1 is rts 12352 1.1 is fdrega: 12353 1.1 is mov.l %a2,%d0 12354 1.1 is rts 12355 1.1 is fdregb: 12356 1.1 is mov.l %a3,%d0 12357 1.1 is rts 12358 1.1 is fdregc: 12359 1.1 is mov.l %a4,%d0 12360 1.1 is rts 12361 1.1 is fdregd: 12362 1.1 is mov.l %a5,%d0 12363 1.1 is rts 12364 1.1 is fdrege: 12365 1.1 is mov.l (%a6),%d0 12366 1.1 is rts 12367 1.1 is fdregf: 12368 1.1 is mov.l EXC_A7(%a6),%d0 12369 1.1 is rts 12370 1.1 is 12371 1.1 is ######################################################################### 12372 1.1 is # XDEF **************************************************************** # 12373 1.1 is # store_dreg_l(): store longword to data register specified by d1 # 12374 1.1 is # # 12375 1.1 is # XREF **************************************************************** # 12376 1.1 is # None # 12377 1.1 is # # 12378 1.1 is # INPUT *************************************************************** # 12379 1.1 is # d0 = longowrd value to store # 12380 1.1 is # d1 = index of register to fetch from # 12381 1.1 is # # 12382 1.1 is # OUTPUT ************************************************************** # 12383 1.1 is # (data register is updated) # 12384 1.1 is # # 12385 1.1 is # ALGORITHM *********************************************************** # 12386 1.1 is # According to the index value in d1, store the longword value # 12387 1.1 is # in d0 to the corresponding data register. D0/D1 are on the stack # 12388 1.1 is # while the rest are in their initial places. # 12389 1.1 is # # 12390 1.1 is ######################################################################### 12391 1.1 is 12392 1.1 is global store_dreg_l 12393 1.1 is store_dreg_l: 12394 1.1 is mov.w (tbl_sdregl.b,%pc,%d1.w*2),%d1 12395 1.1 is jmp (tbl_sdregl.b,%pc,%d1.w*1) 12396 1.1 is 12397 1.1 is tbl_sdregl: 12398 1.1 is short sdregl0 - tbl_sdregl 12399 1.1 is short sdregl1 - tbl_sdregl 12400 1.1 is short sdregl2 - tbl_sdregl 12401 1.1 is short sdregl3 - tbl_sdregl 12402 1.1 is short sdregl4 - tbl_sdregl 12403 1.1 is short sdregl5 - tbl_sdregl 12404 1.1 is short sdregl6 - tbl_sdregl 12405 1.1 is short sdregl7 - tbl_sdregl 12406 1.1 is 12407 1.1 is sdregl0: 12408 1.1 is mov.l %d0,EXC_DREGS+0x0(%a6) 12409 1.1 is rts 12410 1.1 is sdregl1: 12411 1.1 is mov.l %d0,EXC_DREGS+0x4(%a6) 12412 1.1 is rts 12413 1.1 is sdregl2: 12414 1.1 is mov.l %d0,%d2 12415 1.1 is rts 12416 1.1 is sdregl3: 12417 1.1 is mov.l %d0,%d3 12418 1.1 is rts 12419 1.1 is sdregl4: 12420 1.1 is mov.l %d0,%d4 12421 1.1 is rts 12422 1.1 is sdregl5: 12423 1.1 is mov.l %d0,%d5 12424 1.1 is rts 12425 1.1 is sdregl6: 12426 1.1 is mov.l %d0,%d6 12427 1.1 is rts 12428 1.1 is sdregl7: 12429 1.1 is mov.l %d0,%d7 12430 1.1 is rts 12431 1.1 is 12432 1.1 is ######################################################################### 12433 1.1 is # XDEF **************************************************************** # 12434 1.1 is # store_dreg_w(): store word to data register specified by d1 # 12435 1.1 is # # 12436 1.1 is # XREF **************************************************************** # 12437 1.1 is # None # 12438 1.1 is # # 12439 1.1 is # INPUT *************************************************************** # 12440 1.1 is # d0 = word value to store # 12441 1.1 is # d1 = index of register to fetch from # 12442 1.1 is # # 12443 1.1 is # OUTPUT ************************************************************** # 12444 1.1 is # (data register is updated) # 12445 1.1 is # # 12446 1.1 is # ALGORITHM *********************************************************** # 12447 1.1 is # According to the index value in d1, store the word value # 12448 1.1 is # in d0 to the corresponding data register. D0/D1 are on the stack # 12449 1.1 is # while the rest are in their initial places. # 12450 1.1 is # # 12451 1.1 is ######################################################################### 12452 1.1 is 12453 1.1 is global store_dreg_w 12454 1.1 is store_dreg_w: 12455 1.1 is mov.w (tbl_sdregw.b,%pc,%d1.w*2),%d1 12456 1.1 is jmp (tbl_sdregw.b,%pc,%d1.w*1) 12457 1.1 is 12458 1.1 is tbl_sdregw: 12459 1.1 is short sdregw0 - tbl_sdregw 12460 1.1 is short sdregw1 - tbl_sdregw 12461 1.1 is short sdregw2 - tbl_sdregw 12462 1.1 is short sdregw3 - tbl_sdregw 12463 1.1 is short sdregw4 - tbl_sdregw 12464 1.1 is short sdregw5 - tbl_sdregw 12465 1.1 is short sdregw6 - tbl_sdregw 12466 1.1 is short sdregw7 - tbl_sdregw 12467 1.1 is 12468 1.1 is sdregw0: 12469 1.1 is mov.w %d0,2+EXC_DREGS+0x0(%a6) 12470 1.1 is rts 12471 1.1 is sdregw1: 12472 1.1 is mov.w %d0,2+EXC_DREGS+0x4(%a6) 12473 1.1 is rts 12474 1.1 is sdregw2: 12475 1.1 is mov.w %d0,%d2 12476 1.1 is rts 12477 1.1 is sdregw3: 12478 1.1 is mov.w %d0,%d3 12479 1.1 is rts 12480 1.1 is sdregw4: 12481 1.1 is mov.w %d0,%d4 12482 1.1 is rts 12483 1.1 is sdregw5: 12484 1.1 is mov.w %d0,%d5 12485 1.1 is rts 12486 1.1 is sdregw6: 12487 1.1 is mov.w %d0,%d6 12488 1.1 is rts 12489 1.1 is sdregw7: 12490 1.1 is mov.w %d0,%d7 12491 1.1 is rts 12492 1.1 is 12493 1.1 is ######################################################################### 12494 1.1 is # XDEF **************************************************************** # 12495 1.1 is # store_dreg_b(): store byte to data register specified by d1 # 12496 1.1 is # # 12497 1.1 is # XREF **************************************************************** # 12498 1.1 is # None # 12499 1.1 is # # 12500 1.1 is # INPUT *************************************************************** # 12501 1.1 is # d0 = byte value to store # 12502 1.1 is # d1 = index of register to fetch from # 12503 1.1 is # # 12504 1.1 is # OUTPUT ************************************************************** # 12505 1.1 is # (data register is updated) # 12506 1.1 is # # 12507 1.1 is # ALGORITHM *********************************************************** # 12508 1.1 is # According to the index value in d1, store the byte value # 12509 1.1 is # in d0 to the corresponding data register. D0/D1 are on the stack # 12510 1.1 is # while the rest are in their initial places. # 12511 1.1 is # # 12512 1.1 is ######################################################################### 12513 1.1 is 12514 1.1 is global store_dreg_b 12515 1.1 is store_dreg_b: 12516 1.1 is mov.w (tbl_sdregb.b,%pc,%d1.w*2),%d1 12517 1.1 is jmp (tbl_sdregb.b,%pc,%d1.w*1) 12518 1.1 is 12519 1.1 is tbl_sdregb: 12520 1.1 is short sdregb0 - tbl_sdregb 12521 1.1 is short sdregb1 - tbl_sdregb 12522 1.1 is short sdregb2 - tbl_sdregb 12523 1.1 is short sdregb3 - tbl_sdregb 12524 1.1 is short sdregb4 - tbl_sdregb 12525 1.1 is short sdregb5 - tbl_sdregb 12526 1.1 is short sdregb6 - tbl_sdregb 12527 1.1 is short sdregb7 - tbl_sdregb 12528 1.1 is 12529 1.1 is sdregb0: 12530 1.1 is mov.b %d0,3+EXC_DREGS+0x0(%a6) 12531 1.1 is rts 12532 1.1 is sdregb1: 12533 1.1 is mov.b %d0,3+EXC_DREGS+0x4(%a6) 12534 1.1 is rts 12535 1.1 is sdregb2: 12536 1.1 is mov.b %d0,%d2 12537 1.1 is rts 12538 1.1 is sdregb3: 12539 1.1 is mov.b %d0,%d3 12540 1.1 is rts 12541 1.1 is sdregb4: 12542 1.1 is mov.b %d0,%d4 12543 1.1 is rts 12544 1.1 is sdregb5: 12545 1.1 is mov.b %d0,%d5 12546 1.1 is rts 12547 1.1 is sdregb6: 12548 1.1 is mov.b %d0,%d6 12549 1.1 is rts 12550 1.1 is sdregb7: 12551 1.1 is mov.b %d0,%d7 12552 1.1 is rts 12553 1.1 is 12554 1.1 is ######################################################################### 12555 1.1 is # XDEF **************************************************************** # 12556 1.1 is # inc_areg(): increment an address register by the value in d0 # 12557 1.1 is # # 12558 1.1 is # XREF **************************************************************** # 12559 1.1 is # None # 12560 1.1 is # # 12561 1.1 is # INPUT *************************************************************** # 12562 1.1 is # d0 = amount to increment by # 12563 1.1 is # d1 = index of address register to increment # 12564 1.1 is # # 12565 1.1 is # OUTPUT ************************************************************** # 12566 1.1 is # (address register is updated) # 12567 1.1 is # # 12568 1.1 is # ALGORITHM *********************************************************** # 12569 1.1 is # Typically used for an instruction w/ a post-increment <ea>, # 12570 1.1 is # this routine adds the increment value in d0 to the address register # 12571 1.1 is # specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside # 12572 1.1 is # in their original places. # 12573 1.1 is # For a7, if the increment amount is one, then we have to # 12574 1.1 is # increment by two. For any a7 update, set the mia7_flag so that if # 12575 1.1 is # an access error exception occurs later in emulation, this address # 12576 1.1 is # register update can be undone. # 12577 1.1 is # # 12578 1.1 is ######################################################################### 12579 1.1 is 12580 1.1 is global inc_areg 12581 1.1 is inc_areg: 12582 1.1 is mov.w (tbl_iareg.b,%pc,%d1.w*2),%d1 12583 1.1 is jmp (tbl_iareg.b,%pc,%d1.w*1) 12584 1.1 is 12585 1.1 is tbl_iareg: 12586 1.1 is short iareg0 - tbl_iareg 12587 1.1 is short iareg1 - tbl_iareg 12588 1.1 is short iareg2 - tbl_iareg 12589 1.1 is short iareg3 - tbl_iareg 12590 1.1 is short iareg4 - tbl_iareg 12591 1.1 is short iareg5 - tbl_iareg 12592 1.1 is short iareg6 - tbl_iareg 12593 1.1 is short iareg7 - tbl_iareg 12594 1.1 is 12595 1.1 is iareg0: add.l %d0,EXC_DREGS+0x8(%a6) 12596 1.1 is rts 12597 1.1 is iareg1: add.l %d0,EXC_DREGS+0xc(%a6) 12598 1.1 is rts 12599 1.1 is iareg2: add.l %d0,%a2 12600 1.1 is rts 12601 1.1 is iareg3: add.l %d0,%a3 12602 1.1 is rts 12603 1.1 is iareg4: add.l %d0,%a4 12604 1.1 is rts 12605 1.1 is iareg5: add.l %d0,%a5 12606 1.1 is rts 12607 1.1 is iareg6: add.l %d0,(%a6) 12608 1.1 is rts 12609 1.1 is iareg7: mov.b &mia7_flg,SPCOND_FLG(%a6) 12610 1.1 is cmpi.b %d0,&0x1 12611 1.1 is beq.b iareg7b 12612 1.1 is add.l %d0,EXC_A7(%a6) 12613 1.1 is rts 12614 1.1 is iareg7b: 12615 1.1 is addq.l &0x2,EXC_A7(%a6) 12616 1.1 is rts 12617 1.1 is 12618 1.1 is ######################################################################### 12619 1.1 is # XDEF **************************************************************** # 12620 1.1 is # dec_areg(): decrement an address register by the value in d0 # 12621 1.1 is # # 12622 1.1 is # XREF **************************************************************** # 12623 1.1 is # None # 12624 1.1 is # # 12625 1.1 is # INPUT *************************************************************** # 12626 1.1 is # d0 = amount to decrement by # 12627 1.1 is # d1 = index of address register to decrement # 12628 1.1 is # # 12629 1.1 is # OUTPUT ************************************************************** # 12630 1.1 is # (address register is updated) # 12631 1.1 is # # 12632 1.1 is # ALGORITHM *********************************************************** # 12633 1.1 is # Typically used for an instruction w/ a pre-decrement <ea>, # 12634 1.1 is # this routine adds the decrement value in d0 to the address register # 12635 1.1 is # specified by d1. A0/A1/A6/A7 reside on the stack. The rest reside # 12636 1.1 is # in their original places. # 12637 1.1 is # For a7, if the decrement amount is one, then we have to # 12638 1.1 is # decrement by two. For any a7 update, set the mda7_flag so that if # 12639 1.1 is # an access error exception occurs later in emulation, this address # 12640 1.1 is # register update can be undone. # 12641 1.1 is # # 12642 1.1 is ######################################################################### 12643 1.1 is 12644 1.1 is global dec_areg 12645 1.1 is dec_areg: 12646 1.1 is mov.w (tbl_dareg.b,%pc,%d1.w*2),%d1 12647 1.1 is jmp (tbl_dareg.b,%pc,%d1.w*1) 12648 1.1 is 12649 1.1 is tbl_dareg: 12650 1.1 is short dareg0 - tbl_dareg 12651 1.1 is short dareg1 - tbl_dareg 12652 1.1 is short dareg2 - tbl_dareg 12653 1.1 is short dareg3 - tbl_dareg 12654 1.1 is short dareg4 - tbl_dareg 12655 1.1 is short dareg5 - tbl_dareg 12656 1.1 is short dareg6 - tbl_dareg 12657 1.1 is short dareg7 - tbl_dareg 12658 1.1 is 12659 1.1 is dareg0: sub.l %d0,EXC_DREGS+0x8(%a6) 12660 1.1 is rts 12661 1.1 is dareg1: sub.l %d0,EXC_DREGS+0xc(%a6) 12662 1.1 is rts 12663 1.1 is dareg2: sub.l %d0,%a2 12664 1.1 is rts 12665 1.1 is dareg3: sub.l %d0,%a3 12666 1.1 is rts 12667 1.1 is dareg4: sub.l %d0,%a4 12668 1.1 is rts 12669 1.1 is dareg5: sub.l %d0,%a5 12670 1.1 is rts 12671 1.1 is dareg6: sub.l %d0,(%a6) 12672 1.1 is rts 12673 1.1 is dareg7: mov.b &mda7_flg,SPCOND_FLG(%a6) 12674 1.1 is cmpi.b %d0,&0x1 12675 1.1 is beq.b dareg7b 12676 1.1 is sub.l %d0,EXC_A7(%a6) 12677 1.1 is rts 12678 1.1 is dareg7b: 12679 1.1 is subq.l &0x2,EXC_A7(%a6) 12680 1.1 is rts 12681 1.1 is 12682 1.1 is ############################################################################## 12683 1.1 is 12684 1.1 is ######################################################################### 12685 1.1 is # XDEF **************************************************************** # 12686 1.1 is # load_fpn1(): load FP register value into FP_SRC(a6). # 12687 1.1 is # # 12688 1.1 is # XREF **************************************************************** # 12689 1.1 is # None # 12690 1.1 is # # 12691 1.1 is # INPUT *************************************************************** # 12692 1.1 is # d0 = index of FP register to load # 12693 1.1 is # # 12694 1.1 is # OUTPUT ************************************************************** # 12695 1.1 is # FP_SRC(a6) = value loaded from FP register file # 12696 1.1 is # # 12697 1.1 is # ALGORITHM *********************************************************** # 12698 1.1 is # Using the index in d0, load FP_SRC(a6) with a number from the # 12699 1.1 is # FP register file. # 12700 1.1 is # # 12701 1.1 is ######################################################################### 12702 1.1 is 12703 1.1 is global load_fpn1 12704 1.1 is load_fpn1: 12705 1.1 is mov.w (tbl_load_fpn1.b,%pc,%d0.w*2), %d0 12706 1.1 is jmp (tbl_load_fpn1.b,%pc,%d0.w*1) 12707 1.1 is 12708 1.1 is tbl_load_fpn1: 12709 1.1 is short load_fpn1_0 - tbl_load_fpn1 12710 1.1 is short load_fpn1_1 - tbl_load_fpn1 12711 1.1 is short load_fpn1_2 - tbl_load_fpn1 12712 1.1 is short load_fpn1_3 - tbl_load_fpn1 12713 1.1 is short load_fpn1_4 - tbl_load_fpn1 12714 1.1 is short load_fpn1_5 - tbl_load_fpn1 12715 1.1 is short load_fpn1_6 - tbl_load_fpn1 12716 1.1 is short load_fpn1_7 - tbl_load_fpn1 12717 1.1 is 12718 1.1 is load_fpn1_0: 12719 1.1 is mov.l 0+EXC_FP0(%a6), 0+FP_SRC(%a6) 12720 1.1 is mov.l 4+EXC_FP0(%a6), 4+FP_SRC(%a6) 12721 1.1 is mov.l 8+EXC_FP0(%a6), 8+FP_SRC(%a6) 12722 1.1 is lea FP_SRC(%a6), %a0 12723 1.1 is rts 12724 1.1 is load_fpn1_1: 12725 1.1 is mov.l 0+EXC_FP1(%a6), 0+FP_SRC(%a6) 12726 1.1 is mov.l 4+EXC_FP1(%a6), 4+FP_SRC(%a6) 12727 1.1 is mov.l 8+EXC_FP1(%a6), 8+FP_SRC(%a6) 12728 1.1 is lea FP_SRC(%a6), %a0 12729 1.1 is rts 12730 1.1 is load_fpn1_2: 12731 1.1 is fmovm.x &0x20, FP_SRC(%a6) 12732 1.1 is lea FP_SRC(%a6), %a0 12733 1.1 is rts 12734 1.1 is load_fpn1_3: 12735 1.1 is fmovm.x &0x10, FP_SRC(%a6) 12736 1.1 is lea FP_SRC(%a6), %a0 12737 1.1 is rts 12738 1.1 is load_fpn1_4: 12739 1.1 is fmovm.x &0x08, FP_SRC(%a6) 12740 1.1 is lea FP_SRC(%a6), %a0 12741 1.1 is rts 12742 1.1 is load_fpn1_5: 12743 1.1 is fmovm.x &0x04, FP_SRC(%a6) 12744 1.1 is lea FP_SRC(%a6), %a0 12745 1.1 is rts 12746 1.1 is load_fpn1_6: 12747 1.1 is fmovm.x &0x02, FP_SRC(%a6) 12748 1.1 is lea FP_SRC(%a6), %a0 12749 1.1 is rts 12750 1.1 is load_fpn1_7: 12751 1.1 is fmovm.x &0x01, FP_SRC(%a6) 12752 1.1 is lea FP_SRC(%a6), %a0 12753 1.1 is rts 12754 1.1 is 12755 1.1 is ############################################################################# 12756 1.1 is 12757 1.1 is ######################################################################### 12758 1.1 is # XDEF **************************************************************** # 12759 1.1 is # load_fpn2(): load FP register value into FP_DST(a6). # 12760 1.1 is # # 12761 1.1 is # XREF **************************************************************** # 12762 1.1 is # None # 12763 1.1 is # # 12764 1.1 is # INPUT *************************************************************** # 12765 1.1 is # d0 = index of FP register to load # 12766 1.1 is # # 12767 1.1 is # OUTPUT ************************************************************** # 12768 1.1 is # FP_DST(a6) = value loaded from FP register file # 12769 1.1 is # # 12770 1.1 is # ALGORITHM *********************************************************** # 12771 1.1 is # Using the index in d0, load FP_DST(a6) with a number from the # 12772 1.1 is # FP register file. # 12773 1.1 is # # 12774 1.1 is ######################################################################### 12775 1.1 is 12776 1.1 is global load_fpn2 12777 1.1 is load_fpn2: 12778 1.1 is mov.w (tbl_load_fpn2.b,%pc,%d0.w*2), %d0 12779 1.1 is jmp (tbl_load_fpn2.b,%pc,%d0.w*1) 12780 1.1 is 12781 1.1 is tbl_load_fpn2: 12782 1.1 is short load_fpn2_0 - tbl_load_fpn2 12783 1.1 is short load_fpn2_1 - tbl_load_fpn2 12784 1.1 is short load_fpn2_2 - tbl_load_fpn2 12785 1.1 is short load_fpn2_3 - tbl_load_fpn2 12786 1.1 is short load_fpn2_4 - tbl_load_fpn2 12787 1.1 is short load_fpn2_5 - tbl_load_fpn2 12788 1.1 is short load_fpn2_6 - tbl_load_fpn2 12789 1.1 is short load_fpn2_7 - tbl_load_fpn2 12790 1.1 is 12791 1.1 is load_fpn2_0: 12792 1.1 is mov.l 0+EXC_FP0(%a6), 0+FP_DST(%a6) 12793 1.1 is mov.l 4+EXC_FP0(%a6), 4+FP_DST(%a6) 12794 1.1 is mov.l 8+EXC_FP0(%a6), 8+FP_DST(%a6) 12795 1.1 is lea FP_DST(%a6), %a0 12796 1.1 is rts 12797 1.1 is load_fpn2_1: 12798 1.1 is mov.l 0+EXC_FP1(%a6), 0+FP_DST(%a6) 12799 1.1 is mov.l 4+EXC_FP1(%a6), 4+FP_DST(%a6) 12800 1.1 is mov.l 8+EXC_FP1(%a6), 8+FP_DST(%a6) 12801 1.1 is lea FP_DST(%a6), %a0 12802 1.1 is rts 12803 1.1 is load_fpn2_2: 12804 1.1 is fmovm.x &0x20, FP_DST(%a6) 12805 1.1 is lea FP_DST(%a6), %a0 12806 1.1 is rts 12807 1.1 is load_fpn2_3: 12808 1.1 is fmovm.x &0x10, FP_DST(%a6) 12809 1.1 is lea FP_DST(%a6), %a0 12810 1.1 is rts 12811 1.1 is load_fpn2_4: 12812 1.1 is fmovm.x &0x08, FP_DST(%a6) 12813 1.1 is lea FP_DST(%a6), %a0 12814 1.1 is rts 12815 1.1 is load_fpn2_5: 12816 1.1 is fmovm.x &0x04, FP_DST(%a6) 12817 1.1 is lea FP_DST(%a6), %a0 12818 1.1 is rts 12819 1.1 is load_fpn2_6: 12820 1.1 is fmovm.x &0x02, FP_DST(%a6) 12821 1.1 is lea FP_DST(%a6), %a0 12822 1.1 is rts 12823 1.1 is load_fpn2_7: 12824 1.1 is fmovm.x &0x01, FP_DST(%a6) 12825 1.1 is lea FP_DST(%a6), %a0 12826 1.1 is rts 12827 1.1 is 12828 1.1 is ############################################################################# 12829 1.1 is 12830 1.1 is ######################################################################### 12831 1.1 is # XDEF **************************************************************** # 12832 1.1 is # store_fpreg(): store an fp value to the fpreg designated d0. # 12833 1.1 is # # 12834 1.1 is # XREF **************************************************************** # 12835 1.1 is # None # 12836 1.1 is # # 12837 1.1 is # INPUT *************************************************************** # 12838 1.1 is # fp0 = extended precision value to store # 12839 1.1 is # d0 = index of floating-point register # 12840 1.1 is # # 12841 1.1 is # OUTPUT ************************************************************** # 12842 1.1 is # None # 12843 1.1 is # # 12844 1.1 is # ALGORITHM *********************************************************** # 12845 1.1 is # Store the value in fp0 to the FP register designated by the # 12846 1.1 is # value in d0. The FP number can be DENORM or SNAN so we have to be # 12847 1.1 is # careful that we don't take an exception here. # 12848 1.1 is # # 12849 1.1 is ######################################################################### 12850 1.1 is 12851 1.1 is global store_fpreg 12852 1.1 is store_fpreg: 12853 1.1 is mov.w (tbl_store_fpreg.b,%pc,%d0.w*2), %d0 12854 1.1 is jmp (tbl_store_fpreg.b,%pc,%d0.w*1) 12855 1.1 is 12856 1.1 is tbl_store_fpreg: 12857 1.1 is short store_fpreg_0 - tbl_store_fpreg 12858 1.1 is short store_fpreg_1 - tbl_store_fpreg 12859 1.1 is short store_fpreg_2 - tbl_store_fpreg 12860 1.1 is short store_fpreg_3 - tbl_store_fpreg 12861 1.1 is short store_fpreg_4 - tbl_store_fpreg 12862 1.1 is short store_fpreg_5 - tbl_store_fpreg 12863 1.1 is short store_fpreg_6 - tbl_store_fpreg 12864 1.1 is short store_fpreg_7 - tbl_store_fpreg 12865 1.1 is 12866 1.1 is store_fpreg_0: 12867 1.1 is fmovm.x &0x80, EXC_FP0(%a6) 12868 1.1 is rts 12869 1.1 is store_fpreg_1: 12870 1.1 is fmovm.x &0x80, EXC_FP1(%a6) 12871 1.1 is rts 12872 1.1 is store_fpreg_2: 12873 1.1 is fmovm.x &0x01, -(%sp) 12874 1.1 is fmovm.x (%sp)+, &0x20 12875 1.1 is rts 12876 1.1 is store_fpreg_3: 12877 1.1 is fmovm.x &0x01, -(%sp) 12878 1.1 is fmovm.x (%sp)+, &0x10 12879 1.1 is rts 12880 1.1 is store_fpreg_4: 12881 1.1 is fmovm.x &0x01, -(%sp) 12882 1.1 is fmovm.x (%sp)+, &0x08 12883 1.1 is rts 12884 1.1 is store_fpreg_5: 12885 1.1 is fmovm.x &0x01, -(%sp) 12886 1.1 is fmovm.x (%sp)+, &0x04 12887 1.1 is rts 12888 1.1 is store_fpreg_6: 12889 1.1 is fmovm.x &0x01, -(%sp) 12890 1.1 is fmovm.x (%sp)+, &0x02 12891 1.1 is rts 12892 1.1 is store_fpreg_7: 12893 1.1 is fmovm.x &0x01, -(%sp) 12894 1.1 is fmovm.x (%sp)+, &0x01 12895 1.1 is rts 12896 1.1 is 12897 1.1 is ######################################################################### 12898 1.1 is # XDEF **************************************************************** # 12899 1.1 is # get_packed(): fetch a packed operand from memory and then # 12900 1.1 is # convert it to a floating-point binary number. # 12901 1.1 is # # 12902 1.1 is # XREF **************************************************************** # 12903 1.1 is # _dcalc_ea() - calculate the correct <ea> # 12904 1.1 is # _mem_read() - fetch the packed operand from memory # 12905 1.1 is # facc_in_x() - the fetch failed so jump to special exit code # 12906 1.1 is # decbin() - convert packed to binary extended precision # 12907 1.1 is # # 12908 1.1 is # INPUT *************************************************************** # 12909 1.1 is # None # 12910 1.1 is # # 12911 1.1 is # OUTPUT ************************************************************** # 12912 1.1 is # If no failure on _mem_read(): # 12913 1.1 is # FP_SRC(a6) = packed operand now as a binary FP number # 12914 1.1 is # # 12915 1.1 is # ALGORITHM *********************************************************** # 12916 1.1 is # Get the correct <ea> whihc is the value on the exception stack # 12917 1.1 is # frame w/ maybe a correction factor if the <ea> is -(an) or (an)+. # 12918 1.1 is # Then, fetch the operand from memory. If the fetch fails, exit # 12919 1.1 is # through facc_in_x(). # 12920 1.1 is # If the packed operand is a ZERO,NAN, or INF, convert it to # 12921 1.1 is # its binary representation here. Else, call decbin() which will # 12922 1.1 is # convert the packed value to an extended precision binary value. # 12923 1.1 is # # 12924 1.1 is ######################################################################### 12925 1.1 is 12926 1.1 is # the stacked <ea> for packed is correct except for -(An). 12927 1.1 is # the base reg must be updated for both -(An) and (An)+. 12928 1.1 is global get_packed 12929 1.1 is get_packed: 12930 1.1 is mov.l &0xc,%d0 # packed is 12 bytes 12931 1.1 is bsr.l _dcalc_ea # fetch <ea>; correct An 12932 1.1 is 12933 1.1 is lea FP_SRC(%a6),%a1 # pass: ptr to super dst 12934 1.1 is mov.l &0xc,%d0 # pass: 12 bytes 12935 1.1 is bsr.l _dmem_read # read packed operand 12936 1.1 is 12937 1.1 is tst.l %d1 # did dfetch fail? 12938 1.1 is bne.l facc_in_x # yes 12939 1.1 is 12940 1.1 is # The packed operand is an INF or a NAN if the exponent field is all ones. 12941 1.1 is bfextu FP_SRC(%a6){&1:&15},%d0 # get exp 12942 1.1 is cmpi.w %d0,&0x7fff # INF or NAN? 12943 1.1 is bne.b gp_try_zero # no 12944 1.1 is rts # operand is an INF or NAN 12945 1.1 is 12946 1.1 is # The packed operand is a zero if the mantissa is all zero, else it's 12947 1.1 is # a normal packed op. 12948 1.1 is gp_try_zero: 12949 1.1 is mov.b 3+FP_SRC(%a6),%d0 # get byte 4 12950 1.1 is andi.b &0x0f,%d0 # clear all but last nybble 12951 1.1 is bne.b gp_not_spec # not a zero 12952 1.1 is tst.l FP_SRC_HI(%a6) # is lw 2 zero? 12953 1.1 is bne.b gp_not_spec # not a zero 12954 1.1 is tst.l FP_SRC_LO(%a6) # is lw 3 zero? 12955 1.1 is bne.b gp_not_spec # not a zero 12956 1.1 is rts # operand is a ZERO 12957 1.1 is gp_not_spec: 12958 1.1 is lea FP_SRC(%a6),%a0 # pass: ptr to packed op 12959 1.1 is bsr.l decbin # convert to extended 12960 1.1 is fmovm.x &0x80,FP_SRC(%a6) # make this the srcop 12961 1.1 is rts 12962 1.1 is 12963 1.1 is ######################################################################### 12964 1.1 is # decbin(): Converts normalized packed bcd value pointed to by register # 12965 1.1 is # a0 to extended-precision value in fp0. # 12966 1.1 is # # 12967 1.1 is # INPUT *************************************************************** # 12968 1.1 is # a0 = pointer to normalized packed bcd value # 12969 1.1 is # # 12970 1.1 is # OUTPUT ************************************************************** # 12971 1.1 is # fp0 = exact fp representation of the packed bcd value. # 12972 1.1 is # # 12973 1.1 is # ALGORITHM *********************************************************** # 12974 1.1 is # Expected is a normal bcd (i.e. non-exceptional; all inf, zero, # 12975 1.1 is # and NaN operands are dispatched without entering this routine) # 12976 1.1 is # value in 68881/882 format at location (a0). # 12977 1.1 is # # 12978 1.1 is # A1. Convert the bcd exponent to binary by successive adds and # 12979 1.1 is # muls. Set the sign according to SE. Subtract 16 to compensate # 12980 1.1 is # for the mantissa which is to be interpreted as 17 integer # 12981 1.1 is # digits, rather than 1 integer and 16 fraction digits. # 12982 1.1 is # Note: this operation can never overflow. # 12983 1.1 is # # 12984 1.1 is # A2. Convert the bcd mantissa to binary by successive # 12985 1.1 is # adds and muls in FP0. Set the sign according to SM. # 12986 1.1 is # The mantissa digits will be converted with the decimal point # 12987 1.1 is # assumed following the least-significant digit. # 12988 1.1 is # Note: this operation can never overflow. # 12989 1.1 is # # 12990 1.1 is # A3. Count the number of leading/trailing zeros in the # 12991 1.1 is # bcd string. If SE is positive, count the leading zeros; # 12992 1.1 is # if negative, count the trailing zeros. Set the adjusted # 12993 1.1 is # exponent equal to the exponent from A1 and the zero count # 12994 1.1 is # added if SM = 1 and subtracted if SM = 0. Scale the # 12995 1.1 is # mantissa the equivalent of forcing in the bcd value: # 12996 1.1 is # # 12997 1.1 is # SM = 0 a non-zero digit in the integer position # 12998 1.1 is # SM = 1 a non-zero digit in Mant0, lsd of the fraction # 12999 1.1 is # # 13000 1.1 is # this will insure that any value, regardless of its # 13001 1.1 is # representation (ex. 0.1E2, 1E1, 10E0, 100E-1), is converted # 13002 1.1 is # consistently. # 13003 1.1 is # # 13004 1.1 is # A4. Calculate the factor 10^exp in FP1 using a table of # 13005 1.1 is # 10^(2^n) values. To reduce the error in forming factors # 13006 1.1 is # greater than 10^27, a directed rounding scheme is used with # 13007 1.1 is # tables rounded to RN, RM, and RP, according to the table # 13008 1.1 is # in the comments of the pwrten section. # 13009 1.1 is # # 13010 1.1 is # A5. Form the final binary number by scaling the mantissa by # 13011 1.1 is # the exponent factor. This is done by multiplying the # 13012 1.1 is # mantissa in FP0 by the factor in FP1 if the adjusted # 13013 1.1 is # exponent sign is positive, and dividing FP0 by FP1 if # 13014 1.1 is # it is negative. # 13015 1.1 is # # 13016 1.1 is # Clean up and return. Check if the final mul or div was inexact. # 13017 1.1 is # If so, set INEX1 in USER_FPSR. # 13018 1.1 is # # 13019 1.1 is ######################################################################### 13020 1.1 is 13021 1.1 is # 13022 1.1 is # PTENRN, PTENRM, and PTENRP are arrays of powers of 10 rounded 13023 1.1 is # to nearest, minus, and plus, respectively. The tables include 13024 1.1 is # 10**{1,2,4,8,16,32,64,128,256,512,1024,2048,4096}. No rounding 13025 1.1 is # is required until the power is greater than 27, however, all 13026 1.1 is # tables include the first 5 for ease of indexing. 13027 1.1 is # 13028 1.1 is RTABLE: 13029 1.1 is byte 0,0,0,0 13030 1.1 is byte 2,3,2,3 13031 1.1 is byte 2,3,3,2 13032 1.1 is byte 3,2,2,3 13033 1.1 is 13034 1.1 is set FNIBS,7 13035 1.1 is set FSTRT,0 13036 1.1 is 13037 1.1 is set ESTRT,4 13038 1.1 is set EDIGITS,2 13039 1.1 is 13040 1.1 is global decbin 13041 1.1 is decbin: 13042 1.1 is mov.l 0x0(%a0),FP_SCR0_EX(%a6) # make a copy of input 13043 1.1 is mov.l 0x4(%a0),FP_SCR0_HI(%a6) # so we don't alter it 13044 1.1 is mov.l 0x8(%a0),FP_SCR0_LO(%a6) 13045 1.1 is 13046 1.1 is lea FP_SCR0(%a6),%a0 13047 1.1 is 13048 1.1 is movm.l &0x3c00,-(%sp) # save d2-d5 13049 1.1 is fmovm.x &0x1,-(%sp) # save fp1 13050 1.1 is # 13051 1.1 is # Calculate exponent: 13052 1.1 is # 1. Copy bcd value in memory for use as a working copy. 13053 1.1 is # 2. Calculate absolute value of exponent in d1 by mul and add. 13054 1.1 is # 3. Correct for exponent sign. 13055 1.1 is # 4. Subtract 16 to compensate for interpreting the mant as all integer digits. 13056 1.1 is # (i.e., all digits assumed left of the decimal point.) 13057 1.1 is # 13058 1.1 is # Register usage: 13059 1.1 is # 13060 1.1 is # calc_e: 13061 1.1 is # (*) d0: temp digit storage 13062 1.1 is # (*) d1: accumulator for binary exponent 13063 1.1 is # (*) d2: digit count 13064 1.1 is # (*) d3: offset pointer 13065 1.1 is # ( ) d4: first word of bcd 13066 1.1 is # ( ) a0: pointer to working bcd value 13067 1.1 is # ( ) a6: pointer to original bcd value 13068 1.1 is # (*) FP_SCR1: working copy of original bcd value 13069 1.1 is # (*) L_SCR1: copy of original exponent word 13070 1.1 is # 13071 1.1 is calc_e: 13072 1.1 is mov.l &EDIGITS,%d2 # # of nibbles (digits) in fraction part 13073 1.1 is mov.l &ESTRT,%d3 # counter to pick up digits 13074 1.1 is mov.l (%a0),%d4 # get first word of bcd 13075 1.1 is clr.l %d1 # zero d1 for accumulator 13076 1.1 is e_gd: 13077 1.1 is mulu.l &0xa,%d1 # mul partial product by one digit place 13078 1.1 is bfextu %d4{%d3:&4},%d0 # get the digit and zero extend into d0 13079 1.1 is add.l %d0,%d1 # d1 = d1 + d0 13080 1.1 is addq.b &4,%d3 # advance d3 to the next digit 13081 1.1 is dbf.w %d2,e_gd # if we have used all 3 digits, exit loop 13082 1.1 is btst &30,%d4 # get SE 13083 1.1 is beq.b e_pos # don't negate if pos 13084 1.1 is neg.l %d1 # negate before subtracting 13085 1.1 is e_pos: 13086 1.1 is sub.l &16,%d1 # sub to compensate for shift of mant 13087 1.1 is bge.b e_save # if still pos, do not neg 13088 1.1 is neg.l %d1 # now negative, make pos and set SE 13089 1.1 is or.l &0x40000000,%d4 # set SE in d4, 13090 1.1 is or.l &0x40000000,(%a0) # and in working bcd 13091 1.1 is e_save: 13092 1.1 is mov.l %d1,-(%sp) # save exp on stack 13093 1.1 is # 13094 1.1 is # 13095 1.1 is # Calculate mantissa: 13096 1.1 is # 1. Calculate absolute value of mantissa in fp0 by mul and add. 13097 1.1 is # 2. Correct for mantissa sign. 13098 1.1 is # (i.e., all digits assumed left of the decimal point.) 13099 1.1 is # 13100 1.1 is # Register usage: 13101 1.1 is # 13102 1.1 is # calc_m: 13103 1.1 is # (*) d0: temp digit storage 13104 1.1 is # (*) d1: lword counter 13105 1.1 is # (*) d2: digit count 13106 1.1 is # (*) d3: offset pointer 13107 1.1 is # ( ) d4: words 2 and 3 of bcd 13108 1.1 is # ( ) a0: pointer to working bcd value 13109 1.1 is # ( ) a6: pointer to original bcd value 13110 1.1 is # (*) fp0: mantissa accumulator 13111 1.1 is # ( ) FP_SCR1: working copy of original bcd value 13112 1.1 is # ( ) L_SCR1: copy of original exponent word 13113 1.1 is # 13114 1.1 is calc_m: 13115 1.1 is mov.l &1,%d1 # word counter, init to 1 13116 1.1 is fmov.s &0x00000000,%fp0 # accumulator 13117 1.1 is # 13118 1.1 is # 13119 1.1 is # Since the packed number has a long word between the first & second parts, 13120 1.1 is # get the integer digit then skip down & get the rest of the 13121 1.1 is # mantissa. We will unroll the loop once. 13122 1.1 is # 13123 1.1 is bfextu (%a0){&28:&4},%d0 # integer part is ls digit in long word 13124 1.1 is fadd.b %d0,%fp0 # add digit to sum in fp0 13125 1.1 is # 13126 1.1 is # 13127 1.1 is # Get the rest of the mantissa. 13128 1.1 is # 13129 1.1 is loadlw: 13130 1.1 is mov.l (%a0,%d1.L*4),%d4 # load mantissa lonqword into d4 13131 1.1 is mov.l &FSTRT,%d3 # counter to pick up digits 13132 1.1 is mov.l &FNIBS,%d2 # reset number of digits per a0 ptr 13133 1.1 is md2b: 13134 1.1 is fmul.s &0x41200000,%fp0 # fp0 = fp0 * 10 13135 1.1 is bfextu %d4{%d3:&4},%d0 # get the digit and zero extend 13136 1.1 is fadd.b %d0,%fp0 # fp0 = fp0 + digit 13137 1.1 is # 13138 1.1 is # 13139 1.1 is # If all the digits (8) in that long word have been converted (d2=0), 13140 1.1 is # then inc d1 (=2) to point to the next long word and reset d3 to 0 13141 1.1 is # to initialize the digit offset, and set d2 to 7 for the digit count; 13142 1.1 is # else continue with this long word. 13143 1.1 is # 13144 1.1 is addq.b &4,%d3 # advance d3 to the next digit 13145 1.1 is dbf.w %d2,md2b # check for last digit in this lw 13146 1.1 is nextlw: 13147 1.1 is addq.l &1,%d1 # inc lw pointer in mantissa 13148 1.1 is cmp.l %d1,&2 # test for last lw 13149 1.1 is ble.b loadlw # if not, get last one 13150 1.1 is # 13151 1.1 is # Check the sign of the mant and make the value in fp0 the same sign. 13152 1.1 is # 13153 1.1 is m_sign: 13154 1.1 is btst &31,(%a0) # test sign of the mantissa 13155 1.1 is beq.b ap_st_z # if clear, go to append/strip zeros 13156 1.1 is fneg.x %fp0 # if set, negate fp0 13157 1.1 is # 13158 1.1 is # Append/strip zeros: 13159 1.1 is # 13160 1.1 is # For adjusted exponents which have an absolute value greater than 27*, 13161 1.1 is # this routine calculates the amount needed to normalize the mantissa 13162 1.1 is # for the adjusted exponent. That number is subtracted from the exp 13163 1.1 is # if the exp was positive, and added if it was negative. The purpose 13164 1.1 is # of this is to reduce the value of the exponent and the possibility 13165 1.1 is # of error in calculation of pwrten. 13166 1.1 is # 13167 1.1 is # 1. Branch on the sign of the adjusted exponent. 13168 1.1 is # 2p.(positive exp) 13169 1.1 is # 2. Check M16 and the digits in lwords 2 and 3 in decending order. 13170 1.1 is # 3. Add one for each zero encountered until a non-zero digit. 13171 1.1 is # 4. Subtract the count from the exp. 13172 1.1 is # 5. Check if the exp has crossed zero in #3 above; make the exp abs 13173 1.1 is # and set SE. 13174 1.1 is # 6. Multiply the mantissa by 10**count. 13175 1.1 is # 2n.(negative exp) 13176 1.1 is # 2. Check the digits in lwords 3 and 2 in decending order. 13177 1.1 is # 3. Add one for each zero encountered until a non-zero digit. 13178 1.1 is # 4. Add the count to the exp. 13179 1.1 is # 5. Check if the exp has crossed zero in #3 above; clear SE. 13180 1.1 is # 6. Divide the mantissa by 10**count. 13181 1.1 is # 13182 1.1 is # *Why 27? If the adjusted exponent is within -28 < expA < 28, than 13183 1.1 is # any adjustment due to append/strip zeros will drive the resultane 13184 1.1 is # exponent towards zero. Since all pwrten constants with a power 13185 1.1 is # of 27 or less are exact, there is no need to use this routine to 13186 1.1 is # attempt to lessen the resultant exponent. 13187 1.1 is # 13188 1.1 is # Register usage: 13189 1.1 is # 13190 1.1 is # ap_st_z: 13191 1.1 is # (*) d0: temp digit storage 13192 1.1 is # (*) d1: zero count 13193 1.1 is # (*) d2: digit count 13194 1.1 is # (*) d3: offset pointer 13195 1.1 is # ( ) d4: first word of bcd 13196 1.1 is # (*) d5: lword counter 13197 1.1 is # ( ) a0: pointer to working bcd value 13198 1.1 is # ( ) FP_SCR1: working copy of original bcd value 13199 1.1 is # ( ) L_SCR1: copy of original exponent word 13200 1.1 is # 13201 1.1 is # 13202 1.1 is # First check the absolute value of the exponent to see if this 13203 1.1 is # routine is necessary. If so, then check the sign of the exponent 13204 1.1 is # and do append (+) or strip (-) zeros accordingly. 13205 1.1 is # This section handles a positive adjusted exponent. 13206 1.1 is # 13207 1.1 is ap_st_z: 13208 1.1 is mov.l (%sp),%d1 # load expA for range test 13209 1.1 is cmp.l %d1,&27 # test is with 27 13210 1.1 is ble.w pwrten # if abs(expA) <28, skip ap/st zeros 13211 1.1 is btst &30,(%a0) # check sign of exp 13212 1.1 is bne.b ap_st_n # if neg, go to neg side 13213 1.1 is clr.l %d1 # zero count reg 13214 1.1 is mov.l (%a0),%d4 # load lword 1 to d4 13215 1.1 is bfextu %d4{&28:&4},%d0 # get M16 in d0 13216 1.1 is bne.b ap_p_fx # if M16 is non-zero, go fix exp 13217 1.1 is addq.l &1,%d1 # inc zero count 13218 1.1 is mov.l &1,%d5 # init lword counter 13219 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 2 to d4 13220 1.1 is bne.b ap_p_cl # if lw 2 is zero, skip it 13221 1.1 is addq.l &8,%d1 # and inc count by 8 13222 1.1 is addq.l &1,%d5 # inc lword counter 13223 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 3 to d4 13224 1.1 is ap_p_cl: 13225 1.1 is clr.l %d3 # init offset reg 13226 1.1 is mov.l &7,%d2 # init digit counter 13227 1.1 is ap_p_gd: 13228 1.1 is bfextu %d4{%d3:&4},%d0 # get digit 13229 1.1 is bne.b ap_p_fx # if non-zero, go to fix exp 13230 1.1 is addq.l &4,%d3 # point to next digit 13231 1.1 is addq.l &1,%d1 # inc digit counter 13232 1.1 is dbf.w %d2,ap_p_gd # get next digit 13233 1.1 is ap_p_fx: 13234 1.1 is mov.l %d1,%d0 # copy counter to d2 13235 1.1 is mov.l (%sp),%d1 # get adjusted exp from memory 13236 1.1 is sub.l %d0,%d1 # subtract count from exp 13237 1.1 is bge.b ap_p_fm # if still pos, go to pwrten 13238 1.1 is neg.l %d1 # now its neg; get abs 13239 1.1 is mov.l (%a0),%d4 # load lword 1 to d4 13240 1.1 is or.l &0x40000000,%d4 # and set SE in d4 13241 1.1 is or.l &0x40000000,(%a0) # and in memory 13242 1.1 is # 13243 1.1 is # Calculate the mantissa multiplier to compensate for the striping of 13244 1.1 is # zeros from the mantissa. 13245 1.1 is # 13246 1.1 is ap_p_fm: 13247 1.1 is lea.l PTENRN(%pc),%a1 # get address of power-of-ten table 13248 1.1 is clr.l %d3 # init table index 13249 1.1 is fmov.s &0x3f800000,%fp1 # init fp1 to 1 13250 1.1 is mov.l &3,%d2 # init d2 to count bits in counter 13251 1.1 is ap_p_el: 13252 1.1 is asr.l &1,%d0 # shift lsb into carry 13253 1.1 is bcc.b ap_p_en # if 1, mul fp1 by pwrten factor 13254 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 13255 1.1 is ap_p_en: 13256 1.1 is add.l &12,%d3 # inc d3 to next rtable entry 13257 1.1 is tst.l %d0 # check if d0 is zero 13258 1.1 is bne.b ap_p_el # if not, get next bit 13259 1.1 is fmul.x %fp1,%fp0 # mul mantissa by 10**(no_bits_shifted) 13260 1.1 is bra.b pwrten # go calc pwrten 13261 1.1 is # 13262 1.1 is # This section handles a negative adjusted exponent. 13263 1.1 is # 13264 1.1 is ap_st_n: 13265 1.1 is clr.l %d1 # clr counter 13266 1.1 is mov.l &2,%d5 # set up d5 to point to lword 3 13267 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 3 13268 1.1 is bne.b ap_n_cl # if not zero, check digits 13269 1.1 is sub.l &1,%d5 # dec d5 to point to lword 2 13270 1.1 is addq.l &8,%d1 # inc counter by 8 13271 1.1 is mov.l (%a0,%d5.L*4),%d4 # get lword 2 13272 1.1 is ap_n_cl: 13273 1.1 is mov.l &28,%d3 # point to last digit 13274 1.1 is mov.l &7,%d2 # init digit counter 13275 1.1 is ap_n_gd: 13276 1.1 is bfextu %d4{%d3:&4},%d0 # get digit 13277 1.1 is bne.b ap_n_fx # if non-zero, go to exp fix 13278 1.1 is subq.l &4,%d3 # point to previous digit 13279 1.1 is addq.l &1,%d1 # inc digit counter 13280 1.1 is dbf.w %d2,ap_n_gd # get next digit 13281 1.1 is ap_n_fx: 13282 1.1 is mov.l %d1,%d0 # copy counter to d0 13283 1.1 is mov.l (%sp),%d1 # get adjusted exp from memory 13284 1.1 is sub.l %d0,%d1 # subtract count from exp 13285 1.1 is bgt.b ap_n_fm # if still pos, go fix mantissa 13286 1.1 is neg.l %d1 # take abs of exp and clr SE 13287 1.1 is mov.l (%a0),%d4 # load lword 1 to d4 13288 1.1 is and.l &0xbfffffff,%d4 # and clr SE in d4 13289 1.1 is and.l &0xbfffffff,(%a0) # and in memory 13290 1.1 is # 13291 1.1 is # Calculate the mantissa multiplier to compensate for the appending of 13292 1.1 is # zeros to the mantissa. 13293 1.1 is # 13294 1.1 is ap_n_fm: 13295 1.1 is lea.l PTENRN(%pc),%a1 # get address of power-of-ten table 13296 1.1 is clr.l %d3 # init table index 13297 1.1 is fmov.s &0x3f800000,%fp1 # init fp1 to 1 13298 1.1 is mov.l &3,%d2 # init d2 to count bits in counter 13299 1.1 is ap_n_el: 13300 1.1 is asr.l &1,%d0 # shift lsb into carry 13301 1.1 is bcc.b ap_n_en # if 1, mul fp1 by pwrten factor 13302 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 13303 1.1 is ap_n_en: 13304 1.1 is add.l &12,%d3 # inc d3 to next rtable entry 13305 1.1 is tst.l %d0 # check if d0 is zero 13306 1.1 is bne.b ap_n_el # if not, get next bit 13307 1.1 is fdiv.x %fp1,%fp0 # div mantissa by 10**(no_bits_shifted) 13308 1.1 is # 13309 1.1 is # 13310 1.1 is # Calculate power-of-ten factor from adjusted and shifted exponent. 13311 1.1 is # 13312 1.1 is # Register usage: 13313 1.1 is # 13314 1.1 is # pwrten: 13315 1.1 is # (*) d0: temp 13316 1.1 is # ( ) d1: exponent 13317 1.1 is # (*) d2: {FPCR[6:5],SM,SE} as index in RTABLE; temp 13318 1.1 is # (*) d3: FPCR work copy 13319 1.1 is # ( ) d4: first word of bcd 13320 1.1 is # (*) a1: RTABLE pointer 13321 1.1 is # calc_p: 13322 1.1 is # (*) d0: temp 13323 1.1 is # ( ) d1: exponent 13324 1.1 is # (*) d3: PWRTxx table index 13325 1.1 is # ( ) a0: pointer to working copy of bcd 13326 1.1 is # (*) a1: PWRTxx pointer 13327 1.1 is # (*) fp1: power-of-ten accumulator 13328 1.1 is # 13329 1.1 is # Pwrten calculates the exponent factor in the selected rounding mode 13330 1.1 is # according to the following table: 13331 1.1 is # 13332 1.1 is # Sign of Mant Sign of Exp Rounding Mode PWRTEN Rounding Mode 13333 1.1 is # 13334 1.1 is # ANY ANY RN RN 13335 1.1 is # 13336 1.1 is # + + RP RP 13337 1.1 is # - + RP RM 13338 1.1 is # + - RP RM 13339 1.1 is # - - RP RP 13340 1.1 is # 13341 1.1 is # + + RM RM 13342 1.1 is # - + RM RP 13343 1.1 is # + - RM RP 13344 1.1 is # - - RM RM 13345 1.1 is # 13346 1.1 is # + + RZ RM 13347 1.1 is # - + RZ RM 13348 1.1 is # + - RZ RP 13349 1.1 is # - - RZ RP 13350 1.1 is # 13351 1.1 is # 13352 1.1 is pwrten: 13353 1.1 is mov.l USER_FPCR(%a6),%d3 # get user's FPCR 13354 1.1 is bfextu %d3{&26:&2},%d2 # isolate rounding mode bits 13355 1.1 is mov.l (%a0),%d4 # reload 1st bcd word to d4 13356 1.1 is asl.l &2,%d2 # format d2 to be 13357 1.1 is bfextu %d4{&0:&2},%d0 # {FPCR[6],FPCR[5],SM,SE} 13358 1.1 is add.l %d0,%d2 # in d2 as index into RTABLE 13359 1.1 is lea.l RTABLE(%pc),%a1 # load rtable base 13360 1.1 is mov.b (%a1,%d2),%d0 # load new rounding bits from table 13361 1.1 is clr.l %d3 # clear d3 to force no exc and extended 13362 1.1 is bfins %d0,%d3{&26:&2} # stuff new rounding bits in FPCR 13363 1.1 is fmov.l %d3,%fpcr # write new FPCR 13364 1.1 is asr.l &1,%d0 # write correct PTENxx table 13365 1.1 is bcc.b not_rp # to a1 13366 1.1 is lea.l PTENRP(%pc),%a1 # it is RP 13367 1.1 is bra.b calc_p # go to init section 13368 1.1 is not_rp: 13369 1.1 is asr.l &1,%d0 # keep checking 13370 1.1 is bcc.b not_rm 13371 1.1 is lea.l PTENRM(%pc),%a1 # it is RM 13372 1.1 is bra.b calc_p # go to init section 13373 1.1 is not_rm: 13374 1.1 is lea.l PTENRN(%pc),%a1 # it is RN 13375 1.1 is calc_p: 13376 1.1 is mov.l %d1,%d0 # copy exp to d0;use d0 13377 1.1 is bpl.b no_neg # if exp is negative, 13378 1.1 is neg.l %d0 # invert it 13379 1.1 is or.l &0x40000000,(%a0) # and set SE bit 13380 1.1 is no_neg: 13381 1.1 is clr.l %d3 # table index 13382 1.1 is fmov.s &0x3f800000,%fp1 # init fp1 to 1 13383 1.1 is e_loop: 13384 1.1 is asr.l &1,%d0 # shift next bit into carry 13385 1.1 is bcc.b e_next # if zero, skip the mul 13386 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 13387 1.1 is e_next: 13388 1.1 is add.l &12,%d3 # inc d3 to next rtable entry 13389 1.1 is tst.l %d0 # check if d0 is zero 13390 1.1 is bne.b e_loop # not zero, continue shifting 13391 1.1 is # 13392 1.1 is # 13393 1.1 is # Check the sign of the adjusted exp and make the value in fp0 the 13394 1.1 is # same sign. If the exp was pos then multiply fp1*fp0; 13395 1.1 is # else divide fp0/fp1. 13396 1.1 is # 13397 1.1 is # Register Usage: 13398 1.1 is # norm: 13399 1.1 is # ( ) a0: pointer to working bcd value 13400 1.1 is # (*) fp0: mantissa accumulator 13401 1.1 is # ( ) fp1: scaling factor - 10**(abs(exp)) 13402 1.1 is # 13403 1.1 is pnorm: 13404 1.1 is btst &30,(%a0) # test the sign of the exponent 13405 1.1 is beq.b mul # if clear, go to multiply 13406 1.1 is div: 13407 1.1 is fdiv.x %fp1,%fp0 # exp is negative, so divide mant by exp 13408 1.1 is bra.b end_dec 13409 1.1 is mul: 13410 1.1 is fmul.x %fp1,%fp0 # exp is positive, so multiply by exp 13411 1.1 is # 13412 1.1 is # 13413 1.1 is # Clean up and return with result in fp0. 13414 1.1 is # 13415 1.1 is # If the final mul/div in decbin incurred an inex exception, 13416 1.1 is # it will be inex2, but will be reported as inex1 by get_op. 13417 1.1 is # 13418 1.1 is end_dec: 13419 1.1 is fmov.l %fpsr,%d0 # get status register 13420 1.1 is bclr &inex2_bit+8,%d0 # test for inex2 and clear it 13421 1.1 is beq.b no_exc # skip this if no exc 13422 1.1 is ori.w &inx1a_mask,2+USER_FPSR(%a6) # set INEX1/AINEX 13423 1.1 is no_exc: 13424 1.1 is add.l &0x4,%sp # clear 1 lw param 13425 1.1 is fmovm.x (%sp)+,&0x40 # restore fp1 13426 1.1 is movm.l (%sp)+,&0x3c # restore d2-d5 13427 1.1 is fmov.l &0x0,%fpcr 13428 1.1 is fmov.l &0x0,%fpsr 13429 1.1 is rts 13430 1.1 is 13431 1.1 is ######################################################################### 13432 1.1 is # bindec(): Converts an input in extended precision format to bcd format# 13433 1.1 is # # 13434 1.1 is # INPUT *************************************************************** # 13435 1.1 is # a0 = pointer to the input extended precision value in memory. # 13436 1.1 is # the input may be either normalized, unnormalized, or # 13437 1.1 is # denormalized. # 13438 1.1 is # d0 = contains the k-factor sign-extended to 32-bits. # 13439 1.1 is # # 13440 1.1 is # OUTPUT ************************************************************** # 13441 1.1 is # FP_SCR0(a6) = bcd format result on the stack. # 13442 1.1 is # # 13443 1.1 is # ALGORITHM *********************************************************** # 13444 1.1 is # # 13445 1.1 is # A1. Set RM and size ext; Set SIGMA = sign of input. # 13446 1.1 is # The k-factor is saved for use in d7. Clear the # 13447 1.1 is # BINDEC_FLG for separating normalized/denormalized # 13448 1.1 is # input. If input is unnormalized or denormalized, # 13449 1.1 is # normalize it. # 13450 1.1 is # # 13451 1.1 is # A2. Set X = abs(input). # 13452 1.1 is # # 13453 1.1 is # A3. Compute ILOG. # 13454 1.1 is # ILOG is the log base 10 of the input value. It is # 13455 1.1 is # approximated by adding e + 0.f when the original # 13456 1.1 is # value is viewed as 2^^e * 1.f in extended precision. # 13457 1.1 is # This value is stored in d6. # 13458 1.1 is # # 13459 1.1 is # A4. Clr INEX bit. # 13460 1.1 is # The operation in A3 above may have set INEX2. # 13461 1.1 is # # 13462 1.1 is # A5. Set ICTR = 0; # 13463 1.1 is # ICTR is a flag used in A13. It must be set before the # 13464 1.1 is # loop entry A6. # 13465 1.1 is # # 13466 1.1 is # A6. Calculate LEN. # 13467 1.1 is # LEN is the number of digits to be displayed. The # 13468 1.1 is # k-factor can dictate either the total number of digits, # 13469 1.1 is # if it is a positive number, or the number of digits # 13470 1.1 is # after the decimal point which are to be included as # 13471 1.1 is # significant. See the 68882 manual for examples. # 13472 1.1 is # If LEN is computed to be greater than 17, set OPERR in # 13473 1.1 is # USER_FPSR. LEN is stored in d4. # 13474 1.1 is # # 13475 1.1 is # A7. Calculate SCALE. # 13476 1.1 is # SCALE is equal to 10^ISCALE, where ISCALE is the number # 13477 1.1 is # of decimal places needed to insure LEN integer digits # 13478 1.1 is # in the output before conversion to bcd. LAMBDA is the # 13479 1.1 is # sign of ISCALE, used in A9. Fp1 contains # 13480 1.1 is # 10^^(abs(ISCALE)) using a rounding mode which is a # 13481 1.1 is # function of the original rounding mode and the signs # 13482 1.1 is # of ISCALE and X. A table is given in the code. # 13483 1.1 is # # 13484 1.1 is # A8. Clr INEX; Force RZ. # 13485 1.1 is # The operation in A3 above may have set INEX2. # 13486 1.1 is # RZ mode is forced for the scaling operation to insure # 13487 1.1 is # only one rounding error. The grs bits are collected in # 13488 1.1 is # the INEX flag for use in A10. # 13489 1.1 is # # 13490 1.1 is # A9. Scale X -> Y. # 13491 1.1 is # The mantissa is scaled to the desired number of # 13492 1.1 is # significant digits. The excess digits are collected # 13493 1.1 is # in INEX2. # 13494 1.1 is # # 13495 1.1 is # A10. Or in INEX. # 13496 1.2 wiz # If INEX is set, round error occurred. This is # 13497 1.1 is # compensated for by 'or-ing' in the INEX2 flag to # 13498 1.1 is # the lsb of Y. # 13499 1.1 is # # 13500 1.1 is # A11. Restore original FPCR; set size ext. # 13501 1.1 is # Perform FINT operation in the user's rounding mode. # 13502 1.1 is # Keep the size to extended. # 13503 1.1 is # # 13504 1.1 is # A12. Calculate YINT = FINT(Y) according to user's rounding # 13505 1.1 is # mode. The FPSP routine sintd0 is used. The output # 13506 1.1 is # is in fp0. # 13507 1.1 is # # 13508 1.1 is # A13. Check for LEN digits. # 13509 1.1 is # If the int operation results in more than LEN digits, # 13510 1.1 is # or less than LEN -1 digits, adjust ILOG and repeat from # 13511 1.1 is # A6. This test occurs only on the first pass. If the # 13512 1.1 is # result is exactly 10^LEN, decrement ILOG and divide # 13513 1.1 is # the mantissa by 10. # 13514 1.1 is # # 13515 1.1 is # A14. Convert the mantissa to bcd. # 13516 1.1 is # The binstr routine is used to convert the LEN digit # 13517 1.1 is # mantissa to bcd in memory. The input to binstr is # 13518 1.1 is # to be a fraction; i.e. (mantissa)/10^LEN and adjusted # 13519 1.1 is # such that the decimal point is to the left of bit 63. # 13520 1.1 is # The bcd digits are stored in the correct position in # 13521 1.1 is # the final string area in memory. # 13522 1.1 is # # 13523 1.1 is # A15. Convert the exponent to bcd. # 13524 1.1 is # As in A14 above, the exp is converted to bcd and the # 13525 1.1 is # digits are stored in the final string. # 13526 1.1 is # Test the length of the final exponent string. If the # 13527 1.1 is # length is 4, set operr. # 13528 1.1 is # # 13529 1.1 is # A16. Write sign bits to final string. # 13530 1.1 is # # 13531 1.1 is ######################################################################### 13532 1.1 is 13533 1.1 is set BINDEC_FLG, EXC_TEMP # DENORM flag 13534 1.1 is 13535 1.1 is # Constants in extended precision 13536 1.1 is PLOG2: 13537 1.1 is long 0x3FFD0000,0x9A209A84,0xFBCFF798,0x00000000 13538 1.1 is PLOG2UP1: 13539 1.1 is long 0x3FFD0000,0x9A209A84,0xFBCFF799,0x00000000 13540 1.1 is 13541 1.1 is # Constants in single precision 13542 1.1 is FONE: 13543 1.1 is long 0x3F800000,0x00000000,0x00000000,0x00000000 13544 1.1 is FTWO: 13545 1.1 is long 0x40000000,0x00000000,0x00000000,0x00000000 13546 1.1 is FTEN: 13547 1.1 is long 0x41200000,0x00000000,0x00000000,0x00000000 13548 1.1 is F4933: 13549 1.1 is long 0x459A2800,0x00000000,0x00000000,0x00000000 13550 1.1 is 13551 1.1 is RBDTBL: 13552 1.1 is byte 0,0,0,0 13553 1.1 is byte 3,3,2,2 13554 1.1 is byte 3,2,2,3 13555 1.1 is byte 2,3,3,2 13556 1.1 is 13557 1.1 is # Implementation Notes: 13558 1.1 is # 13559 1.1 is # The registers are used as follows: 13560 1.1 is # 13561 1.1 is # d0: scratch; LEN input to binstr 13562 1.1 is # d1: scratch 13563 1.1 is # d2: upper 32-bits of mantissa for binstr 13564 1.1 is # d3: scratch;lower 32-bits of mantissa for binstr 13565 1.1 is # d4: LEN 13566 1.1 is # d5: LAMBDA/ICTR 13567 1.1 is # d6: ILOG 13568 1.1 is # d7: k-factor 13569 1.1 is # a0: ptr for original operand/final result 13570 1.1 is # a1: scratch pointer 13571 1.1 is # a2: pointer to FP_X; abs(original value) in ext 13572 1.1 is # fp0: scratch 13573 1.1 is # fp1: scratch 13574 1.1 is # fp2: scratch 13575 1.1 is # F_SCR1: 13576 1.1 is # F_SCR2: 13577 1.1 is # L_SCR1: 13578 1.1 is # L_SCR2: 13579 1.1 is 13580 1.1 is global bindec 13581 1.1 is bindec: 13582 1.1 is movm.l &0x3f20,-(%sp) # {%d2-%d7/%a2} 13583 1.1 is fmovm.x &0x7,-(%sp) # {%fp0-%fp2} 13584 1.1 is 13585 1.1 is # A1. Set RM and size ext. Set SIGMA = sign input; 13586 1.1 is # The k-factor is saved for use in d7. Clear BINDEC_FLG for 13587 1.1 is # separating normalized/denormalized input. If the input 13588 1.1 is # is a denormalized number, set the BINDEC_FLG memory word 13589 1.1 is # to signal denorm. If the input is unnormalized, normalize 13590 1.1 is # the input and test for denormalized result. 13591 1.1 is # 13592 1.1 is fmov.l &rm_mode*0x10,%fpcr # set RM and ext 13593 1.1 is mov.l (%a0),L_SCR2(%a6) # save exponent for sign check 13594 1.1 is mov.l %d0,%d7 # move k-factor to d7 13595 1.1 is 13596 1.1 is clr.b BINDEC_FLG(%a6) # clr norm/denorm flag 13597 1.1 is cmpi.b STAG(%a6),&DENORM # is input a DENORM? 13598 1.1 is bne.w A2_str # no; input is a NORM 13599 1.1 is 13600 1.1 is # 13601 1.1 is # Normalize the denorm 13602 1.1 is # 13603 1.1 is un_de_norm: 13604 1.1 is mov.w (%a0),%d0 13605 1.1 is and.w &0x7fff,%d0 # strip sign of normalized exp 13606 1.1 is mov.l 4(%a0),%d1 13607 1.1 is mov.l 8(%a0),%d2 13608 1.1 is norm_loop: 13609 1.1 is sub.w &1,%d0 13610 1.1 is lsl.l &1,%d2 13611 1.1 is roxl.l &1,%d1 13612 1.1 is tst.l %d1 13613 1.1 is bge.b norm_loop 13614 1.1 is # 13615 1.1 is # Test if the normalized input is denormalized 13616 1.1 is # 13617 1.1 is tst.w %d0 13618 1.1 is bgt.b pos_exp # if greater than zero, it is a norm 13619 1.1 is st BINDEC_FLG(%a6) # set flag for denorm 13620 1.1 is pos_exp: 13621 1.1 is and.w &0x7fff,%d0 # strip sign of normalized exp 13622 1.1 is mov.w %d0,(%a0) 13623 1.1 is mov.l %d1,4(%a0) 13624 1.1 is mov.l %d2,8(%a0) 13625 1.1 is 13626 1.1 is # A2. Set X = abs(input). 13627 1.1 is # 13628 1.1 is A2_str: 13629 1.1 is mov.l (%a0),FP_SCR1(%a6) # move input to work space 13630 1.1 is mov.l 4(%a0),FP_SCR1+4(%a6) # move input to work space 13631 1.1 is mov.l 8(%a0),FP_SCR1+8(%a6) # move input to work space 13632 1.1 is and.l &0x7fffffff,FP_SCR1(%a6) # create abs(X) 13633 1.1 is 13634 1.1 is # A3. Compute ILOG. 13635 1.1 is # ILOG is the log base 10 of the input value. It is approx- 13636 1.1 is # imated by adding e + 0.f when the original value is viewed 13637 1.1 is # as 2^^e * 1.f in extended precision. This value is stored 13638 1.1 is # in d6. 13639 1.1 is # 13640 1.1 is # Register usage: 13641 1.1 is # Input/Output 13642 1.1 is # d0: k-factor/exponent 13643 1.1 is # d2: x/x 13644 1.1 is # d3: x/x 13645 1.1 is # d4: x/x 13646 1.1 is # d5: x/x 13647 1.1 is # d6: x/ILOG 13648 1.1 is # d7: k-factor/Unchanged 13649 1.1 is # a0: ptr for original operand/final result 13650 1.1 is # a1: x/x 13651 1.1 is # a2: x/x 13652 1.1 is # fp0: x/float(ILOG) 13653 1.1 is # fp1: x/x 13654 1.1 is # fp2: x/x 13655 1.1 is # F_SCR1:x/x 13656 1.1 is # F_SCR2:Abs(X)/Abs(X) with $3fff exponent 13657 1.1 is # L_SCR1:x/x 13658 1.1 is # L_SCR2:first word of X packed/Unchanged 13659 1.1 is 13660 1.1 is tst.b BINDEC_FLG(%a6) # check for denorm 13661 1.1 is beq.b A3_cont # if clr, continue with norm 13662 1.1 is mov.l &-4933,%d6 # force ILOG = -4933 13663 1.1 is bra.b A4_str 13664 1.1 is A3_cont: 13665 1.1 is mov.w FP_SCR1(%a6),%d0 # move exp to d0 13666 1.1 is mov.w &0x3fff,FP_SCR1(%a6) # replace exponent with 0x3fff 13667 1.1 is fmov.x FP_SCR1(%a6),%fp0 # now fp0 has 1.f 13668 1.1 is sub.w &0x3fff,%d0 # strip off bias 13669 1.1 is fadd.w %d0,%fp0 # add in exp 13670 1.1 is fsub.s FONE(%pc),%fp0 # subtract off 1.0 13671 1.1 is fbge.w pos_res # if pos, branch 13672 1.1 is fmul.x PLOG2UP1(%pc),%fp0 # if neg, mul by LOG2UP1 13673 1.1 is fmov.l %fp0,%d6 # put ILOG in d6 as a lword 13674 1.1 is bra.b A4_str # go move out ILOG 13675 1.1 is pos_res: 13676 1.1 is fmul.x PLOG2(%pc),%fp0 # if pos, mul by LOG2 13677 1.1 is fmov.l %fp0,%d6 # put ILOG in d6 as a lword 13678 1.1 is 13679 1.1 is 13680 1.1 is # A4. Clr INEX bit. 13681 1.1 is # The operation in A3 above may have set INEX2. 13682 1.1 is 13683 1.1 is A4_str: 13684 1.1 is fmov.l &0,%fpsr # zero all of fpsr - nothing needed 13685 1.1 is 13686 1.1 is 13687 1.1 is # A5. Set ICTR = 0; 13688 1.1 is # ICTR is a flag used in A13. It must be set before the 13689 1.1 is # loop entry A6. The lower word of d5 is used for ICTR. 13690 1.1 is 13691 1.1 is clr.w %d5 # clear ICTR 13692 1.1 is 13693 1.1 is # A6. Calculate LEN. 13694 1.1 is # LEN is the number of digits to be displayed. The k-factor 13695 1.1 is # can dictate either the total number of digits, if it is 13696 1.1 is # a positive number, or the number of digits after the 13697 1.1 is # original decimal point which are to be included as 13698 1.1 is # significant. See the 68882 manual for examples. 13699 1.1 is # If LEN is computed to be greater than 17, set OPERR in 13700 1.1 is # USER_FPSR. LEN is stored in d4. 13701 1.1 is # 13702 1.1 is # Register usage: 13703 1.1 is # Input/Output 13704 1.1 is # d0: exponent/Unchanged 13705 1.1 is # d2: x/x/scratch 13706 1.1 is # d3: x/x 13707 1.1 is # d4: exc picture/LEN 13708 1.1 is # d5: ICTR/Unchanged 13709 1.1 is # d6: ILOG/Unchanged 13710 1.1 is # d7: k-factor/Unchanged 13711 1.1 is # a0: ptr for original operand/final result 13712 1.1 is # a1: x/x 13713 1.1 is # a2: x/x 13714 1.1 is # fp0: float(ILOG)/Unchanged 13715 1.1 is # fp1: x/x 13716 1.1 is # fp2: x/x 13717 1.1 is # F_SCR1:x/x 13718 1.1 is # F_SCR2:Abs(X) with $3fff exponent/Unchanged 13719 1.1 is # L_SCR1:x/x 13720 1.1 is # L_SCR2:first word of X packed/Unchanged 13721 1.1 is 13722 1.1 is A6_str: 13723 1.1 is tst.l %d7 # branch on sign of k 13724 1.1 is ble.b k_neg # if k <= 0, LEN = ILOG + 1 - k 13725 1.1 is mov.l %d7,%d4 # if k > 0, LEN = k 13726 1.1 is bra.b len_ck # skip to LEN check 13727 1.1 is k_neg: 13728 1.1 is mov.l %d6,%d4 # first load ILOG to d4 13729 1.1 is sub.l %d7,%d4 # subtract off k 13730 1.1 is addq.l &1,%d4 # add in the 1 13731 1.1 is len_ck: 13732 1.1 is tst.l %d4 # LEN check: branch on sign of LEN 13733 1.1 is ble.b LEN_ng # if neg, set LEN = 1 13734 1.1 is cmp.l %d4,&17 # test if LEN > 17 13735 1.1 is ble.b A7_str # if not, forget it 13736 1.1 is mov.l &17,%d4 # set max LEN = 17 13737 1.1 is tst.l %d7 # if negative, never set OPERR 13738 1.1 is ble.b A7_str # if positive, continue 13739 1.1 is or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR 13740 1.1 is bra.b A7_str # finished here 13741 1.1 is LEN_ng: 13742 1.1 is mov.l &1,%d4 # min LEN is 1 13743 1.1 is 13744 1.1 is 13745 1.1 is # A7. Calculate SCALE. 13746 1.1 is # SCALE is equal to 10^ISCALE, where ISCALE is the number 13747 1.1 is # of decimal places needed to insure LEN integer digits 13748 1.1 is # in the output before conversion to bcd. LAMBDA is the sign 13749 1.1 is # of ISCALE, used in A9. Fp1 contains 10^^(abs(ISCALE)) using 13750 1.1 is # the rounding mode as given in the following table (see 13751 1.1 is # Coonen, p. 7.23 as ref.; however, the SCALE variable is 13752 1.1 is # of opposite sign in bindec.sa from Coonen). 13753 1.1 is # 13754 1.1 is # Initial USE 13755 1.1 is # FPCR[6:5] LAMBDA SIGN(X) FPCR[6:5] 13756 1.1 is # ---------------------------------------------- 13757 1.1 is # RN 00 0 0 00/0 RN 13758 1.1 is # RN 00 0 1 00/0 RN 13759 1.1 is # RN 00 1 0 00/0 RN 13760 1.1 is # RN 00 1 1 00/0 RN 13761 1.1 is # RZ 01 0 0 11/3 RP 13762 1.1 is # RZ 01 0 1 11/3 RP 13763 1.1 is # RZ 01 1 0 10/2 RM 13764 1.1 is # RZ 01 1 1 10/2 RM 13765 1.1 is # RM 10 0 0 11/3 RP 13766 1.1 is # RM 10 0 1 10/2 RM 13767 1.1 is # RM 10 1 0 10/2 RM 13768 1.1 is # RM 10 1 1 11/3 RP 13769 1.1 is # RP 11 0 0 10/2 RM 13770 1.1 is # RP 11 0 1 11/3 RP 13771 1.1 is # RP 11 1 0 11/3 RP 13772 1.1 is # RP 11 1 1 10/2 RM 13773 1.1 is # 13774 1.1 is # Register usage: 13775 1.1 is # Input/Output 13776 1.1 is # d0: exponent/scratch - final is 0 13777 1.1 is # d2: x/0 or 24 for A9 13778 1.1 is # d3: x/scratch - offset ptr into PTENRM array 13779 1.1 is # d4: LEN/Unchanged 13780 1.1 is # d5: 0/ICTR:LAMBDA 13781 1.1 is # d6: ILOG/ILOG or k if ((k<=0)&(ILOG<k)) 13782 1.1 is # d7: k-factor/Unchanged 13783 1.1 is # a0: ptr for original operand/final result 13784 1.1 is # a1: x/ptr to PTENRM array 13785 1.1 is # a2: x/x 13786 1.1 is # fp0: float(ILOG)/Unchanged 13787 1.1 is # fp1: x/10^ISCALE 13788 1.1 is # fp2: x/x 13789 1.1 is # F_SCR1:x/x 13790 1.1 is # F_SCR2:Abs(X) with $3fff exponent/Unchanged 13791 1.1 is # L_SCR1:x/x 13792 1.1 is # L_SCR2:first word of X packed/Unchanged 13793 1.1 is 13794 1.1 is A7_str: 13795 1.1 is tst.l %d7 # test sign of k 13796 1.1 is bgt.b k_pos # if pos and > 0, skip this 13797 1.1 is cmp.l %d7,%d6 # test k - ILOG 13798 1.1 is blt.b k_pos # if ILOG >= k, skip this 13799 1.1 is mov.l %d7,%d6 # if ((k<0) & (ILOG < k)) ILOG = k 13800 1.1 is k_pos: 13801 1.1 is mov.l %d6,%d0 # calc ILOG + 1 - LEN in d0 13802 1.1 is addq.l &1,%d0 # add the 1 13803 1.1 is sub.l %d4,%d0 # sub off LEN 13804 1.1 is swap %d5 # use upper word of d5 for LAMBDA 13805 1.1 is clr.w %d5 # set it zero initially 13806 1.1 is clr.w %d2 # set up d2 for very small case 13807 1.1 is tst.l %d0 # test sign of ISCALE 13808 1.1 is bge.b iscale # if pos, skip next inst 13809 1.1 is addq.w &1,%d5 # if neg, set LAMBDA true 13810 1.1 is cmp.l %d0,&0xffffecd4 # test iscale <= -4908 13811 1.1 is bgt.b no_inf # if false, skip rest 13812 1.1 is add.l &24,%d0 # add in 24 to iscale 13813 1.1 is mov.l &24,%d2 # put 24 in d2 for A9 13814 1.1 is no_inf: 13815 1.1 is neg.l %d0 # and take abs of ISCALE 13816 1.1 is iscale: 13817 1.1 is fmov.s FONE(%pc),%fp1 # init fp1 to 1 13818 1.1 is bfextu USER_FPCR(%a6){&26:&2},%d1 # get initial rmode bits 13819 1.1 is lsl.w &1,%d1 # put them in bits 2:1 13820 1.1 is add.w %d5,%d1 # add in LAMBDA 13821 1.1 is lsl.w &1,%d1 # put them in bits 3:1 13822 1.1 is tst.l L_SCR2(%a6) # test sign of original x 13823 1.1 is bge.b x_pos # if pos, don't set bit 0 13824 1.1 is addq.l &1,%d1 # if neg, set bit 0 13825 1.1 is x_pos: 13826 1.1 is lea.l RBDTBL(%pc),%a2 # load rbdtbl base 13827 1.1 is mov.b (%a2,%d1),%d3 # load d3 with new rmode 13828 1.1 is lsl.l &4,%d3 # put bits in proper position 13829 1.1 is fmov.l %d3,%fpcr # load bits into fpu 13830 1.1 is lsr.l &4,%d3 # put bits in proper position 13831 1.1 is tst.b %d3 # decode new rmode for pten table 13832 1.1 is bne.b not_rn # if zero, it is RN 13833 1.1 is lea.l PTENRN(%pc),%a1 # load a1 with RN table base 13834 1.1 is bra.b rmode # exit decode 13835 1.1 is not_rn: 13836 1.1 is lsr.b &1,%d3 # get lsb in carry 13837 1.1 is bcc.b not_rp2 # if carry clear, it is RM 13838 1.1 is lea.l PTENRP(%pc),%a1 # load a1 with RP table base 13839 1.1 is bra.b rmode # exit decode 13840 1.1 is not_rp2: 13841 1.1 is lea.l PTENRM(%pc),%a1 # load a1 with RM table base 13842 1.1 is rmode: 13843 1.1 is clr.l %d3 # clr table index 13844 1.1 is e_loop2: 13845 1.1 is lsr.l &1,%d0 # shift next bit into carry 13846 1.1 is bcc.b e_next2 # if zero, skip the mul 13847 1.1 is fmul.x (%a1,%d3),%fp1 # mul by 10**(d3_bit_no) 13848 1.1 is e_next2: 13849 1.1 is add.l &12,%d3 # inc d3 to next pwrten table entry 13850 1.1 is tst.l %d0 # test if ISCALE is zero 13851 1.1 is bne.b e_loop2 # if not, loop 13852 1.1 is 13853 1.1 is # A8. Clr INEX; Force RZ. 13854 1.1 is # The operation in A3 above may have set INEX2. 13855 1.1 is # RZ mode is forced for the scaling operation to insure 13856 1.1 is # only one rounding error. The grs bits are collected in 13857 1.1 is # the INEX flag for use in A10. 13858 1.1 is # 13859 1.1 is # Register usage: 13860 1.1 is # Input/Output 13861 1.1 is 13862 1.1 is fmov.l &0,%fpsr # clr INEX 13863 1.1 is fmov.l &rz_mode*0x10,%fpcr # set RZ rounding mode 13864 1.1 is 13865 1.1 is # A9. Scale X -> Y. 13866 1.1 is # The mantissa is scaled to the desired number of significant 13867 1.1 is # digits. The excess digits are collected in INEX2. If mul, 13868 1.1 is # Check d2 for excess 10 exponential value. If not zero, 13869 1.1 is # the iscale value would have caused the pwrten calculation 13870 1.1 is # to overflow. Only a negative iscale can cause this, so 13871 1.1 is # multiply by 10^(d2), which is now only allowed to be 24, 13872 1.1 is # with a multiply by 10^8 and 10^16, which is exact since 13873 1.1 is # 10^24 is exact. If the input was denormalized, we must 13874 1.1 is # create a busy stack frame with the mul command and the 13875 1.1 is # two operands, and allow the fpu to complete the multiply. 13876 1.1 is # 13877 1.1 is # Register usage: 13878 1.1 is # Input/Output 13879 1.1 is # d0: FPCR with RZ mode/Unchanged 13880 1.1 is # d2: 0 or 24/unchanged 13881 1.1 is # d3: x/x 13882 1.1 is # d4: LEN/Unchanged 13883 1.1 is # d5: ICTR:LAMBDA 13884 1.1 is # d6: ILOG/Unchanged 13885 1.1 is # d7: k-factor/Unchanged 13886 1.1 is # a0: ptr for original operand/final result 13887 1.1 is # a1: ptr to PTENRM array/Unchanged 13888 1.1 is # a2: x/x 13889 1.1 is # fp0: float(ILOG)/X adjusted for SCALE (Y) 13890 1.1 is # fp1: 10^ISCALE/Unchanged 13891 1.1 is # fp2: x/x 13892 1.1 is # F_SCR1:x/x 13893 1.1 is # F_SCR2:Abs(X) with $3fff exponent/Unchanged 13894 1.1 is # L_SCR1:x/x 13895 1.1 is # L_SCR2:first word of X packed/Unchanged 13896 1.1 is 13897 1.1 is A9_str: 13898 1.1 is fmov.x (%a0),%fp0 # load X from memory 13899 1.1 is fabs.x %fp0 # use abs(X) 13900 1.1 is tst.w %d5 # LAMBDA is in lower word of d5 13901 1.1 is bne.b sc_mul # if neg (LAMBDA = 1), scale by mul 13902 1.1 is fdiv.x %fp1,%fp0 # calculate X / SCALE -> Y to fp0 13903 1.1 is bra.w A10_st # branch to A10 13904 1.1 is 13905 1.1 is sc_mul: 13906 1.1 is tst.b BINDEC_FLG(%a6) # check for denorm 13907 1.1 is beq.w A9_norm # if norm, continue with mul 13908 1.1 is 13909 1.1 is # for DENORM, we must calculate: 13910 1.1 is # fp0 = input_op * 10^ISCALE * 10^24 13911 1.1 is # since the input operand is a DENORM, we can't multiply it directly. 13912 1.1 is # so, we do the multiplication of the exponents and mantissas separately. 13913 1.1 is # in this way, we avoid underflow on intermediate stages of the 13914 1.1 is # multiplication and guarantee a result without exception. 13915 1.1 is fmovm.x &0x2,-(%sp) # save 10^ISCALE to stack 13916 1.1 is 13917 1.1 is mov.w (%sp),%d3 # grab exponent 13918 1.1 is andi.w &0x7fff,%d3 # clear sign 13919 1.1 is ori.w &0x8000,(%a0) # make DENORM exp negative 13920 1.1 is add.w (%a0),%d3 # add DENORM exp to 10^ISCALE exp 13921 1.1 is subi.w &0x3fff,%d3 # subtract BIAS 13922 1.1 is add.w 36(%a1),%d3 13923 1.1 is subi.w &0x3fff,%d3 # subtract BIAS 13924 1.1 is add.w 48(%a1),%d3 13925 1.1 is subi.w &0x3fff,%d3 # subtract BIAS 13926 1.1 is 13927 1.1 is bmi.w sc_mul_err # is result is DENORM, punt!!! 13928 1.1 is 13929 1.1 is andi.w &0x8000,(%sp) # keep sign 13930 1.1 is or.w %d3,(%sp) # insert new exponent 13931 1.1 is andi.w &0x7fff,(%a0) # clear sign bit on DENORM again 13932 1.1 is mov.l 0x8(%a0),-(%sp) # put input op mantissa on stk 13933 1.1 is mov.l 0x4(%a0),-(%sp) 13934 1.1 is mov.l &0x3fff0000,-(%sp) # force exp to zero 13935 1.1 is fmovm.x (%sp)+,&0x80 # load normalized DENORM into fp0 13936 1.1 is fmul.x (%sp)+,%fp0 13937 1.1 is 13938 1.1 is # fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8 13939 1.1 is # fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16 13940 1.1 is mov.l 36+8(%a1),-(%sp) # get 10^8 mantissa 13941 1.1 is mov.l 36+4(%a1),-(%sp) 13942 1.1 is mov.l &0x3fff0000,-(%sp) # force exp to zero 13943 1.1 is mov.l 48+8(%a1),-(%sp) # get 10^16 mantissa 13944 1.1 is mov.l 48+4(%a1),-(%sp) 13945 1.1 is mov.l &0x3fff0000,-(%sp)# force exp to zero 13946 1.1 is fmul.x (%sp)+,%fp0 # multiply fp0 by 10^8 13947 1.1 is fmul.x (%sp)+,%fp0 # multiply fp0 by 10^16 13948 1.1 is bra.b A10_st 13949 1.1 is 13950 1.1 is sc_mul_err: 13951 1.1 is bra.b sc_mul_err 13952 1.1 is 13953 1.1 is A9_norm: 13954 1.1 is tst.w %d2 # test for small exp case 13955 1.1 is beq.b A9_con # if zero, continue as normal 13956 1.1 is fmul.x 36(%a1),%fp0 # multiply fp0 by 10^8 13957 1.1 is fmul.x 48(%a1),%fp0 # multiply fp0 by 10^16 13958 1.1 is A9_con: 13959 1.1 is fmul.x %fp1,%fp0 # calculate X * SCALE -> Y to fp0 13960 1.1 is 13961 1.1 is # A10. Or in INEX. 13962 1.2 wiz # If INEX is set, round error occurred. This is compensated 13963 1.1 is # for by 'or-ing' in the INEX2 flag to the lsb of Y. 13964 1.1 is # 13965 1.1 is # Register usage: 13966 1.1 is # Input/Output 13967 1.1 is # d0: FPCR with RZ mode/FPSR with INEX2 isolated 13968 1.1 is # d2: x/x 13969 1.1 is # d3: x/x 13970 1.1 is # d4: LEN/Unchanged 13971 1.1 is # d5: ICTR:LAMBDA 13972 1.1 is # d6: ILOG/Unchanged 13973 1.1 is # d7: k-factor/Unchanged 13974 1.1 is # a0: ptr for original operand/final result 13975 1.1 is # a1: ptr to PTENxx array/Unchanged 13976 1.1 is # a2: x/ptr to FP_SCR1(a6) 13977 1.1 is # fp0: Y/Y with lsb adjusted 13978 1.1 is # fp1: 10^ISCALE/Unchanged 13979 1.1 is # fp2: x/x 13980 1.1 is 13981 1.1 is A10_st: 13982 1.1 is fmov.l %fpsr,%d0 # get FPSR 13983 1.1 is fmov.x %fp0,FP_SCR1(%a6) # move Y to memory 13984 1.1 is lea.l FP_SCR1(%a6),%a2 # load a2 with ptr to FP_SCR1 13985 1.1 is btst &9,%d0 # check if INEX2 set 13986 1.1 is beq.b A11_st # if clear, skip rest 13987 1.1 is or.l &1,8(%a2) # or in 1 to lsb of mantissa 13988 1.1 is fmov.x FP_SCR1(%a6),%fp0 # write adjusted Y back to fpu 13989 1.1 is 13990 1.1 is 13991 1.1 is # A11. Restore original FPCR; set size ext. 13992 1.1 is # Perform FINT operation in the user's rounding mode. Keep 13993 1.1 is # the size to extended. The sintdo entry point in the sint 13994 1.1 is # routine expects the FPCR value to be in USER_FPCR for 13995 1.1 is # mode and precision. The original FPCR is saved in L_SCR1. 13996 1.1 is 13997 1.1 is A11_st: 13998 1.1 is mov.l USER_FPCR(%a6),L_SCR1(%a6) # save it for later 13999 1.1 is and.l &0x00000030,USER_FPCR(%a6) # set size to ext, 14000 1.1 is # ;block exceptions 14001 1.1 is 14002 1.1 is 14003 1.1 is # A12. Calculate YINT = FINT(Y) according to user's rounding mode. 14004 1.1 is # The FPSP routine sintd0 is used. The output is in fp0. 14005 1.1 is # 14006 1.1 is # Register usage: 14007 1.1 is # Input/Output 14008 1.1 is # d0: FPSR with AINEX cleared/FPCR with size set to ext 14009 1.1 is # d2: x/x/scratch 14010 1.1 is # d3: x/x 14011 1.1 is # d4: LEN/Unchanged 14012 1.1 is # d5: ICTR:LAMBDA/Unchanged 14013 1.1 is # d6: ILOG/Unchanged 14014 1.1 is # d7: k-factor/Unchanged 14015 1.1 is # a0: ptr for original operand/src ptr for sintdo 14016 1.1 is # a1: ptr to PTENxx array/Unchanged 14017 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged 14018 1.1 is # a6: temp pointer to FP_SCR1(a6) - orig value saved and restored 14019 1.1 is # fp0: Y/YINT 14020 1.1 is # fp1: 10^ISCALE/Unchanged 14021 1.1 is # fp2: x/x 14022 1.1 is # F_SCR1:x/x 14023 1.1 is # F_SCR2:Y adjusted for inex/Y with original exponent 14024 1.1 is # L_SCR1:x/original USER_FPCR 14025 1.1 is # L_SCR2:first word of X packed/Unchanged 14026 1.1 is 14027 1.1 is A12_st: 14028 1.1 is movm.l &0xc0c0,-(%sp) # save regs used by sintd0 {%d0-%d1/%a0-%a1} 14029 1.1 is mov.l L_SCR1(%a6),-(%sp) 14030 1.1 is mov.l L_SCR2(%a6),-(%sp) 14031 1.1 is 14032 1.1 is lea.l FP_SCR1(%a6),%a0 # a0 is ptr to FP_SCR1(a6) 14033 1.1 is fmov.x %fp0,(%a0) # move Y to memory at FP_SCR1(a6) 14034 1.1 is tst.l L_SCR2(%a6) # test sign of original operand 14035 1.1 is bge.b do_fint12 # if pos, use Y 14036 1.1 is or.l &0x80000000,(%a0) # if neg, use -Y 14037 1.1 is do_fint12: 14038 1.1 is mov.l USER_FPSR(%a6),-(%sp) 14039 1.1 is # bsr sintdo # sint routine returns int in fp0 14040 1.1 is 14041 1.1 is fmov.l USER_FPCR(%a6),%fpcr 14042 1.1 is fmov.l &0x0,%fpsr # clear the AEXC bits!!! 14043 1.1 is ## mov.l USER_FPCR(%a6),%d0 # ext prec/keep rnd mode 14044 1.1 is ## andi.l &0x00000030,%d0 14045 1.1 is ## fmov.l %d0,%fpcr 14046 1.1 is fint.x FP_SCR1(%a6),%fp0 # do fint() 14047 1.1 is fmov.l %fpsr,%d0 14048 1.1 is or.w %d0,FPSR_EXCEPT(%a6) 14049 1.1 is ## fmov.l &0x0,%fpcr 14050 1.1 is ## fmov.l %fpsr,%d0 # don't keep ccodes 14051 1.1 is ## or.w %d0,FPSR_EXCEPT(%a6) 14052 1.1 is 14053 1.1 is mov.b (%sp),USER_FPSR(%a6) 14054 1.1 is add.l &4,%sp 14055 1.1 is 14056 1.1 is mov.l (%sp)+,L_SCR2(%a6) 14057 1.1 is mov.l (%sp)+,L_SCR1(%a6) 14058 1.1 is movm.l (%sp)+,&0x303 # restore regs used by sint {%d0-%d1/%a0-%a1} 14059 1.1 is 14060 1.1 is mov.l L_SCR2(%a6),FP_SCR1(%a6) # restore original exponent 14061 1.1 is mov.l L_SCR1(%a6),USER_FPCR(%a6) # restore user's FPCR 14062 1.1 is 14063 1.1 is # A13. Check for LEN digits. 14064 1.1 is # If the int operation results in more than LEN digits, 14065 1.1 is # or less than LEN -1 digits, adjust ILOG and repeat from 14066 1.1 is # A6. This test occurs only on the first pass. If the 14067 1.1 is # result is exactly 10^LEN, decrement ILOG and divide 14068 1.1 is # the mantissa by 10. The calculation of 10^LEN cannot 14069 1.1 is # be inexact, since all powers of ten upto 10^27 are exact 14070 1.1 is # in extended precision, so the use of a previous power-of-ten 14071 1.1 is # table will introduce no error. 14072 1.1 is # 14073 1.1 is # 14074 1.1 is # Register usage: 14075 1.1 is # Input/Output 14076 1.1 is # d0: FPCR with size set to ext/scratch final = 0 14077 1.1 is # d2: x/x 14078 1.1 is # d3: x/scratch final = x 14079 1.1 is # d4: LEN/LEN adjusted 14080 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR 14081 1.1 is # d6: ILOG/ILOG adjusted 14082 1.1 is # d7: k-factor/Unchanged 14083 1.1 is # a0: pointer into memory for packed bcd string formation 14084 1.1 is # a1: ptr to PTENxx array/Unchanged 14085 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged 14086 1.1 is # fp0: int portion of Y/abs(YINT) adjusted 14087 1.1 is # fp1: 10^ISCALE/Unchanged 14088 1.1 is # fp2: x/10^LEN 14089 1.1 is # F_SCR1:x/x 14090 1.1 is # F_SCR2:Y with original exponent/Unchanged 14091 1.1 is # L_SCR1:original USER_FPCR/Unchanged 14092 1.1 is # L_SCR2:first word of X packed/Unchanged 14093 1.1 is 14094 1.1 is A13_st: 14095 1.1 is swap %d5 # put ICTR in lower word of d5 14096 1.1 is tst.w %d5 # check if ICTR = 0 14097 1.1 is bne not_zr # if non-zero, go to second test 14098 1.1 is # 14099 1.1 is # Compute 10^(LEN-1) 14100 1.1 is # 14101 1.1 is fmov.s FONE(%pc),%fp2 # init fp2 to 1.0 14102 1.1 is mov.l %d4,%d0 # put LEN in d0 14103 1.1 is subq.l &1,%d0 # d0 = LEN -1 14104 1.1 is clr.l %d3 # clr table index 14105 1.1 is l_loop: 14106 1.1 is lsr.l &1,%d0 # shift next bit into carry 14107 1.1 is bcc.b l_next # if zero, skip the mul 14108 1.1 is fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no) 14109 1.1 is l_next: 14110 1.1 is add.l &12,%d3 # inc d3 to next pwrten table entry 14111 1.1 is tst.l %d0 # test if LEN is zero 14112 1.1 is bne.b l_loop # if not, loop 14113 1.1 is # 14114 1.1 is # 10^LEN-1 is computed for this test and A14. If the input was 14115 1.1 is # denormalized, check only the case in which YINT > 10^LEN. 14116 1.1 is # 14117 1.1 is tst.b BINDEC_FLG(%a6) # check if input was norm 14118 1.1 is beq.b A13_con # if norm, continue with checking 14119 1.1 is fabs.x %fp0 # take abs of YINT 14120 1.1 is bra test_2 14121 1.1 is # 14122 1.1 is # Compare abs(YINT) to 10^(LEN-1) and 10^LEN 14123 1.1 is # 14124 1.1 is A13_con: 14125 1.1 is fabs.x %fp0 # take abs of YINT 14126 1.1 is fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^(LEN-1) 14127 1.1 is fbge.w test_2 # if greater, do next test 14128 1.1 is subq.l &1,%d6 # subtract 1 from ILOG 14129 1.1 is mov.w &1,%d5 # set ICTR 14130 1.1 is fmov.l &rm_mode*0x10,%fpcr # set rmode to RM 14131 1.1 is fmul.s FTEN(%pc),%fp2 # compute 10^LEN 14132 1.1 is bra.w A6_str # return to A6 and recompute YINT 14133 1.1 is test_2: 14134 1.1 is fmul.s FTEN(%pc),%fp2 # compute 10^LEN 14135 1.1 is fcmp.x %fp0,%fp2 # compare abs(YINT) with 10^LEN 14136 1.1 is fblt.w A14_st # if less, all is ok, go to A14 14137 1.1 is fbgt.w fix_ex # if greater, fix and redo 14138 1.1 is fdiv.s FTEN(%pc),%fp0 # if equal, divide by 10 14139 1.1 is addq.l &1,%d6 # and inc ILOG 14140 1.1 is bra.b A14_st # and continue elsewhere 14141 1.1 is fix_ex: 14142 1.1 is addq.l &1,%d6 # increment ILOG by 1 14143 1.1 is mov.w &1,%d5 # set ICTR 14144 1.1 is fmov.l &rm_mode*0x10,%fpcr # set rmode to RM 14145 1.1 is bra.w A6_str # return to A6 and recompute YINT 14146 1.1 is # 14147 1.1 is # Since ICTR <> 0, we have already been through one adjustment, 14148 1.1 is # and shouldn't have another; this is to check if abs(YINT) = 10^LEN 14149 1.1 is # 10^LEN is again computed using whatever table is in a1 since the 14150 1.1 is # value calculated cannot be inexact. 14151 1.1 is # 14152 1.1 is not_zr: 14153 1.1 is fmov.s FONE(%pc),%fp2 # init fp2 to 1.0 14154 1.1 is mov.l %d4,%d0 # put LEN in d0 14155 1.1 is clr.l %d3 # clr table index 14156 1.1 is z_loop: 14157 1.1 is lsr.l &1,%d0 # shift next bit into carry 14158 1.1 is bcc.b z_next # if zero, skip the mul 14159 1.1 is fmul.x (%a1,%d3),%fp2 # mul by 10**(d3_bit_no) 14160 1.1 is z_next: 14161 1.1 is add.l &12,%d3 # inc d3 to next pwrten table entry 14162 1.1 is tst.l %d0 # test if LEN is zero 14163 1.1 is bne.b z_loop # if not, loop 14164 1.1 is fabs.x %fp0 # get abs(YINT) 14165 1.1 is fcmp.x %fp0,%fp2 # check if abs(YINT) = 10^LEN 14166 1.1 is fbneq.w A14_st # if not, skip this 14167 1.1 is fdiv.s FTEN(%pc),%fp0 # divide abs(YINT) by 10 14168 1.1 is addq.l &1,%d6 # and inc ILOG by 1 14169 1.1 is addq.l &1,%d4 # and inc LEN 14170 1.1 is fmul.s FTEN(%pc),%fp2 # if LEN++, the get 10^^LEN 14171 1.1 is 14172 1.1 is # A14. Convert the mantissa to bcd. 14173 1.1 is # The binstr routine is used to convert the LEN digit 14174 1.1 is # mantissa to bcd in memory. The input to binstr is 14175 1.1 is # to be a fraction; i.e. (mantissa)/10^LEN and adjusted 14176 1.1 is # such that the decimal point is to the left of bit 63. 14177 1.1 is # The bcd digits are stored in the correct position in 14178 1.1 is # the final string area in memory. 14179 1.1 is # 14180 1.1 is # 14181 1.1 is # Register usage: 14182 1.1 is # Input/Output 14183 1.1 is # d0: x/LEN call to binstr - final is 0 14184 1.1 is # d1: x/0 14185 1.1 is # d2: x/ms 32-bits of mant of abs(YINT) 14186 1.1 is # d3: x/ls 32-bits of mant of abs(YINT) 14187 1.1 is # d4: LEN/Unchanged 14188 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR 14189 1.1 is # d6: ILOG 14190 1.1 is # d7: k-factor/Unchanged 14191 1.1 is # a0: pointer into memory for packed bcd string formation 14192 1.1 is # /ptr to first mantissa byte in result string 14193 1.1 is # a1: ptr to PTENxx array/Unchanged 14194 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged 14195 1.1 is # fp0: int portion of Y/abs(YINT) adjusted 14196 1.1 is # fp1: 10^ISCALE/Unchanged 14197 1.1 is # fp2: 10^LEN/Unchanged 14198 1.1 is # F_SCR1:x/Work area for final result 14199 1.1 is # F_SCR2:Y with original exponent/Unchanged 14200 1.1 is # L_SCR1:original USER_FPCR/Unchanged 14201 1.1 is # L_SCR2:first word of X packed/Unchanged 14202 1.1 is 14203 1.1 is A14_st: 14204 1.1 is fmov.l &rz_mode*0x10,%fpcr # force rz for conversion 14205 1.1 is fdiv.x %fp2,%fp0 # divide abs(YINT) by 10^LEN 14206 1.1 is lea.l FP_SCR0(%a6),%a0 14207 1.1 is fmov.x %fp0,(%a0) # move abs(YINT)/10^LEN to memory 14208 1.1 is mov.l 4(%a0),%d2 # move 2nd word of FP_RES to d2 14209 1.1 is mov.l 8(%a0),%d3 # move 3rd word of FP_RES to d3 14210 1.1 is clr.l 4(%a0) # zero word 2 of FP_RES 14211 1.1 is clr.l 8(%a0) # zero word 3 of FP_RES 14212 1.1 is mov.l (%a0),%d0 # move exponent to d0 14213 1.1 is swap %d0 # put exponent in lower word 14214 1.1 is beq.b no_sft # if zero, don't shift 14215 1.1 is sub.l &0x3ffd,%d0 # sub bias less 2 to make fract 14216 1.1 is tst.l %d0 # check if > 1 14217 1.1 is bgt.b no_sft # if so, don't shift 14218 1.1 is neg.l %d0 # make exp positive 14219 1.1 is m_loop: 14220 1.1 is lsr.l &1,%d2 # shift d2:d3 right, add 0s 14221 1.1 is roxr.l &1,%d3 # the number of places 14222 1.1 is dbf.w %d0,m_loop # given in d0 14223 1.1 is no_sft: 14224 1.1 is tst.l %d2 # check for mantissa of zero 14225 1.1 is bne.b no_zr # if not, go on 14226 1.1 is tst.l %d3 # continue zero check 14227 1.1 is beq.b zer_m # if zero, go directly to binstr 14228 1.1 is no_zr: 14229 1.1 is clr.l %d1 # put zero in d1 for addx 14230 1.1 is add.l &0x00000080,%d3 # inc at bit 7 14231 1.1 is addx.l %d1,%d2 # continue inc 14232 1.1 is and.l &0xffffff80,%d3 # strip off lsb not used by 882 14233 1.1 is zer_m: 14234 1.1 is mov.l %d4,%d0 # put LEN in d0 for binstr call 14235 1.1 is addq.l &3,%a0 # a0 points to M16 byte in result 14236 1.1 is bsr binstr # call binstr to convert mant 14237 1.1 is 14238 1.1 is 14239 1.1 is # A15. Convert the exponent to bcd. 14240 1.1 is # As in A14 above, the exp is converted to bcd and the 14241 1.1 is # digits are stored in the final string. 14242 1.1 is # 14243 1.1 is # Digits are stored in L_SCR1(a6) on return from BINDEC as: 14244 1.1 is # 14245 1.1 is # 32 16 15 0 14246 1.1 is # ----------------------------------------- 14247 1.1 is # | 0 | e3 | e2 | e1 | e4 | X | X | X | 14248 1.1 is # ----------------------------------------- 14249 1.1 is # 14250 1.1 is # And are moved into their proper places in FP_SCR0. If digit e4 14251 1.1 is # is non-zero, OPERR is signaled. In all cases, all 4 digits are 14252 1.1 is # written as specified in the 881/882 manual for packed decimal. 14253 1.1 is # 14254 1.1 is # Register usage: 14255 1.1 is # Input/Output 14256 1.1 is # d0: x/LEN call to binstr - final is 0 14257 1.1 is # d1: x/scratch (0);shift count for final exponent packing 14258 1.1 is # d2: x/ms 32-bits of exp fraction/scratch 14259 1.1 is # d3: x/ls 32-bits of exp fraction 14260 1.1 is # d4: LEN/Unchanged 14261 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR 14262 1.1 is # d6: ILOG 14263 1.1 is # d7: k-factor/Unchanged 14264 1.1 is # a0: ptr to result string/ptr to L_SCR1(a6) 14265 1.1 is # a1: ptr to PTENxx array/Unchanged 14266 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged 14267 1.1 is # fp0: abs(YINT) adjusted/float(ILOG) 14268 1.1 is # fp1: 10^ISCALE/Unchanged 14269 1.1 is # fp2: 10^LEN/Unchanged 14270 1.1 is # F_SCR1:Work area for final result/BCD result 14271 1.1 is # F_SCR2:Y with original exponent/ILOG/10^4 14272 1.1 is # L_SCR1:original USER_FPCR/Exponent digits on return from binstr 14273 1.1 is # L_SCR2:first word of X packed/Unchanged 14274 1.1 is 14275 1.1 is A15_st: 14276 1.1 is tst.b BINDEC_FLG(%a6) # check for denorm 14277 1.1 is beq.b not_denorm 14278 1.1 is ftest.x %fp0 # test for zero 14279 1.1 is fbeq.w den_zero # if zero, use k-factor or 4933 14280 1.1 is fmov.l %d6,%fp0 # float ILOG 14281 1.1 is fabs.x %fp0 # get abs of ILOG 14282 1.1 is bra.b convrt 14283 1.1 is den_zero: 14284 1.1 is tst.l %d7 # check sign of the k-factor 14285 1.1 is blt.b use_ilog # if negative, use ILOG 14286 1.1 is fmov.s F4933(%pc),%fp0 # force exponent to 4933 14287 1.1 is bra.b convrt # do it 14288 1.1 is use_ilog: 14289 1.1 is fmov.l %d6,%fp0 # float ILOG 14290 1.1 is fabs.x %fp0 # get abs of ILOG 14291 1.1 is bra.b convrt 14292 1.1 is not_denorm: 14293 1.1 is ftest.x %fp0 # test for zero 14294 1.1 is fbneq.w not_zero # if zero, force exponent 14295 1.1 is fmov.s FONE(%pc),%fp0 # force exponent to 1 14296 1.1 is bra.b convrt # do it 14297 1.1 is not_zero: 14298 1.1 is fmov.l %d6,%fp0 # float ILOG 14299 1.1 is fabs.x %fp0 # get abs of ILOG 14300 1.1 is convrt: 14301 1.1 is fdiv.x 24(%a1),%fp0 # compute ILOG/10^4 14302 1.1 is fmov.x %fp0,FP_SCR1(%a6) # store fp0 in memory 14303 1.1 is mov.l 4(%a2),%d2 # move word 2 to d2 14304 1.1 is mov.l 8(%a2),%d3 # move word 3 to d3 14305 1.1 is mov.w (%a2),%d0 # move exp to d0 14306 1.1 is beq.b x_loop_fin # if zero, skip the shift 14307 1.1 is sub.w &0x3ffd,%d0 # subtract off bias 14308 1.1 is neg.w %d0 # make exp positive 14309 1.1 is x_loop: 14310 1.1 is lsr.l &1,%d2 # shift d2:d3 right 14311 1.1 is roxr.l &1,%d3 # the number of places 14312 1.1 is dbf.w %d0,x_loop # given in d0 14313 1.1 is x_loop_fin: 14314 1.1 is clr.l %d1 # put zero in d1 for addx 14315 1.1 is add.l &0x00000080,%d3 # inc at bit 6 14316 1.1 is addx.l %d1,%d2 # continue inc 14317 1.1 is and.l &0xffffff80,%d3 # strip off lsb not used by 882 14318 1.1 is mov.l &4,%d0 # put 4 in d0 for binstr call 14319 1.1 is lea.l L_SCR1(%a6),%a0 # a0 is ptr to L_SCR1 for exp digits 14320 1.1 is bsr binstr # call binstr to convert exp 14321 1.1 is mov.l L_SCR1(%a6),%d0 # load L_SCR1 lword to d0 14322 1.1 is mov.l &12,%d1 # use d1 for shift count 14323 1.1 is lsr.l %d1,%d0 # shift d0 right by 12 14324 1.1 is bfins %d0,FP_SCR0(%a6){&4:&12} # put e3:e2:e1 in FP_SCR0 14325 1.1 is lsr.l %d1,%d0 # shift d0 right by 12 14326 1.1 is bfins %d0,FP_SCR0(%a6){&16:&4} # put e4 in FP_SCR0 14327 1.1 is tst.b %d0 # check if e4 is zero 14328 1.1 is beq.b A16_st # if zero, skip rest 14329 1.1 is or.l &opaop_mask,USER_FPSR(%a6) # set OPERR & AIOP in USER_FPSR 14330 1.1 is 14331 1.1 is 14332 1.1 is # A16. Write sign bits to final string. 14333 1.1 is # Sigma is bit 31 of initial value; RHO is bit 31 of d6 (ILOG). 14334 1.1 is # 14335 1.1 is # Register usage: 14336 1.1 is # Input/Output 14337 1.1 is # d0: x/scratch - final is x 14338 1.1 is # d2: x/x 14339 1.1 is # d3: x/x 14340 1.1 is # d4: LEN/Unchanged 14341 1.1 is # d5: ICTR:LAMBDA/LAMBDA:ICTR 14342 1.1 is # d6: ILOG/ILOG adjusted 14343 1.1 is # d7: k-factor/Unchanged 14344 1.1 is # a0: ptr to L_SCR1(a6)/Unchanged 14345 1.1 is # a1: ptr to PTENxx array/Unchanged 14346 1.1 is # a2: ptr to FP_SCR1(a6)/Unchanged 14347 1.1 is # fp0: float(ILOG)/Unchanged 14348 1.1 is # fp1: 10^ISCALE/Unchanged 14349 1.1 is # fp2: 10^LEN/Unchanged 14350 1.1 is # F_SCR1:BCD result with correct signs 14351 1.1 is # F_SCR2:ILOG/10^4 14352 1.1 is # L_SCR1:Exponent digits on return from binstr 14353 1.1 is # L_SCR2:first word of X packed/Unchanged 14354 1.1 is 14355 1.1 is A16_st: 14356 1.1 is clr.l %d0 # clr d0 for collection of signs 14357 1.1 is and.b &0x0f,FP_SCR0(%a6) # clear first nibble of FP_SCR0 14358 1.1 is tst.l L_SCR2(%a6) # check sign of original mantissa 14359 1.1 is bge.b mant_p # if pos, don't set SM 14360 1.1 is mov.l &2,%d0 # move 2 in to d0 for SM 14361 1.1 is mant_p: 14362 1.1 is tst.l %d6 # check sign of ILOG 14363 1.1 is bge.b wr_sgn # if pos, don't set SE 14364 1.1 is addq.l &1,%d0 # set bit 0 in d0 for SE 14365 1.1 is wr_sgn: 14366 1.1 is bfins %d0,FP_SCR0(%a6){&0:&2} # insert SM and SE into FP_SCR0 14367 1.1 is 14368 1.1 is # Clean up and restore all registers used. 14369 1.1 is 14370 1.1 is fmov.l &0,%fpsr # clear possible inex2/ainex bits 14371 1.1 is fmovm.x (%sp)+,&0xe0 # {%fp0-%fp2} 14372 1.1 is movm.l (%sp)+,&0x4fc # {%d2-%d7/%a2} 14373 1.1 is rts 14374 1.1 is 14375 1.1 is global PTENRN 14376 1.1 is PTENRN: 14377 1.1 is long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 14378 1.1 is long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 14379 1.1 is long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 14380 1.1 is long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 14381 1.1 is long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 14382 1.1 is long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32 14383 1.1 is long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64 14384 1.1 is long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128 14385 1.1 is long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256 14386 1.1 is long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512 14387 1.1 is long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024 14388 1.1 is long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048 14389 1.1 is long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096 14390 1.1 is 14391 1.1 is global PTENRP 14392 1.1 is PTENRP: 14393 1.1 is long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 14394 1.1 is long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 14395 1.1 is long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 14396 1.1 is long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 14397 1.1 is long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 14398 1.1 is long 0x40690000,0x9DC5ADA8,0x2B70B59E # 10 ^ 32 14399 1.1 is long 0x40D30000,0xC2781F49,0xFFCFA6D6 # 10 ^ 64 14400 1.1 is long 0x41A80000,0x93BA47C9,0x80E98CE0 # 10 ^ 128 14401 1.1 is long 0x43510000,0xAA7EEBFB,0x9DF9DE8E # 10 ^ 256 14402 1.1 is long 0x46A30000,0xE319A0AE,0xA60E91C7 # 10 ^ 512 14403 1.1 is long 0x4D480000,0xC9767586,0x81750C18 # 10 ^ 1024 14404 1.1 is long 0x5A920000,0x9E8B3B5D,0xC53D5DE5 # 10 ^ 2048 14405 1.1 is long 0x75250000,0xC4605202,0x8A20979B # 10 ^ 4096 14406 1.1 is 14407 1.1 is global PTENRM 14408 1.1 is PTENRM: 14409 1.1 is long 0x40020000,0xA0000000,0x00000000 # 10 ^ 1 14410 1.1 is long 0x40050000,0xC8000000,0x00000000 # 10 ^ 2 14411 1.1 is long 0x400C0000,0x9C400000,0x00000000 # 10 ^ 4 14412 1.1 is long 0x40190000,0xBEBC2000,0x00000000 # 10 ^ 8 14413 1.1 is long 0x40340000,0x8E1BC9BF,0x04000000 # 10 ^ 16 14414 1.1 is long 0x40690000,0x9DC5ADA8,0x2B70B59D # 10 ^ 32 14415 1.1 is long 0x40D30000,0xC2781F49,0xFFCFA6D5 # 10 ^ 64 14416 1.1 is long 0x41A80000,0x93BA47C9,0x80E98CDF # 10 ^ 128 14417 1.1 is long 0x43510000,0xAA7EEBFB,0x9DF9DE8D # 10 ^ 256 14418 1.1 is long 0x46A30000,0xE319A0AE,0xA60E91C6 # 10 ^ 512 14419 1.1 is long 0x4D480000,0xC9767586,0x81750C17 # 10 ^ 1024 14420 1.1 is long 0x5A920000,0x9E8B3B5D,0xC53D5DE4 # 10 ^ 2048 14421 1.1 is long 0x75250000,0xC4605202,0x8A20979A # 10 ^ 4096 14422 1.1 is 14423 1.1 is ######################################################################### 14424 1.1 is # binstr(): Converts a 64-bit binary integer to bcd. # 14425 1.1 is # # 14426 1.1 is # INPUT *************************************************************** # 14427 1.1 is # d2:d3 = 64-bit binary integer # 14428 1.1 is # d0 = desired length (LEN) # 14429 1.1 is # a0 = pointer to start in memory for bcd characters # 14430 1.1 is # (This pointer must point to byte 4 of the first # 14431 1.1 is # lword of the packed decimal memory string.) # 14432 1.1 is # # 14433 1.1 is # OUTPUT ************************************************************** # 14434 1.1 is # a0 = pointer to LEN bcd digits representing the 64-bit integer. # 14435 1.1 is # # 14436 1.1 is # ALGORITHM *********************************************************** # 14437 1.1 is # The 64-bit binary is assumed to have a decimal point before # 14438 1.1 is # bit 63. The fraction is multiplied by 10 using a mul by 2 # 14439 1.1 is # shift and a mul by 8 shift. The bits shifted out of the # 14440 1.1 is # msb form a decimal digit. This process is iterated until # 14441 1.1 is # LEN digits are formed. # 14442 1.1 is # # 14443 1.1 is # A1. Init d7 to 1. D7 is the byte digit counter, and if 1, the # 14444 1.1 is # digit formed will be assumed the least significant. This is # 14445 1.1 is # to force the first byte formed to have a 0 in the upper 4 bits. # 14446 1.1 is # # 14447 1.1 is # A2. Beginning of the loop: # 14448 1.1 is # Copy the fraction in d2:d3 to d4:d5. # 14449 1.1 is # # 14450 1.1 is # A3. Multiply the fraction in d2:d3 by 8 using bit-field # 14451 1.1 is # extracts and shifts. The three msbs from d2 will go into d1. # 14452 1.1 is # # 14453 1.1 is # A4. Multiply the fraction in d4:d5 by 2 using shifts. The msb # 14454 1.1 is # will be collected by the carry. # 14455 1.1 is # # 14456 1.1 is # A5. Add using the carry the 64-bit quantities in d2:d3 and d4:d5 # 14457 1.1 is # into d2:d3. D1 will contain the bcd digit formed. # 14458 1.1 is # # 14459 1.1 is # A6. Test d7. If zero, the digit formed is the ms digit. If non- # 14460 1.1 is # zero, it is the ls digit. Put the digit in its place in the # 14461 1.1 is # upper word of d0. If it is the ls digit, write the word # 14462 1.1 is # from d0 to memory. # 14463 1.1 is # # 14464 1.1 is # A7. Decrement d6 (LEN counter) and repeat the loop until zero. # 14465 1.1 is # # 14466 1.1 is ######################################################################### 14467 1.1 is 14468 1.1 is # Implementation Notes: 14469 1.1 is # 14470 1.1 is # The registers are used as follows: 14471 1.1 is # 14472 1.1 is # d0: LEN counter 14473 1.1 is # d1: temp used to form the digit 14474 1.1 is # d2: upper 32-bits of fraction for mul by 8 14475 1.1 is # d3: lower 32-bits of fraction for mul by 8 14476 1.1 is # d4: upper 32-bits of fraction for mul by 2 14477 1.1 is # d5: lower 32-bits of fraction for mul by 2 14478 1.1 is # d6: temp for bit-field extracts 14479 1.1 is # d7: byte digit formation word;digit count {0,1} 14480 1.1 is # a0: pointer into memory for packed bcd string formation 14481 1.1 is # 14482 1.1 is 14483 1.1 is global binstr 14484 1.1 is binstr: 14485 1.1 is movm.l &0xff00,-(%sp) # {%d0-%d7} 14486 1.1 is 14487 1.1 is # 14488 1.1 is # A1: Init d7 14489 1.1 is # 14490 1.1 is mov.l &1,%d7 # init d7 for second digit 14491 1.1 is subq.l &1,%d0 # for dbf d0 would have LEN+1 passes 14492 1.1 is # 14493 1.1 is # A2. Copy d2:d3 to d4:d5. Start loop. 14494 1.1 is # 14495 1.1 is loop: 14496 1.1 is mov.l %d2,%d4 # copy the fraction before muls 14497 1.1 is mov.l %d3,%d5 # to d4:d5 14498 1.1 is # 14499 1.1 is # A3. Multiply d2:d3 by 8; extract msbs into d1. 14500 1.1 is # 14501 1.1 is bfextu %d2{&0:&3},%d1 # copy 3 msbs of d2 into d1 14502 1.1 is asl.l &3,%d2 # shift d2 left by 3 places 14503 1.1 is bfextu %d3{&0:&3},%d6 # copy 3 msbs of d3 into d6 14504 1.1 is asl.l &3,%d3 # shift d3 left by 3 places 14505 1.1 is or.l %d6,%d2 # or in msbs from d3 into d2 14506 1.1 is # 14507 1.1 is # A4. Multiply d4:d5 by 2; add carry out to d1. 14508 1.1 is # 14509 1.1 is asl.l &1,%d5 # mul d5 by 2 14510 1.1 is roxl.l &1,%d4 # mul d4 by 2 14511 1.1 is swap %d6 # put 0 in d6 lower word 14512 1.1 is addx.w %d6,%d1 # add in extend from mul by 2 14513 1.1 is # 14514 1.1 is # A5. Add mul by 8 to mul by 2. D1 contains the digit formed. 14515 1.1 is # 14516 1.1 is add.l %d5,%d3 # add lower 32 bits 14517 1.1 is nop # ERRATA FIX #13 (Rev. 1.2 6/6/90) 14518 1.1 is addx.l %d4,%d2 # add with extend upper 32 bits 14519 1.1 is nop # ERRATA FIX #13 (Rev. 1.2 6/6/90) 14520 1.1 is addx.w %d6,%d1 # add in extend from add to d1 14521 1.1 is swap %d6 # with d6 = 0; put 0 in upper word 14522 1.1 is # 14523 1.1 is # A6. Test d7 and branch. 14524 1.1 is # 14525 1.1 is tst.w %d7 # if zero, store digit & to loop 14526 1.1 is beq.b first_d # if non-zero, form byte & write 14527 1.1 is sec_d: 14528 1.1 is swap %d7 # bring first digit to word d7b 14529 1.1 is asl.w &4,%d7 # first digit in upper 4 bits d7b 14530 1.1 is add.w %d1,%d7 # add in ls digit to d7b 14531 1.1 is mov.b %d7,(%a0)+ # store d7b byte in memory 14532 1.1 is swap %d7 # put LEN counter in word d7a 14533 1.1 is clr.w %d7 # set d7a to signal no digits done 14534 1.1 is dbf.w %d0,loop # do loop some more! 14535 1.1 is bra.b end_bstr # finished, so exit 14536 1.1 is first_d: 14537 1.1 is swap %d7 # put digit word in d7b 14538 1.1 is mov.w %d1,%d7 # put new digit in d7b 14539 1.1 is swap %d7 # put LEN counter in word d7a 14540 1.1 is addq.w &1,%d7 # set d7a to signal first digit done 14541 1.1 is dbf.w %d0,loop # do loop some more! 14542 1.1 is swap %d7 # put last digit in string 14543 1.1 is lsl.w &4,%d7 # move it to upper 4 bits 14544 1.1 is mov.b %d7,(%a0)+ # store it in memory string 14545 1.1 is # 14546 1.1 is # Clean up and return with result in fp0. 14547 1.1 is # 14548 1.1 is end_bstr: 14549 1.1 is movm.l (%sp)+,&0xff # {%d0-%d7} 14550 1.1 is rts 14551 1.1 is 14552 1.1 is ######################################################################### 14553 1.1 is # XDEF **************************************************************** # 14554 1.1 is # facc_in_b(): dmem_read_byte failed # 14555 1.1 is # facc_in_w(): dmem_read_word failed # 14556 1.1 is # facc_in_l(): dmem_read_long failed # 14557 1.1 is # facc_in_d(): dmem_read of dbl prec failed # 14558 1.1 is # facc_in_x(): dmem_read of ext prec failed # 14559 1.1 is # # 14560 1.1 is # facc_out_b(): dmem_write_byte failed # 14561 1.1 is # facc_out_w(): dmem_write_word failed # 14562 1.1 is # facc_out_l(): dmem_write_long failed # 14563 1.1 is # facc_out_d(): dmem_write of dbl prec failed # 14564 1.1 is # facc_out_x(): dmem_write of ext prec failed # 14565 1.1 is # # 14566 1.1 is # XREF **************************************************************** # 14567 1.1 is # _real_access() - exit through access error handler # 14568 1.1 is # # 14569 1.1 is # INPUT *************************************************************** # 14570 1.1 is # None # 14571 1.1 is # # 14572 1.1 is # OUTPUT ************************************************************** # 14573 1.1 is # None # 14574 1.1 is # # 14575 1.1 is # ALGORITHM *********************************************************** # 14576 1.1 is # Flow jumps here when an FP data fetch call gets an error # 14577 1.1 is # result. This means the operating system wants an access error frame # 14578 1.1 is # made out of the current exception stack frame. # 14579 1.1 is # So, we first call restore() which makes sure that any updated # 14580 1.1 is # -(an)+ register gets returned to its pre-exception value and then # 14581 1.1 is # we change the stack to an acess error stack frame. # 14582 1.1 is # # 14583 1.1 is ######################################################################### 14584 1.1 is 14585 1.1 is facc_in_b: 14586 1.1 is movq.l &0x1,%d0 # one byte 14587 1.1 is bsr.w restore # fix An 14588 1.1 is 14589 1.1 is mov.w &0x0121,EXC_VOFF(%a6) # set FSLW 14590 1.1 is bra.w facc_finish 14591 1.1 is 14592 1.1 is facc_in_w: 14593 1.1 is movq.l &0x2,%d0 # two bytes 14594 1.1 is bsr.w restore # fix An 14595 1.1 is 14596 1.1 is mov.w &0x0141,EXC_VOFF(%a6) # set FSLW 14597 1.1 is bra.b facc_finish 14598 1.1 is 14599 1.1 is facc_in_l: 14600 1.1 is movq.l &0x4,%d0 # four bytes 14601 1.1 is bsr.w restore # fix An 14602 1.1 is 14603 1.1 is mov.w &0x0101,EXC_VOFF(%a6) # set FSLW 14604 1.1 is bra.b facc_finish 14605 1.1 is 14606 1.1 is facc_in_d: 14607 1.1 is movq.l &0x8,%d0 # eight bytes 14608 1.1 is bsr.w restore # fix An 14609 1.1 is 14610 1.1 is mov.w &0x0161,EXC_VOFF(%a6) # set FSLW 14611 1.1 is bra.b facc_finish 14612 1.1 is 14613 1.1 is facc_in_x: 14614 1.1 is movq.l &0xc,%d0 # twelve bytes 14615 1.1 is bsr.w restore # fix An 14616 1.1 is 14617 1.1 is mov.w &0x0161,EXC_VOFF(%a6) # set FSLW 14618 1.1 is bra.b facc_finish 14619 1.1 is 14620 1.1 is ################################################################ 14621 1.1 is 14622 1.1 is facc_out_b: 14623 1.1 is movq.l &0x1,%d0 # one byte 14624 1.1 is bsr.w restore # restore An 14625 1.1 is 14626 1.1 is mov.w &0x00a1,EXC_VOFF(%a6) # set FSLW 14627 1.1 is bra.b facc_finish 14628 1.1 is 14629 1.1 is facc_out_w: 14630 1.1 is movq.l &0x2,%d0 # two bytes 14631 1.1 is bsr.w restore # restore An 14632 1.1 is 14633 1.1 is mov.w &0x00c1,EXC_VOFF(%a6) # set FSLW 14634 1.1 is bra.b facc_finish 14635 1.1 is 14636 1.1 is facc_out_l: 14637 1.1 is movq.l &0x4,%d0 # four bytes 14638 1.1 is bsr.w restore # restore An 14639 1.1 is 14640 1.1 is mov.w &0x0081,EXC_VOFF(%a6) # set FSLW 14641 1.1 is bra.b facc_finish 14642 1.1 is 14643 1.1 is facc_out_d: 14644 1.1 is movq.l &0x8,%d0 # eight bytes 14645 1.1 is bsr.w restore # restore An 14646 1.1 is 14647 1.1 is mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW 14648 1.1 is bra.b facc_finish 14649 1.1 is 14650 1.1 is facc_out_x: 14651 1.1 is mov.l &0xc,%d0 # twelve bytes 14652 1.1 is bsr.w restore # restore An 14653 1.1 is 14654 1.1 is mov.w &0x00e1,EXC_VOFF(%a6) # set FSLW 14655 1.1 is 14656 1.1 is # here's where we actually create the access error frame from the 14657 1.1 is # current exception stack frame. 14658 1.1 is facc_finish: 14659 1.1 is mov.l USER_FPIAR(%a6),EXC_PC(%a6) # store current PC 14660 1.1 is 14661 1.1 is fmovm.x EXC_FPREGS(%a6),&0xc0 # restore fp0-fp1 14662 1.1 is fmovm.l USER_FPCR(%a6),%fpcr,%fpsr,%fpiar # restore ctrl regs 14663 1.1 is movm.l EXC_DREGS(%a6),&0x0303 # restore d0-d1/a0-a1 14664 1.1 is 14665 1.1 is unlk %a6 14666 1.1 is 14667 1.1 is mov.l (%sp),-(%sp) # store SR, hi(PC) 14668 1.1 is mov.l 0x8(%sp),0x4(%sp) # store lo(PC) 14669 1.1 is mov.l 0xc(%sp),0x8(%sp) # store EA 14670 1.1 is mov.l &0x00000001,0xc(%sp) # store FSLW 14671 1.1 is mov.w 0x6(%sp),0xc(%sp) # fix FSLW (size) 14672 1.1 is mov.w &0x4008,0x6(%sp) # store voff 14673 1.1 is 14674 1.1 is btst &0x5,(%sp) # supervisor or user mode? 14675 1.1 is beq.b facc_out2 # user 14676 1.1 is bset &0x2,0xd(%sp) # set supervisor TM bit 14677 1.1 is 14678 1.1 is facc_out2: 14679 1.1 is bra.l _real_access 14680 1.1 is 14681 1.1 is ################################################################## 14682 1.1 is 14683 1.1 is # if the effective addressing mode was predecrement or postincrement, 14684 1.1 is # the emulation has already changed its value to the correct post- 14685 1.1 is # instruction value. but since we're exiting to the access error 14686 1.1 is # handler, then AN must be returned to its pre-instruction value. 14687 1.1 is # we do that here. 14688 1.1 is restore: 14689 1.1 is mov.b EXC_OPWORD+0x1(%a6),%d1 14690 1.1 is andi.b &0x38,%d1 # extract opmode 14691 1.1 is cmpi.b %d1,&0x18 # postinc? 14692 1.1 is beq.w rest_inc 14693 1.1 is cmpi.b %d1,&0x20 # predec? 14694 1.1 is beq.w rest_dec 14695 1.1 is rts 14696 1.1 is 14697 1.1 is rest_inc: 14698 1.1 is mov.b EXC_OPWORD+0x1(%a6),%d1 14699 1.1 is andi.w &0x0007,%d1 # fetch An 14700 1.1 is 14701 1.1 is mov.w (tbl_rest_inc.b,%pc,%d1.w*2),%d1 14702 1.1 is jmp (tbl_rest_inc.b,%pc,%d1.w*1) 14703 1.1 is 14704 1.1 is tbl_rest_inc: 14705 1.1 is short ri_a0 - tbl_rest_inc 14706 1.1 is short ri_a1 - tbl_rest_inc 14707 1.1 is short ri_a2 - tbl_rest_inc 14708 1.1 is short ri_a3 - tbl_rest_inc 14709 1.1 is short ri_a4 - tbl_rest_inc 14710 1.1 is short ri_a5 - tbl_rest_inc 14711 1.1 is short ri_a6 - tbl_rest_inc 14712 1.1 is short ri_a7 - tbl_rest_inc 14713 1.1 is 14714 1.1 is ri_a0: 14715 1.1 is sub.l %d0,EXC_DREGS+0x8(%a6) # fix stacked a0 14716 1.1 is rts 14717 1.1 is ri_a1: 14718 1.1 is sub.l %d0,EXC_DREGS+0xc(%a6) # fix stacked a1 14719 1.1 is rts 14720 1.1 is ri_a2: 14721 1.1 is sub.l %d0,%a2 # fix a2 14722 1.1 is rts 14723 1.1 is ri_a3: 14724 1.1 is sub.l %d0,%a3 # fix a3 14725 1.1 is rts 14726 1.1 is ri_a4: 14727 1.1 is sub.l %d0,%a4 # fix a4 14728 1.1 is rts 14729 1.1 is ri_a5: 14730 1.1 is sub.l %d0,%a5 # fix a5 14731 1.1 is rts 14732 1.1 is ri_a6: 14733 1.1 is sub.l %d0,(%a6) # fix stacked a6 14734 1.1 is rts 14735 1.1 is # if it's a fmove out instruction, we don't have to fix a7 14736 1.1 is # because we hadn't changed it yet. if it's an opclass two 14737 1.1 is # instruction (data moved in) and the exception was in supervisor 14738 1.1 is # mode, then also also wasn't updated. if it was user mode, then 14739 1.1 is # restore the correct a7 which is in the USP currently. 14740 1.1 is ri_a7: 14741 1.1 is cmpi.b EXC_VOFF(%a6),&0x30 # move in or out? 14742 1.1 is bne.b ri_a7_done # out 14743 1.1 is 14744 1.1 is btst &0x5,EXC_SR(%a6) # user or supervisor? 14745 1.1 is bne.b ri_a7_done # supervisor 14746 1.1 is movc %usp,%a0 # restore USP 14747 1.1 is sub.l %d0,%a0 14748 1.1 is movc %a0,%usp 14749 1.1 is ri_a7_done: 14750 1.1 is rts 14751 1.1 is 14752 1.1 is # need to invert adjustment value if the <ea> was predec 14753 1.1 is rest_dec: 14754 1.1 is neg.l %d0 14755 1.1 is bra.b rest_inc 14756