11.7Sandvar* $NetBSD: README,v 1.7 2021/08/21 23:00:31 andvar Exp $
21.1Sbriggs* NetBSD/m68k FPE (floating point emulation) README file
31.4Sbriggs* Created Oct/??/95 by kenn@remus.rutgers.edu (Ken Nakata)
41.5Stsutsui* Last updated Oct/15/2011 by tsutsui
51.1Sbriggs
61.1Sbriggs1. INSTALLATION AND COMPILATION
71.1Sbriggs
81.1SbriggsTo compile a kernel with FPE built-in, do the following:
91.1Sbriggs
101.2Sbriggs1) Add a line "options FPU_EMULATE" to your config file.  If you are
111.1Sbriggsgoing to use the resulted kernel on a machine with an FPU for
121.1Sbriggsdebugging purpose, add "options DEBUG_WITH_FPU" as well.
131.1Sbriggs
141.2Sbriggs2) Follow the usual procedure to build a new kernel.
151.1Sbriggs
161.1SbriggsNOTE:  If you add "options DEBUG_WITH_FPU", FPE will accept cpID=6 as
171.1Sbriggsemulated FPU.  You will need a modified gas that generates cpID=6 for
181.1Sbriggsfloating point instructions, instead of normal cpID=1.  Mount unionfs
191.4Sbriggsor copy the gas source directory and apply the following patch:
201.1Sbriggs
211.1Sbriggs*** /usr/src/gnu/usr.bin/gas/config/tc-m68k.c   Mon Nov 21 16:30:41 1994
221.1Sbriggs--- gas/config/tc-m68k.c    Fri Sep 29 07:59:06 1995
231.1Sbriggs***************
241.1Sbriggs*** 1275,1281 ****
251.1Sbriggs                /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */
261.1Sbriggs                memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0]));
271.1Sbriggs                the_ins.operands[0].mode=MSCR;
281.1Sbriggs!               the_ins.operands[0].reg=COPNUM;         /* COP #1 */
291.1Sbriggs                opsfound++;
301.1Sbriggs        }
311.1Sbriggs  
321.1Sbriggs--- 1275,1281 ----
331.1Sbriggs                /* memcpy((char *)(&the_ins.operands[1]), (char *)(&the_ins.operands[0]), opsfound*sizeof(the_ins.operands[0])); */
341.1Sbriggs                memset((char *)(&the_ins.operands[0]), '\0', sizeof(the_ins.operands[0]));
351.1Sbriggs                the_ins.operands[0].mode=MSCR;
361.1Sbriggs!               the_ins.operands[0].reg=COP5;           /* COP #6 */
371.1Sbriggs                opsfound++;
381.1Sbriggs        }
391.1Sbriggs  
401.1Sbriggs
411.1SbriggsAlso, with the DEBUG_WITH_FPU option, you will be able to run only ONE
421.1Sbriggsprocess that uses FPE at once to get correct results.
431.1Sbriggs
441.1Sbriggs
451.1Sbriggs2. MISSING PARTS
461.1Sbriggs
471.1SbriggsFor missing instructions, refer to the Section 3.  Other than that,
481.1Sbriggsthere is one thing that is missing from this version of FPE: packed
491.1SbriggsBCD support.
501.1Sbriggs
511.1SbriggsI have no plan to support it since it's rarely used.  However, all we
521.1Sbriggsneed to support it is explosion/implosion functions between the
531.1Sbriggsinternal FP representation and the m68k PBCD format, so you are more
541.1Sbriggsthan welcome to write such functions if you wish to.
551.1Sbriggs
561.1Sbriggs
571.1Sbriggs3. IMPLEMENTED INSTRUCTIONS
581.1Sbriggs
591.1SbriggsThis is the list of implemented and unimplemented FPU instructions.
601.4SbriggsAll 040's directly supported type 0 instructions are already
611.4Sbriggsimplemented except FSGLDIV and FSGLMUL.
621.1Sbriggs
631.1SbriggsType field = bit 8-6 of opcode word
641.1Sbriggs
651.1Sbriggs* Implemented Instructions
661.1Sbriggs
671.1SbriggsType=0: FMOVE (mem->FPr), FINT, FINTRZ, FSQRT, FABS, FNEG, FGETEXP,
681.4Sbriggs	FGETMAN, FDIV, FADD, FMUL, FSGLDIV(*), FSCALE, FSGLMUL(*), FSUB,
691.1Sbriggs	FCMP, FTST, FMOVE (FPr->mem), FMOVEM (FPr), FMOVEM (FPcr),
701.5Stsutsui	FMOVECR, FLOGNP1, FLOGN, FLOG10, FLOG2, FMOD, FREM,
711.6Sisaki	FCOSH, FSINH, FTANH, FCOS, FSIN, FTAN, FSINCOS,
721.6Sisaki	FETOX, FETOXM1, FTENTOX, FTWOTOX, FATANH, FACOS, FASIN, FATAN
731.1Sbriggs
741.1SbriggsType=1: FDBcc, FScc, FTRAPcc,
751.1Sbriggs
761.1SbriggsType=2: FBcc (word, incl. FNOP)
771.1Sbriggs
781.1SbriggsType=3: FBcc (long)
791.1Sbriggs
801.1SbriggsType=4: none
811.1Sbriggs
821.1SbriggsType=5: none
831.1Sbriggs
841.1Sbriggs	*: currently FSGLMUL and FSGLDIV are just aliases of
851.1Sbriggs	   FMUL and FDIV, respectively
861.1Sbriggs
871.1Sbriggs* Unimplemented Instructions
881.1Sbriggs
891.6SisakiType=0: none
901.1Sbriggs
911.1SbriggsType=1: none
921.1Sbriggs
931.1SbriggsType=2: none
941.1Sbriggs
951.1SbriggsType=3: none
961.1Sbriggs
971.1SbriggsType=4: FSAVE
981.1Sbriggs
991.1SbriggsType=5: FRESTORE
1001.1Sbriggs
1011.1Sbriggs
1021.1Sbriggs4. HOW TO ADD A NEW INSTRUCTION SUPPORT
1031.1Sbriggs
1041.1SbriggsSince we need not support FSAVE and FRESTORE operations, all
1051.1Sbriggsinstructions we have to implement are type 0, all of which are
1061.1Sbriggsarithmetic operations.  It is particularly easy to add a new
1071.1Sbriggsarithmetic instruction to the existing ones (not that it is easy to
1081.1Sbriggswrite a "stable" function to perform floating point operation. That's
1091.1Sbriggsentirely another matter).  In "fpu_emulate.c", there's a function
1101.1Sbriggsfpu_emul_arith() which calls emulation functions for all arithmetic
1111.1Sbriggsoperations.  In it, there's a large switch() { case ... } which
1121.1Sbriggsdispatches each instruction emulator.  An emulation function of any
1131.1Sbriggstype 0 arithmetic instruction follows this prototype:
1141.1Sbriggs
1151.1Sbriggs	struct fpn *fpu_op(struct fpemu *fe);
1161.1Sbriggs
1171.1SbriggsWhere fe is a pointer to a struct fpemu in which frame, fpframe, and
1181.1Sbriggsfetched operands are accessible.  That's right, you don't have to
1191.7Sandvarfetch the operands by yourself in your emulation function.  For
1201.1Sbriggsinstance, the parts calling FSQRT, FSUB, FADD and FTST look like:
1211.1Sbriggs
1221.1Sbriggs	switch(word1 & 0x3F) {
1231.1Sbriggs[...]
1241.1Sbriggs	case 0x04:	/* fsqrt */
1251.1Sbriggs		res = fpu_sqrt(fe);
1261.1Sbriggs		break;
1271.1Sbriggs[...]
1281.1Sbriggs	case 0x28:	/* fsub */
1291.1Sbriggs		fe->fe_f2.fp_sign = !fe->fe_f2.fp_sign; /* f2 = -f2 */
1301.1Sbriggs	case 0x22:	/* fadd */
1311.1Sbriggs		res = fpu_add(fe);
1321.1Sbriggs		break;
1331.1Sbriggs[...]
1341.1Sbriggs	case 0x3A:	/* ftst */
1351.1Sbriggs		res = &fe->fe_f2;
1361.1Sbriggs		no_store = 1;
1371.1Sbriggs		break;
1381.1Sbriggs[...]
1391.1Sbriggs	default:
1401.1Sbriggs		sig = SIGILL;
1411.1Sbriggs	} /* switch */
1421.1Sbriggs
1431.1SbriggsHere, fe->fe_f1 and fe->fe_f2 are fetched operands.  You can use
1441.1Sbriggsfe->fe_f3 for storing the result, or you can return a pointer to
1451.1Sbriggseither operand if you want to.  At any rate, you have to follow
1461.1Sbriggsthe following rules:
1471.1Sbriggs
1481.1Sbriggs	1) A dyadic instruction takes two operands fe->fe_f1 and fe->fe_f2.
1491.1Sbriggs	2) A monadic instruction takes one operands fe->fe_f2 (NOT fe_f1).
1501.1Sbriggs	3) Must return a pointer to struct fpn where the result is stored,
1511.1Sbriggs	and assign the pointer to the variable "res".
1521.1Sbriggs	4) If exceptions are detected, set corresponding bits in fe->fe_fpsr.
1531.1Sbriggs	The rest is taken care of in fpu_emul_arith().
1541.1Sbriggs	5) Condition code need not be calculated.  It's taken care of in
1551.1Sbriggs	fpu_emul_arith().
1561.1Sbriggs
1571.4SbriggsActually, after above was written, stubs for the missing functions were
1581.4Sbriggsadded to the source, so you do not have to change fpu_emul_arith() at
1591.4Sbriggsall.  Function names and prototypes are in fpu_arith_proto.h, and all
1601.4Sbriggsexcept fpu_sincos() follow the rules above.  fpu_sincos() is declared
1611.4Sbriggsas
1621.4Sbriggs
1631.4Sbriggs	struct fpn *fpu_sincos(struct fpemu *fe, int cosreg);
1641.4Sbriggs
1651.4Sbriggswhere cosreg is the FP register number to which cosine of the argument
1661.4Sbriggsis calculated and assigned.  Sine of the argument is stored into the
1671.4Sbriggsdestination register in the same manner as the other arithmetic
1681.4Sbriggsfunctions.
169