Path: blob/master/arch/parisc/math-emu/fpudispatch.c
10817 views
/*1* Linux/PA-RISC Project (http://www.parisc-linux.org/)2*3* Floating-point emulation code4* Copyright (C) 2001 Hewlett-Packard (Paul Bame) <[email protected]>5*6* This program is free software; you can redistribute it and/or modify7* it under the terms of the GNU General Public License as published by8* the Free Software Foundation; either version 2, or (at your option)9* any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA19*/20/*21* BEGIN_DESC22*23* File:24* @(#) pa/fp/fpudispatch.c $Revision: 1.1 $25*26* Purpose:27* <<please update with a synopsis of the functionality provided by this file>>28*29* External Interfaces:30* <<the following list was autogenerated, please review>>31* emfpudispatch(ir, dummy1, dummy2, fpregs)32* fpudispatch(ir, excp_code, holder, fpregs)33*34* Internal Interfaces:35* <<the following list was autogenerated, please review>>36* static u_int decode_06(u_int, u_int *)37* static u_int decode_0c(u_int, u_int, u_int, u_int *)38* static u_int decode_0e(u_int, u_int, u_int, u_int *)39* static u_int decode_26(u_int, u_int *)40* static u_int decode_2e(u_int, u_int *)41* static void update_status_cbit(u_int *, u_int, u_int, u_int)42*43* Theory:44* <<please update with a overview of the operation of this file>>45*46* END_DESC47*/4849#define FPUDEBUG 05051#include "float.h"52#include <linux/kernel.h>53#include <asm/processor.h>54/* #include <sys/debug.h> */55/* #include <machine/sys/mdep_private.h> */5657#define COPR_INST 0x300000005859/*60* definition of extru macro. If pos and len are constants, the compiler61* will generate an extru instruction when optimized62*/63#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))64/* definitions of bit field locations in the instruction */65#define fpmajorpos 566#define fpr1pos 1067#define fpr2pos 1568#define fptpos 3169#define fpsubpos 1870#define fpclass1subpos 1671#define fpclasspos 2272#define fpfmtpos 2073#define fpdfpos 1874#define fpnulpos 2675/*76* the following are the extra bits for the 0E major op77*/78#define fpxr1pos 2479#define fpxr2pos 1980#define fpxtpos 2581#define fpxpos 2382#define fp0efmtpos 2083/*84* the following are for the multi-ops85*/86#define fprm1pos 1087#define fprm2pos 1588#define fptmpos 3189#define fprapos 2590#define fptapos 2091#define fpmultifmt 2692/*93* the following are for the fused FP instructions94*/95/* fprm1pos 10 */96/* fprm2pos 15 */97#define fpraupos 1898#define fpxrm2pos 1999/* fpfmtpos 20 */100#define fpralpos 23101#define fpxrm1pos 24102/* fpxtpos 25 */103#define fpfusedsubop 26104/* fptpos 31 */105106/*107* offset to constant zero in the FP emulation registers108*/109#define fpzeroreg (32*sizeof(double)/sizeof(u_int))110111/*112* extract the major opcode from the instruction113*/114#define get_major(op) extru(op,fpmajorpos,6)115/*116* extract the two bit class field from the FP instruction. The class is at bit117* positions 21-22118*/119#define get_class(op) extru(op,fpclasspos,2)120/*121* extract the 3 bit subop field. For all but class 1 instructions, it is122* located at bit positions 16-18123*/124#define get_subop(op) extru(op,fpsubpos,3)125/*126* extract the 2 or 3 bit subop field from class 1 instructions. It is located127* at bit positions 15-16 (PA1.1) or 14-16 (PA2.0)128*/129#define get_subop1_PA1_1(op) extru(op,fpclass1subpos,2) /* PA89 (1.1) fmt */130#define get_subop1_PA2_0(op) extru(op,fpclass1subpos,3) /* PA 2.0 fmt */131132/* definitions of unimplemented exceptions */133#define MAJOR_0C_EXCP 0x09134#define MAJOR_0E_EXCP 0x0b135#define MAJOR_06_EXCP 0x03136#define MAJOR_26_EXCP 0x23137#define MAJOR_2E_EXCP 0x2b138#define PA83_UNIMP_EXCP 0x01139140/*141* Special Defines for TIMEX specific code142*/143144#define FPU_TYPE_FLAG_POS (EM_FPU_TYPE_OFFSET>>2)145#define TIMEX_ROLEX_FPU_MASK (TIMEX_EXTEN_FLAG|ROLEX_EXTEN_FLAG)146147/*148* Static function definitions149*/150#define _PROTOTYPES151#if defined(_PROTOTYPES) || defined(_lint)152static u_int decode_0c(u_int, u_int, u_int, u_int *);153static u_int decode_0e(u_int, u_int, u_int, u_int *);154static u_int decode_06(u_int, u_int *);155static u_int decode_26(u_int, u_int *);156static u_int decode_2e(u_int, u_int *);157static void update_status_cbit(u_int *, u_int, u_int, u_int);158#else /* !_PROTOTYPES&&!_lint */159static u_int decode_0c();160static u_int decode_0e();161static u_int decode_06();162static u_int decode_26();163static u_int decode_2e();164static void update_status_cbit();165#endif /* _PROTOTYPES&&!_lint */166167#define VASSERT(x)168169static void parisc_linux_get_fpu_type(u_int fpregs[])170{171/* on pa-linux the fpu type is not filled in by the172* caller; it is constructed here173*/174if (boot_cpu_data.cpu_type == pcxs)175fpregs[FPU_TYPE_FLAG_POS] = TIMEX_EXTEN_FLAG;176else if (boot_cpu_data.cpu_type == pcxt ||177boot_cpu_data.cpu_type == pcxt_)178fpregs[FPU_TYPE_FLAG_POS] = ROLEX_EXTEN_FLAG;179else if (boot_cpu_data.cpu_type >= pcxu)180fpregs[FPU_TYPE_FLAG_POS] = PA2_0_FPU_FLAG;181}182183/*184* this routine will decode the excepting floating point instruction and185* call the approiate emulation routine.186* It is called by decode_fpu with the following parameters:187* fpudispatch(current_ir, unimplemented_code, 0, &Fpu_register)188* where current_ir is the instruction to be emulated,189* unimplemented_code is the exception_code that the hardware generated190* and &Fpu_register is the address of emulated FP reg 0.191*/192u_int193fpudispatch(u_int ir, u_int excp_code, u_int holder, u_int fpregs[])194{195u_int class, subop;196u_int fpu_type_flags;197198/* All FP emulation code assumes that ints are 4-bytes in length */199VASSERT(sizeof(int) == 4);200201parisc_linux_get_fpu_type(fpregs);202203fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */204205class = get_class(ir);206if (class == 1) {207if (fpu_type_flags & PA2_0_FPU_FLAG)208subop = get_subop1_PA2_0(ir);209else210subop = get_subop1_PA1_1(ir);211}212else213subop = get_subop(ir);214215if (FPUDEBUG) printk("class %d subop %d\n", class, subop);216217switch (excp_code) {218case MAJOR_0C_EXCP:219case PA83_UNIMP_EXCP:220return(decode_0c(ir,class,subop,fpregs));221case MAJOR_0E_EXCP:222return(decode_0e(ir,class,subop,fpregs));223case MAJOR_06_EXCP:224return(decode_06(ir,fpregs));225case MAJOR_26_EXCP:226return(decode_26(ir,fpregs));227case MAJOR_2E_EXCP:228return(decode_2e(ir,fpregs));229default:230/* "crashme Night Gallery painting nr 2. (asm_crash.s).231* This was fixed for multi-user kernels, but232* workstation kernels had a panic here. This allowed233* any arbitrary user to panic the kernel by executing234* setting the FP exception registers to strange values235* and generating an emulation trap. The emulation and236* exception code must never be able to panic the237* kernel.238*/239return(UNIMPLEMENTEDEXCEPTION);240}241}242243/*244* this routine is called by $emulation_trap to emulate a coprocessor245* instruction if one doesn't exist246*/247u_int248emfpudispatch(u_int ir, u_int dummy1, u_int dummy2, u_int fpregs[])249{250u_int class, subop, major;251u_int fpu_type_flags;252253/* All FP emulation code assumes that ints are 4-bytes in length */254VASSERT(sizeof(int) == 4);255256fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */257258major = get_major(ir);259class = get_class(ir);260if (class == 1) {261if (fpu_type_flags & PA2_0_FPU_FLAG)262subop = get_subop1_PA2_0(ir);263else264subop = get_subop1_PA1_1(ir);265}266else267subop = get_subop(ir);268switch (major) {269case 0x0C:270return(decode_0c(ir,class,subop,fpregs));271case 0x0E:272return(decode_0e(ir,class,subop,fpregs));273case 0x06:274return(decode_06(ir,fpregs));275case 0x26:276return(decode_26(ir,fpregs));277case 0x2E:278return(decode_2e(ir,fpregs));279default:280return(PA83_UNIMP_EXCP);281}282}283284285static u_int286decode_0c(u_int ir, u_int class, u_int subop, u_int fpregs[])287{288u_int r1,r2,t; /* operand register offsets */289u_int fmt; /* also sf for class 1 conversions */290u_int df; /* for class 1 conversions */291u_int *status;292u_int retval, local_status;293u_int fpu_type_flags;294295if (ir == COPR_INST) {296fpregs[0] = EMULATION_VERSION << 11;297return(NOEXCEPTION);298}299status = &fpregs[0]; /* fp status register */300local_status = fpregs[0]; /* and local copy */301r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(u_int);302if (r1 == 0) /* map fr0 source to constant zero */303r1 = fpzeroreg;304t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);305if (t == 0 && class != 2) /* don't allow fr0 as a dest */306return(MAJOR_0C_EXCP);307fmt = extru(ir,fpfmtpos,2); /* get fmt completer */308309switch (class) {310case 0:311switch (subop) {312case 0: /* COPR 0,0 emulated above*/313case 1:314return(MAJOR_0C_EXCP);315case 2: /* FCPY */316switch (fmt) {317case 2: /* illegal */318return(MAJOR_0C_EXCP);319case 3: /* quad */320t &= ~3; /* force to even reg #s */321r1 &= ~3;322fpregs[t+3] = fpregs[r1+3];323fpregs[t+2] = fpregs[r1+2];324case 1: /* double */325fpregs[t+1] = fpregs[r1+1];326case 0: /* single */327fpregs[t] = fpregs[r1];328return(NOEXCEPTION);329}330case 3: /* FABS */331switch (fmt) {332case 2: /* illegal */333return(MAJOR_0C_EXCP);334case 3: /* quad */335t &= ~3; /* force to even reg #s */336r1 &= ~3;337fpregs[t+3] = fpregs[r1+3];338fpregs[t+2] = fpregs[r1+2];339case 1: /* double */340fpregs[t+1] = fpregs[r1+1];341case 0: /* single */342/* copy and clear sign bit */343fpregs[t] = fpregs[r1] & 0x7fffffff;344return(NOEXCEPTION);345}346case 6: /* FNEG */347switch (fmt) {348case 2: /* illegal */349return(MAJOR_0C_EXCP);350case 3: /* quad */351t &= ~3; /* force to even reg #s */352r1 &= ~3;353fpregs[t+3] = fpregs[r1+3];354fpregs[t+2] = fpregs[r1+2];355case 1: /* double */356fpregs[t+1] = fpregs[r1+1];357case 0: /* single */358/* copy and invert sign bit */359fpregs[t] = fpregs[r1] ^ 0x80000000;360return(NOEXCEPTION);361}362case 7: /* FNEGABS */363switch (fmt) {364case 2: /* illegal */365return(MAJOR_0C_EXCP);366case 3: /* quad */367t &= ~3; /* force to even reg #s */368r1 &= ~3;369fpregs[t+3] = fpregs[r1+3];370fpregs[t+2] = fpregs[r1+2];371case 1: /* double */372fpregs[t+1] = fpregs[r1+1];373case 0: /* single */374/* copy and set sign bit */375fpregs[t] = fpregs[r1] | 0x80000000;376return(NOEXCEPTION);377}378case 4: /* FSQRT */379switch (fmt) {380case 0:381return(sgl_fsqrt(&fpregs[r1],0,382&fpregs[t],status));383case 1:384return(dbl_fsqrt(&fpregs[r1],0,385&fpregs[t],status));386case 2:387case 3: /* quad not implemented */388return(MAJOR_0C_EXCP);389}390case 5: /* FRND */391switch (fmt) {392case 0:393return(sgl_frnd(&fpregs[r1],0,394&fpregs[t],status));395case 1:396return(dbl_frnd(&fpregs[r1],0,397&fpregs[t],status));398case 2:399case 3: /* quad not implemented */400return(MAJOR_0C_EXCP);401}402} /* end of switch (subop) */403404case 1: /* class 1 */405df = extru(ir,fpdfpos,2); /* get dest format */406if ((df & 2) || (fmt & 2)) {407/*408* fmt's 2 and 3 are illegal of not implemented409* quad conversions410*/411return(MAJOR_0C_EXCP);412}413/*414* encode source and dest formats into 2 bits.415* high bit is source, low bit is dest.416* bit = 1 --> double precision417*/418fmt = (fmt << 1) | df;419switch (subop) {420case 0: /* FCNVFF */421switch(fmt) {422case 0: /* sgl/sgl */423return(MAJOR_0C_EXCP);424case 1: /* sgl/dbl */425return(sgl_to_dbl_fcnvff(&fpregs[r1],0,426&fpregs[t],status));427case 2: /* dbl/sgl */428return(dbl_to_sgl_fcnvff(&fpregs[r1],0,429&fpregs[t],status));430case 3: /* dbl/dbl */431return(MAJOR_0C_EXCP);432}433case 1: /* FCNVXF */434switch(fmt) {435case 0: /* sgl/sgl */436return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,437&fpregs[t],status));438case 1: /* sgl/dbl */439return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,440&fpregs[t],status));441case 2: /* dbl/sgl */442return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,443&fpregs[t],status));444case 3: /* dbl/dbl */445return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,446&fpregs[t],status));447}448case 2: /* FCNVFX */449switch(fmt) {450case 0: /* sgl/sgl */451return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,452&fpregs[t],status));453case 1: /* sgl/dbl */454return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,455&fpregs[t],status));456case 2: /* dbl/sgl */457return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,458&fpregs[t],status));459case 3: /* dbl/dbl */460return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,461&fpregs[t],status));462}463case 3: /* FCNVFXT */464switch(fmt) {465case 0: /* sgl/sgl */466return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,467&fpregs[t],status));468case 1: /* sgl/dbl */469return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,470&fpregs[t],status));471case 2: /* dbl/sgl */472return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,473&fpregs[t],status));474case 3: /* dbl/dbl */475return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,476&fpregs[t],status));477}478case 5: /* FCNVUF (PA2.0 only) */479switch(fmt) {480case 0: /* sgl/sgl */481return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,482&fpregs[t],status));483case 1: /* sgl/dbl */484return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,485&fpregs[t],status));486case 2: /* dbl/sgl */487return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,488&fpregs[t],status));489case 3: /* dbl/dbl */490return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,491&fpregs[t],status));492}493case 6: /* FCNVFU (PA2.0 only) */494switch(fmt) {495case 0: /* sgl/sgl */496return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,497&fpregs[t],status));498case 1: /* sgl/dbl */499return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,500&fpregs[t],status));501case 2: /* dbl/sgl */502return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,503&fpregs[t],status));504case 3: /* dbl/dbl */505return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,506&fpregs[t],status));507}508case 7: /* FCNVFUT (PA2.0 only) */509switch(fmt) {510case 0: /* sgl/sgl */511return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,512&fpregs[t],status));513case 1: /* sgl/dbl */514return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,515&fpregs[t],status));516case 2: /* dbl/sgl */517return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,518&fpregs[t],status));519case 3: /* dbl/dbl */520return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,521&fpregs[t],status));522}523case 4: /* undefined */524return(MAJOR_0C_EXCP);525} /* end of switch subop */526527case 2: /* class 2 */528fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];529r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int);530if (r2 == 0)531r2 = fpzeroreg;532if (fpu_type_flags & PA2_0_FPU_FLAG) {533/* FTEST if nullify bit set, otherwise FCMP */534if (extru(ir, fpnulpos, 1)) { /* FTEST */535switch (fmt) {536case 0:537/*538* arg0 is not used539* second param is the t field used for540* ftest,acc and ftest,rej541* third param is the subop (y-field)542*/543BUG();544/* Unsupported545* return(ftest(0L,extru(ir,fptpos,5),546* &fpregs[0],subop));547*/548case 1:549case 2:550case 3:551return(MAJOR_0C_EXCP);552}553} else { /* FCMP */554switch (fmt) {555case 0:556retval = sgl_fcmp(&fpregs[r1],557&fpregs[r2],extru(ir,fptpos,5),558&local_status);559update_status_cbit(status,local_status,560fpu_type_flags, subop);561return(retval);562case 1:563retval = dbl_fcmp(&fpregs[r1],564&fpregs[r2],extru(ir,fptpos,5),565&local_status);566update_status_cbit(status,local_status,567fpu_type_flags, subop);568return(retval);569case 2: /* illegal */570case 3: /* quad not implemented */571return(MAJOR_0C_EXCP);572}573}574} /* end of if for PA2.0 */575else { /* PA1.0 & PA1.1 */576switch (subop) {577case 2:578case 3:579case 4:580case 5:581case 6:582case 7:583return(MAJOR_0C_EXCP);584case 0: /* FCMP */585switch (fmt) {586case 0:587retval = sgl_fcmp(&fpregs[r1],588&fpregs[r2],extru(ir,fptpos,5),589&local_status);590update_status_cbit(status,local_status,591fpu_type_flags, subop);592return(retval);593case 1:594retval = dbl_fcmp(&fpregs[r1],595&fpregs[r2],extru(ir,fptpos,5),596&local_status);597update_status_cbit(status,local_status,598fpu_type_flags, subop);599return(retval);600case 2: /* illegal */601case 3: /* quad not implemented */602return(MAJOR_0C_EXCP);603}604case 1: /* FTEST */605switch (fmt) {606case 0:607/*608* arg0 is not used609* second param is the t field used for610* ftest,acc and ftest,rej611* third param is the subop (y-field)612*/613BUG();614/* unsupported615* return(ftest(0L,extru(ir,fptpos,5),616* &fpregs[0],subop));617*/618case 1:619case 2:620case 3:621return(MAJOR_0C_EXCP);622}623} /* end of switch subop */624} /* end of else for PA1.0 & PA1.1 */625case 3: /* class 3 */626r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int);627if (r2 == 0)628r2 = fpzeroreg;629switch (subop) {630case 5:631case 6:632case 7:633return(MAJOR_0C_EXCP);634635case 0: /* FADD */636switch (fmt) {637case 0:638return(sgl_fadd(&fpregs[r1],&fpregs[r2],639&fpregs[t],status));640case 1:641return(dbl_fadd(&fpregs[r1],&fpregs[r2],642&fpregs[t],status));643case 2: /* illegal */644case 3: /* quad not implemented */645return(MAJOR_0C_EXCP);646}647case 1: /* FSUB */648switch (fmt) {649case 0:650return(sgl_fsub(&fpregs[r1],&fpregs[r2],651&fpregs[t],status));652case 1:653return(dbl_fsub(&fpregs[r1],&fpregs[r2],654&fpregs[t],status));655case 2: /* illegal */656case 3: /* quad not implemented */657return(MAJOR_0C_EXCP);658}659case 2: /* FMPY */660switch (fmt) {661case 0:662return(sgl_fmpy(&fpregs[r1],&fpregs[r2],663&fpregs[t],status));664case 1:665return(dbl_fmpy(&fpregs[r1],&fpregs[r2],666&fpregs[t],status));667case 2: /* illegal */668case 3: /* quad not implemented */669return(MAJOR_0C_EXCP);670}671case 3: /* FDIV */672switch (fmt) {673case 0:674return(sgl_fdiv(&fpregs[r1],&fpregs[r2],675&fpregs[t],status));676case 1:677return(dbl_fdiv(&fpregs[r1],&fpregs[r2],678&fpregs[t],status));679case 2: /* illegal */680case 3: /* quad not implemented */681return(MAJOR_0C_EXCP);682}683case 4: /* FREM */684switch (fmt) {685case 0:686return(sgl_frem(&fpregs[r1],&fpregs[r2],687&fpregs[t],status));688case 1:689return(dbl_frem(&fpregs[r1],&fpregs[r2],690&fpregs[t],status));691case 2: /* illegal */692case 3: /* quad not implemented */693return(MAJOR_0C_EXCP);694}695} /* end of class 3 switch */696} /* end of switch(class) */697698/* If we get here, something is really wrong! */699return(MAJOR_0C_EXCP);700}701702static u_int703decode_0e(ir,class,subop,fpregs)704u_int ir,class,subop;705u_int fpregs[];706{707u_int r1,r2,t; /* operand register offsets */708u_int fmt; /* also sf for class 1 conversions */709u_int df; /* dest format for class 1 conversions */710u_int *status;711u_int retval, local_status;712u_int fpu_type_flags;713714status = &fpregs[0];715local_status = fpregs[0];716r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1)));717if (r1 == 0)718r1 = fpzeroreg;719t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));720if (t == 0 && class != 2)721return(MAJOR_0E_EXCP);722if (class < 2) /* class 0 or 1 has 2 bit fmt */723fmt = extru(ir,fpfmtpos,2);724else /* class 2 and 3 have 1 bit fmt */725fmt = extru(ir,fp0efmtpos,1);726/*727* An undefined combination, double precision accessing the728* right half of a FPR, can get us into trouble.729* Let's just force proper alignment on it.730*/731if (fmt == DBL) {732r1 &= ~1;733if (class != 1)734t &= ~1;735}736737switch (class) {738case 0:739switch (subop) {740case 0: /* unimplemented */741case 1:742return(MAJOR_0E_EXCP);743case 2: /* FCPY */744switch (fmt) {745case 2:746case 3:747return(MAJOR_0E_EXCP);748case 1: /* double */749fpregs[t+1] = fpregs[r1+1];750case 0: /* single */751fpregs[t] = fpregs[r1];752return(NOEXCEPTION);753}754case 3: /* FABS */755switch (fmt) {756case 2:757case 3:758return(MAJOR_0E_EXCP);759case 1: /* double */760fpregs[t+1] = fpregs[r1+1];761case 0: /* single */762fpregs[t] = fpregs[r1] & 0x7fffffff;763return(NOEXCEPTION);764}765case 6: /* FNEG */766switch (fmt) {767case 2:768case 3:769return(MAJOR_0E_EXCP);770case 1: /* double */771fpregs[t+1] = fpregs[r1+1];772case 0: /* single */773fpregs[t] = fpregs[r1] ^ 0x80000000;774return(NOEXCEPTION);775}776case 7: /* FNEGABS */777switch (fmt) {778case 2:779case 3:780return(MAJOR_0E_EXCP);781case 1: /* double */782fpregs[t+1] = fpregs[r1+1];783case 0: /* single */784fpregs[t] = fpregs[r1] | 0x80000000;785return(NOEXCEPTION);786}787case 4: /* FSQRT */788switch (fmt) {789case 0:790return(sgl_fsqrt(&fpregs[r1],0,791&fpregs[t], status));792case 1:793return(dbl_fsqrt(&fpregs[r1],0,794&fpregs[t], status));795case 2:796case 3:797return(MAJOR_0E_EXCP);798}799case 5: /* FRMD */800switch (fmt) {801case 0:802return(sgl_frnd(&fpregs[r1],0,803&fpregs[t], status));804case 1:805return(dbl_frnd(&fpregs[r1],0,806&fpregs[t], status));807case 2:808case 3:809return(MAJOR_0E_EXCP);810}811} /* end of switch (subop */812813case 1: /* class 1 */814df = extru(ir,fpdfpos,2); /* get dest format */815/*816* Fix Crashme problem (writing to 31R in double precision)817* here too.818*/819if (df == DBL) {820t &= ~1;821}822if ((df & 2) || (fmt & 2))823return(MAJOR_0E_EXCP);824825fmt = (fmt << 1) | df;826switch (subop) {827case 0: /* FCNVFF */828switch(fmt) {829case 0: /* sgl/sgl */830return(MAJOR_0E_EXCP);831case 1: /* sgl/dbl */832return(sgl_to_dbl_fcnvff(&fpregs[r1],0,833&fpregs[t],status));834case 2: /* dbl/sgl */835return(dbl_to_sgl_fcnvff(&fpregs[r1],0,836&fpregs[t],status));837case 3: /* dbl/dbl */838return(MAJOR_0E_EXCP);839}840case 1: /* FCNVXF */841switch(fmt) {842case 0: /* sgl/sgl */843return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,844&fpregs[t],status));845case 1: /* sgl/dbl */846return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,847&fpregs[t],status));848case 2: /* dbl/sgl */849return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,850&fpregs[t],status));851case 3: /* dbl/dbl */852return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,853&fpregs[t],status));854}855case 2: /* FCNVFX */856switch(fmt) {857case 0: /* sgl/sgl */858return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,859&fpregs[t],status));860case 1: /* sgl/dbl */861return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,862&fpregs[t],status));863case 2: /* dbl/sgl */864return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,865&fpregs[t],status));866case 3: /* dbl/dbl */867return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,868&fpregs[t],status));869}870case 3: /* FCNVFXT */871switch(fmt) {872case 0: /* sgl/sgl */873return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,874&fpregs[t],status));875case 1: /* sgl/dbl */876return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,877&fpregs[t],status));878case 2: /* dbl/sgl */879return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,880&fpregs[t],status));881case 3: /* dbl/dbl */882return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,883&fpregs[t],status));884}885case 5: /* FCNVUF (PA2.0 only) */886switch(fmt) {887case 0: /* sgl/sgl */888return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,889&fpregs[t],status));890case 1: /* sgl/dbl */891return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,892&fpregs[t],status));893case 2: /* dbl/sgl */894return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,895&fpregs[t],status));896case 3: /* dbl/dbl */897return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,898&fpregs[t],status));899}900case 6: /* FCNVFU (PA2.0 only) */901switch(fmt) {902case 0: /* sgl/sgl */903return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,904&fpregs[t],status));905case 1: /* sgl/dbl */906return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,907&fpregs[t],status));908case 2: /* dbl/sgl */909return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,910&fpregs[t],status));911case 3: /* dbl/dbl */912return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,913&fpregs[t],status));914}915case 7: /* FCNVFUT (PA2.0 only) */916switch(fmt) {917case 0: /* sgl/sgl */918return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,919&fpregs[t],status));920case 1: /* sgl/dbl */921return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,922&fpregs[t],status));923case 2: /* dbl/sgl */924return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,925&fpregs[t],status));926case 3: /* dbl/dbl */927return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,928&fpregs[t],status));929}930case 4: /* undefined */931return(MAJOR_0C_EXCP);932} /* end of switch subop */933case 2: /* class 2 */934/*935* Be careful out there.936* Crashme can generate cases where FR31R is specified937* as the source or target of a double precision operation.938* Since we just pass the address of the floating-point939* register to the emulation routines, this can cause940* corruption of fpzeroreg.941*/942if (fmt == DBL)943r2 = (extru(ir,fpr2pos,5)<<1);944else945r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));946fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];947if (r2 == 0)948r2 = fpzeroreg;949if (fpu_type_flags & PA2_0_FPU_FLAG) {950/* FTEST if nullify bit set, otherwise FCMP */951if (extru(ir, fpnulpos, 1)) { /* FTEST */952/* not legal */953return(MAJOR_0E_EXCP);954} else { /* FCMP */955switch (fmt) {956/*957* fmt is only 1 bit long958*/959case 0:960retval = sgl_fcmp(&fpregs[r1],961&fpregs[r2],extru(ir,fptpos,5),962&local_status);963update_status_cbit(status,local_status,964fpu_type_flags, subop);965return(retval);966case 1:967retval = dbl_fcmp(&fpregs[r1],968&fpregs[r2],extru(ir,fptpos,5),969&local_status);970update_status_cbit(status,local_status,971fpu_type_flags, subop);972return(retval);973}974}975} /* end of if for PA2.0 */976else { /* PA1.0 & PA1.1 */977switch (subop) {978case 1:979case 2:980case 3:981case 4:982case 5:983case 6:984case 7:985return(MAJOR_0E_EXCP);986case 0: /* FCMP */987switch (fmt) {988/*989* fmt is only 1 bit long990*/991case 0:992retval = sgl_fcmp(&fpregs[r1],993&fpregs[r2],extru(ir,fptpos,5),994&local_status);995update_status_cbit(status,local_status,996fpu_type_flags, subop);997return(retval);998case 1:999retval = dbl_fcmp(&fpregs[r1],1000&fpregs[r2],extru(ir,fptpos,5),1001&local_status);1002update_status_cbit(status,local_status,1003fpu_type_flags, subop);1004return(retval);1005}1006} /* end of switch subop */1007} /* end of else for PA1.0 & PA1.1 */1008case 3: /* class 3 */1009/*1010* Be careful out there.1011* Crashme can generate cases where FR31R is specified1012* as the source or target of a double precision operation.1013* Since we just pass the address of the floating-point1014* register to the emulation routines, this can cause1015* corruption of fpzeroreg.1016*/1017if (fmt == DBL)1018r2 = (extru(ir,fpr2pos,5)<<1);1019else1020r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));1021if (r2 == 0)1022r2 = fpzeroreg;1023switch (subop) {1024case 5:1025case 6:1026case 7:1027return(MAJOR_0E_EXCP);10281029/*1030* Note that fmt is only 1 bit for class 3 */1031case 0: /* FADD */1032switch (fmt) {1033case 0:1034return(sgl_fadd(&fpregs[r1],&fpregs[r2],1035&fpregs[t],status));1036case 1:1037return(dbl_fadd(&fpregs[r1],&fpregs[r2],1038&fpregs[t],status));1039}1040case 1: /* FSUB */1041switch (fmt) {1042case 0:1043return(sgl_fsub(&fpregs[r1],&fpregs[r2],1044&fpregs[t],status));1045case 1:1046return(dbl_fsub(&fpregs[r1],&fpregs[r2],1047&fpregs[t],status));1048}1049case 2: /* FMPY or XMPYU */1050/*1051* check for integer multiply (x bit set)1052*/1053if (extru(ir,fpxpos,1)) {1054/*1055* emulate XMPYU1056*/1057switch (fmt) {1058case 0:1059/*1060* bad instruction if t specifies1061* the right half of a register1062*/1063if (t & 1)1064return(MAJOR_0E_EXCP);1065BUG();1066/* unsupported1067* impyu(&fpregs[r1],&fpregs[r2],1068* &fpregs[t]);1069*/1070return(NOEXCEPTION);1071case 1:1072return(MAJOR_0E_EXCP);1073}1074}1075else { /* FMPY */1076switch (fmt) {1077case 0:1078return(sgl_fmpy(&fpregs[r1],1079&fpregs[r2],&fpregs[t],status));1080case 1:1081return(dbl_fmpy(&fpregs[r1],1082&fpregs[r2],&fpregs[t],status));1083}1084}1085case 3: /* FDIV */1086switch (fmt) {1087case 0:1088return(sgl_fdiv(&fpregs[r1],&fpregs[r2],1089&fpregs[t],status));1090case 1:1091return(dbl_fdiv(&fpregs[r1],&fpregs[r2],1092&fpregs[t],status));1093}1094case 4: /* FREM */1095switch (fmt) {1096case 0:1097return(sgl_frem(&fpregs[r1],&fpregs[r2],1098&fpregs[t],status));1099case 1:1100return(dbl_frem(&fpregs[r1],&fpregs[r2],1101&fpregs[t],status));1102}1103} /* end of class 3 switch */1104} /* end of switch(class) */11051106/* If we get here, something is really wrong! */1107return(MAJOR_0E_EXCP);1108}110911101111/*1112* routine to decode the 06 (FMPYADD and FMPYCFXT) instruction1113*/1114static u_int1115decode_06(ir,fpregs)1116u_int ir;1117u_int fpregs[];1118{1119u_int rm1, rm2, tm, ra, ta; /* operands */1120u_int fmt;1121u_int error = 0;1122u_int status;1123u_int fpu_type_flags;1124union {1125double dbl;1126float flt;1127struct { u_int i1; u_int i2; } ints;1128} mtmp, atmp;112911301131status = fpregs[0]; /* use a local copy of status reg */1132fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */1133fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */1134if (fmt == 0) { /* DBL */1135rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);1136if (rm1 == 0)1137rm1 = fpzeroreg;1138rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);1139if (rm2 == 0)1140rm2 = fpzeroreg;1141tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);1142if (tm == 0)1143return(MAJOR_06_EXCP);1144ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);1145ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);1146if (ta == 0)1147return(MAJOR_06_EXCP);11481149if (fpu_type_flags & TIMEX_ROLEX_FPU_MASK) {11501151if (ra == 0) {1152/* special case FMPYCFXT, see sgl case below */1153if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],1154&mtmp.ints.i1,&status))1155error = 1;1156if (dbl_to_sgl_fcnvfxt(&fpregs[ta],1157&atmp.ints.i1,&atmp.ints.i1,&status))1158error = 1;1159}1160else {11611162if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,1163&status))1164error = 1;1165if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,1166&status))1167error = 1;1168}1169}11701171else11721173{1174if (ra == 0)1175ra = fpzeroreg;11761177if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,1178&status))1179error = 1;1180if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,1181&status))1182error = 1;11831184}11851186if (error)1187return(MAJOR_06_EXCP);1188else {1189/* copy results */1190fpregs[tm] = mtmp.ints.i1;1191fpregs[tm+1] = mtmp.ints.i2;1192fpregs[ta] = atmp.ints.i1;1193fpregs[ta+1] = atmp.ints.i2;1194fpregs[0] = status;1195return(NOEXCEPTION);1196}1197}1198else { /* SGL */1199/*1200* calculate offsets for single precision numbers1201* See table 6-14 in PA-89 architecture for mapping1202*/1203rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */1204rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */12051206rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */1207rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */12081209tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */1210tm |= extru(ir,fptmpos-4,1); /* add right word offset */12111212ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */1213ra |= extru(ir,fprapos-4,1); /* add right word offset */12141215ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */1216ta |= extru(ir,fptapos-4,1); /* add right word offset */12171218if (ra == 0x20 &&(fpu_type_flags & TIMEX_ROLEX_FPU_MASK)) {1219/* special case FMPYCFXT (really 0)1220* This instruction is only present on the Timex and1221* Rolex fpu's in so if it is the special case and1222* one of these fpu's we run the FMPYCFXT instruction1223*/1224if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,1225&status))1226error = 1;1227if (sgl_to_sgl_fcnvfxt(&fpregs[ta],&atmp.ints.i1,1228&atmp.ints.i1,&status))1229error = 1;1230}1231else {1232if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,1233&status))1234error = 1;1235if (sgl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,1236&status))1237error = 1;1238}1239if (error)1240return(MAJOR_06_EXCP);1241else {1242/* copy results */1243fpregs[tm] = mtmp.ints.i1;1244fpregs[ta] = atmp.ints.i1;1245fpregs[0] = status;1246return(NOEXCEPTION);1247}1248}1249}12501251/*1252* routine to decode the 26 (FMPYSUB) instruction1253*/1254static u_int1255decode_26(ir,fpregs)1256u_int ir;1257u_int fpregs[];1258{1259u_int rm1, rm2, tm, ra, ta; /* operands */1260u_int fmt;1261u_int error = 0;1262u_int status;1263union {1264double dbl;1265float flt;1266struct { u_int i1; u_int i2; } ints;1267} mtmp, atmp;126812691270status = fpregs[0];1271fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */1272if (fmt == 0) { /* DBL */1273rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);1274if (rm1 == 0)1275rm1 = fpzeroreg;1276rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);1277if (rm2 == 0)1278rm2 = fpzeroreg;1279tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);1280if (tm == 0)1281return(MAJOR_26_EXCP);1282ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);1283if (ra == 0)1284return(MAJOR_26_EXCP);1285ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);1286if (ta == 0)1287return(MAJOR_26_EXCP);12881289if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))1290error = 1;1291if (dbl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))1292error = 1;1293if (error)1294return(MAJOR_26_EXCP);1295else {1296/* copy results */1297fpregs[tm] = mtmp.ints.i1;1298fpregs[tm+1] = mtmp.ints.i2;1299fpregs[ta] = atmp.ints.i1;1300fpregs[ta+1] = atmp.ints.i2;1301fpregs[0] = status;1302return(NOEXCEPTION);1303}1304}1305else { /* SGL */1306/*1307* calculate offsets for single precision numbers1308* See table 6-14 in PA-89 architecture for mapping1309*/1310rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */1311rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */13121313rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */1314rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */13151316tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */1317tm |= extru(ir,fptmpos-4,1); /* add right word offset */13181319ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */1320ra |= extru(ir,fprapos-4,1); /* add right word offset */13211322ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */1323ta |= extru(ir,fptapos-4,1); /* add right word offset */13241325if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))1326error = 1;1327if (sgl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))1328error = 1;1329if (error)1330return(MAJOR_26_EXCP);1331else {1332/* copy results */1333fpregs[tm] = mtmp.ints.i1;1334fpregs[ta] = atmp.ints.i1;1335fpregs[0] = status;1336return(NOEXCEPTION);1337}1338}13391340}13411342/*1343* routine to decode the 2E (FMPYFADD,FMPYNFADD) instructions1344*/1345static u_int1346decode_2e(ir,fpregs)1347u_int ir;1348u_int fpregs[];1349{1350u_int rm1, rm2, ra, t; /* operands */1351u_int fmt;13521353fmt = extru(ir,fpfmtpos,1); /* get fmt completer */1354if (fmt == DBL) { /* DBL */1355rm1 = extru(ir,fprm1pos,5) * sizeof(double)/sizeof(u_int);1356if (rm1 == 0)1357rm1 = fpzeroreg;1358rm2 = extru(ir,fprm2pos,5) * sizeof(double)/sizeof(u_int);1359if (rm2 == 0)1360rm2 = fpzeroreg;1361ra = ((extru(ir,fpraupos,3)<<2)|(extru(ir,fpralpos,3)>>1)) *1362sizeof(double)/sizeof(u_int);1363if (ra == 0)1364ra = fpzeroreg;1365t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);1366if (t == 0)1367return(MAJOR_2E_EXCP);13681369if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */1370return(dbl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],1371&fpregs[ra], &fpregs[0], &fpregs[t]));1372} else {1373return(dbl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],1374&fpregs[ra], &fpregs[0], &fpregs[t]));1375}1376} /* end DBL */1377else { /* SGL */1378rm1 = (extru(ir,fprm1pos,5)<<1)|(extru(ir,fpxrm1pos,1));1379if (rm1 == 0)1380rm1 = fpzeroreg;1381rm2 = (extru(ir,fprm2pos,5)<<1)|(extru(ir,fpxrm2pos,1));1382if (rm2 == 0)1383rm2 = fpzeroreg;1384ra = (extru(ir,fpraupos,3)<<3)|extru(ir,fpralpos,3);1385if (ra == 0)1386ra = fpzeroreg;1387t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));1388if (t == 0)1389return(MAJOR_2E_EXCP);13901391if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */1392return(sgl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],1393&fpregs[ra], &fpregs[0], &fpregs[t]));1394} else {1395return(sgl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],1396&fpregs[ra], &fpregs[0], &fpregs[t]));1397}1398} /* end SGL */1399}14001401/*1402* update_status_cbit1403*1404* This routine returns the correct FP status register value in1405* *status, based on the C-bit & V-bit returned by the FCMP1406* emulation routine in new_status. The architecture type1407* (PA83, PA89 or PA2.0) is available in fpu_type. The y_field1408* and the architecture type are used to determine what flavor1409* of FCMP is being emulated.1410*/1411static void1412update_status_cbit(status, new_status, fpu_type, y_field)1413u_int *status, new_status;1414u_int fpu_type;1415u_int y_field;1416{1417/*1418* For PA89 FPU's which implement the Compare Queue and1419* for PA2.0 FPU's, update the Compare Queue if the y-field = 0,1420* otherwise update the specified bit in the Compare Array.1421* Note that the y-field will always be 0 for non-PA2.0 FPU's.1422*/1423if ((fpu_type & TIMEX_EXTEN_FLAG) ||1424(fpu_type & ROLEX_EXTEN_FLAG) ||1425(fpu_type & PA2_0_FPU_FLAG)) {1426if (y_field == 0) {1427*status = ((*status & 0x04000000) >> 5) | /* old Cbit */1428((*status & 0x003ff000) >> 1) | /* old CQ */1429(new_status & 0xffc007ff); /* all other bits*/1430} else {1431*status = (*status & 0x04000000) | /* old Cbit */1432((new_status & 0x04000000) >> (y_field+4)) |1433(new_status & ~0x04000000 & /* other bits */1434~(0x04000000 >> (y_field+4)));1435}1436}1437/* if PA83, just update the C-bit */1438else {1439*status = new_status;1440}1441}144214431444