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