Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | | | x_operr.sa 3.5 7/1/91 | | fpsp_operr --- FPSP handler for operand error exception | | See 68040 User's Manual pp. 9-44f | | Note 1: For trap disabled 040 does the following: | If the dest is a fp reg, then an extended precision non_signaling | NAN is stored in the dest reg. If the dest format is b, w, or l and | the source op is a NAN, then garbage is stored as the result (actually | the upper 32 bits of the mantissa are sent to the integer unit). If | the dest format is integer (b, w, l) and the operr is caused by | integer overflow, or the source op is inf, then the result stored is | garbage. | There are three cases in which operr is incorrectly signaled on the | 040. This occurs for move_out of format b, w, or l for the largest | negative integer (-2^7 for b, -2^15 for w, -2^31 for l). | | On opclass = 011 fmove.(b,w,l) that causes a conversion | overflow -> OPERR, the exponent in wbte (and fpte) is: | byte 56 - (62 - exp) | word 48 - (62 - exp) | long 32 - (62 - exp) | | where exp = (true exp) - 1 | | So, wbtemp and fptemp will contain the following on erroneously | signalled operr: | fpts = 1 | fpte = $4000 (15 bit externally) | byte fptm = $ffffffff ffffff80 | word fptm = $ffffffff ffff8000 | long fptm = $ffffffff 80000000 | | Note 2: For trap enabled 040 does the following: | If the inst is move_out, then same as Note 1. | If the inst is not move_out, the dest is not modified. | The exceptional operand is not defined for integer overflow | during a move_out. | | Copyright (C) Motorola, Inc. 1990 | All Rights Reserved | | For details on the license for this file, please see the | file, README, in this same directory. X_OPERR: |idnt 2,1 | Motorola 040 Floating Point Software Package |section 8 #include "fpsp.h" |xref mem_write |xref real_operr |xref real_inex |xref get_fline |xref fpsp_done |xref reg_dest .global fpsp_operr fpsp_operr: | link %a6,#-LOCAL_SIZE fsave -(%a7) moveml %d0-%d1/%a0-%a1,USER_DA(%a6) fmovemx %fp0-%fp3,USER_FP0(%a6) fmoveml %fpcr/%fpsr/%fpiar,USER_FPCR(%a6) | | Check if this is an opclass 3 instruction. | If so, fall through, else branch to operr_end | btstb #TFLAG,T_BYTE(%a6) beqs operr_end | | If the destination size is B,W,or L, the operr must be | handled here. | movel CMDREG1B(%a6),%d0 bfextu %d0{#3:#3},%d0 |0=long, 4=word, 6=byte cmpib #0,%d0 |determine size; check long beq operr_long cmpib #4,%d0 |check word beq operr_word cmpib #6,%d0 |check byte beq operr_byte | | The size is not B,W,or L, so the operr is handled by the | kernel handler. Set the operr bits and clean up, leaving | only the integer exception frame on the stack, and the | fpu in the original exceptional state. | operr_end: bsetb #operr_bit,FPSR_EXCEPT(%a6) bsetb #aiop_bit,FPSR_AEXCEPT(%a6) moveml USER_DA(%a6),%d0-%d1/%a0-%a1 fmovemx USER_FP0(%a6),%fp0-%fp3 fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar frestore (%a7)+ unlk %a6 bral real_operr operr_long: moveql #4,%d1 |write size to d1 moveb STAG(%a6),%d0 |test stag for nan andib #0xe0,%d0 |clr all but tag cmpib #0x60,%d0 |check for nan beq operr_nan cmpil #0x80000000,FPTEMP_LO(%a6) |test if ls lword is special bnes chklerr |if not equal, check for incorrect operr bsr check_upper |check if exp and ms mant are special tstl %d0 bnes chklerr |if d0 is true, check for incorrect operr movel #0x80000000,%d0 |store special case result bsr operr_store bra not_enabled |clean and exit | | CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE | chklerr: movew FPTEMP_EX(%a6),%d0 andw #0x7FFF,%d0 |ignore sign bit cmpw #0x3FFE,%d0 |this is the only possible exponent value bnes chklerr2 fixlong: movel FPTEMP_LO(%a6),%d0 bsr operr_store bra not_enabled chklerr2: movew FPTEMP_EX(%a6),%d0 andw #0x7FFF,%d0 |ignore sign bit cmpw #0x4000,%d0 bcc store_max |exponent out of range movel FPTEMP_LO(%a6),%d0 andl #0x7FFF0000,%d0 |look for all 1's on bits 30-16 cmpl #0x7FFF0000,%d0 beqs fixlong tstl FPTEMP_LO(%a6) bpls chklepos cmpl #0xFFFFFFFF,FPTEMP_HI(%a6) beqs fixlong bra store_max chklepos: tstl FPTEMP_HI(%a6) beqs fixlong bra store_max operr_word: moveql #2,%d1 |write size to d1 moveb STAG(%a6),%d0 |test stag for nan andib #0xe0,%d0 |clr all but tag cmpib #0x60,%d0 |check for nan beq operr_nan cmpil #0xffff8000,FPTEMP_LO(%a6) |test if ls lword is special bnes chkwerr |if not equal, check for incorrect operr bsr check_upper |check if exp and ms mant are special tstl %d0 bnes chkwerr |if d0 is true, check for incorrect operr movel #0x80000000,%d0 |store special case result bsr operr_store bra not_enabled |clean and exit | | CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE | chkwerr: movew FPTEMP_EX(%a6),%d0 andw #0x7FFF,%d0 |ignore sign bit cmpw #0x3FFE,%d0 |this is the only possible exponent value bnes store_max movel FPTEMP_LO(%a6),%d0 swap %d0 bsr operr_store bra not_enabled operr_byte: moveql #1,%d1 |write size to d1 moveb STAG(%a6),%d0 |test stag for nan andib #0xe0,%d0 |clr all but tag cmpib #0x60,%d0 |check for nan beqs operr_nan cmpil #0xffffff80,FPTEMP_LO(%a6) |test if ls lword is special bnes chkberr |if not equal, check for incorrect operr bsr check_upper |check if exp and ms mant are special tstl %d0 bnes chkberr |if d0 is true, check for incorrect operr movel #0x80000000,%d0 |store special case result bsr operr_store bra not_enabled |clean and exit | | CHECK FOR INCORRECTLY GENERATED OPERR EXCEPTION HERE | chkberr: movew FPTEMP_EX(%a6),%d0 andw #0x7FFF,%d0 |ignore sign bit cmpw #0x3FFE,%d0 |this is the only possible exponent value bnes store_max movel FPTEMP_LO(%a6),%d0 asll #8,%d0 swap %d0 bsr operr_store bra not_enabled | | This operr condition is not of the special case. Set operr | and aiop and write the portion of the nan to memory for the | given size. | operr_nan: orl #opaop_mask,USER_FPSR(%a6) |set operr & aiop movel ETEMP_HI(%a6),%d0 |output will be from upper 32 bits bsr operr_store bra end_operr | | Store_max loads the max pos or negative for the size, sets | the operr and aiop bits, and clears inex and ainex, incorrectly | set by the 040. | store_max: orl #opaop_mask,USER_FPSR(%a6) |set operr & aiop bclrb #inex2_bit,FPSR_EXCEPT(%a6) bclrb #ainex_bit,FPSR_AEXCEPT(%a6) fmovel #0,%FPSR tstw FPTEMP_EX(%a6) |check sign blts load_neg movel #0x7fffffff,%d0 bsr operr_store bra end_operr load_neg: movel #0x80000000,%d0 bsr operr_store bra end_operr | | This routine stores the data in d0, for the given size in d1, | to memory or data register as required. A read of the fline | is required to determine the destination. | operr_store: movel %d0,L_SCR1(%a6) |move write data to L_SCR1 movel %d1,-(%a7) |save register size bsrl get_fline |fline returned in d0 movel (%a7)+,%d1 bftst %d0{#26:#3} |if mode is zero, dest is Dn bnes dest_mem | | Destination is Dn. Get register number from d0. Data is on | the stack at (a7). D1 has size: 1=byte,2=word,4=long/single | andil #7,%d0 |isolate register number cmpil #4,%d1 beqs op_long |the most frequent case cmpil #2,%d1 bnes op_con orl #8,%d0 bras op_con op_long: orl #0x10,%d0 op_con: movel %d0,%d1 |format size:reg for reg_dest bral reg_dest |call to reg_dest returns to caller | ;of operr_store | | Destination is memory. Get <ea> from integer exception frame | and call mem_write. | dest_mem: leal L_SCR1(%a6),%a0 |put ptr to write data in a0 movel EXC_EA(%a6),%a1 |put user destination address in a1 movel %d1,%d0 |put size in d0 bsrl mem_write rts | | Check the exponent for $c000 and the upper 32 bits of the | mantissa for $ffffffff. If both are true, return d0 clr | and store the lower n bits of the least lword of FPTEMP | to d0 for write out. If not, it is a real operr, and set d0. | check_upper: cmpil #0xffffffff,FPTEMP_HI(%a6) |check if first byte is all 1's bnes true_operr |if not all 1's then was true operr cmpiw #0xc000,FPTEMP_EX(%a6) |check if incorrectly signalled beqs not_true_operr |branch if not true operr cmpiw #0xbfff,FPTEMP_EX(%a6) |check if incorrectly signalled beqs not_true_operr |branch if not true operr true_operr: movel #1,%d0 |signal real operr rts not_true_operr: clrl %d0 |signal no real operr rts | | End_operr tests for operr enabled. If not, it cleans up the stack | and does an rte. If enabled, it cleans up the stack and branches | to the kernel operr handler with only the integer exception | frame on the stack and the fpu in the original exceptional state | with correct data written to the destination. | end_operr: btstb #operr_bit,FPCR_ENABLE(%a6) beqs not_enabled enabled: moveml USER_DA(%a6),%d0-%d1/%a0-%a1 fmovemx USER_FP0(%a6),%fp0-%fp3 fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar frestore (%a7)+ unlk %a6 bral real_operr not_enabled: | | It is possible to have either inex2 or inex1 exceptions with the | operr. If the inex enable bit is set in the FPCR, and either | inex2 or inex1 occurred, we must clean up and branch to the | real inex handler. | ck_inex: moveb FPCR_ENABLE(%a6),%d0 andb FPSR_EXCEPT(%a6),%d0 andib #0x3,%d0 beq operr_exit | | Inexact enabled and reported, and we must take an inexact exception. | take_inex: moveb #INEX_VEC,EXC_VEC+1(%a6) movel USER_FPSR(%a6),FPSR_SHADOW(%a6) orl #sx_mask,E_BYTE(%a6) moveml USER_DA(%a6),%d0-%d1/%a0-%a1 fmovemx USER_FP0(%a6),%fp0-%fp3 fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar frestore (%a7)+ unlk %a6 bral real_inex | | Since operr is only an E1 exception, there is no need to frestore | any state back to the fpu. | operr_exit: moveml USER_DA(%a6),%d0-%d1/%a0-%a1 fmovemx USER_FP0(%a6),%fp0-%fp3 fmoveml USER_FPCR(%a6),%fpcr/%fpsr/%fpiar unlk %a6 bral fpsp_done |end |